summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk8
-rw-r--r--api/3.xml15
-rw-r--r--api/current.xml9781
-rw-r--r--camera/libcameraservice/CameraHardwareStub.cpp55
-rw-r--r--camera/libcameraservice/CameraHardwareStub.h10
-rw-r--r--camera/libcameraservice/CameraService.cpp349
-rw-r--r--camera/libcameraservice/CameraService.h39
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java48
-rw-r--r--cmds/dumpstate/dumpstate.c33
-rw-r--r--cmds/dumpstate/dumpstate.h31
-rw-r--r--cmds/installd/commands.c13
-rw-r--r--core/java/android/app/Activity.java105
-rw-r--r--core/java/android/app/ActivityManager.java93
-rw-r--r--core/java/android/app/ActivityManagerNative.java89
-rw-r--r--core/java/android/app/ActivityThread.java202
-rw-r--r--core/java/android/app/ApplicationContext.java60
-rw-r--r--core/java/android/app/ApplicationThreadNative.java18
-rw-r--r--core/java/android/app/Dialog.java4
-rw-r--r--core/java/android/app/ExpandableListActivity.java23
-rw-r--r--core/java/android/app/IActivityManager.java18
-rw-r--r--core/java/android/app/IApplicationThread.java2
-rw-r--r--core/java/android/app/Instrumentation.java2
-rw-r--r--core/java/android/app/IntentService.java74
-rw-r--r--core/java/android/app/LauncherActivity.java278
-rw-r--r--core/java/android/app/ListActivity.java26
-rw-r--r--core/java/android/app/Notification.java9
-rw-r--r--core/java/android/app/NotificationManager.java4
-rw-r--r--core/java/android/app/PendingIntent.java13
-rw-r--r--core/java/android/app/SearchDialog.java193
-rw-r--r--core/java/android/app/SearchManager.java32
-rw-r--r--core/java/android/app/Service.java26
-rw-r--r--core/java/android/appwidget/AppWidgetHost.java248
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java312
-rw-r--r--core/java/android/appwidget/AppWidgetManager.java320
-rwxr-xr-xcore/java/android/appwidget/AppWidgetProvider.java154
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.aidl (renamed from core/java/android/os/HandlerInterface.java)30
-rw-r--r--core/java/android/appwidget/AppWidgetProviderInfo.java168
-rw-r--r--core/java/android/appwidget/package.html136
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java12
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java101
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java29
-rw-r--r--core/java/android/bluetooth/BluetoothIntent.java32
-rw-r--r--core/java/android/bluetooth/HeadsetBase.java33
-rw-r--r--core/java/android/bluetooth/IBluetoothDevice.aidl12
-rw-r--r--core/java/android/bluetooth/ScoSocket.java19
-rw-r--r--core/java/android/content/AsyncQueryHandler.java14
-rw-r--r--core/java/android/content/BroadcastReceiver.java32
-rw-r--r--core/java/android/content/ContentProvider.java139
-rw-r--r--core/java/android/content/ContentProviderNative.java43
-rw-r--r--core/java/android/content/ContentResolver.java320
-rw-r--r--core/java/android/content/ContentServiceNative.java7
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/content/IContentProvider.java4
-rw-r--r--core/java/android/content/Intent.java155
-rw-r--r--core/java/android/content/SyncManager.java42
-rw-r--r--core/java/android/content/TempProviderSyncAdapter.java24
-rw-r--r--core/java/android/content/package.html7
-rwxr-xr-xcore/java/android/content/pm/ConfigurationInfo.java5
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl7
-rw-r--r--core/java/android/content/pm/PackageInfo.java18
-rw-r--r--core/java/android/content/pm/PackageManager.java35
-rw-r--r--core/java/android/content/pm/PackageParser.java12
-rw-r--r--core/java/android/content/res/AssetFileDescriptor.java271
-rw-r--r--core/java/android/content/res/AssetManager.java4
-rw-r--r--core/java/android/content/res/ColorStateList.java36
-rw-r--r--core/java/android/content/res/Resources.java256
-rw-r--r--core/java/android/content/res/StringBlock.java62
-rw-r--r--core/java/android/content/res/TypedArray.java28
-rw-r--r--core/java/android/database/DatabaseUtils.java1
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java57
-rw-r--r--core/java/android/database/sqlite/SQLiteOpenHelper.java2
-rw-r--r--core/java/android/database/sqlite/SQLiteProgram.java2
-rw-r--r--core/java/android/database/sqlite/SQLiteQuery.java20
-rw-r--r--core/java/android/database/sqlite/SQLiteStatement.java56
-rw-r--r--core/java/android/database/sqlite/package.html2
-rw-r--r--core/java/android/emoji/EmojiFactory.java273
-rw-r--r--core/java/android/gadget/GadgetHost.java72
-rw-r--r--core/java/android/gadget/GadgetHostView.java102
-rw-r--r--core/java/android/gadget/GadgetInfo.java126
-rw-r--r--core/java/android/gadget/GadgetManager.java180
-rw-r--r--core/java/android/gadget/package.html4
-rw-r--r--core/java/android/hardware/Camera.java18
-rw-r--r--core/java/android/hardware/GeomagneticField.java409
-rw-r--r--core/java/android/hardware/ISensorService.aidl2
-rw-r--r--core/java/android/hardware/SensorManager.java33
-rw-r--r--core/java/android/inputmethodservice/AbstractInputMethodService.java10
-rw-r--r--core/java/android/inputmethodservice/ExtractButton.java30
-rw-r--r--core/java/android/inputmethodservice/ExtractEditText.java107
-rw-r--r--core/java/android/inputmethodservice/IInputMethodSessionWrapper.java9
-rw-r--r--core/java/android/inputmethodservice/IInputMethodWrapper.java98
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java967
-rwxr-xr-xcore/java/android/inputmethodservice/Keyboard.java67
-rwxr-xr-xcore/java/android/inputmethodservice/KeyboardView.java318
-rw-r--r--core/java/android/inputmethodservice/SoftInputWindow.java4
-rw-r--r--core/java/android/net/ConnectivityManager.java51
-rw-r--r--core/java/android/net/IConnectivityManager.aidl4
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java102
-rw-r--r--core/java/android/net/Uri.java9
-rw-r--r--core/java/android/net/UrlQuerySanitizer.java126
-rw-r--r--core/java/android/net/http/AndroidHttpClient.java68
-rw-r--r--core/java/android/net/http/CertificateChainValidator.java154
-rw-r--r--core/java/android/net/http/RequestHandle.java10
-rw-r--r--core/java/android/os/BatteryStats.java425
-rw-r--r--core/java/android/os/Binder.java44
-rw-r--r--core/java/android/os/Build.java3
-rw-r--r--core/java/android/os/Debug.java26
-rw-r--r--core/java/android/os/Environment.java12
-rw-r--r--core/java/android/os/IBinder.java11
-rw-r--r--core/java/android/os/ICheckinService.aidl9
-rw-r--r--core/java/android/os/IMountService.aidl27
-rw-r--r--core/java/android/os/INetStatService.aidl15
-rw-r--r--core/java/android/os/IPowerManager.aidl1
-rw-r--r--core/java/android/os/NetStat.java224
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java18
-rw-r--r--core/java/android/os/ResultReceiver.aidl (renamed from core/res/res/drawable/checkbox_background.xml)11
-rw-r--r--core/java/android/os/ResultReceiver.java130
-rw-r--r--core/java/android/package.html2
-rw-r--r--core/java/android/pim/ICalendar.java15
-rw-r--r--core/java/android/pim/RecurrenceSet.java1
-rw-r--r--core/java/android/preference/Preference.java7
-rw-r--r--core/java/android/preference/PreferenceActivity.java7
-rw-r--r--core/java/android/preference/PreferenceGroup.java4
-rw-r--r--core/java/android/preference/PreferenceGroupAdapter.java5
-rw-r--r--core/java/android/preference/PreferenceScreen.java1
-rw-r--r--core/java/android/preference/VolumePreference.java7
-rw-r--r--core/java/android/provider/Browser.java12
-rw-r--r--core/java/android/provider/Checkin.java36
-rw-r--r--core/java/android/provider/Contacts.java75
-rw-r--r--core/java/android/provider/Gmail.java112
-rw-r--r--core/java/android/provider/Im.java137
-rw-r--r--core/java/android/provider/MediaStore.java74
-rw-r--r--core/java/android/provider/Settings.java168
-rw-r--r--core/java/android/provider/Sync.java37
-rw-r--r--core/java/android/provider/Telephony.java5
-rw-r--r--core/java/android/provider/UserDictionary.java23
-rw-r--r--core/java/android/provider/package.html2
-rw-r--r--core/java/android/server/BluetoothA2dpService.java125
-rw-r--r--core/java/android/server/BluetoothDeviceService.java521
-rw-r--r--core/java/android/server/BluetoothEventLoop.java196
-rw-r--r--core/java/android/server/checkin/CheckinProvider.java388
-rw-r--r--core/java/android/server/checkin/FallbackCheckinService.java49
-rw-r--r--core/java/android/server/checkin/package.html5
-rw-r--r--core/java/android/server/search/SearchableInfo.java112
-rw-r--r--core/java/android/speech/RecognizerIntent.java73
-rw-r--r--core/java/android/speech/srec/MicrophoneInputStream.java12
-rw-r--r--core/java/android/speech/srec/package.html1
-rw-r--r--core/java/android/text/Annotation.java26
-rw-r--r--core/java/android/text/Html.java36
-rw-r--r--core/java/android/text/InputType.java46
-rw-r--r--core/java/android/text/NoCopySpan.java31
-rw-r--r--core/java/android/text/ParcelableSpan.java (renamed from location/java/com/android/internal/location/protocol/GAddress.java)20
-rw-r--r--core/java/android/text/Selection.java6
-rw-r--r--core/java/android/text/SpanWatcher.java2
-rw-r--r--core/java/android/text/SpannableStringBuilder.java4
-rw-r--r--core/java/android/text/Spanned.java8
-rw-r--r--core/java/android/text/StaticLayout.java78
-rw-r--r--core/java/android/text/Styled.java249
-rw-r--r--core/java/android/text/TextUtils.java265
-rw-r--r--core/java/android/text/TextWatcher.java2
-rw-r--r--core/java/android/text/format/DateFormat.java29
-rw-r--r--core/java/android/text/format/DateUtils.java216
-rw-r--r--core/java/android/text/format/Time.java1
-rw-r--r--core/java/android/text/method/ArrowKeyMovementMethod.java27
-rw-r--r--core/java/android/text/method/BaseKeyListener.java33
-rw-r--r--core/java/android/text/method/KeyListener.java7
-rw-r--r--core/java/android/text/method/LinkMovementMethod.java2
-rw-r--r--core/java/android/text/method/MetaKeyKeyListener.java30
-rw-r--r--core/java/android/text/method/MovementMethod.java8
-rw-r--r--core/java/android/text/method/NumberKeyListener.java6
-rw-r--r--core/java/android/text/method/PasswordTransformationMethod.java10
-rw-r--r--core/java/android/text/method/QwertyKeyListener.java37
-rw-r--r--core/java/android/text/method/ScrollingMovementMethod.java24
-rw-r--r--core/java/android/text/method/SingleLineTransformationMethod.java12
-rw-r--r--core/java/android/text/method/TextKeyListener.java19
-rw-r--r--core/java/android/text/method/Touch.java5
-rw-r--r--core/java/android/text/style/AbsoluteSizeSpan.java24
-rw-r--r--core/java/android/text/style/AlignmentSpan.java28
-rw-r--r--core/java/android/text/style/BackgroundColorSpan.java24
-rw-r--r--core/java/android/text/style/BulletSpan.java42
-rw-r--r--core/java/android/text/style/ForegroundColorSpan.java24
-rw-r--r--core/java/android/text/style/ImageSpan.java8
-rw-r--r--core/java/android/text/style/LeadingMarginSpan.java29
-rw-r--r--core/java/android/text/style/QuoteSpan.java29
-rw-r--r--core/java/android/text/style/RelativeSizeSpan.java24
-rw-r--r--core/java/android/text/style/ScaleXSpan.java24
-rw-r--r--core/java/android/text/style/StrikethroughSpan.java22
-rw-r--r--core/java/android/text/style/StyleSpan.java23
-rw-r--r--core/java/android/text/style/SubscriptSpan.java22
-rw-r--r--core/java/android/text/style/SuperscriptSpan.java22
-rw-r--r--core/java/android/text/style/TextAppearanceSpan.java70
-rw-r--r--core/java/android/text/style/TypefaceSpan.java23
-rw-r--r--core/java/android/text/style/URLSpan.java31
-rw-r--r--core/java/android/text/style/UnderlineSpan.java22
-rw-r--r--core/java/android/text/util/Regex.java12
-rw-r--r--core/java/android/text/util/Rfc822Validator.java12
-rw-r--r--core/java/android/util/DisplayMetrics.java27
-rw-r--r--core/java/android/util/SparseIntArray.java13
-rw-r--r--core/java/android/util/TypedValue.java23
-rw-r--r--core/java/android/view/FocusFinder.java2
-rw-r--r--core/java/android/view/GestureDetector.java264
-rw-r--r--core/java/android/view/HapticFeedbackConstants.java42
-rw-r--r--core/java/android/view/IWindowManager.aidl3
-rw-r--r--core/java/android/view/IWindowSession.aidl3
-rw-r--r--core/java/android/view/KeyCharacterMap.java24
-rw-r--r--core/java/android/view/KeyEvent.java80
-rwxr-xr-xcore/java/android/view/OrientationEventListener.java174
-rw-r--r--core/java/android/view/OrientationListener.java99
-rw-r--r--core/java/android/view/RemotableViewMethod.java (renamed from location/java/com/android/internal/location/protocol/GrectangleMessageTypes.java)27
-rw-r--r--core/java/android/view/SurfaceHolder.java2
-rw-r--r--core/java/android/view/TouchDelegate.java12
-rw-r--r--core/java/android/view/View.java483
-rw-r--r--core/java/android/view/ViewConfiguration.java231
-rw-r--r--core/java/android/view/ViewDebug.java376
-rw-r--r--core/java/android/view/ViewGroup.java73
-rw-r--r--core/java/android/view/ViewRoot.java252
-rw-r--r--core/java/android/view/ViewTreeObserver.java66
-rw-r--r--core/java/android/view/VolumePanel.java122
-rw-r--r--core/java/android/view/Window.java15
-rw-r--r--core/java/android/view/WindowManager.java55
-rw-r--r--core/java/android/view/WindowManagerPolicy.java49
-rwxr-xr-xcore/java/android/view/WindowOrientationListener.java196
-rw-r--r--core/java/android/view/animation/AlphaAnimation.java2
-rw-r--r--core/java/android/view/animation/Animation.java108
-rw-r--r--core/java/android/view/animation/AnimationSet.java100
-rw-r--r--core/java/android/view/animation/LayoutAnimationController.java156
-rw-r--r--core/java/android/view/animation/RotateAnimation.java2
-rw-r--r--core/java/android/view/animation/ScaleAnimation.java2
-rw-r--r--core/java/android/view/animation/TranslateAnimation.java2
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java525
-rw-r--r--core/java/android/view/inputmethod/DefaultInputMethod.java239
-rw-r--r--core/java/android/view/inputmethod/EditorInfo.java157
-rw-r--r--core/java/android/view/inputmethod/ExtractedText.java27
-rw-r--r--core/java/android/view/inputmethod/ExtractedTextRequest.java9
-rw-r--r--core/java/android/view/inputmethod/InputConnection.java108
-rw-r--r--core/java/android/view/inputmethod/InputConnectionWrapper.java74
-rw-r--r--core/java/android/view/inputmethod/InputMethod.java44
-rw-r--r--core/java/android/view/inputmethod/InputMethodInfo.java17
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java757
-rw-r--r--core/java/android/view/inputmethod/InputMethodSession.java12
-rw-r--r--core/java/android/view/inputmethod/MutableInputConnectionWrapper.java38
-rw-r--r--core/java/android/webkit/BrowserFrame.java25
-rw-r--r--core/java/android/webkit/ByteArrayBuilder.java8
-rw-r--r--core/java/android/webkit/CacheManager.java3
-rw-r--r--core/java/android/webkit/CallbackProxy.java14
-rw-r--r--core/java/android/webkit/CookieManager.java16
-rw-r--r--core/java/android/webkit/FileLoader.java8
-rw-r--r--core/java/android/webkit/FrameLoader.java14
-rw-r--r--core/java/android/webkit/LoadListener.java239
-rw-r--r--core/java/android/webkit/MimeTypeMap.java1
-rw-r--r--core/java/android/webkit/PluginContentLoader.java96
-rw-r--r--core/java/android/webkit/PluginData.java116
-rw-r--r--core/java/android/webkit/TextDialog.java181
-rw-r--r--core/java/android/webkit/UrlInterceptHandler.java15
-rw-r--r--core/java/android/webkit/UrlInterceptRegistry.java34
-rw-r--r--core/java/android/webkit/WebSettings.java25
-rw-r--r--core/java/android/webkit/WebView.java746
-rw-r--r--core/java/android/webkit/WebViewCore.java94
-rw-r--r--core/java/android/webkit/WebViewDatabase.java47
-rw-r--r--core/java/android/webkit/gears/DesktopAndroid.java6
-rw-r--r--core/java/android/webkit/gears/GearsPluginSettings.java95
-rw-r--r--core/java/android/webkit/gears/HtmlDialogAndroid.java174
-rw-r--r--core/java/android/webkit/gears/HttpRequestAndroid.java745
-rw-r--r--core/java/android/webkit/gears/IGearsDialogService.java107
-rw-r--r--core/java/android/webkit/gears/UrlInterceptHandlerGears.java164
-rw-r--r--core/java/android/widget/AbsListView.java180
-rw-r--r--core/java/android/widget/AbsSeekBar.java45
-rw-r--r--core/java/android/widget/Adapter.java2
-rw-r--r--core/java/android/widget/AnalogClock.java19
-rw-r--r--core/java/android/widget/ArrayAdapter.java13
-rw-r--r--core/java/android/widget/AutoCompleteTextView.java209
-rw-r--r--core/java/android/widget/BaseAdapter.java4
-rw-r--r--core/java/android/widget/Chronometer.java67
-rw-r--r--core/java/android/widget/CompoundButton.java7
-rw-r--r--core/java/android/widget/CursorAdapter.java20
-rw-r--r--core/java/android/widget/CursorFilter.java5
-rw-r--r--core/java/android/widget/DatePicker.java27
-rw-r--r--core/java/android/widget/ExpandableListView.java16
-rw-r--r--core/java/android/widget/FastScroller.java39
-rw-r--r--core/java/android/widget/Filter.java31
-rw-r--r--core/java/android/widget/FrameLayout.java2
-rw-r--r--core/java/android/widget/Gallery.java8
-rw-r--r--core/java/android/widget/GridView.java33
-rw-r--r--core/java/android/widget/HorizontalScrollView.java1197
-rw-r--r--core/java/android/widget/ImageView.java16
-rw-r--r--core/java/android/widget/LinearLayout.java17
-rw-r--r--core/java/android/widget/ListView.java161
-rw-r--r--core/java/android/widget/MediaController.java1
-rw-r--r--core/java/android/widget/MultiAutoCompleteTextView.java4
-rw-r--r--core/java/android/widget/PopupWindow.java244
-rw-r--r--core/java/android/widget/ProgressBar.java9
-rw-r--r--core/java/android/widget/RadioGroup.java17
-rw-r--r--core/java/android/widget/RelativeLayout.java29
-rw-r--r--core/java/android/widget/RemoteViews.aidl (renamed from core/java/android/gadget/GadgetInfo.aidl)4
-rw-r--r--core/java/android/widget/RemoteViews.java693
-rw-r--r--core/java/android/widget/ResourceCursorAdapter.java22
-rw-r--r--core/java/android/widget/ScrollBarDrawable.java8
-rw-r--r--core/java/android/widget/ScrollView.java44
-rw-r--r--core/java/android/widget/Scroller.java20
-rw-r--r--core/java/android/widget/SimpleAdapter.java27
-rw-r--r--core/java/android/widget/SlidingDrawer.java (renamed from core/java/com/android/internal/widget/SlidingDrawer.java)98
-rw-r--r--core/java/android/widget/TabHost.java6
-rw-r--r--core/java/android/widget/TextView.java1403
-rw-r--r--core/java/android/widget/VideoView.java33
-rw-r--r--core/java/android/widget/ViewAnimator.java53
-rw-r--r--core/java/android/widget/ViewFlipper.java4
-rw-r--r--core/java/android/widget/ZoomButton.java4
-rw-r--r--core/java/android/widget/ZoomButtonsController.java848
-rw-r--r--core/java/android/widget/ZoomControls.java8
-rw-r--r--core/java/com/android/internal/app/ExternalMediaFormatActivity.java114
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl8
-rwxr-xr-x[-rw-r--r--]core/java/com/android/internal/app/IUsageStats.aidl (renamed from tests/GadgetHost/src/com/android/gadgethost/TestGadgetProvider.java)21
-rw-r--r--core/java/com/android/internal/app/UsbStorageStopActivity.java123
-rw-r--r--core/java/com/android/internal/appwidget/IAppWidgetHost.aidl (renamed from core/java/com/android/internal/gadget/IGadgetService.aidl)15
-rw-r--r--core/java/com/android/internal/appwidget/IAppWidgetService.aidl50
-rw-r--r--core/java/com/android/internal/appwidget/package.html (renamed from core/java/com/android/internal/gadget/package.html)0
-rw-r--r--core/java/com/android/internal/logging/AndroidConfig.java11
-rw-r--r--core/java/com/android/internal/logging/AndroidHandler.java69
-rw-r--r--core/java/com/android/internal/net/DbSSLSessionCache.java289
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java929
-rw-r--r--core/java/com/android/internal/os/HandlerCaller.java17
-rw-r--r--core/java/com/android/internal/os/HandlerThread.java91
-rw-r--r--core/java/com/android/internal/os/IResultReceiver.aidl25
-rwxr-xr-x[-rw-r--r--]core/java/com/android/internal/os/PkgUsageStats.aidl (renamed from core/res/res/drawable/radiobutton_background.xml)11
-rwxr-xr-xcore/java/com/android/internal/os/PkgUsageStats.java60
-rw-r--r--core/java/com/android/internal/os/RecoverySystem.java128
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java83
-rw-r--r--core/java/com/android/internal/view/IInputConnectionWrapper.java203
-rw-r--r--core/java/com/android/internal/view/IInputContext.aidl16
-rw-r--r--core/java/com/android/internal/view/IInputMethod.aidl9
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl15
-rw-r--r--core/java/com/android/internal/view/IInputMethodSession.aidl2
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java48
-rw-r--r--core/java/com/android/internal/view/menu/ExpandedMenuView.java5
-rw-r--r--core/java/com/android/internal/view/menu/IconMenuItemView.java5
-rw-r--r--core/java/com/android/internal/view/menu/ListMenuItemView.java4
-rw-r--r--core/java/com/android/internal/widget/EditStyledText.java931
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java328
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java42
-rw-r--r--core/java/com/android/internal/widget/NumberPicker.java99
-rw-r--r--core/java/com/android/internal/widget/TextProgressBar.java180
-rw-r--r--core/java/com/google/android/gdata/client/AndroidGDataClient.java21
-rw-r--r--core/java/com/google/android/net/GoogleHttpClient.java102
-rw-r--r--core/java/com/google/android/net/NetStats.java47
-rw-r--r--core/java/com/google/android/net/NetworkStatsEntity.java85
-rw-r--r--core/java/com/google/android/net/SSLClientSessionCacheFactory.java62
-rw-r--r--core/java/com/google/android/util/GoogleWebContentHelper.java2
-rw-r--r--core/java/com/google/android/util/SimplePullParser.java25
-rw-r--r--core/jni/Android.mk13
-rw-r--r--core/jni/AndroidRuntime.cpp73
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp50
-rw-r--r--core/jni/android/graphics/Canvas.cpp36
-rw-r--r--core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp26
-rw-r--r--core/jni/android/graphics/Graphics.cpp11
-rw-r--r--core/jni/android/graphics/GraphicsJNI.h1
-rw-r--r--core/jni/android/graphics/NinePatch.cpp25
-rw-r--r--core/jni/android/graphics/Typeface.cpp6
-rwxr-xr-xcore/jni/android_bluetooth_BluetoothAudioGateway.cpp2
-rw-r--r--core/jni/android_database_SQLiteDatabase.cpp8
-rw-r--r--core/jni/android_emoji_EmojiFactory.cpp292
-rw-r--r--core/jni/android_hardware_Camera.cpp289
-rw-r--r--core/jni/android_media_AudioRecord.cpp47
-rw-r--r--core/jni/android_media_AudioSystem.cpp14
-rw-r--r--core/jni/android_media_AudioTrack.cpp217
-rw-r--r--core/jni/android_media_JetPlayer.cpp87
-rw-r--r--core/jni/android_net_wifi_Wifi.cpp32
-rw-r--r--core/jni/android_os_Debug.cpp136
-rw-r--r--core/jni/android_os_NetStat.cpp158
-rw-r--r--core/jni/android_os_ParcelFileDescriptor.cpp57
-rw-r--r--core/jni/android_server_BluetoothDeviceService.cpp213
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp271
-rw-r--r--core/jni/android_text_format_Time.cpp146
-rw-r--r--core/jni/android_util_AssetManager.cpp17
-rw-r--r--core/jni/android_util_Binder.cpp1
-rw-r--r--core/jni/android_util_EventLog.cpp2
-rw-r--r--core/jni/android_view_Surface.cpp12
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp2
-rw-r--r--core/res/Android.mk2
-rw-r--r--core/res/AndroidManifest.xml88
-rw-r--r--core/res/assets/webkit/nullPlugin.png (renamed from core/res/assets/webkit/nullplugin.png)bin1552 -> 1552 bytes
-rw-r--r--core/res/res/anim/app_starting_exit.xml2
-rw-r--r--core/res/res/anim/dialog_enter.xml8
-rw-r--r--core/res/res/anim/dialog_exit.xml8
-rw-r--r--core/res/res/anim/fade_in.xml5
-rw-r--r--core/res/res/anim/fade_out.xml2
-rw-r--r--core/res/res/anim/grow_fade_in.xml7
-rw-r--r--core/res/res/anim/grow_fade_in_center.xml7
-rw-r--r--core/res/res/anim/grow_fade_in_from_bottom.xml7
-rw-r--r--core/res/res/anim/input_method_enter.xml11
-rw-r--r--core/res/res/anim/input_method_exit.xml11
-rw-r--r--core/res/res/anim/input_method_fancy_enter.xml (renamed from core/res/res/drawable/checkbox.xml)20
-rw-r--r--core/res/res/anim/input_method_fancy_exit.xml28
-rw-r--r--core/res/res/anim/lock_screen_exit.xml (renamed from core/res/res/drawable/radiobutton.xml)14
-rw-r--r--core/res/res/anim/options_panel_enter.xml6
-rw-r--r--core/res/res/anim/options_panel_exit.xml6
-rw-r--r--core/res/res/anim/push_down_in.xml6
-rw-r--r--core/res/res/anim/push_down_out.xml6
-rw-r--r--core/res/res/anim/push_up_in.xml6
-rw-r--r--core/res/res/anim/push_up_out.xml6
-rw-r--r--core/res/res/anim/search_bar_enter.xml6
-rw-r--r--core/res/res/anim/search_bar_exit.xml6
-rw-r--r--core/res/res/anim/shrink_fade_out.xml7
-rw-r--r--core/res/res/anim/shrink_fade_out_center.xml7
-rw-r--r--core/res/res/anim/shrink_fade_out_from_bottom.xml7
-rw-r--r--core/res/res/anim/slide_in_bottom.xml6
-rw-r--r--core/res/res/anim/slide_in_child_bottom.xml6
-rw-r--r--core/res/res/anim/slide_in_left.xml6
-rw-r--r--core/res/res/anim/slide_in_right.xml6
-rw-r--r--core/res/res/anim/slide_in_top.xml6
-rw-r--r--core/res/res/anim/slide_out_bottom.xml6
-rw-r--r--core/res/res/anim/slide_out_left.xml6
-rw-r--r--core/res/res/anim/slide_out_right.xml6
-rw-r--r--core/res/res/anim/slide_out_top.xml6
-rw-r--r--core/res/res/anim/status_bar_enter.xml6
-rw-r--r--core/res/res/anim/status_bar_exit.xml6
-rw-r--r--core/res/res/anim/submenu_enter.xml6
-rw-r--r--core/res/res/anim/submenu_exit.xml6
-rw-r--r--core/res/res/anim/task_close_enter.xml3
-rw-r--r--core/res/res/anim/task_close_exit.xml3
-rw-r--r--core/res/res/anim/task_open_enter.xml3
-rw-r--r--core/res/res/anim/task_open_exit.xml3
-rw-r--r--core/res/res/anim/toast_enter.xml3
-rw-r--r--core/res/res/anim/toast_exit.xml3
-rw-r--r--core/res/res/color/tertiary_text_dark.xml2
-rw-r--r--core/res/res/drawable-land/statusbar_background.pngbin3844 -> 4995 bytes
-rw-r--r--core/res/res/drawable-land/title_bar_tall.pngbin0 -> 18449 bytes
-rw-r--r--core/res/res/drawable/activity_title_bar.9.pngbin0 -> 205 bytes
-rw-r--r--core/res/res/drawable/btn_browser_zoom_fit_page.xml20
-rw-r--r--core/res/res/drawable/btn_browser_zoom_page_overview.xml20
-rw-r--r--core/res/res/drawable/btn_check_off_disable.pngbin1142 -> 903 bytes
-rw-r--r--core/res/res/drawable/btn_check_off_disable_focused.pngbin1243 -> 1073 bytes
-rw-r--r--core/res/res/drawable/btn_check_off_pressed.pngbin1513 -> 1630 bytes
-rw-r--r--core/res/res/drawable/btn_check_off_selected.pngbin1520 -> 1598 bytes
-rw-r--r--core/res/res/drawable/btn_check_on_disable.pngbin1268 -> 973 bytes
-rw-r--r--core/res/res/drawable/btn_check_on_disable_focused.pngbin1341 -> 1138 bytes
-rw-r--r--core/res/res/drawable/btn_check_on_pressed.pngbin1575 -> 1680 bytes
-rw-r--r--core/res/res/drawable/btn_check_on_selected.pngbin1589 -> 1661 bytes
-rw-r--r--core/res/res/drawable/btn_circle.xml32
-rw-r--r--core/res/res/drawable/btn_circle_disable.pngbin0 -> 938 bytes
-rw-r--r--core/res/res/drawable/btn_circle_disable_focused.pngbin0 -> 1436 bytes
-rw-r--r--core/res/res/drawable/btn_circle_longpress.pngbin0 -> 1590 bytes
-rw-r--r--core/res/res/drawable/btn_circle_normal.pngbin0 -> 1249 bytes
-rw-r--r--core/res/res/drawable/btn_circle_pressed.pngbin0 -> 1613 bytes
-rw-r--r--core/res/res/drawable/btn_circle_selected.pngbin0 -> 1645 bytes
-rw-r--r--core/res/res/drawable/btn_default_normal.9.pngbin836 -> 763 bytes
-rw-r--r--core/res/res/drawable/btn_default_normal_disable.9.pngbin3452 -> 474 bytes
-rw-r--r--core/res/res/drawable/btn_default_normal_disable_focused.9.pngbin3574 -> 673 bytes
-rw-r--r--core/res/res/drawable/btn_default_pressed.9.pngbin1134 -> 1083 bytes
-rw-r--r--core/res/res/drawable/btn_default_selected.9.pngbin1117 -> 1099 bytes
-rw-r--r--core/res/res/drawable/btn_default_small_normal.9.pngbin790 -> 679 bytes
-rw-r--r--core/res/res/drawable/btn_default_small_normal_disable.9.pngbin721 -> 456 bytes
-rw-r--r--core/res/res/drawable/btn_default_small_normal_disable_focused.9.pngbin834 -> 648 bytes
-rw-r--r--core/res/res/drawable/btn_default_small_pressed.9.pngbin982 -> 936 bytes
-rw-r--r--core/res/res/drawable/btn_default_small_selected.9.pngbin1017 -> 964 bytes
-rw-r--r--core/res/res/drawable/btn_keyboard_key_normal.9.pngbin737 -> 726 bytes
-rw-r--r--core/res/res/drawable/btn_keyboard_key_normal_off.9.pngbin877 -> 860 bytes
-rw-r--r--core/res/res/drawable/btn_keyboard_key_normal_on.9.pngbin949 -> 926 bytes
-rwxr-xr-xcore/res/res/drawable/btn_keyboard_key_pressed.9.pngbin732 -> 664 bytes
-rw-r--r--core/res/res/drawable/btn_keyboard_key_pressed_off.9.pngbin895 -> 836 bytes
-rw-r--r--core/res/res/drawable/btn_keyboard_key_pressed_on.9.pngbin947 -> 886 bytes
-rw-r--r--core/res/res/drawable/btn_radio_off_pressed.pngbin1864 -> 1928 bytes
-rw-r--r--core/res/res/drawable/btn_radio_off_selected.pngbin1852 -> 1954 bytes
-rw-r--r--core/res/res/drawable/btn_radio_on.pngbin1700 -> 1692 bytes
-rw-r--r--core/res/res/drawable/btn_radio_on_pressed.pngbin1978 -> 1997 bytes
-rw-r--r--core/res/res/drawable/btn_radio_on_selected.pngbin1954 -> 2009 bytes
-rw-r--r--core/res/res/drawable/btn_rating_star_off_normal.pngbin3036 -> 2760 bytes
-rw-r--r--core/res/res/drawable/btn_rating_star_off_pressed.pngbin3882 -> 3613 bytes
-rw-r--r--core/res/res/drawable/btn_rating_star_off_selected.pngbin3870 -> 3622 bytes
-rw-r--r--core/res/res/drawable/btn_rating_star_on_normal.pngbin3469 -> 3290 bytes
-rw-r--r--core/res/res/drawable/btn_rating_star_on_pressed.pngbin3905 -> 3756 bytes
-rw-r--r--core/res/res/drawable/btn_rating_star_on_selected.pngbin3950 -> 3768 bytes
-rw-r--r--core/res/res/drawable/btn_square_overlay.xml26
-rw-r--r--core/res/res/drawable/btn_square_overlay_disabled.pngbin0 -> 653 bytes
-rw-r--r--core/res/res/drawable/btn_square_overlay_disabled_focused.pngbin0 -> 826 bytes
-rw-r--r--core/res/res/drawable/btn_square_overlay_normal.pngbin0 -> 910 bytes
-rw-r--r--core/res/res/drawable/btn_square_overlay_pressed.pngbin0 -> 1201 bytes
-rw-r--r--core/res/res/drawable/btn_square_overlay_selected.pngbin0 -> 1237 bytes
-rwxr-xr-xcore/res/res/drawable/btn_star_big_off.pngbin1460 -> 1316 bytes
-rwxr-xr-xcore/res/res/drawable/btn_star_big_off_pressed.pngbin4401 -> 1507 bytes
-rwxr-xr-xcore/res/res/drawable/btn_star_big_off_selected.pngbin4407 -> 1471 bytes
-rwxr-xr-xcore/res/res/drawable/btn_star_big_on.pngbin4449 -> 1521 bytes
-rwxr-xr-xcore/res/res/drawable/btn_star_big_on_pressed.pngbin4249 -> 1540 bytes
-rwxr-xr-xcore/res/res/drawable/btn_star_big_on_selected.pngbin4232 -> 1456 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_down.xml27
-rw-r--r--core/res/res/drawable/btn_zoom_down_disabled.9.pngbin0 -> 1455 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_down_disabled_focused.9.pngbin0 -> 1804 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_down_longpress.9.pngbin0 -> 2492 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_down_normal.9.pngbin0 -> 1983 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_down_pressed.9.pngbin0 -> 2522 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_down_selected.9.pngbin0 -> 2532 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_up.xml27
-rw-r--r--core/res/res/drawable/btn_zoom_up_disabled.9.pngbin0 -> 1445 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_up_disabled_focused.9.pngbin0 -> 1798 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_up_longpress.9.pngbin0 -> 2513 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_up_normal.9.pngbin0 -> 1962 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_up_pressed.9.pngbin0 -> 2547 bytes
-rw-r--r--core/res/res/drawable/btn_zoom_up_selected.9.pngbin0 -> 2540 bytes
-rw-r--r--core/res/res/drawable/checkbox_label_background.9.pngbin2863 -> 0 bytes
-rw-r--r--core/res/res/drawable/checkbox_off_background_focus_yellow.pngbin3320 -> 0 bytes
-rw-r--r--core/res/res/drawable/checkbox_on_background_focus_yellow.pngbin3570 -> 0 bytes
-rw-r--r--core/res/res/drawable/dark_header.9.pngbin0 -> 179 bytes
-rw-r--r--core/res/res/drawable/divider_horizontal_bright.9.pngbin207 -> 240 bytes
-rw-r--r--core/res/res/drawable/divider_horizontal_dark.9.pngbin219 -> 232 bytes
-rw-r--r--core/res/res/drawable/divider_horizontal_dim_dark.9.pngbin201 -> 232 bytes
-rw-r--r--core/res/res/drawable/extract_edit_text.xml21
-rw-r--r--core/res/res/drawable/ic_btn_round_more.xml22
-rw-r--r--core/res/res/drawable/ic_btn_round_more_disabled.pngbin0 -> 421 bytes
-rw-r--r--core/res/res/drawable/ic_btn_round_more_normal.pngbin0 -> 968 bytes
-rw-r--r--core/res/res/drawable/ic_btn_speak_now.pngbin0 -> 954 bytes
-rw-r--r--core/res/res/drawable/ic_btn_square_browser_zoom_fit_page.xml20
-rw-r--r--core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_disabled.pngbin0 -> 291 bytes
-rw-r--r--core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_normal.pngbin0 -> 439 bytes
-rw-r--r--core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.pngbin0 -> 839 bytes
-rwxr-xr-xcore/res/res/drawable/ic_lock_airplane_mode.pngbin0 -> 1119 bytes
-rwxr-xr-xcore/res/res/drawable/ic_lock_airplane_mode_off.pngbin0 -> 1570 bytes
-rw-r--r--core/res/res/drawable/ic_lock_power_off.pngbin1713 -> 1709 bytes
-rw-r--r--core/res/res/drawable/ic_lock_silent_mode.pngbin1362 -> 1362 bytes
-rw-r--r--core/res/res/drawable/ic_lock_silent_mode_off.pngbin1555 -> 1554 bytes
-rw-r--r--core/res/res/drawable/keyboard_accessory_bg_landscape.9.pngbin0 -> 197 bytes
-rw-r--r--core/res/res/drawable/keyboard_background.9.pngbin203 -> 189 bytes
-rw-r--r--core/res/res/drawable/keyboard_suggest_strip_shadow.9.pngbin0 -> 165 bytes
-rw-r--r--core/res/res/drawable/keyboard_textfield_selected.9.pngbin0 -> 782 bytes
-rw-r--r--core/res/res/drawable/menu_background.9.pngbin3385 -> 3390 bytes
-rw-r--r--core/res/res/drawable/popup_inline_error_above.9.pngbin0 -> 2043 bytes
-rw-r--r--core/res/res/drawable/presence_away.pngbin3500 -> 810 bytes
-rw-r--r--core/res/res/drawable/presence_busy.pngbin3529 -> 811 bytes
-rw-r--r--core/res/res/drawable/presence_invisible.pngbin1084 -> 693 bytes
-rw-r--r--core/res/res/drawable/presence_offline.pngbin3577 -> 767 bytes
-rw-r--r--core/res/res/drawable/presence_online.pngbin3528 -> 812 bytes
-rw-r--r--core/res/res/drawable/radiobutton_label_background.9.pngbin2863 -> 0 bytes
-rw-r--r--core/res/res/drawable/radiobutton_off_background_focus_yellow.pngbin3670 -> 0 bytes
-rw-r--r--core/res/res/drawable/radiobutton_on_background_focus_yellow.pngbin3736 -> 0 bytes
-rwxr-xr-xcore/res/res/drawable/scrollbar_handle_accelerated_anim2.9.pngbin1115 -> 1144 bytes
-rwxr-xr-xcore/res/res/drawable/scrollbar_handle_horizontal.9.pngbin316 -> 266 bytes
-rwxr-xr-xcore/res/res/drawable/scrollbar_handle_vertical.9.pngbin334 -> 254 bytes
-rw-r--r--core/res/res/drawable/seek_thumb.xml2
-rw-r--r--core/res/res/drawable/seek_thumb_normal.pngbin970 -> 880 bytes
-rw-r--r--core/res/res/drawable/seek_thumb_pressed.pngbin970 -> 1073 bytes
-rw-r--r--core/res/res/drawable/seek_thumb_selected.pngbin970 -> 1090 bytes
-rw-r--r--core/res/res/drawable/stat_sys_phone_call.pngbin772 -> 773 bytes
-rw-r--r--core/res/res/drawable/stat_sys_phone_call_bluetooth.pngbin0 -> 815 bytes
-rw-r--r--core/res/res/drawable/stat_sys_ringer_silent.pngbin906 -> 767 bytes
-rw-r--r--[-rwxr-xr-x]core/res/res/drawable/stat_sys_signal_flightmode.pngbin818 -> 898 bytes
-rw-r--r--core/res/res/drawable/statusbar_background.pngbin3677 -> 3519 bytes
-rw-r--r--core/res/res/drawable/sym_action_add.pngbin0 -> 930 bytes
-rw-r--r--core/res/res/drawable/sym_action_call.pngbin3568 -> 904 bytes
-rw-r--r--core/res/res/drawable/sym_action_chat.pngbin3407 -> 808 bytes
-rw-r--r--core/res/res/drawable/sym_action_email.pngbin3385 -> 791 bytes
-rw-r--r--core/res/res/drawable/sym_action_map.pngbin3779 -> 0 bytes
-rw-r--r--core/res/res/drawable/sym_action_sms.pngbin3409 -> 0 bytes
-rw-r--r--core/res/res/drawable/textfield_default.9.pngbin604 -> 758 bytes
-rw-r--r--core/res/res/drawable/textfield_disabled.9.pngbin521 -> 545 bytes
-rw-r--r--[-rwxr-xr-x]core/res/res/drawable/textfield_disabled_selected.9.pngbin629 -> 570 bytes
-rw-r--r--core/res/res/drawable/textfield_pressed.9.pngbin794 -> 1040 bytes
-rw-r--r--core/res/res/drawable/textfield_selected.9.pngbin801 -> 790 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_down_disabled.9.pngbin956 -> 444 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_down_disabled_focused.9.pngbin938 -> 611 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_down_normal.9.pngbin884 -> 806 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_down_pressed.9.pngbin1482 -> 1257 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_down_selected.9.pngbin1459 -> 1292 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_input_disabled.9.pngbin484 -> 280 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_input_normal.9.pngbin567 -> 582 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_input_pressed.9.pngbin593 -> 604 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_input_selected.9.pngbin578 -> 517 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_up_disabled.9.pngbin1278 -> 512 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_up_disabled_focused.9.pngbin1258 -> 724 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_up_normal.9.pngbin1173 -> 1058 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_up_pressed.9.pngbin1864 -> 1500 bytes
-rwxr-xr-xcore/res/res/drawable/timepicker_up_selected.9.pngbin1847 -> 1519 bytes
-rw-r--r--core/res/res/drawable/title_bar.9.pngbin3014 -> 0 bytes
-rw-r--r--core/res/res/drawable/title_bar.xml20
-rw-r--r--core/res/res/drawable/title_bar_shadow.9.pngbin0 -> 178 bytes
-rw-r--r--core/res/res/drawable/title_bar_shadow.pngbin2851 -> 0 bytes
-rw-r--r--core/res/res/drawable/title_bar_tall.pngbin0 -> 12764 bytes
-rw-r--r--core/res/res/layout/activity_list.xml38
-rw-r--r--core/res/res/layout/activity_list_item_2.xml25
-rw-r--r--core/res/res/layout/alert_dialog_simple_text.xml26
-rw-r--r--core/res/res/layout/date_picker.xml1
-rw-r--r--core/res/res/layout/date_picker_dialog.xml14
-rw-r--r--core/res/res/layout/expanded_menu_layout.xml2
-rw-r--r--core/res/res/layout/global_actions_item.xml60
-rw-r--r--core/res/res/layout/google_web_content_helper_layout.xml2
-rw-r--r--core/res/res/layout/input_method.xml2
-rw-r--r--core/res/res/layout/input_method_extract_view.xml41
-rw-r--r--core/res/res/layout/js_prompt.xml5
-rw-r--r--core/res/res/layout/keyguard_screen_glogin_unlock.xml168
-rw-r--r--core/res/res/layout/keyguard_screen_lock.xml27
-rw-r--r--core/res/res/layout/keyguard_screen_sim_pin_landscape.xml5
-rw-r--r--core/res/res/layout/keyguard_screen_sim_pin_portrait.xml414
-rw-r--r--core/res/res/layout/keyguard_screen_unlock_landscape.xml8
-rw-r--r--core/res/res/layout/keyguard_screen_unlock_portrait.xml21
-rw-r--r--core/res/res/layout/list_menu_item_layout.xml4
-rw-r--r--core/res/res/layout/number_picker.xml30
-rw-r--r--core/res/res/layout/number_picker_edit.xml1
-rw-r--r--core/res/res/layout/preference.xml8
-rw-r--r--core/res/res/layout/preference_child.xml17
-rw-r--r--core/res/res/layout/preferences.xml5
-rw-r--r--core/res/res/layout/resolve_list_item.xml45
-rw-r--r--core/res/res/layout/search_bar.xml12
-rw-r--r--core/res/res/layout/select_dialog_item.xml3
-rw-r--r--core/res/res/layout/select_dialog_singlechoice.xml3
-rw-r--r--core/res/res/layout/status_bar.xml2
-rw-r--r--core/res/res/layout/status_bar_latest_event_content.xml4
-rw-r--r--core/res/res/layout/time_picker.xml2
-rw-r--r--core/res/res/layout/time_picker_dialog.xml14
-rw-r--r--core/res/res/layout/zoom_browser_accessory_buttons.xml35
-rw-r--r--core/res/res/layout/zoom_container.xml29
-rw-r--r--core/res/res/layout/zoom_controls.xml8
-rw-r--r--core/res/res/layout/zoom_magnify.xml6
-rw-r--r--core/res/res/values-cs-rCZ/strings.xml1112
-rw-r--r--core/res/res/values-cs/strings.xml185
-rw-r--r--core/res/res/values-de/strings.xml184
-rw-r--r--core/res/res/values-en-rAU/strings.xml90
-rw-r--r--core/res/res/values-en-rGB/strings.xml762
-rw-r--r--core/res/res/values-en-rSG/arrays.xml32
-rw-r--r--core/res/res/values-en-rSG/strings.xml91
-rw-r--r--core/res/res/values-es-rES/arrays.xml32
-rw-r--r--core/res/res/values-es-rUS/strings.xml904
-rw-r--r--core/res/res/values-es/strings.xml253
-rw-r--r--core/res/res/values-fr-rFR/arrays.xml32
-rw-r--r--core/res/res/values-fr/strings.xml507
-rw-r--r--core/res/res/values-it-rIT/arrays.xml32
-rw-r--r--core/res/res/values-it/strings.xml397
-rw-r--r--core/res/res/values-ja-rJP/arrays.xml32
-rw-r--r--core/res/res/values-ja/strings.xml515
-rw-r--r--core/res/res/values-ko/strings.xml815
-rw-r--r--core/res/res/values-mcc204-ko/strings.xml19
-rw-r--r--core/res/res/values-mcc230-ko/strings.xml19
-rw-r--r--core/res/res/values-mcc232-ko/strings.xml19
-rw-r--r--core/res/res/values-mcc234-ko/strings.xml19
-rw-r--r--core/res/res/values-mcc260-ko/strings.xml19
-rw-r--r--core/res/res/values-mcc262-ko/strings.xml19
-rw-r--r--core/res/res/values-nb/strings.xml815
-rw-r--r--core/res/res/values-nl-rNL/strings.xml905
-rw-r--r--core/res/res/values-nl/strings.xml201
-rw-r--r--core/res/res/values-pl/strings.xml241
-rw-r--r--core/res/res/values-ru/strings.xml171
-rw-r--r--core/res/res/values-zh-rCN/strings.xml171
-rw-r--r--core/res/res/values-zh-rTW/strings.xml171
-rw-r--r--core/res/res/values/arrays.xml152
-rw-r--r--core/res/res/values/attrs.xml266
-rw-r--r--core/res/res/values/attrs_manifest.xml23
-rw-r--r--core/res/res/values/colors.xml4
-rw-r--r--core/res/res/values/config.xml37
-rw-r--r--core/res/res/values/dimens.xml2
-rw-r--r--core/res/res/values/ids.xml5
-rw-r--r--core/res/res/values/public.xml97
-rw-r--r--core/res/res/values/strings.xml177
-rw-r--r--core/res/res/values/styles.xml143
-rw-r--r--core/res/res/values/themes.xml10
-rw-r--r--data/etc/Android.mk2
-rw-r--r--data/etc/platform.xml1
-rwxr-xr-xdata/localization/export-to-xlb36
-rwxr-xr-xdata/localization/import-from-xtb94
-rw-r--r--data/localization/tc-files33
-rwxr-xr-xdata/localization/xlb-merge31
-rw-r--r--data/sounds/Android.mk233
-rw-r--r--data/sounds/OriginalAudio.mk68
-rw-r--r--data/sounds/effects/Effect_Tick.ogg (renamed from data/sounds/Effect_Tick.ogg)bin3994 -> 3994 bytes
-rw-r--r--data/sounds/effects/KeypressDelete.oggbin0 -> 6193 bytes
-rw-r--r--data/sounds/effects/KeypressDelete.wavbin0 -> 29892 bytes
-rw-r--r--data/sounds/effects/KeypressReturn.oggbin0 -> 7972 bytes
-rw-r--r--data/sounds/effects/KeypressReturn.wavbin0 -> 64320 bytes
-rw-r--r--data/sounds/effects/KeypressSpacebar.oggbin0 -> 7392 bytes
-rw-r--r--data/sounds/effects/KeypressSpacebar.wavbin0 -> 49400 bytes
-rw-r--r--data/sounds/effects/KeypressStandard.oggbin0 -> 5194 bytes
-rw-r--r--data/sounds/effects/KeypressStandard.wavbin0 -> 17992 bytes
-rw-r--r--data/sounds/newwavelabs/BeatPlucker.oggbin41228 -> 28433 bytes
-rw-r--r--data/sounds/newwavelabs/BentleyDubs.oggbin42260 -> 30759 bytes
-rw-r--r--data/sounds/newwavelabs/BirdLoop.oggbin60966 -> 41828 bytes
-rw-r--r--data/sounds/newwavelabs/CaribbeanIce.oggbin43950 -> 30615 bytes
-rw-r--r--data/sounds/newwavelabs/CrazyDream.oggbin294366 -> 206809 bytes
-rw-r--r--data/sounds/newwavelabs/CurveBall.oggbin43742 -> 30925 bytes
-rw-r--r--data/sounds/newwavelabs/DreamTheme.oggbin254089 -> 175423 bytes
-rw-r--r--data/sounds/newwavelabs/EtherShake.oggbin43709 -> 31563 bytes
-rw-r--r--data/sounds/newwavelabs/FriendlyGhost.oggbin54075 -> 46425 bytes
-rw-r--r--data/sounds/newwavelabs/GameOverGuitar.oggbin59211 -> 49978 bytes
-rw-r--r--data/sounds/newwavelabs/Growl.oggbin55285 -> 41094 bytes
-rw-r--r--data/sounds/newwavelabs/InsertCoin.oggbin21452 -> 15146 bytes
-rw-r--r--data/sounds/newwavelabs/LoopyLounge.oggbin53696 -> 38307 bytes
-rw-r--r--data/sounds/newwavelabs/LoveFlute.oggbin47306 -> 34627 bytes
-rw-r--r--data/sounds/newwavelabs/MidEvilJaunt.oggbin40741 -> 28124 bytes
-rw-r--r--data/sounds/newwavelabs/MildlyAlarming.oggbin41692 -> 34864 bytes
-rw-r--r--data/sounds/newwavelabs/NewPlayer.oggbin21246 -> 15563 bytes
-rw-r--r--data/sounds/newwavelabs/Noises1.oggbin39618 -> 36287 bytes
-rw-r--r--data/sounds/newwavelabs/Noises2.oggbin44059 -> 39025 bytes
-rw-r--r--data/sounds/newwavelabs/Noises3.oggbin37281 -> 26662 bytes
-rw-r--r--data/sounds/newwavelabs/OrganDub.oggbin44107 -> 32640 bytes
-rw-r--r--data/sounds/newwavelabs/RomancingTheTone.oggbin46148 -> 31641 bytes
-rw-r--r--data/sounds/newwavelabs/SitarVsSitar.oggbin44191 -> 28898 bytes
-rw-r--r--data/sounds/newwavelabs/SpringyJalopy.oggbin41238 -> 26144 bytes
-rw-r--r--data/sounds/newwavelabs/Terminated.oggbin50822 -> 36620 bytes
-rw-r--r--data/sounds/newwavelabs/TwirlAway.oggbin38979 -> 26298 bytes
-rw-r--r--data/sounds/newwavelabs/VeryAlarmed.oggbin43648 -> 28691 bytes
-rw-r--r--data/sounds/newwavelabs/World.oggbin43473 -> 31136 bytes
-rwxr-xr-xdata/sounds/testfiles/test.mid (renamed from data/sounds/test.mid)bin2956 -> 2956 bytes
-rw-r--r--docs/docs-redirect.html4
-rw-r--r--docs/html/_build_id.cs2
-rwxr-xr-xdocs/html/about.jd13
-rw-r--r--docs/html/app.yaml29
-rw-r--r--docs/html/community/index.jd162
-rw-r--r--docs/html/favicon.icobin0 -> 1150 bytes
-rw-r--r--docs/html/goodies/index.jd85
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper1_1024x768.pngbin42181 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper1_1280x800.pngbin48098 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper1_1440x900.pngbin54844 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper1_1600x1200.pngbin70619 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper1_1680x1050.pngbin64785 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper1_1920x1200.pngbin73761 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper1_2560x1600.pngbin120591 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper1_thumbnail.pngbin7953 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper2_1024x768.pngbin183833 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper2_1280x800.pngbin242116 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper2_1440x900.pngbin323386 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper2_1600x1200.pngbin498565 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper2_1680x1050.pngbin450824 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper2_1920x1200.pngbin592473 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper2_2560x1600.pngbin1025582 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper2_thumbnail.pngbin6558 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper3_1024x768.pngbin99066 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper3_1280x800.pngbin126316 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper3_1440x900.pngbin143988 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper3_1600x1200.pngbin163220 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper3_1680x1050.pngbin169823 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper3_1920x1200.pngbin196865 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper3_2560x1600.pngbin194785 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper3_thumbnail.pngbin4494 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper4_1024x768.pngbin15917 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper4_1280x800.pngbin17296 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper4_1440x900.pngbin18061 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper4_1600x1200.pngbin23167 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper4_1680x1050.pngbin20703 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper4_1920x1200.pngbin22709 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper4_2560x1600.pngbin32802 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper4_thumbnail.pngbin4913 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper5_1024x768.jpgbin65004 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper5_1280x800.jpgbin77434 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper5_1440x900.jpgbin79572 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper5_1600x1200.jpgbin93356 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper5_1680x1050.jpgbin91781 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper5_1920x1080.jpgbin95046 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper5_1920x1200.jpgbin99396 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper5_2560x1600.jpgbin137815 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper5_thumbnail.jpgbin7351 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper6_1024x768.jpgbin79675 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper6_1280x800.jpgbin91634 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper6_1440x900.jpgbin99794 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper6_1600x1200.jpgbin113072 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper6_1680x1050.jpgbin113303 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper6_1920x1200.jpgbin126091 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper6_2560x1600.jpgbin173505 -> 0 bytes
-rw-r--r--docs/html/goodies/wallpaper/android-wallpaper6_thumbnail.jpgbin7320 -> 0 bytes
-rw-r--r--docs/html/googleb38c1d60b7ba5d19.html0
-rw-r--r--docs/html/guide/appendix/faq/commontasks.jd180
-rw-r--r--docs/html/guide/appendix/faq/framework.jd2
-rw-r--r--docs/html/guide/appendix/faq/licensingandoss.jd2
-rw-r--r--docs/html/guide/appendix/faq/security.jd2
-rw-r--r--docs/html/guide/appendix/faq/troubleshooting.jd26
-rw-r--r--docs/html/guide/appendix/glossary.jd2
-rw-r--r--docs/html/guide/appendix/media-formats.jd10
-rwxr-xr-xdocs/html/guide/basics/anatomy.jd134
-rw-r--r--docs/html/guide/basics/android-sdk.jd11
-rw-r--r--docs/html/guide/basics/app-framework.jd4
-rw-r--r--docs/html/guide/basics/what-is-android.jd2
-rw-r--r--docs/html/guide/developing/debug-tasks.jd2
-rw-r--r--docs/html/guide/developing/device.jd44
-rw-r--r--docs/html/guide/developing/eclipse-adt.jd60
-rw-r--r--docs/html/guide/developing/instrumentation/index.jd54
-rw-r--r--docs/html/guide/developing/instrumentation/inst-framework.jd139
-rw-r--r--docs/html/guide/developing/instrumentation/inst-testing.jd207
-rw-r--r--docs/html/guide/developing/other-ide.jd49
-rw-r--r--docs/html/guide/developing/tools/adb.jd2
-rw-r--r--docs/html/guide/developing/tools/adt.jd2
-rw-r--r--docs/html/guide/developing/tools/emulator.jd2
-rw-r--r--docs/html/guide/guide_toc.cs115
-rw-r--r--docs/html/guide/index.jd142
-rw-r--r--docs/html/guide/practices/design/seamlessness.jd5
-rw-r--r--docs/html/guide/publishing/app-signing.jd2
-rw-r--r--docs/html/guide/publishing/preparing.jd48
-rw-r--r--docs/html/guide/publishing/publishing.jd6
-rw-r--r--docs/html/guide/publishing/versioning.jd36
-rw-r--r--docs/html/guide/samples/index.jd14
-rw-r--r--docs/html/guide/topics/fundamentals.jd699
-rw-r--r--docs/html/guide/topics/graphics/2d-graphics.jd51
-rw-r--r--docs/html/guide/topics/graphics/index.jd218
-rw-r--r--docs/html/guide/topics/intents/intents-filters.jd2
-rw-r--r--docs/html/guide/topics/location/geo/mapkey.jd212
-rw-r--r--docs/html/guide/topics/location/index.jd2
-rw-r--r--docs/html/guide/topics/manifest/action-element.jd46
-rw-r--r--docs/html/guide/topics/manifest/activity-alias-element.jd129
-rw-r--r--docs/html/guide/topics/manifest/activity-element.jd565
-rw-r--r--docs/html/guide/topics/manifest/application-element.jd226
-rw-r--r--docs/html/guide/topics/manifest/category-element.jd38
-rw-r--r--docs/html/guide/topics/manifest/data-element.jd148
-rw-r--r--docs/html/guide/topics/manifest/grant-uri-permission-element.jd85
-rw-r--r--docs/html/guide/topics/manifest/instrumentation-element.jd61
-rw-r--r--docs/html/guide/topics/manifest/intent-filter-element.jd130
-rw-r--r--docs/html/guide/topics/manifest/manifest-element.jd94
-rw-r--r--docs/html/guide/topics/manifest/manifest-intro.jd511
-rw-r--r--docs/html/guide/topics/manifest/manifest.jd3063
-rw-r--r--docs/html/guide/topics/manifest/meta-data-element.jd90
-rw-r--r--docs/html/guide/topics/manifest/permission-element.jd131
-rw-r--r--docs/html/guide/topics/manifest/permission-group-element.jd59
-rw-r--r--docs/html/guide/topics/manifest/permission-tree-element.jd61
-rw-r--r--docs/html/guide/topics/manifest/provider-element.jd267
-rw-r--r--docs/html/guide/topics/manifest/receiver-element.jd164
-rw-r--r--docs/html/guide/topics/manifest/service-element.jd176
-rw-r--r--docs/html/guide/topics/manifest/uses-library-element.jd32
-rw-r--r--docs/html/guide/topics/manifest/uses-permission-element.jd39
-rw-r--r--docs/html/guide/topics/manifest/uses-sdk-element.jd49
-rw-r--r--docs/html/guide/topics/resources/available-resources.jd12
-rw-r--r--docs/html/guide/topics/resources/resources-i18n.jd2
-rw-r--r--docs/html/guide/topics/ui/binding.jd (renamed from docs/html/guide/topics/views/binding.jd)5
-rw-r--r--docs/html/guide/topics/ui/custom-components.jd (renamed from docs/html/guide/topics/views/custom-components.jd)4
-rw-r--r--docs/html/guide/topics/ui/declaring-layout.jd275
-rw-r--r--docs/html/guide/topics/ui/how-android-draws.jd94
-rw-r--r--docs/html/guide/topics/ui/index.jd235
-rw-r--r--docs/html/guide/topics/ui/layout-objects.jd (renamed from docs/html/guide/topics/views/layout.jd)92
-rw-r--r--docs/html/guide/topics/ui/menus.jd (renamed from docs/html/guide/topics/views/menus.jd)30
-rw-r--r--docs/html/guide/topics/ui/themes.jd (renamed from docs/html/guide/topics/views/themes.jd)66
-rw-r--r--docs/html/guide/topics/ui/ui-events.jd283
-rw-r--r--docs/html/guide/topics/views/declaring-layout.jd228
-rw-r--r--docs/html/guide/topics/views/how-android-draws.jd90
-rw-r--r--docs/html/guide/topics/views/index.jd216
-rw-r--r--docs/html/guide/topics/views/ui-events.jd113
-rw-r--r--docs/html/guide/tutorials/hello-world.jd171
-rw-r--r--[-rwxr-xr-x]docs/html/guide/tutorials/notepad/codelab/NotepadCodeLab.zipbin362176 -> 431473 bytes
-rw-r--r--docs/html/guide/tutorials/notepad/notepad-ex1.jd3
-rw-r--r--docs/html/guide/tutorials/notepad/notepad-ex2.jd95
-rw-r--r--docs/html/guide/tutorials/notepad/notepad-ex3.jd3
-rw-r--r--docs/html/guide/tutorials/notepad/notepad-extra-credit.jd6
-rw-r--r--docs/html/guide/tutorials/views/hello-autocomplete.jd2
-rw-r--r--docs/html/guide/tutorials/views/hello-formstuff.jd20
-rw-r--r--docs/html/guide/tutorials/views/hello-gridview.jd1
-rw-r--r--docs/html/guide/tutorials/views/hello-mapview.jd34
-rw-r--r--docs/html/guide/tutorials/views/index.jd56
-rw-r--r--docs/html/images/adc1r1_deck.pdfbin3809156 -> 0 bytes
-rw-r--r--docs/html/images/binder_rpc.pngbin0 -> 30742 bytes
-rw-r--r--docs/html/images/judgebio_charles.jpgbin16354 -> 0 bytes
-rw-r--r--docs/html/images/judgebio_dibona.jpgbin10286 -> 0 bytes
-rw-r--r--docs/html/images/judgebio_gadi.jpgbin8040 -> 0 bytes
-rw-r--r--docs/html/images/judgebio_jens.jpgbin17098 -> 0 bytes
-rw-r--r--docs/html/images/judgebio_jeremiah.jpgbin17703 -> 0 bytes
-rw-r--r--docs/html/images/judgebio_kristian.jpgbin18145 -> 0 bytes
-rw-r--r--docs/html/images/judgebio_leon.jpgbin17302 -> 0 bytes
-rwxr-xr-xdocs/html/images/options_menu.pngbin0 -> 24241 bytes
-rwxr-xr-xdocs/html/images/radio_buttons.pngbin0 -> 24017 bytes
-rw-r--r--docs/html/images/table_layout.pngbin24161 -> 3456 bytes
-rw-r--r--docs/html/index.jd82
-rw-r--r--docs/html/license.jd143
-rw-r--r--docs/html/offline.jd36
-rw-r--r--docs/html/resources/bootcamp.pdfbin2188758 -> 0 bytes
-rw-r--r--docs/html/roadmap.jd120
-rw-r--r--docs/html/robots.txt6
-rw-r--r--docs/html/samples/index.jd6
-rw-r--r--docs/html/sdk/1.0_r1/RELEASENOTES.jd100
-rw-r--r--docs/html/sdk/1.0_r1/index.jd51
-rw-r--r--docs/html/sdk/1.0_r1/installing.jd171
-rw-r--r--docs/html/sdk/1.0_r1/terms.jd7
-rw-r--r--docs/html/sdk/1.0_r1/upgrading.jd103
-rw-r--r--docs/html/sdk/1.0_r2/index.jd65
-rw-r--r--docs/html/sdk/1.0_r2/installing.jd221
-rw-r--r--docs/html/sdk/1.0_r2/requirements.jd44
-rw-r--r--docs/html/sdk/1.0_r2/upgrading.jd148
-rw-r--r--docs/html/sdk/1.1_r1/index.jd62
-rw-r--r--docs/html/sdk/1.1_r1/installing.jd312
-rw-r--r--docs/html/sdk/1.1_r1/requirements.jd (renamed from docs/html/sdk/1.0_r1/requirements.jd)16
-rw-r--r--docs/html/sdk/1.1_r1/upgrading.jd150
-rw-r--r--docs/html/sdk/RELEASENOTES.jd327
-rw-r--r--docs/html/sdk/adt_download.jd (renamed from docs/html/guide/developing/tools/adt_download.jd)4
-rw-r--r--docs/html/sdk/android-1.1.jd249
-rw-r--r--docs/html/sdk/download.jd86
-rw-r--r--docs/html/sdk/index.html6
-rw-r--r--docs/html/sdk/index.jd5
-rw-r--r--docs/html/sdk/sdk_toc.cs63
-rw-r--r--docs/html/sdk/terms.jd1
-rw-r--r--docs/html/sdk/terms_body.html216
-rw-r--r--[-rwxr-xr-x]docs/html/search.jd146
-rw-r--r--docs/html/sitemap.txt5444
-rw-r--r--graphics/java/android/graphics/Bitmap.java202
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java134
-rw-r--r--graphics/java/android/graphics/Canvas.java91
-rw-r--r--graphics/java/android/graphics/NinePatch.java17
-rw-r--r--graphics/java/android/graphics/Paint.java8
-rw-r--r--graphics/java/android/graphics/drawable/AnimationDrawable.java10
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java129
-rw-r--r--graphics/java/android/graphics/drawable/ClipDrawable.java27
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java57
-rw-r--r--graphics/java/android/graphics/drawable/DrawableContainer.java26
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java234
-rw-r--r--graphics/java/android/graphics/drawable/InsetDrawable.java40
-rw-r--r--graphics/java/android/graphics/drawable/LayerDrawable.java124
-rw-r--r--graphics/java/android/graphics/drawable/LevelListDrawable.java110
-rw-r--r--graphics/java/android/graphics/drawable/NinePatchDrawable.java135
-rw-r--r--graphics/java/android/graphics/drawable/RotateDrawable.java30
-rw-r--r--graphics/java/android/graphics/drawable/ScaleDrawable.java36
-rw-r--r--graphics/java/android/graphics/drawable/ShapeDrawable.java28
-rw-r--r--graphics/java/android/graphics/drawable/StateListDrawable.java124
-rw-r--r--graphics/java/android/graphics/drawable/TransitionDrawable.java43
-rw-r--r--graphics/java/android/graphics/drawable/package.html2
-rw-r--r--graphics/java/android/graphics/drawable/shapes/PathShape.java7
-rw-r--r--graphics/java/android/graphics/drawable/shapes/RectShape.java7
-rw-r--r--graphics/java/android/graphics/drawable/shapes/RoundRectShape.java11
-rw-r--r--graphics/java/android/graphics/drawable/shapes/Shape.java7
-rw-r--r--include/GLES/egl.h268
-rw-r--r--include/GLES/gl.h639
-rw-r--r--include/media/AudioRecord.h9
-rw-r--r--include/media/AudioSystem.h71
-rw-r--r--include/media/AudioTrack.h14
-rw-r--r--include/media/IAudioFlinger.h23
-rw-r--r--include/media/IAudioFlingerClient.h55
-rw-r--r--include/media/IMediaRecorder.h4
-rw-r--r--include/media/JetPlayer.h16
-rw-r--r--include/media/MediaPlayerInterface.h32
-rw-r--r--include/media/PVMediaRecorder.h4
-rw-r--r--include/media/PVPlayer.h18
-rw-r--r--include/media/ToneGenerator.h3
-rw-r--r--include/media/mediaplayer.h68
-rw-r--r--include/media/mediarecorder.h51
-rw-r--r--include/media/thread_init.h1
-rw-r--r--include/private/opengles/gl_context.h1
-rw-r--r--include/ui/Camera.h43
-rw-r--r--include/ui/CameraHardwareInterface.h35
-rw-r--r--include/ui/CameraParameters.h9
-rw-r--r--include/ui/EGLDisplaySurface.h11
-rw-r--r--include/ui/EGLNativeSurface.h2
-rw-r--r--include/ui/EGLNativeWindowSurface.h7
-rw-r--r--include/ui/EventHub.h6
-rw-r--r--include/ui/ICamera.h16
-rw-r--r--include/ui/ICameraClient.h3
-rw-r--r--include/ui/ICameraService.h2
-rw-r--r--include/ui/ISurface.h43
-rw-r--r--include/ui/KeycodeLabels.h4
-rw-r--r--include/ui/PixelFormat.h20
-rw-r--r--include/utils/ResourceTypes.h28
-rw-r--r--include/utils/logger.h46
-rw-r--r--include/utils/threads.h35
-rw-r--r--libs/audioflinger/A2dpAudioInterface.cpp76
-rw-r--r--libs/audioflinger/A2dpAudioInterface.h10
-rw-r--r--libs/audioflinger/AudioDumpInterface.h5
-rw-r--r--libs/audioflinger/AudioFlinger.cpp2109
-rw-r--r--libs/audioflinger/AudioFlinger.h631
-rw-r--r--libs/audioflinger/AudioHardwareGeneric.cpp8
-rw-r--r--libs/audioflinger/AudioHardwareGeneric.h8
-rw-r--r--libs/audioflinger/AudioHardwareStub.cpp8
-rw-r--r--libs/audioflinger/AudioHardwareStub.h5
-rw-r--r--libs/surfaceflinger/Android.mk7
-rw-r--r--libs/surfaceflinger/BootAnimation.cpp197
-rw-r--r--libs/surfaceflinger/BootAnimation.h5
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp39
-rw-r--r--libs/surfaceflinger/DisplayHardware/DisplayHardware.h6
-rw-r--r--libs/surfaceflinger/LayerBase.cpp24
-rw-r--r--libs/surfaceflinger/LayerBase.h34
-rw-r--r--libs/surfaceflinger/LayerBitmap.cpp13
-rw-r--r--libs/surfaceflinger/LayerBitmap.h3
-rw-r--r--libs/surfaceflinger/LayerBlur.cpp3
-rw-r--r--libs/surfaceflinger/LayerBuffer.cpp182
-rw-r--r--libs/surfaceflinger/LayerBuffer.h34
-rw-r--r--libs/surfaceflinger/LayerOrientationAnim.cpp287
-rw-r--r--libs/surfaceflinger/LayerOrientationAnim.h (renamed from libs/surfaceflinger/LayerScreenshot.h)42
-rw-r--r--libs/surfaceflinger/OrientationAnimation.cpp155
-rw-r--r--libs/surfaceflinger/OrientationAnimation.h73
-rw-r--r--libs/surfaceflinger/RFBServer.cpp722
-rw-r--r--libs/surfaceflinger/RFBServer.h316
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.cpp212
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.h23
-rw-r--r--libs/surfaceflinger/VRamHeap.cpp2
-rw-r--r--libs/ui/Camera.cpp78
-rw-r--r--libs/ui/CameraParameters.cpp20
-rw-r--r--libs/ui/EGLDisplaySurface.cpp75
-rw-r--r--libs/ui/EGLNativeWindowSurface.cpp27
-rw-r--r--libs/ui/EventHub.cpp43
-rw-r--r--libs/ui/ICamera.cpp91
-rw-r--r--libs/ui/ICameraClient.cpp36
-rw-r--r--libs/ui/ISurface.cpp67
-rw-r--r--libs/ui/PixelFormat.cpp33
-rw-r--r--libs/utils/CallStack.cpp25
-rw-r--r--libs/utils/Parcel.cpp13
-rw-r--r--libs/utils/ResourceTypes.cpp23
-rw-r--r--libs/utils/String16.cpp22
-rw-r--r--libs/utils/String8.cpp4
-rw-r--r--libs/utils/Threads.cpp224
-rw-r--r--location/data/Android.mk6
-rw-r--r--location/java/android/location/Location.java11
-rw-r--r--location/java/com/android/internal/location/CellState.java11
-rw-r--r--location/java/com/android/internal/location/GpsLocationProvider.java16
-rw-r--r--location/java/com/android/internal/location/ILocationCollector.java73
-rw-r--r--location/java/com/android/internal/location/INetworkLocationManager.java37
-rw-r--r--location/java/com/android/internal/location/INetworkLocationProvider.java95
-rw-r--r--location/java/com/android/internal/location/LocationCache.java608
-rw-r--r--location/java/com/android/internal/location/LocationCollector.java499
-rw-r--r--location/java/com/android/internal/location/LocationMasfClient.java1194
-rw-r--r--location/java/com/android/internal/location/NetworkLocationProvider.java561
-rw-r--r--location/java/com/android/internal/location/ProtoRequestListener.java61
-rw-r--r--location/java/com/android/internal/location/protocol/GAddressComponent.java23
-rw-r--r--location/java/com/android/internal/location/protocol/GAppProfile.java26
-rw-r--r--location/java/com/android/internal/location/protocol/GCell.java29
-rw-r--r--location/java/com/android/internal/location/protocol/GCellularPlatformProfile.java30
-rw-r--r--location/java/com/android/internal/location/protocol/GCellularProfile.java26
-rw-r--r--location/java/com/android/internal/location/protocol/GDebugProfile.java37
-rw-r--r--location/java/com/android/internal/location/protocol/GDeviceLocation.java24
-rw-r--r--location/java/com/android/internal/location/protocol/GFeature.java38
-rw-r--r--location/java/com/android/internal/location/protocol/GGeocodeRequest.java24
-rw-r--r--location/java/com/android/internal/location/protocol/GGpsProfile.java29
-rw-r--r--location/java/com/android/internal/location/protocol/GLocReply.java24
-rw-r--r--location/java/com/android/internal/location/protocol/GLocReplyElement.java24
-rw-r--r--location/java/com/android/internal/location/protocol/GLocRequest.java26
-rw-r--r--location/java/com/android/internal/location/protocol/GLocRequestElement.java26
-rw-r--r--location/java/com/android/internal/location/protocol/GLocation.java41
-rw-r--r--location/java/com/android/internal/location/protocol/GPlatformProfile.java28
-rw-r--r--location/java/com/android/internal/location/protocol/GPrefetchMode.java25
-rw-r--r--location/java/com/android/internal/location/protocol/GRectangle.java23
-rw-r--r--location/java/com/android/internal/location/protocol/GUserProfile.java23
-rw-r--r--location/java/com/android/internal/location/protocol/GWifiDevice.java26
-rw-r--r--location/java/com/android/internal/location/protocol/GWifiPlatformProfile.java29
-rw-r--r--location/java/com/android/internal/location/protocol/GWifiProfile.java24
-rw-r--r--location/java/com/android/internal/location/protocol/GaddressMessageTypes.java39
-rw-r--r--location/java/com/android/internal/location/protocol/GcellularMessageTypes.java57
-rw-r--r--location/java/com/android/internal/location/protocol/GdebugprofileMessageTypes.java37
-rw-r--r--location/java/com/android/internal/location/protocol/GfeatureMessageTypes.java39
-rw-r--r--location/java/com/android/internal/location/protocol/GlocationMessageTypes.java138
-rw-r--r--location/java/com/android/internal/location/protocol/GwifiMessageTypes.java47
-rw-r--r--location/java/com/android/internal/location/protocol/LocserverMessageTypes.java80
-rw-r--r--location/java/com/android/internal/location/protocol/ResponseCodes.java45
-rw-r--r--media/java/android/media/AsyncPlayer.java9
-rw-r--r--media/java/android/media/AudioFormat.java4
-rw-r--r--media/java/android/media/AudioManager.java325
-rw-r--r--media/java/android/media/AudioRecord.java213
-rw-r--r--media/java/android/media/AudioService.java455
-rw-r--r--media/java/android/media/AudioSystem.java20
-rw-r--r--media/java/android/media/AudioTrack.java704
-rw-r--r--media/java/android/media/IAudioService.aidl2
-rw-r--r--media/java/android/media/JetPlayer.java141
-rw-r--r--media/java/android/media/MediaFile.java6
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java14
-rw-r--r--media/java/android/media/MediaPlayer.java136
-rw-r--r--media/java/android/media/MediaRecorder.java353
-rw-r--r--media/java/android/media/MediaScanner.java10
-rw-r--r--media/java/android/media/Ringtone.java13
-rw-r--r--media/java/android/media/SoundPool.java7
-rw-r--r--media/jni/android_media_MediaPlayer.cpp46
-rw-r--r--media/jni/android_media_MediaRecorder.cpp228
-rw-r--r--media/jni/soundpool/SoundPool.cpp51
-rw-r--r--media/jni/soundpool/SoundPool.h5
-rw-r--r--media/libmedia/Android.mk1
-rw-r--r--media/libmedia/AudioRecord.cpp25
-rw-r--r--media/libmedia/AudioSystem.cpp144
-rw-r--r--media/libmedia/AudioTrack.cpp62
-rw-r--r--media/libmedia/IAudioFlinger.cpp93
-rw-r--r--media/libmedia/IAudioFlingerClient.cpp77
-rw-r--r--media/libmedia/IMediaRecorder.cpp68
-rw-r--r--media/libmedia/JetPlayer.cpp81
-rw-r--r--media/libmedia/ToneGenerator.cpp43
-rw-r--r--media/libmedia/mediaplayer.cpp25
-rw-r--r--media/libmedia/mediarecorder.cpp162
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp267
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.cpp32
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.h3
-rw-r--r--media/libmediaplayerservice/MidiFile.cpp22
-rw-r--r--media/libmediaplayerservice/MidiFile.h2
-rw-r--r--media/libmediaplayerservice/VorbisPlayer.cpp6
-rw-r--r--media/sdutils/sdutil.cpp14
-rw-r--r--media/tests/MediaFrameworkTest/AndroidManifest.xml5
-rwxr-xr-xmedia/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java3
-rwxr-xr-xmedia/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java568
-rwxr-xr-xmedia/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaRecorderStressTestRunner.java38
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java18
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java95
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java1215
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java22
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java111
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java2
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java475
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java198
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java13
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java9
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java7
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java7
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java7
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java27
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java7
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java7
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStateUnitTestTemplate.java7
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java7
-rw-r--r--opengl/include/EGL/egl.h330
-rw-r--r--opengl/include/EGL/eglext.h138
-rw-r--r--opengl/include/EGL/eglnatives.h (renamed from include/GLES/eglnatives.h)52
-rw-r--r--opengl/include/EGL/eglplatform.h117
-rw-r--r--opengl/include/GLES/egl.h15
-rw-r--r--opengl/include/GLES/gl.h769
-rw-r--r--opengl/include/GLES/glext.h622
-rw-r--r--opengl/include/GLES/glplatform.h39
-rw-r--r--opengl/include/KHR/khrplatform.h241
-rw-r--r--opengl/java/android/opengl/Matrix.java57
-rw-r--r--opengl/java/android/opengl/Visibility.java1
-rw-r--r--opengl/libGLES_CM/Android.mk24
-rw-r--r--opengl/libagl/egl.cpp45
-rw-r--r--opengl/libagl/state.cpp6
-rw-r--r--opengl/libagl/texture.cpp12
-rw-r--r--opengl/libs/Android.mk53
-rw-r--r--opengl/libs/EGL/egl.cpp (renamed from opengl/libGLES_CM/gl_wrapper.cpp)526
-rw-r--r--opengl/libs/EGL/gpu.cpp212
-rw-r--r--opengl/libs/GLES_CM/gl.cpp116
-rw-r--r--opengl/libs/GLES_CM/gl_api.in (renamed from opengl/libGLES_CM/gl_api.cpp)2
-rw-r--r--opengl/libs/GLES_CM/gl_logger.cpp (renamed from opengl/libGLES_CM/gl_logger.cpp)23
-rw-r--r--opengl/libs/egl_entries.in (renamed from opengl/libGLES_CM/egl_entries.cpp)7
-rw-r--r--opengl/libs/egl_impl.h43
-rw-r--r--opengl/libs/gl_entries.in (renamed from opengl/libGLES_CM/gl_entries.cpp)2
-rw-r--r--opengl/libs/gl_enums.in (renamed from opengl/libGLES_CM/gl_enums.in)0
-rw-r--r--opengl/libs/gl_logger.h (renamed from opengl/libGLES_CM/gl_logger.h)6
-rw-r--r--opengl/libs/hooks.h134
-rw-r--r--opengl/libs/tools/enumextract.sh (renamed from opengl/libGLES_CM/enumextract.sh)0
-rw-r--r--opengl/tests/angeles/Android.mk4
-rw-r--r--opengl/tests/angeles/app-linux.c3
-rw-r--r--opengl/tests/filter/Android.mk3
-rw-r--r--opengl/tests/filter/filter.c7
-rw-r--r--opengl/tests/finish/Android.mk3
-rw-r--r--opengl/tests/finish/finish.c5
-rw-r--r--opengl/tests/sfsim/Android.mk15
-rw-r--r--opengl/tests/sfsim/egl_surface.cpp346
-rw-r--r--opengl/tests/sfsim/egl_surface.h113
-rw-r--r--opengl/tests/sfsim/sfsim.c112
-rw-r--r--opengl/tests/textures/Android.mk3
-rw-r--r--opengl/tests/textures/textures.c4
-rw-r--r--opengl/tests/tritex/Android.mk3
-rw-r--r--opengl/tests/tritex/tritex.c4
-rw-r--r--packages/SettingsProvider/Android.mk2
-rw-r--r--packages/SettingsProvider/etc/Android.mk4
-rw-r--r--packages/SettingsProvider/etc/bookmarks.xml52
-rw-r--r--packages/SettingsProvider/etc/favorites.xml3
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml41
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java154
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java36
-rw-r--r--packages/SubscribedFeedsProvider/AndroidManifest.xml5
-rw-r--r--packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java41
-rw-r--r--packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java (renamed from packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsService.java)113
-rw-r--r--preloaded-classes18
-rw-r--r--services/java/Android.mk (renamed from services/Android.mk)0
-rw-r--r--services/java/com/android/server/AlarmManagerService.java101
-rw-r--r--services/java/com/android/server/AppWidgetService.java1148
-rw-r--r--services/java/com/android/server/BatteryService.java158
-rw-r--r--services/java/com/android/server/ConnectivityService.java29
-rw-r--r--services/java/com/android/server/DeviceStorageMonitorService.java58
-rw-r--r--services/java/com/android/server/FallbackCheckinService.java75
-rw-r--r--services/java/com/android/server/GadgetService.java292
-rwxr-xr-xservices/java/com/android/server/HardwareService.java82
-rw-r--r--services/java/com/android/server/HeadsetObserver.java48
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java763
-rw-r--r--services/java/com/android/server/KeyInputQueue.java1
-rw-r--r--services/java/com/android/server/LocationManagerService.java1604
-rw-r--r--services/java/com/android/server/MountListener.java108
-rw-r--r--services/java/com/android/server/MountService.java433
-rw-r--r--services/java/com/android/server/NetStatService.java31
-rw-r--r--services/java/com/android/server/NotificationManagerService.java15
-rw-r--r--services/java/com/android/server/PackageManagerService.java294
-rw-r--r--services/java/com/android/server/PowerManagerService.java119
-rw-r--r--services/java/com/android/server/SensorService.java17
-rw-r--r--services/java/com/android/server/SystemServer.java100
-rw-r--r--services/java/com/android/server/TelephonyRegistry.java62
-rw-r--r--services/java/com/android/server/WifiService.java130
-rw-r--r--services/java/com/android/server/WindowManagerService.java812
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java542
-rw-r--r--services/java/com/android/server/am/BaseErrorDialog.java2
-rw-r--r--services/java/com/android/server/am/BatteryStatsService.java79
-rw-r--r--services/java/com/android/server/am/HistoryRecord.java43
-rwxr-xr-xservices/java/com/android/server/am/UsageStatsService.java532
-rw-r--r--services/java/com/android/server/status/AnimatedImageView.java1
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java63
-rw-r--r--services/java/com/android/server/status/StatusBarService.java101
-rw-r--r--services/jni/Android.mk (renamed from core/jni/server/Android.mk)0
-rw-r--r--services/jni/com_android_server_AlarmManagerService.cpp (renamed from core/jni/server/com_android_server_AlarmManagerService.cpp)7
-rw-r--r--services/jni/com_android_server_BatteryService.cpp (renamed from core/jni/server/com_android_server_BatteryService.cpp)0
-rw-r--r--services/jni/com_android_server_HardwareService.cpp (renamed from core/jni/server/com_android_server_HardwareService.cpp)14
-rw-r--r--services/jni/com_android_server_KeyInputQueue.cpp (renamed from core/jni/server/com_android_server_KeyInputQueue.cpp)21
-rw-r--r--services/jni/com_android_server_SensorService.cpp (renamed from core/jni/server/com_android_server_SensorService.cpp)0
-rw-r--r--services/jni/com_android_server_SystemServer.cpp (renamed from core/jni/server/com_android_server_SystemServer.cpp)0
-rw-r--r--services/jni/onload.cpp (renamed from core/jni/server/onload.cpp)0
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java8
-rw-r--r--telephony/java/android/telephony/gsm/SmsMessage.java28
-rw-r--r--telephony/java/com/android/internal/telephony/Connection.java5
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl32
-rw-r--r--telephony/java/com/android/internal/telephony/Phone.java7
-rw-r--r--telephony/java/com/android/internal/telephony/WapPushOverSms.java227
-rw-r--r--telephony/java/com/android/internal/telephony/WspTypeDecoder.java344
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/BaseCommands.java8
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/CallTracker.java107
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java11
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java197
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GSMConnection.java56
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GSMPhone.java63
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java4
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java2
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/MccTable.java14
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/PdpConnection.java21
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/RIL.java9
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/RILConstants.java27
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/RestrictedState.java122
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SIMRecords.java29
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java427
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java352
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SpnOverride.java78
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/TelephonyEventLog.java33
-rw-r--r--test-runner/android/test/InstrumentationTestRunner.java33
-rw-r--r--test-runner/android/test/ServiceTestCase.java4
-rw-r--r--test-runner/android/test/TestCaseUtil.java38
-rw-r--r--test-runner/android/test/TouchUtils.java24
-rw-r--r--test-runner/android/test/mock/MockContentProvider.java7
-rw-r--r--test-runner/android/test/mock/MockPackageManager.java17
-rw-r--r--tests/AndroidTests/Android.mk2
-rw-r--r--tests/AndroidTests/AndroidManifest.xml2
-rw-r--r--tests/AndroidTests/DisabledTestApp/Android.mk2
-rw-r--r--tests/AndroidTests/EnabledTestApp/Android.mk2
-rwxr-xr-xtests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java28
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java497
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/BuildTest.java1
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/CheckinProviderTest.java187
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java9
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/DatabaseLocaleTest.java33
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/DatabaseLockTest.java170
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java1
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/DbSSLSessionCacheTest.java259
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/HtmlTest.java4
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/MenuTest.java15
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTestSuite.java94
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTests.java1234
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/SSLClientSessionCacheFactoryTest.java54
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java2
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java20
-rw-r--r--tests/CoreTests/android/Android.mk2
-rw-r--r--tests/CoreTests/android/AndroidManifest.xml1
-rw-r--r--tests/CoreTests/android/core/DatabaseSessionCache.java312
-rw-r--r--tests/CoreTests/android/core/SSLPerformanceTest.java432
-rw-r--r--tests/CoreTests/android/core/SSLSocketTest.java243
-rw-r--r--tests/CoreTests/android/core/TestHandler.java174
-rw-r--r--tests/CoreTests/android/location/LocationManagerProximityTest.java49
-rw-r--r--tests/CoreTests/android/test/InstrumentationTestRunnerTest.java21
-rw-r--r--tests/CoreTests/android/webkit/CookieTest.java5
-rw-r--r--tests/CoreTests/android/webkit/UrlInterceptRegistryTest.java88
-rw-r--r--tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java568
-rw-r--r--tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java118
-rw-r--r--tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java15
-rw-r--r--tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java11
-rwxr-xr-xtests/CoreTests/run_core_test.sh4
-rw-r--r--tests/DpiTest/Android.mk10
-rw-r--r--tests/DpiTest/AndroidManifest.xml28
-rw-r--r--tests/DpiTest/res/drawable-120dpi/logo120dpi.pngbin0 -> 5178 bytes
-rw-r--r--tests/DpiTest/res/drawable-240dpi/logo240dpi.pngbin0 -> 13388 bytes
-rw-r--r--tests/DpiTest/res/drawable/logo160dpi.pngbin0 -> 8114 bytes
-rw-r--r--tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java167
-rw-r--r--tests/DumpRenderTree/AndroidManifest.xml2
-rw-r--r--tests/DumpRenderTree/results/layout_tests_crashed.txt1
-rw-r--r--tests/DumpRenderTree/results/layout_tests_failed.txt280
-rw-r--r--tests/DumpRenderTree/results/layout_tests_nontext.txt1753
-rw-r--r--tests/DumpRenderTree/results/layout_tests_passed.txt1046
-rwxr-xr-xtests/DumpRenderTree/run_layout_tests.py286
-rwxr-xr-xtests/DumpRenderTree/run_page_cycler.py101
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java46
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java15
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java607
-rwxr-xr-xtests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java27
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java518
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java152
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java13
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java426
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java (renamed from tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java)4
-rw-r--r--tests/FrameworkTest/AndroidManifest.xml15
-rw-r--r--tests/FrameworkTest/src/com/android/frameworktest/drawable/MutateDrawable.java49
-rw-r--r--tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithFirstScreenUnSelectable.java (renamed from core/java/com/android/internal/os/HandlerHelper.java)31
-rw-r--r--tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/MutateDrawableTest.java51
-rw-r--r--tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ScrollingThroughListOfFocusablesTest.java13
-rw-r--r--tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/VerticalGravityTest.java2
-rw-r--r--tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListScrollListenerTest.java3
-rw-r--r--tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListSetSelectionTest.java5
-rw-r--r--tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java64
-rw-r--r--tests/FrameworkTest/tests/src/com/android/frameworktest/widget/ListViewTest.java2
-rw-r--r--tests/GadgetHost/AndroidManifest.xml26
-rw-r--r--tests/GadgetHost/res/xml/gadget_info.xml7
-rw-r--r--tests/GadgetHost/src/com/android/gadgethost/GadgetHostActivity.java130
-rw-r--r--tests/GadgetHost/src/com/android/gadgethost/GadgetPickActivity.java73
-rwxr-xr-xtests/ImfTest/AndroidManifest.xml120
-rw-r--r--tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml36
-rwxr-xr-x[-rw-r--r--]tests/ImfTest/res/layout/full_screen_edit_text.xml (renamed from core/res/res/layout/time_picker_text.xml)14
-rwxr-xr-xtests/ImfTest/res/layout/one_edit_text_activity.xml50
-rw-r--r--tests/ImfTest/res/values/config.xml (renamed from location/java/com/android/internal/location/protocol/GLatLng.java)34
-rwxr-xr-xtests/ImfTest/res/values/strings.xml11
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java85
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java79
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java49
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java49
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java57
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java57
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java46
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java46
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java12
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java102
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java96
-rwxr-xr-xtests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java46
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java50
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java52
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java45
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java56
-rw-r--r--tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java51
-rwxr-xr-xtests/ImfTest/tests/Android.mk16
-rwxr-xr-xtests/ImfTest/tests/AndroidManifest.xml34
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java49
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java48
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java48
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java49
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java49
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java49
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java58
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java135
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java40
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java36
-rwxr-xr-x[-rw-r--r--]tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java (renamed from location/java/com/android/internal/location/protocol/GlatlngMessageTypes.java)27
-rwxr-xr-x[-rw-r--r--]tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java (renamed from include/GLES/egltypes.h)38
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java50
-rwxr-xr-xtests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java53
-rw-r--r--tests/SmokeTest/tests/AndroidManifest.xml2
-rw-r--r--tests/StatusBar/Android.mk2
-rw-r--r--tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java4
-rw-r--r--tests/appwidgets/AppWidgetHostTest/Android.mk (renamed from tests/GadgetHost/Android.mk)2
-rw-r--r--tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml36
-rw-r--r--tests/appwidgets/AppWidgetHostTest/res/drawable/oh_hai_icon.pngbin0 -> 2988 bytes
-rw-r--r--tests/appwidgets/AppWidgetHostTest/res/layout/appwidget_host.xml (renamed from tests/GadgetHost/res/layout/gadget_host.xml)11
-rw-r--r--tests/appwidgets/AppWidgetHostTest/res/layout/test_appwidget.xml (renamed from tests/GadgetHost/res/layout/test_gadget.xml)1
-rw-r--r--tests/appwidgets/AppWidgetHostTest/res/layout/test_appwidget_configure.xml44
-rw-r--r--tests/appwidgets/AppWidgetHostTest/res/values/strings.xml24
-rw-r--r--tests/appwidgets/AppWidgetHostTest/res/xml/appwidget_info.xml10
-rw-r--r--tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetContainerView.java (renamed from tests/GadgetHost/src/com/android/gadgethost/GadgetContainerView.java)8
-rw-r--r--tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java198
-rw-r--r--tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetConfigure.java57
-rw-r--r--tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java69
-rw-r--r--tests/appwidgets/AppWidgetProviderTest/Android.mk11
-rw-r--r--tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml13
-rw-r--r--tests/appwidgets/AppWidgetProviderTest/res/layout/test_appwidget.xml26
-rw-r--r--tests/appwidgets/AppWidgetProviderTest/res/values/strings.xml (renamed from tests/GadgetHost/res/values/strings.xml)5
-rw-r--r--tests/appwidgets/AppWidgetProviderTest/res/xml/appwidget_info.xml7
-rw-r--r--tests/appwidgets/AppWidgetProviderTest/src/com/android/tests/appwidgetprovider/TestAppWidgetProvider.java60
-rw-r--r--tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java17
-rw-r--r--tools/aapt/Images.cpp49
-rw-r--r--tools/aapt/Main.cpp6
-rw-r--r--tools/aapt/Package.cpp10
-rw-r--r--tools/aapt/ResourceTable.cpp5
-rw-r--r--tools/aapt/XMLNode.cpp4
-rw-r--r--tools/aidl/aidl.cpp70
-rw-r--r--tools/aidl/options.cpp23
-rw-r--r--tools/aidl/options.h1
-rw-r--r--tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java57
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint.java1
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java177
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java33
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java107
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java38
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java41
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java3
-rw-r--r--tools/preload/Android.mk14
-rw-r--r--tools/preload/Compile.java27
-rw-r--r--tools/preload/LoadedClass.java6
-rw-r--r--tools/preload/MemoryUsage.java11
-rw-r--r--tools/preload/Operation.java18
-rw-r--r--tools/preload/Policy.java114
-rw-r--r--tools/preload/Proc.java93
-rw-r--r--tools/preload/Record.java46
-rw-r--r--tools/preload/WritePreloadedClassFile.java55
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl2
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java2
-rw-r--r--wifi/java/android/net/wifi/WifiMonitor.java84
-rw-r--r--wifi/java/android/net/wifi/WifiNative.java23
-rw-r--r--wifi/java/android/net/wifi/WifiStateTracker.java159
1369 files changed, 86069 insertions, 38426 deletions
diff --git a/Android.mk b/Android.mk
index d67a21e..8013c93 100644
--- a/Android.mk
+++ b/Android.mk
@@ -97,7 +97,10 @@ LOCAL_SRC_FILES += \
core/java/android/view/IWindowManager.aidl \
core/java/android/view/IWindowSession.aidl \
core/java/com/android/internal/app/IBatteryStats.aidl \
- core/java/com/android/internal/gadget/IGadgetService.aidl \
+ core/java/com/android/internal/app/IUsageStats.aidl \
+ core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
+ core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
+ core/java/com/android/internal/os/IResultReceiver.aidl \
core/java/com/android/internal/view/IInputContext.aidl \
core/java/com/android/internal/view/IInputContextCallback.aidl \
core/java/com/android/internal/view/IInputMethod.aidl \
@@ -165,7 +168,7 @@ aidl_files := \
frameworks/base/core/java/android/content/Intent.aidl \
frameworks/base/core/java/android/content/SyncStats.aidl \
frameworks/base/core/java/android/content/res/Configuration.aidl \
- frameworks/base/core/java/android/gadget/GadgetInfo.aidl \
+ frameworks/base/core/java/android/appwidget/AppWidgetProviderInfo.aidl \
frameworks/base/core/java/android/net/Uri.aidl \
frameworks/base/core/java/android/os/Bundle.aidl \
frameworks/base/core/java/android/os/ParcelFileDescriptor.aidl \
@@ -173,6 +176,7 @@ aidl_files := \
frameworks/base/core/java/android/view/MotionEvent.aidl \
frameworks/base/core/java/android/view/Surface.aidl \
frameworks/base/core/java/android/view/WindowManager.aidl \
+ frameworks/base/core/java/android/widget/RemoteViews.aidl \
frameworks/base/core/java/com/android/internal/view/IInputContext.aidl \
frameworks/base/core/java/com/android/internal/view/IInputMethod.aidl \
frameworks/base/core/java/com/android/internal/view/IInputMethodCallback.aidl \
diff --git a/api/3.xml b/api/3.xml
index 9d9ce98..512fef8 100644
--- a/api/3.xml
+++ b/api/3.xml
@@ -25763,17 +25763,6 @@
visibility="public"
>
</field>
-<field name="CATEGORY_GADGET"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.intent.category.GADGET&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="CATEGORY_HOME"
type="java.lang.String"
transient="false"
@@ -79027,7 +79016,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value="&quot;name ASC&quot;"
+ value="&quot;bucket_display_name&quot;"
static="true"
final="true"
deprecated="not deprecated"
@@ -79385,7 +79374,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value="&quot;name ASC&quot;"
+ value="&quot;_display_name&quot;"
static="true"
final="true"
deprecated="not deprecated"
diff --git a/api/current.xml b/api/current.xml
index 5363da2..9deab57 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -144,6 +144,17 @@
visibility="public"
>
</field>
+<field name="BIND_APPWIDGET"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.BIND_APPWIDGET&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="BIND_INPUT_METHOD"
type="java.lang.String"
transient="false"
@@ -595,6 +606,17 @@
visibility="public"
>
</field>
+<field name="MOUNT_FORMAT_FILESYSTEMS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.MOUNT_FORMAT_FILESYSTEMS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MOUNT_UNMOUNT_FILESYSTEMS"
type="java.lang.String"
transient="false"
@@ -606,6 +628,17 @@
visibility="public"
>
</field>
+<field name="PACKAGE_USAGE_STATS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.PACKAGE_USAGE_STATS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="PERSISTENT_ACTIVITY"
type="java.lang.String"
transient="false"
@@ -1013,6 +1046,17 @@
visibility="public"
>
</field>
+<field name="UPDATE_DEVICE_STATS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.UPDATE_DEVICE_STATS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="VIBRATE"
type="java.lang.String"
transient="false"
@@ -1571,6 +1615,17 @@
visibility="public"
>
</field>
+<field name="allowSingleTap"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843353"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="allowTaskReparenting"
type="int"
transient="false"
@@ -1626,6 +1681,17 @@
visibility="public"
>
</field>
+<field name="animateOnClick"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843356"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="animation"
type="int"
transient="false"
@@ -1857,6 +1923,17 @@
visibility="public"
>
</field>
+<field name="bottomOffset"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843351"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="bottomRightRadius"
type="int"
transient="false"
@@ -2224,7 +2301,7 @@
type="int"
transient="false"
volatile="false"
- value="16843336"
+ value="16843330"
static="true"
final="true"
deprecated="not deprecated"
@@ -2352,6 +2429,17 @@
visibility="public"
>
</field>
+<field name="configure"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843357"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="constantSize"
type="int"
transient="false"
@@ -2363,6 +2451,17 @@
visibility="public"
>
</field>
+<field name="content"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843355"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="cropToPadding"
type="int"
transient="false"
@@ -2737,6 +2836,17 @@
visibility="public"
>
</field>
+<field name="dropDownAnchor"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843363"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="dropDownHintAppearance"
type="int"
transient="false"
@@ -2781,6 +2891,17 @@
visibility="public"
>
</field>
+<field name="dropDownWidth"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843362"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="duplicateParentState"
type="int"
transient="false"
@@ -2847,17 +2968,6 @@
visibility="public"
>
</field>
-<field name="editorPrivateContentType"
- type="int"
- transient="false"
- volatile="false"
- value="16843299"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="ellipsize"
type="int"
transient="false"
@@ -3104,7 +3214,7 @@
type="int"
transient="false"
volatile="false"
- value="16843349"
+ value="16843343"
static="true"
final="true"
deprecated="not deprecated"
@@ -3441,6 +3551,17 @@
visibility="public"
>
</field>
+<field name="handle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843354"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="handleProfiling"
type="int"
transient="false"
@@ -3452,6 +3573,17 @@
visibility="public"
>
</field>
+<field name="hapticFeedbackEnabled"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843358"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="hasCode"
type="int"
transient="false"
@@ -3522,7 +3654,7 @@
type="int"
transient="false"
volatile="false"
- value="16843333"
+ value="16843327"
static="true"
final="true"
deprecated="not deprecated"
@@ -3566,7 +3698,7 @@
type="int"
transient="false"
volatile="false"
- value="16843343"
+ value="16843337"
static="true"
final="true"
deprecated="not deprecated"
@@ -3617,6 +3749,39 @@
visibility="public"
>
</field>
+<field name="imeActionId"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843366"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="imeActionLabel"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843365"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="imeOptions"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843364"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="inAnimation"
type="int"
transient="false"
@@ -3742,7 +3907,18 @@
type="int"
transient="false"
volatile="false"
- value="16843351"
+ value="16843345"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="innerRadius"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843359"
static="true"
final="true"
deprecated="not deprecated"
@@ -3863,7 +4039,7 @@
type="int"
transient="false"
volatile="false"
- value="16843340"
+ value="16843334"
static="true"
final="true"
deprecated="not deprecated"
@@ -3874,7 +4050,7 @@
type="int"
transient="false"
volatile="false"
- value="16843342"
+ value="16843336"
static="true"
final="true"
deprecated="not deprecated"
@@ -3885,7 +4061,7 @@
type="int"
transient="false"
volatile="false"
- value="16843348"
+ value="16843342"
static="true"
final="true"
deprecated="not deprecated"
@@ -3896,7 +4072,7 @@
type="int"
transient="false"
volatile="false"
- value="16843341"
+ value="16843335"
static="true"
final="true"
deprecated="not deprecated"
@@ -3973,7 +4149,7 @@
type="int"
transient="false"
volatile="false"
- value="16843339"
+ value="16843333"
static="true"
final="true"
deprecated="not deprecated"
@@ -3984,7 +4160,7 @@
type="int"
transient="false"
volatile="false"
- value="16843332"
+ value="16843326"
static="true"
final="true"
deprecated="not deprecated"
@@ -3995,7 +4171,7 @@
type="int"
transient="false"
volatile="false"
- value="16843346"
+ value="16843340"
static="true"
final="true"
deprecated="not deprecated"
@@ -4006,7 +4182,7 @@
type="int"
transient="false"
volatile="false"
- value="16843345"
+ value="16843339"
static="true"
final="true"
deprecated="not deprecated"
@@ -4017,7 +4193,7 @@
type="int"
transient="false"
volatile="false"
- value="16843344"
+ value="16843338"
static="true"
final="true"
deprecated="not deprecated"
@@ -4083,7 +4259,7 @@
type="int"
transient="false"
volatile="false"
- value="16843331"
+ value="16843325"
static="true"
final="true"
deprecated="not deprecated"
@@ -4094,7 +4270,7 @@
type="int"
transient="false"
volatile="false"
- value="16843347"
+ value="16843341"
static="true"
final="true"
deprecated="not deprecated"
@@ -5359,7 +5535,7 @@
type="int"
transient="false"
volatile="false"
- value="16843338"
+ value="16843332"
static="true"
final="true"
deprecated="not deprecated"
@@ -5370,7 +5546,7 @@
type="int"
transient="false"
volatile="false"
- value="16843337"
+ value="16843331"
static="true"
final="true"
deprecated="not deprecated"
@@ -5381,7 +5557,7 @@
type="int"
transient="false"
volatile="false"
- value="16843329"
+ value="16843323"
static="true"
final="true"
deprecated="not deprecated"
@@ -5487,6 +5663,17 @@
visibility="public"
>
</field>
+<field name="privateImeOptions"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843299"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="process"
type="int"
transient="false"
@@ -5821,7 +6008,7 @@
type="int"
transient="false"
volatile="false"
- value="16843335"
+ value="16843329"
static="true"
final="true"
deprecated="not deprecated"
@@ -6279,6 +6466,17 @@
visibility="public"
>
</field>
+<field name="sharedUserLabel"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843361"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="shouldDisableView"
type="int"
transient="false"
@@ -6330,7 +6528,7 @@
value="16843101"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -6602,7 +6800,7 @@
type="int"
transient="false"
volatile="false"
- value="16843330"
+ value="16843324"
static="true"
final="true"
deprecated="not deprecated"
@@ -7324,6 +7522,17 @@
visibility="public"
>
</field>
+<field name="thickness"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843360"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="thicknessRatio"
type="int"
transient="false"
@@ -7511,6 +7720,17 @@
visibility="public"
>
</field>
+<field name="topOffset"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843352"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="topRightRadius"
type="int"
transient="false"
@@ -7570,7 +7790,7 @@
type="int"
transient="false"
volatile="false"
- value="16843350"
+ value="16843344"
static="true"
final="true"
deprecated="not deprecated"
@@ -7636,7 +7856,7 @@
type="int"
transient="false"
volatile="false"
- value="16843328"
+ value="16843322"
static="true"
final="true"
deprecated="not deprecated"
@@ -7658,7 +7878,7 @@
type="int"
transient="false"
volatile="false"
- value="16843334"
+ value="16843328"
static="true"
final="true"
deprecated="not deprecated"
@@ -7698,6 +7918,61 @@
visibility="public"
>
</field>
+<field name="voiceLanguage"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843349"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="voiceLanguageModel"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843347"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="voiceMaxResults"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843350"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="voicePromptText"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843348"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="voiceSearchMode"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843346"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="webViewStyle"
type="int"
transient="false"
@@ -7863,6 +8138,17 @@
visibility="public"
>
</field>
+<field name="windowNoDisplay"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843294"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="windowNoTitle"
type="int"
transient="false"
@@ -7985,6 +8271,23 @@
>
</field>
</class>
+<class name="R.bool"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="R.bool"
+ type="android.R.bool"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+</class>
<class name="R.color"
extends="java.lang.Object"
abstract="false"
@@ -8475,6 +8778,17 @@
visibility="public"
>
</field>
+<field name="dark_header"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301686"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="dialog_frame"
type="int"
transient="false"
@@ -8783,6 +9097,17 @@
visibility="public"
>
</field>
+<field name="ic_btn_speak_now"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301685"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ic_delete"
type="int"
transient="false"
@@ -10169,6 +10494,17 @@
visibility="public"
>
</field>
+<field name="title_bar_tall"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301687"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="toast_frame"
type="int"
transient="false"
@@ -10208,6 +10544,17 @@
visibility="public"
>
</constructor>
+<field name="addToDictionary"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16908330"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="background"
type="int"
transient="false"
@@ -10439,17 +10786,6 @@
visibility="public"
>
</field>
-<field name="inputMethod"
- type="int"
- transient="false"
- volatile="false"
- value="16908324"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="keyboardView"
type="int"
transient="false"
@@ -10549,6 +10885,28 @@
visibility="public"
>
</field>
+<field name="startSelectingText"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16908328"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="stopSelectingText"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16908329"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="summary"
type="int"
transient="false"
@@ -10560,6 +10918,17 @@
visibility="public"
>
</field>
+<field name="switchInputMethod"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16908324"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="tabcontent"
type="int"
transient="false"
@@ -10649,6 +11018,56 @@
>
</field>
</class>
+<class name="R.integer"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="R.integer"
+ type="android.R.integer"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="config_longAnimTime"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17694722"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="config_mediumAnimTime"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17694721"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="config_shortAnimTime"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17694720"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="R.layout"
extends="java.lang.Object"
abstract="false"
@@ -10947,6 +11366,17 @@
visibility="public"
>
</field>
+<field name="VideoView_error_text_invalid_progressive_playback"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17039381"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="VideoView_error_text_unknown"
type="int"
transient="false"
@@ -11035,6 +11465,17 @@
visibility="public"
>
</field>
+<field name="dialog_alert_title"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17039380"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="emptyPhoneNumber"
type="int"
transient="false"
@@ -13234,7 +13675,18 @@
<parameter name="event" type="android.view.MotionEvent">
</parameter>
</method>
-<method name="onUserLeaving"
+<method name="onUserInteraction"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onUserLeaveHint"
return="void"
abstract="false"
native="false"
@@ -13632,6 +14084,19 @@
<parameter name="textColor" type="int">
</parameter>
</method>
+<method name="setVisible"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="visible" type="boolean">
+</parameter>
+</method>
<method name="setVolumeControlStream"
return="void"
abstract="false"
@@ -13946,6 +14411,17 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="getDeviceConfigurationInfo"
+ return="android.content.pm.ConfigurationInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getMemoryInfo"
return="void"
abstract="false"
@@ -14028,6 +14504,19 @@
<exception name="SecurityException" type="java.lang.SecurityException">
</exception>
</method>
+<method name="restartPackage"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
<field name="RECENT_WITH_EXCLUDED"
type="int"
transient="false"
@@ -14499,6 +14988,81 @@
visibility="public"
>
</field>
+<field name="IMPORTANCE_BACKGROUND"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="400"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMPORTANCE_EMPTY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="500"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMPORTANCE_FOREGROUND"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="100"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMPORTANCE_SERVICE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="300"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMPORTANCE_VISIBLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="200"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="importance"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="lru"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="pid"
type="int"
transient="false"
@@ -18103,6 +18667,51 @@
>
</method>
</class>
+<class name="IntentService"
+ extends="android.app.Service"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="IntentService"
+ type="android.app.IntentService"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</constructor>
+<method name="onBind"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onHandleIntent"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+</class>
<class name="KeyguardManager"
extends="java.lang.Object"
abstract="false"
@@ -18219,7 +18828,7 @@
</constructor>
<method name="getTargetIntent"
return="android.content.Intent"
- abstract="true"
+ abstract="false"
native="false"
synchronized="false"
static="false"
@@ -18228,6 +18837,117 @@
visibility="protected"
>
</method>
+<method name="intentForPosition"
+ return="android.content.Intent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
+<method name="makeListItems"
+ return="java.util.List&lt;android.app.LauncherActivity.ListItem&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="LauncherActivity.IconResizer"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="LauncherActivity.IconResizer"
+ type="android.app.LauncherActivity.IconResizer"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="createIconThumbnail"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="icon" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
+</class>
+<class name="LauncherActivity.ListItem"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="LauncherActivity.ListItem"
+ type="android.app.LauncherActivity.ListItem"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="className"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="icon"
+ type="android.graphics.drawable.Drawable"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="label"
+ type="java.lang.CharSequence"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="packageName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="ListActivity"
extends="android.app.Activity"
@@ -20298,6 +21018,729 @@
</method>
</interface>
</package>
+<package name="android.appwidget"
+>
+<class name="AppWidgetHost"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AppWidgetHost"
+ type="android.appwidget.AppWidgetHost"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="hostId" type="int">
+</parameter>
+</constructor>
+<method name="allocateAppWidgetId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="createView"
+ return="android.appwidget.AppWidgetHostView"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="appWidgetId" type="int">
+</parameter>
+<parameter name="appWidget" type="android.appwidget.AppWidgetProviderInfo">
+</parameter>
+</method>
+<method name="deleteAllHosts"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="deleteAppWidgetId"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetId" type="int">
+</parameter>
+</method>
+<method name="deleteHost"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onCreateView"
+ return="android.appwidget.AppWidgetHostView"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="appWidgetId" type="int">
+</parameter>
+<parameter name="appWidget" type="android.appwidget.AppWidgetProviderInfo">
+</parameter>
+</method>
+<method name="onProviderChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="appWidgetId" type="int">
+</parameter>
+<parameter name="appWidget" type="android.appwidget.AppWidgetProviderInfo">
+</parameter>
+</method>
+<method name="startListening"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="stopListening"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="AppWidgetHostView"
+ extends="android.widget.FrameLayout"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AppWidgetHostView"
+ type="android.appwidget.AppWidgetHostView"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<constructor name="AppWidgetHostView"
+ type="android.appwidget.AppWidgetHostView"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="animationIn" type="int">
+</parameter>
+<parameter name="animationOut" type="int">
+</parameter>
+</constructor>
+<method name="getAppWidgetId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAppWidgetInfo"
+ return="android.appwidget.AppWidgetProviderInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDefaultView"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="getErrorView"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="prepareView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+</method>
+<method name="setAppWidget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetId" type="int">
+</parameter>
+<parameter name="info" type="android.appwidget.AppWidgetProviderInfo">
+</parameter>
+</method>
+<method name="updateAppWidget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="remoteViews" type="android.widget.RemoteViews">
+</parameter>
+</method>
+</class>
+<class name="AppWidgetManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="bindAppWidgetId"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetId" type="int">
+</parameter>
+<parameter name="provider" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="getAppWidgetIds"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="provider" type="android.content.ComponentName">
+</parameter>
+</method>
+<method name="getAppWidgetInfo"
+ return="android.appwidget.AppWidgetProviderInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetId" type="int">
+</parameter>
+</method>
+<method name="getInstalledProviders"
+ return="java.util.List&lt;android.appwidget.AppWidgetProviderInfo&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInstance"
+ return="android.appwidget.AppWidgetManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="updateAppWidget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetIds" type="int[]">
+</parameter>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+</method>
+<method name="updateAppWidget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="appWidgetId" type="int">
+</parameter>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+</method>
+<method name="updateAppWidget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="provider" type="android.content.ComponentName">
+</parameter>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+</method>
+<field name="ACTION_APPWIDGET_CONFIGURE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.appwidget.action.APPWIDGET_CONFIGURE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_APPWIDGET_DELETED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.appwidget.action.APPWIDGET_DELETED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_APPWIDGET_DISABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.appwidget.action.APPWIDGET_DISABLED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_APPWIDGET_ENABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.appwidget.action.APPWIDGET_ENABLED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_APPWIDGET_PICK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.appwidget.action.APPWIDGET_PICK&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_APPWIDGET_UPDATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.appwidget.action.APPWIDGET_UPDATE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_APPWIDGET_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;appWidgetId&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_APPWIDGET_IDS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;appWidgetIds&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INVALID_APPWIDGET_ID"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="META_DATA_APPWIDGET_PROVIDER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.appwidget.provider&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AppWidgetProvider"
+ extends="android.content.BroadcastReceiver"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AppWidgetProvider"
+ type="android.appwidget.AppWidgetProvider"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="onDeleted"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="appWidgetIds" type="int[]">
+</parameter>
+</method>
+<method name="onDisabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="onEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="onReceive"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
+<method name="onUpdate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="appWidgetManager" type="android.appwidget.AppWidgetManager">
+</parameter>
+<parameter name="appWidgetIds" type="int[]">
+</parameter>
+</method>
+</class>
+<class name="AppWidgetProviderInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="AppWidgetProviderInfo"
+ type="android.appwidget.AppWidgetProviderInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="AppWidgetProviderInfo"
+ type="android.appwidget.AppWidgetProviderInfo"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="in" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="configure"
+ type="android.content.ComponentName"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="icon"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="initialLayout"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="label"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="minHeight"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="minWidth"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="provider"
+ type="android.content.ComponentName"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="updatePeriodMillis"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
<package name="android.content"
>
<class name="ActivityNotFoundException"
@@ -20766,6 +22209,21 @@
<parameter name="intent" type="android.content.Intent">
</parameter>
</method>
+<method name="peekService"
+ return="android.os.IBinder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="myContext" type="android.content.Context">
+</parameter>
+<parameter name="service" type="android.content.Intent">
+</parameter>
+</method>
<method name="setDebugUnregister"
return="void"
abstract="false"
@@ -21253,6 +22711,23 @@
visibility="public"
>
</method>
+<method name="openAssetFile"
+ return="android.content.res.AssetFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="mode" type="java.lang.String">
+</parameter>
+<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
+</exception>
+</method>
<method name="openFile"
return="android.os.ParcelFileDescriptor"
abstract="false"
@@ -21561,6 +23036,23 @@
<parameter name="syncToNetwork" type="boolean">
</parameter>
</method>
+<method name="openAssetFileDescriptor"
+ return="android.content.res.AssetFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="mode" type="java.lang.String">
+</parameter>
+<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
+</exception>
+</method>
<method name="openFileDescriptor"
return="android.os.ParcelFileDescriptor"
abstract="false"
@@ -21608,6 +23100,23 @@
<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
</exception>
</method>
+<method name="openOutputStream"
+ return="java.io.OutputStream"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<parameter name="mode" type="java.lang.String">
+</parameter>
+<exception name="FileNotFoundException" type="java.io.FileNotFoundException">
+</exception>
+</method>
<method name="query"
return="android.database.Cursor"
abstract="false"
@@ -26629,6 +28138,17 @@
visibility="public"
>
</field>
+<field name="ACTION_MEDIA_CHECKING"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.MEDIA_CHECKING&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_MEDIA_EJECT"
type="java.lang.String"
transient="false"
@@ -26651,6 +28171,17 @@
visibility="public"
>
</field>
+<field name="ACTION_MEDIA_NOFS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.MEDIA_NOFS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_MEDIA_REMOVED"
type="java.lang.String"
transient="false"
@@ -26761,6 +28292,17 @@
visibility="public"
>
</field>
+<field name="ACTION_PACKAGE_DATA_CLEARED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.PACKAGE_DATA_CLEARED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_PACKAGE_INSTALL"
type="java.lang.String"
transient="false"
@@ -26904,6 +28446,17 @@
visibility="public"
>
</field>
+<field name="ACTION_SEARCH_LONG_PRESS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.SEARCH_LONG_PRESS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_SEND"
type="java.lang.String"
transient="false"
@@ -27014,6 +28567,17 @@
visibility="public"
>
</field>
+<field name="ACTION_USER_PRESENT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.USER_PRESENT&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_VIEW"
type="java.lang.String"
transient="false"
@@ -27124,22 +28688,22 @@
visibility="public"
>
</field>
-<field name="CATEGORY_GADGET"
+<field name="CATEGORY_HOME"
type="java.lang.String"
transient="false"
volatile="false"
- value="&quot;android.intent.category.GADGET&quot;"
+ value="&quot;android.intent.category.HOME&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="CATEGORY_HOME"
+<field name="CATEGORY_INFO"
type="java.lang.String"
transient="false"
volatile="false"
- value="&quot;android.intent.category.HOME&quot;"
+ value="&quot;android.intent.category.INFO&quot;"
static="true"
final="true"
deprecated="not deprecated"
@@ -27288,6 +28852,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_DATA_REMOVED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.extra.DATA_REMOVED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_DONT_KILL_APP"
type="java.lang.String"
transient="false"
@@ -27343,6 +28918,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_REPLACING"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.extra.REPLACING&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_SHORTCUT_ICON"
type="java.lang.String"
transient="false"
@@ -27618,6 +29204,17 @@
visibility="public"
>
</field>
+<field name="FLAG_ACTIVITY_REORDER_TO_FRONT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="131072"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_ACTIVITY_RESET_TASK_IF_NEEDED"
type="int"
transient="false"
@@ -30689,6 +32286,26 @@
visibility="public"
>
</field>
+<field name="sharedUserId"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="sharedUserLabel"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="signatures"
type="android.content.pm.Signature[]"
transient="false"
@@ -31259,6 +32876,21 @@
<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
</exception>
</method>
+<method name="getLaunchIntentForPackage"
+ return="android.content.Intent"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
+</exception>
+</method>
<method name="getNameForUid"
return="java.lang.String"
abstract="true"
@@ -31475,6 +33107,17 @@
<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
</exception>
</method>
+<method name="getSystemSharedLibraryNames"
+ return="java.lang.String[]"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getText"
return="java.lang.CharSequence"
abstract="true"
@@ -31539,6 +33182,17 @@
<parameter name="packageURI" type="android.net.Uri">
</parameter>
</method>
+<method name="isSafeMode"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="queryBroadcastReceivers"
return="java.util.List&lt;android.content.pm.ResolveInfo&gt;"
abstract="true"
@@ -33318,6 +34972,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.os.Parcelable">
+</implements>
<constructor name="AssetFileDescriptor"
type="android.content.res.AssetFileDescriptor"
static="false"
@@ -33345,6 +35001,54 @@
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
+<method name="createInputStream"
+ return="java.io.FileInputStream"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="createOutputStream"
+ return="java.io.FileOutputStream"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDeclaredLength"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getFileDescriptor"
return="java.io.FileDescriptor"
abstract="false"
@@ -33389,6 +35093,84 @@
visibility="public"
>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="UNKNOWN_LENGTH"
+ type="long"
+ transient="false"
+ volatile="false"
+ value="-1L"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="AssetFileDescriptor.AutoCloseInputStream"
+ extends="android.os.ParcelFileDescriptor.AutoCloseInputStream"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AssetFileDescriptor.AutoCloseInputStream"
+ type="android.content.res.AssetFileDescriptor.AutoCloseInputStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="android.content.res.AssetFileDescriptor">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</constructor>
+</class>
+<class name="AssetFileDescriptor.AutoCloseOutputStream"
+ extends="android.os.ParcelFileDescriptor.AutoCloseOutputStream"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AssetFileDescriptor.AutoCloseOutputStream"
+ type="android.content.res.AssetFileDescriptor.AutoCloseOutputStream"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="android.content.res.AssetFileDescriptor">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</constructor>
</class>
<class name="AssetManager"
extends="java.lang.Object"
@@ -34572,6 +36354,23 @@
<exception name="Resources.NotFoundException" type="android.content.res.Resources.NotFoundException">
</exception>
</method>
+<method name="getFraction"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+<parameter name="base" type="int">
+</parameter>
+<parameter name="pbase" type="int">
+</parameter>
+</method>
<method name="getIdentifier"
return="int"
abstract="false"
@@ -35402,6 +37201,21 @@
<parameter name="name" type="java.lang.String">
</parameter>
</method>
+<method name="getLayoutDimension"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+<parameter name="defValue" type="int">
+</parameter>
+</method>
<method name="getNonResourceString"
return="java.lang.String"
abstract="false"
@@ -42735,6 +44549,35 @@
</parameter>
<parameter name="stride" type="int">
</parameter>
+<parameter name="x" type="float">
+</parameter>
+<parameter name="y" type="float">
+</parameter>
+<parameter name="width" type="int">
+</parameter>
+<parameter name="height" type="int">
+</parameter>
+<parameter name="hasAlpha" type="boolean">
+</parameter>
+<parameter name="paint" type="android.graphics.Paint">
+</parameter>
+</method>
+<method name="drawBitmap"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="colors" type="int[]">
+</parameter>
+<parameter name="offset" type="int">
+</parameter>
+<parameter name="stride" type="int">
+</parameter>
<parameter name="x" type="int">
</parameter>
<parameter name="y" type="int">
@@ -52128,6 +53971,17 @@
visibility="public"
>
</method>
+<method name="mutate"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onBoundsChange"
return="void"
abstract="false"
@@ -53808,6 +55662,17 @@
<parameter name="canvas" type="android.graphics.Canvas">
</parameter>
</method>
+<method name="getDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getOpacity"
return="int"
abstract="false"
@@ -53930,6 +55795,17 @@
<parameter name="canvas" type="android.graphics.Canvas">
</parameter>
</method>
+<method name="getDrawable"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getOpacity"
return="int"
abstract="false"
@@ -54542,6 +56418,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.lang.Cloneable">
+</implements>
<constructor name="Shape"
type="android.graphics.drawable.shapes.Shape"
static="false"
@@ -54550,6 +56428,19 @@
visibility="public"
>
</constructor>
+<method name="clone"
+ return="android.graphics.drawable.shapes.Shape"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="CloneNotSupportedException" type="java.lang.CloneNotSupportedException">
+</exception>
+</method>
<method name="draw"
return="void"
abstract="true"
@@ -55193,6 +57084,108 @@
>
</field>
</class>
+<class name="GeomagneticField"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="GeomagneticField"
+ type="android.hardware.GeomagneticField"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="gdLatitudeDeg" type="float">
+</parameter>
+<parameter name="gdLongitudeDeg" type="float">
+</parameter>
+<parameter name="altitudeMeters" type="float">
+</parameter>
+<parameter name="timeMillis" type="long">
+</parameter>
+</constructor>
+<method name="getDeclination"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getFieldStrength"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getHorizontalStrength"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInclination"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getX"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getY"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getZ"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="Sensor"
extends="java.lang.Object"
abstract="false"
@@ -56627,6 +58620,39 @@
<parameter name="defStyle" type="int">
</parameter>
</constructor>
+<method name="finishInternalChanges"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasVerticalScrollBar"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="startInternalChanges"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
</class>
<class name="InputMethodService"
extends="android.inputmethodservice.AbstractInputMethodService"
@@ -56644,8 +58670,8 @@
visibility="public"
>
</constructor>
-<method name="dismissSoftInput"
- return="void"
+<method name="getCandidatesHiddenVisibility"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -56654,8 +58680,6 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="flags" type="int">
-</parameter>
</method>
<method name="getCurrentInputBinding"
return="android.view.inputmethod.InputBinding"
@@ -56723,6 +58747,19 @@
visibility="public"
>
</method>
+<method name="getTextForImeAction"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="imeOptions" type="int">
+</parameter>
+</method>
<method name="getWindow"
return="android.app.Dialog"
abstract="false"
@@ -56734,6 +58771,17 @@
visibility="public"
>
</method>
+<method name="hideStatusIcon"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="hideWindow"
return="void"
abstract="false"
@@ -56767,6 +58815,17 @@
visibility="public"
>
</method>
+<method name="isShowInputRequested"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onAppPrivateCommand"
return="void"
abstract="false"
@@ -56924,6 +58983,86 @@
visibility="public"
>
</method>
+<method name="onExtractTextContextMenuItem"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="onExtractedCursorMovement"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dx" type="int">
+</parameter>
+<parameter name="dy" type="int">
+</parameter>
+</method>
+<method name="onExtractedSelectionChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
+</parameter>
+</method>
+<method name="onExtractedTextClicked"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onExtractingInputChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ei" type="android.view.inputmethod.EditorInfo">
+</parameter>
+</method>
+<method name="onFinishCandidatesView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="finishingInput" type="boolean">
+</parameter>
+</method>
<method name="onFinishInput"
return="void"
abstract="false"
@@ -56935,6 +59074,30 @@
visibility="public"
>
</method>
+<method name="onFinishInputView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="finishingInput" type="boolean">
+</parameter>
+</method>
+<method name="onInitializeInterface"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onKeyDown"
return="boolean"
abstract="false"
@@ -56982,8 +59145,8 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
-<method name="onShowRequested"
- return="void"
+<method name="onShowInputRequested"
+ return="boolean"
abstract="false"
native="false"
synchronized="false"
@@ -56994,6 +59157,23 @@
>
<parameter name="flags" type="int">
</parameter>
+<parameter name="configChange" type="boolean">
+</parameter>
+</method>
+<method name="onStartCandidatesView"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="info" type="android.view.inputmethod.EditorInfo">
+</parameter>
+<parameter name="restarting" type="boolean">
+</parameter>
</method>
<method name="onStartInput"
return="void"
@@ -57064,6 +59244,19 @@
<parameter name="text" type="android.view.inputmethod.ExtractedText">
</parameter>
</method>
+<method name="onUpdateExtractingAccessories"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ei" type="android.view.inputmethod.EditorInfo">
+</parameter>
+</method>
<method name="onUpdateSelection"
return="void"
abstract="false"
@@ -57087,6 +59280,80 @@
<parameter name="candidatesEnd" type="int">
</parameter>
</method>
+<method name="onWindowHidden"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onWindowShown"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="requestHideSelf"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="sendDefaultEditorAction"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromEnterKey" type="boolean">
+</parameter>
+</method>
+<method name="sendDownUpKeyEvents"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyEventCode" type="int">
+</parameter>
+</method>
+<method name="sendKeyChar"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="charCode" type="char">
+</parameter>
+</method>
<method name="setCandidatesView"
return="void"
abstract="false"
@@ -57139,7 +59406,7 @@
<parameter name="view" type="android.view.View">
</parameter>
</method>
-<method name="setStatusIcon"
+<method name="showStatusIcon"
return="void"
abstract="false"
native="false"
@@ -57253,6 +59520,10 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="flags" type="int">
+</parameter>
+<parameter name="resultReceiver" type="android.os.ResultReceiver">
+</parameter>
</method>
<method name="restartInput"
return="void"
@@ -57264,6 +59535,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="ic" type="android.view.inputmethod.InputConnection">
+</parameter>
<parameter name="attribute" type="android.view.inputmethod.EditorInfo">
</parameter>
</method>
@@ -57279,6 +59552,8 @@
>
<parameter name="flags" type="int">
</parameter>
+<parameter name="resultReceiver" type="android.os.ResultReceiver">
+</parameter>
</method>
<method name="startInput"
return="void"
@@ -57290,6 +59565,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="ic" type="android.view.inputmethod.InputConnection">
+</parameter>
<parameter name="attribute" type="android.view.inputmethod.EditorInfo">
</parameter>
</method>
@@ -57360,6 +59637,21 @@
visibility="public"
>
</method>
+<method name="toggleSoftInput"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="showFlags" type="int">
+</parameter>
+<parameter name="hideFlags" type="int">
+</parameter>
+</method>
<method name="updateCursor"
return="void"
abstract="false"
@@ -57461,6 +59753,16 @@
visibility="public"
>
</field>
+<field name="contentTopInsets"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="touchableInsets"
type="int"
transient="false"
@@ -57471,6 +59773,16 @@
visibility="public"
>
</field>
+<field name="visibleTopInsets"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="Keyboard"
extends="java.lang.Object"
@@ -57637,6 +59949,21 @@
visibility="public"
>
</method>
+<method name="getNearestKeys"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="x" type="int">
+</parameter>
+<parameter name="y" type="int">
+</parameter>
+</method>
<method name="getShiftKeyIndex"
return="int"
abstract="false"
@@ -58549,6 +60876,45 @@
<parameter name="keyCodes" type="int[]">
</parameter>
</method>
+<method name="onPress"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="primaryCode" type="int">
+</parameter>
+</method>
+<method name="onRelease"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="primaryCode" type="int">
+</parameter>
+</method>
+<method name="onText"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="java.lang.CharSequence">
+</parameter>
+</method>
<method name="swipeDown"
return="void"
abstract="true"
@@ -59736,6 +62102,21 @@
<parameter name="dest" type="android.location.Location">
</parameter>
</method>
+<method name="dump"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pw" type="android.util.Printer">
+</parameter>
+<parameter name="prefix" type="java.lang.String">
+</parameter>
+</method>
<method name="getAccuracy"
return="float"
abstract="false"
@@ -60879,6 +63260,111 @@
>
</method>
</class>
+<class name="AudioFormat"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AudioFormat"
+ type="android.media.AudioFormat"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="CHANNEL_CONFIGURATION_DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_CONFIGURATION_INVALID"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_CONFIGURATION_MONO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANNEL_CONFIGURATION_STEREO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ENCODING_DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ENCODING_INVALID"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ENCODING_PCM_16BIT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ENCODING_PCM_8BIT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="AudioManager"
extends="java.lang.Object"
abstract="false"
@@ -61270,6 +63756,17 @@
visibility="public"
>
</method>
+<field name="ACTION_AUDIO_BECOMING_NOISY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.AUDIO_BECOMING_NOISY&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ADJUST_LOWER"
type="int"
transient="false"
@@ -61777,6 +64274,986 @@
>
</field>
</class>
+<class name="AudioRecord"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AudioRecord"
+ type="android.media.AudioRecord"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="audioSource" type="int">
+</parameter>
+<parameter name="sampleRateInHz" type="int">
+</parameter>
+<parameter name="channelConfig" type="int">
+</parameter>
+<parameter name="audioFormat" type="int">
+</parameter>
+<parameter name="bufferSizeInBytes" type="int">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+</constructor>
+<method name="getAudioFormat"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAudioSource"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getChannelConfiguration"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getChannelCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getNotificationMarkerPosition"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPositionNotificationPeriod"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getRecordingState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSampleRate"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="read"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="audioData" type="byte[]">
+</parameter>
+<parameter name="offsetInBytes" type="int">
+</parameter>
+<parameter name="sizeInBytes" type="int">
+</parameter>
+</method>
+<method name="read"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="audioData" type="short[]">
+</parameter>
+<parameter name="offsetInShorts" type="int">
+</parameter>
+<parameter name="sizeInShorts" type="int">
+</parameter>
+</method>
+<method name="read"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="audioBuffer" type="java.nio.ByteBuffer">
+</parameter>
+<parameter name="sizeInBytes" type="int">
+</parameter>
+</method>
+<method name="release"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setMarkerReachedListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.media.AudioRecord.OnMarkerReachedListener">
+</parameter>
+</method>
+<method name="setNotificationMarkerPosition"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="markerInFrames" type="int">
+</parameter>
+</method>
+<method name="setPeriodicNotificationListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.media.AudioRecord.OnPeriodicNotificationListener">
+</parameter>
+</method>
+<method name="setPositionNotificationPeriod"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="periodInFrames" type="int">
+</parameter>
+</method>
+<method name="startRecording"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="stop"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<field name="ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_BAD_VALUE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_INVALID_OPERATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RECORDSTATE_RECORDING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RECORDSTATE_STOPPED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATE_INITIALIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATE_UNINITIALIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SUCCESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="AudioRecord.OnMarkerReachedListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onMarkerReached"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="recorder" type="android.media.AudioRecord">
+</parameter>
+</method>
+</interface>
+<interface name="AudioRecord.OnPeriodicNotificationListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onPeriodicNotification"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="recorder" type="android.media.AudioRecord">
+</parameter>
+</method>
+</interface>
+<class name="AudioTrack"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="AudioTrack"
+ type="android.media.AudioTrack"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="streamType" type="int">
+</parameter>
+<parameter name="sampleRateInHz" type="int">
+</parameter>
+<parameter name="channelConfig" type="int">
+</parameter>
+<parameter name="audioFormat" type="int">
+</parameter>
+<parameter name="bufferSizeInBytes" type="int">
+</parameter>
+<parameter name="mode" type="int">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+</constructor>
+<method name="flush"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAudioFormat"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getChannelConfiguration"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getChannelCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMaxVolume"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMinVolume"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getNativeFrameCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</method>
+<method name="getNativeOutputSampleRate"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="streamType" type="int">
+</parameter>
+</method>
+<method name="getNotificationMarkerPosition"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPlayState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPlaybackHeadPosition"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPositionNotificationPeriod"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSampleRate"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStreamType"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pause"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="play"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="release"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="reloadStaticData"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setLoopPoints"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startInFrames" type="int">
+</parameter>
+<parameter name="endInFrames" type="int">
+</parameter>
+<parameter name="loopCount" type="int">
+</parameter>
+</method>
+<method name="setNotificationMarkerPosition"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="markerInFrames" type="int">
+</parameter>
+</method>
+<method name="setPlaybackHeadPosition"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="positionInFrames" type="int">
+</parameter>
+</method>
+<method name="setPlaybackPositionUpdateListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.media.AudioTrack.OnPlaybackPositionUpdateListener">
+</parameter>
+</method>
+<method name="setPlaybackPositionUpdateListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.media.AudioTrack.OnPlaybackPositionUpdateListener">
+</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</method>
+<method name="setPlaybackRate"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sampleRateInHz" type="int">
+</parameter>
+</method>
+<method name="setPositionNotificationPeriod"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="periodInFrames" type="int">
+</parameter>
+</method>
+<method name="setState"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="state" type="int">
+</parameter>
+</method>
+<method name="setStereoVolume"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="leftVolume" type="float">
+</parameter>
+<parameter name="rightVolume" type="float">
+</parameter>
+</method>
+<method name="stop"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="write"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="audioData" type="byte[]">
+</parameter>
+<parameter name="offsetInBytes" type="int">
+</parameter>
+<parameter name="sizeInBytes" type="int">
+</parameter>
+</method>
+<method name="write"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="audioData" type="short[]">
+</parameter>
+<parameter name="offsetInShorts" type="int">
+</parameter>
+<parameter name="sizeInShorts" type="int">
+</parameter>
+</method>
+<field name="ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_BAD_VALUE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR_INVALID_OPERATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_STATIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_STREAM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PLAYSTATE_PAUSED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PLAYSTATE_PLAYING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PLAYSTATE_STOPPED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATE_INITIALIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATE_NO_STATIC_DATA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATE_UNINITIALIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SUCCESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="AudioTrack.OnPlaybackPositionUpdateListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onMarkerReached"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="track" type="android.media.AudioTrack">
+</parameter>
+</method>
+<method name="onPeriodicNotification"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="track" type="android.media.AudioTrack">
+</parameter>
+</method>
+</interface>
<class name="FaceDetector"
extends="java.lang.Object"
abstract="false"
@@ -61916,6 +65393,349 @@
>
</field>
</class>
+<class name="JetPlayer"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="clearQueue"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="clone"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="CloneNotSupportedException" type="java.lang.CloneNotSupportedException">
+</exception>
+</method>
+<method name="closeJetFile"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getJetPlayer"
+ return="android.media.JetPlayer"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMaxTracks"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="loadJetFile"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
+<method name="loadJetFile"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="afd" type="android.content.res.AssetFileDescriptor">
+</parameter>
+</method>
+<method name="pause"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="play"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="queueJetSegment"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="segmentNum" type="int">
+</parameter>
+<parameter name="libNum" type="int">
+</parameter>
+<parameter name="repeatCount" type="int">
+</parameter>
+<parameter name="transpose" type="int">
+</parameter>
+<parameter name="muteFlags" type="int">
+</parameter>
+<parameter name="userID" type="byte">
+</parameter>
+</method>
+<method name="queueJetSegmentMuteArray"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="segmentNum" type="int">
+</parameter>
+<parameter name="libNum" type="int">
+</parameter>
+<parameter name="repeatCount" type="int">
+</parameter>
+<parameter name="transpose" type="int">
+</parameter>
+<parameter name="muteArray" type="boolean[]">
+</parameter>
+<parameter name="userID" type="byte">
+</parameter>
+</method>
+<method name="release"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setEventListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.media.JetPlayer.JetEventListener">
+</parameter>
+</method>
+<method name="setMuteArray"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="muteArray" type="boolean[]">
+</parameter>
+<parameter name="sync" type="boolean">
+</parameter>
+</method>
+<method name="setMuteFlag"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="trackId" type="int">
+</parameter>
+<parameter name="muteFlag" type="boolean">
+</parameter>
+<parameter name="sync" type="boolean">
+</parameter>
+</method>
+<method name="setMuteFlags"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="muteFlags" type="int">
+</parameter>
+<parameter name="sync" type="boolean">
+</parameter>
+</method>
+<method name="setStatusUpdateListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.media.JetPlayer.JetStatusUpdateListener">
+</parameter>
+</method>
+<method name="triggerClip"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="clipId" type="int">
+</parameter>
+</method>
+</class>
+<interface name="JetPlayer.JetEventListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onJetEvent"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="player" type="android.media.JetPlayer">
+</parameter>
+<parameter name="segment" type="short">
+</parameter>
+<parameter name="track" type="byte">
+</parameter>
+<parameter name="channel" type="byte">
+</parameter>
+<parameter name="controller" type="byte">
+</parameter>
+<parameter name="value" type="byte">
+</parameter>
+</method>
+</interface>
+<interface name="JetPlayer.JetStatusUpdateListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onJetNumQueuedSegmentUpdate"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="player" type="android.media.JetPlayer">
+</parameter>
+<parameter name="nbSegments" type="int">
+</parameter>
+</method>
+<method name="onJetPauseUpdate"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="player" type="android.media.JetPlayer">
+</parameter>
+<parameter name="paused" type="int">
+</parameter>
+</method>
+<method name="onJetUserIdUpdate"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="player" type="android.media.JetPlayer">
+</parameter>
+<parameter name="userId" type="int">
+</parameter>
+<parameter name="repeatCount" type="int">
+</parameter>
+</method>
+</interface>
<class name="MediaPlayer"
extends="java.lang.Object"
abstract="false"
@@ -62282,7 +66102,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="l" type="android.media.MediaPlayer.OnErrorListener">
+<parameter name="listener" type="android.media.MediaPlayer.OnErrorListener">
</parameter>
</method>
<method name="setOnPreparedListener"
@@ -62546,7 +66366,7 @@
<method name="prepare"
return="void"
abstract="false"
- native="true"
+ native="false"
synchronized="false"
static="false"
final="false"
@@ -62572,7 +66392,7 @@
<method name="reset"
return="void"
abstract="false"
- native="true"
+ native="false"
synchronized="false"
static="false"
final="false"
@@ -62610,7 +66430,20 @@
<exception name="IllegalStateException" type="java.lang.IllegalStateException">
</exception>
</method>
-<method name="setOutputFile"
+<method name="setCamera"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="c" type="android.hardware.Camera">
+</parameter>
+</method>
+<method name="setMaxDuration"
return="void"
abstract="false"
native="true"
@@ -62620,6 +66453,62 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="max_duration_ms" type="int">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+</method>
+<method name="setOnErrorListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="l" type="android.media.MediaRecorder.OnErrorListener">
+</parameter>
+</method>
+<method name="setOnInfoListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.media.MediaRecorder.OnInfoListener">
+</parameter>
+</method>
+<method name="setOutputFile"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="java.io.FileDescriptor">
+</parameter>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="setOutputFile"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="path" type="java.lang.String">
</parameter>
<exception name="IllegalStateException" type="java.lang.IllegalStateException">
@@ -62653,6 +66542,68 @@
<parameter name="sv" type="android.view.Surface">
</parameter>
</method>
+<method name="setVideoEncoder"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="video_encoder" type="int">
+</parameter>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="setVideoFrameRate"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="rate" type="int">
+</parameter>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="setVideoSize"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="width" type="int">
+</parameter>
+<parameter name="height" type="int">
+</parameter>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
+<method name="setVideoSource"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="video_source" type="int">
+</parameter>
+<exception name="IllegalStateException" type="java.lang.IllegalStateException">
+</exception>
+</method>
<method name="start"
return="void"
abstract="false"
@@ -62679,6 +66630,39 @@
<exception name="IllegalStateException" type="java.lang.IllegalStateException">
</exception>
</method>
+<field name="MEDIA_RECORDER_ERROR_UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MEDIA_RECORDER_INFO_MAX_DURATION_REACHED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="800"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MEDIA_RECORDER_INFO_UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="MediaRecorder.AudioEncoder"
extends="java.lang.Object"
@@ -62742,6 +66726,56 @@
>
</field>
</class>
+<interface name="MediaRecorder.OnErrorListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onError"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mr" type="android.media.MediaRecorder">
+</parameter>
+<parameter name="what" type="int">
+</parameter>
+<parameter name="extra" type="int">
+</parameter>
+</method>
+</interface>
+<interface name="MediaRecorder.OnInfoListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onInfo"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mr" type="android.media.MediaRecorder">
+</parameter>
+<parameter name="what" type="int">
+</parameter>
+<parameter name="extra" type="int">
+</parameter>
+</method>
+</interface>
<class name="MediaRecorder.OutputFormat"
extends="java.lang.Object"
abstract="false"
@@ -62795,6 +66829,90 @@
>
</field>
</class>
+<class name="MediaRecorder.VideoEncoder"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="H263"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="H264"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MPEG_4_SP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="MediaRecorder.VideoSource"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="CAMERA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DEFAULT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="MediaScannerConnection"
extends="java.lang.Object"
abstract="false"
@@ -64100,6 +68218,17 @@
visibility="public"
>
</method>
+<method name="getBackgroundDataSetting"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getNetworkInfo"
return="android.net.NetworkInfo"
abstract="false"
@@ -64195,6 +68324,17 @@
<parameter name="feature" type="java.lang.String">
</parameter>
</method>
+<field name="ACTION_BACKGROUND_DATA_SETTING_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.net.conn.BACKGROUND_DATA_SETTING_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="CONNECTIVITY_ACTION"
type="java.lang.String"
transient="false"
@@ -69725,6 +73865,96 @@
</parameter>
</method>
</class>
+<class name="Visibility"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Visibility"
+ type="android.opengl.Visibility"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="computeBoundingSphere"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="positions" type="float[]">
+</parameter>
+<parameter name="positionsOffset" type="int">
+</parameter>
+<parameter name="positionsCount" type="int">
+</parameter>
+<parameter name="sphere" type="float[]">
+</parameter>
+<parameter name="sphereOffset" type="int">
+</parameter>
+</method>
+<method name="frustumCullSpheres"
+ return="int"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mvp" type="float[]">
+</parameter>
+<parameter name="mvpOffset" type="int">
+</parameter>
+<parameter name="spheres" type="float[]">
+</parameter>
+<parameter name="spheresOffset" type="int">
+</parameter>
+<parameter name="spheresCount" type="int">
+</parameter>
+<parameter name="results" type="int[]">
+</parameter>
+<parameter name="resultsOffset" type="int">
+</parameter>
+<parameter name="resultsCapacity" type="int">
+</parameter>
+</method>
+<method name="visibilityTest"
+ return="int"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ws" type="float[]">
+</parameter>
+<parameter name="wsOffset" type="int">
+</parameter>
+<parameter name="positions" type="float[]">
+</parameter>
+<parameter name="positionsOffset" type="int">
+</parameter>
+<parameter name="indices" type="char[]">
+</parameter>
+<parameter name="indicesOffset" type="int">
+</parameter>
+<parameter name="indexCount" type="int">
+</parameter>
+</method>
+</class>
</package>
<package name="android.os"
>
@@ -70125,544 +74355,6 @@
>
</field>
</class>
-<class name="BatteryStats"
- extends="java.lang.Object"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="BatteryStats"
- type="android.os.BatteryStats"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="computeBatteryRealtime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="curTime" type="long">
-</parameter>
-<parameter name="which" type="int">
-</parameter>
-</method>
-<method name="computeBatteryUptime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="curTime" type="long">
-</parameter>
-<parameter name="which" type="int">
-</parameter>
-</method>
-<method name="computeRealtime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="curTime" type="long">
-</parameter>
-<parameter name="which" type="int">
-</parameter>
-</method>
-<method name="computeUptime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="curTime" type="long">
-</parameter>
-<parameter name="which" type="int">
-</parameter>
-</method>
-<method name="dumpLocked"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="fd" type="java.io.FileDescriptor">
-</parameter>
-<parameter name="pw" type="java.io.PrintWriter">
-</parameter>
-<parameter name="args" type="java.lang.String[]">
-</parameter>
-</method>
-<method name="getBatteryRealtime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="curTime" type="long">
-</parameter>
-</method>
-<method name="getBatteryUptime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="curTime" type="long">
-</parameter>
-</method>
-<method name="getStartCount"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getUidStats"
- return="android.util.SparseArray&lt;? extends android.os.BatteryStats.Uid&gt;"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<field name="STATS_CURRENT"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="STATS_LAST"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="STATS_TOTAL"
- type="int"
- transient="false"
- volatile="false"
- value="0"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="STATS_UNPLUGGED"
- type="int"
- transient="false"
- volatile="false"
- value="3"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="WAKE_TYPE_FULL"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="WAKE_TYPE_PARTIAL"
- type="int"
- transient="false"
- volatile="false"
- value="0"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="WAKE_TYPE_WINDOW"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-</class>
-<class name="BatteryStats.Timer"
- extends="java.lang.Object"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="BatteryStats.Timer"
- type="android.os.BatteryStats.Timer"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getCount"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="which" type="int">
-</parameter>
-</method>
-<method name="getTotalTime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="now" type="long">
-</parameter>
-<parameter name="which" type="int">
-</parameter>
-</method>
-</class>
-<class name="BatteryStats.Uid"
- extends="java.lang.Object"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="BatteryStats.Uid"
- type="android.os.BatteryStats.Uid"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getPackageStats"
- return="java.util.Map&lt;java.lang.String, ? extends android.os.BatteryStats.Uid.Pkg&gt;"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getProcessStats"
- return="java.util.Map&lt;java.lang.String, ? extends android.os.BatteryStats.Uid.Proc&gt;"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getSensorStats"
- return="java.util.Map&lt;java.lang.Integer, ? extends android.os.BatteryStats.Uid.Sensor&gt;"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getWakelockStats"
- return="java.util.Map&lt;java.lang.String, ? extends android.os.BatteryStats.Uid.Wakelock&gt;"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-</class>
-<class name="BatteryStats.Uid.Pkg"
- extends="java.lang.Object"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="BatteryStats.Uid.Pkg"
- type="android.os.BatteryStats.Uid.Pkg"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getServiceStats"
- return="java.util.Map&lt;java.lang.String, ? extends android.os.BatteryStats.Uid.Pkg.Serv&gt;"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getWakeups"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="which" type="int">
-</parameter>
-</method>
-</class>
-<class name="BatteryStats.Uid.Pkg.Serv"
- extends="java.lang.Object"
- abstract="true"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="BatteryStats.Uid.Pkg.Serv"
- type="android.os.BatteryStats.Uid.Pkg.Serv"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getLaunches"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="which" type="int">
-</parameter>
-</method>
-<method name="getStartTime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="now" type="long">
-</parameter>
-<parameter name="which" type="int">
-</parameter>
-</method>
-<method name="getStarts"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="which" type="int">
-</parameter>
-</method>
-</class>
-<class name="BatteryStats.Uid.Proc"
- extends="java.lang.Object"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="BatteryStats.Uid.Proc"
- type="android.os.BatteryStats.Uid.Proc"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getStarts"
- return="int"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="which" type="int">
-</parameter>
-</method>
-<method name="getSystemTime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="which" type="int">
-</parameter>
-</method>
-<method name="getUserTime"
- return="long"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="which" type="int">
-</parameter>
-</method>
-</class>
-<class name="BatteryStats.Uid.Sensor"
- extends="java.lang.Object"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="BatteryStats.Uid.Sensor"
- type="android.os.BatteryStats.Uid.Sensor"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getSensorTime"
- return="android.os.BatteryStats.Timer"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-</class>
-<class name="BatteryStats.Uid.Wakelock"
- extends="java.lang.Object"
- abstract="true"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="BatteryStats.Uid.Wakelock"
- type="android.os.BatteryStats.Uid.Wakelock"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</constructor>
-<method name="getWakeTime"
- return="android.os.BatteryStats.Timer"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="type" type="int">
-</parameter>
-</method>
-</class>
<class name="Binder"
extends="java.lang.Object"
abstract="false"
@@ -70715,6 +74407,21 @@
static="false"
final="false"
deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="java.io.FileDescriptor">
+</parameter>
+<parameter name="args" type="java.lang.String[]">
+</parameter>
+</method>
+<method name="dump"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
visibility="protected"
>
<parameter name="fd" type="java.io.FileDescriptor">
@@ -70946,6 +74653,16 @@
visibility="public"
>
</field>
+<field name="DISPLAY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FINGERPRINT"
type="java.lang.String"
transient="false"
@@ -72379,6 +76096,21 @@
<parameter name="port" type="int">
</parameter>
</method>
+<method name="dumpHprofData"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fileName" type="java.lang.String">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
<method name="enableEmulatorTraceOutput"
return="void"
abstract="false"
@@ -73310,6 +77042,17 @@
visibility="public"
>
</field>
+<field name="MEDIA_CHECKING"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;checking&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MEDIA_MOUNTED"
type="java.lang.String"
transient="false"
@@ -73332,6 +77075,17 @@
visibility="public"
>
</field>
+<field name="MEDIA_NOFS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;nofs&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MEDIA_REMOVED"
type="java.lang.String"
transient="false"
@@ -74125,6 +77879,23 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="dump"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="java.io.FileDescriptor">
+</parameter>
+<parameter name="args" type="java.lang.String[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="getInterfaceDescriptor"
return="java.lang.String"
abstract="true"
@@ -76449,6 +80220,17 @@
visibility="public"
>
</method>
+<method name="getStatSize"
+ return="long"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="open"
return="android.os.ParcelFileDescriptor"
abstract="false"
@@ -76491,6 +80273,17 @@
visibility="public"
>
</field>
+<field name="MODE_APPEND"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="33554432"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MODE_CREATE"
type="int"
transient="false"
@@ -77541,6 +81334,93 @@
>
</constructor>
</class>
+<class name="ResultReceiver"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="ResultReceiver"
+ type="android.os.ResultReceiver"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onReceiveResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="resultCode" type="int">
+</parameter>
+<parameter name="resultData" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="send"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="resultCode" type="int">
+</parameter>
+<parameter name="resultData" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="StatFs"
extends="java.lang.Object"
abstract="false"
@@ -80720,6 +84600,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_APPLICATION_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;com.android.browser.application_id&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="HISTORY_PROJECTION"
type="java.lang.String[]"
transient="false"
@@ -82173,6 +86064,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_FORCE_CREATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;com.android.contacts.action.FORCE_CREATE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SEARCH_SUGGESTION_CLICKED"
type="java.lang.String"
transient="false"
@@ -82206,6 +86108,17 @@
visibility="public"
>
</field>
+<field name="SHOW_OR_CREATE_CONTACT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;com.android.contacts.action.SHOW_OR_CREATE_CONTACT&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="Contacts.Intents.Insert"
extends="java.lang.Object"
@@ -84064,6 +87977,28 @@
visibility="public"
>
</method>
+<field name="ACTION_IMAGE_CAPTURE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.action.IMAGE_CAPTURE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_VIDEO_CAPTURE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.media.action.VIDEO_CAPTURE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="AUTHORITY"
type="java.lang.String"
transient="false"
@@ -84130,6 +88065,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_OUTPUT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;output&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_SCREEN_ORIENTATION"
type="java.lang.String"
transient="false"
@@ -84141,6 +88087,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_VIDEO_QUALITY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.extra.videoQuality&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="INTENT_ACTION_MEDIA_SEARCH"
type="java.lang.String"
transient="false"
@@ -85593,7 +89550,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value="&quot;name ASC&quot;"
+ value="&quot;bucket_display_name&quot;"
static="true"
final="true"
deprecated="not deprecated"
@@ -85951,7 +89908,7 @@
type="java.lang.String"
transient="false"
volatile="false"
- value="&quot;name ASC&quot;"
+ value="&quot;_display_name&quot;"
static="true"
final="true"
deprecated="not deprecated"
@@ -86064,6 +90021,17 @@
visibility="public"
>
</field>
+<field name="BOOKMARK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;bookmark&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="BUCKET_DISPLAY_NAME"
type="java.lang.String"
transient="false"
@@ -86472,6 +90440,17 @@
visibility="public"
>
</field>
+<field name="ACTION_INPUT_METHOD_SETTINGS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.settings.INPUT_METHOD_SETTINGS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_INTERNAL_STORAGE_SETTINGS"
type="java.lang.String"
transient="false"
@@ -86593,6 +90572,17 @@
visibility="public"
>
</field>
+<field name="ACTION_USER_DICTIONARY_SETTINGS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.settings.USER_DICTIONARY_SETTINGS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_WIFI_IP_SETTINGS"
type="java.lang.String"
transient="false"
@@ -87853,6 +91843,17 @@
visibility="public"
>
</field>
+<field name="HAPTIC_FEEDBACK_ENABLED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;haptic_feedback_enabled&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="HTTP_PROXY"
type="java.lang.String"
transient="false"
@@ -88635,6 +92636,202 @@
>
</field>
</class>
+<class name="UserDictionary"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="UserDictionary"
+ type="android.provider.UserDictionary"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="AUTHORITY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;user_dictionary&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONTENT_URI"
+ type="android.net.Uri"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="UserDictionary.Words"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.provider.BaseColumns">
+</implements>
+<constructor name="UserDictionary.Words"
+ type="android.provider.UserDictionary.Words"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="addWord"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="word" type="java.lang.String">
+</parameter>
+<parameter name="frequency" type="int">
+</parameter>
+<parameter name="localeType" type="int">
+</parameter>
+</method>
+<field name="APP_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;appid&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONTENT_ITEM_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;vnd.android.cursor.item/vnd.google.userword&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONTENT_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;vnd.android.cursor.dir/vnd.google.userword&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CONTENT_URI"
+ type="android.net.Uri"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DEFAULT_SORT_ORDER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;frequency DESC&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FREQUENCY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;frequency&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LOCALE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;locale&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LOCALE_TYPE_ALL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LOCALE_TYPE_CURRENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WORD"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;word&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;_id&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
</package>
<package name="android.sax"
>
@@ -88896,329 +93093,138 @@
</implements>
</interface>
</package>
-<package name="android.speech.srec"
->
-<class name="MicrophoneInputStream"
- extends="java.io.InputStream"
- abstract="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="MicrophoneInputStream"
- type="android.speech.srec.MicrophoneInputStream"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="sampleRate" type="int">
-</parameter>
-<parameter name="fifoDepth" type="int">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</constructor>
-<method name="read"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
+<package name="android.speech"
>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-</class>
-<class name="Recognizer"
+<class name="RecognizerIntent"
extends="java.lang.Object"
abstract="false"
static="false"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="Recognizer"
- type="android.speech.srec.Recognizer"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="configFile" type="java.lang.String">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</constructor>
-<method name="advance"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="destroy"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-</method>
-<method name="eventToString"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="event" type="int">
-</parameter>
-</method>
-<method name="getConfigDir"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="locale" type="java.util.Locale">
-</parameter>
-</method>
-<method name="getResult"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="index" type="int">
-</parameter>
-<parameter name="key" type="java.lang.String">
-</parameter>
-</method>
-<method name="getResultCount"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getResultKeys"
- return="java.lang.String[]"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="index" type="int">
-</parameter>
-</method>
-<method name="putAudio"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="buf" type="byte[]">
-</parameter>
-<parameter name="offset" type="int">
-</parameter>
-<parameter name="length" type="int">
-</parameter>
-<parameter name="isLast" type="boolean">
-</parameter>
-</method>
-<method name="putAudio"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="audio" type="java.io.InputStream">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="start"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="stop"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<field name="EVENT_END_OF_VOICING"
- type="int"
+<field name="ACTION_RECOGNIZE_SPEECH"
+ type="java.lang.String"
transient="false"
volatile="false"
- value="6"
+ value="&quot;android.speech.action.RECOGNIZE_SPEECH&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="EVENT_INCOMPLETE"
- type="int"
+<field name="ACTION_WEB_SEARCH"
+ type="java.lang.String"
transient="false"
volatile="false"
- value="2"
+ value="&quot;android.speech.action.WEB_SEARCH&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="EVENT_INVALID"
- type="int"
+<field name="EXTRA_LANGUAGE"
+ type="java.lang.String"
transient="false"
volatile="false"
- value="0"
+ value="&quot;android.speech.extra.LANGUAGE&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="EVENT_MAX_SPEECH"
- type="int"
+<field name="EXTRA_LANGUAGE_MODEL"
+ type="java.lang.String"
transient="false"
volatile="false"
- value="12"
+ value="&quot;android.speech.extra.LANGUAGE_MODEL&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="EVENT_NEED_MORE_AUDIO"
- type="int"
+<field name="EXTRA_MAX_RESULTS"
+ type="java.lang.String"
transient="false"
volatile="false"
- value="11"
+ value="&quot;android.speech.extra.MAX_RESULTS&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="EVENT_NO_MATCH"
- type="int"
+<field name="EXTRA_PROMPT"
+ type="java.lang.String"
transient="false"
volatile="false"
- value="1"
+ value="&quot;android.speech.extra.PROMPT&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="EVENT_RECOGNITION_RESULT"
- type="int"
+<field name="EXTRA_RESULTS"
+ type="java.lang.String"
transient="false"
volatile="false"
- value="8"
+ value="&quot;android.speech.extra.RESULTS&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="EVENT_RECOGNITION_TIMEOUT"
- type="int"
+<field name="EXTRA_RESULTS_PENDINGINTENT"
+ type="java.lang.String"
transient="false"
volatile="false"
- value="10"
+ value="&quot;android.speech.extra.RESULTS_PENDINGINTENT&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="EVENT_SPOKE_TOO_SOON"
- type="int"
+<field name="EXTRA_RESULTS_PENDINGINTENT_BUNDLE"
+ type="java.lang.String"
transient="false"
volatile="false"
- value="7"
+ value="&quot;android.speech.extra.RESULTS_PENDINGINTENT_BUNDLE&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="EVENT_STARTED"
- type="int"
+<field name="LANGUAGE_MODEL_FREE_FORM"
+ type="java.lang.String"
transient="false"
volatile="false"
- value="3"
+ value="&quot;free_form&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="EVENT_START_OF_UTTERANCE_TIMEOUT"
- type="int"
+<field name="LANGUAGE_MODEL_WEB_SEARCH"
+ type="java.lang.String"
transient="false"
volatile="false"
- value="9"
+ value="&quot;web_search&quot;"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="EVENT_START_OF_VOICING"
+<field name="RESULT_AUDIO_ERROR"
type="int"
transient="false"
volatile="false"
@@ -89229,44 +93235,44 @@
visibility="public"
>
</field>
-<field name="EVENT_STOPPED"
+<field name="RESULT_CLIENT_ERROR"
type="int"
transient="false"
volatile="false"
- value="4"
+ value="2"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="KEY_CONFIDENCE"
- type="java.lang.String"
+<field name="RESULT_NETWORK_ERROR"
+ type="int"
transient="false"
volatile="false"
- value="&quot;conf&quot;"
+ value="4"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="KEY_LITERAL"
- type="java.lang.String"
+<field name="RESULT_NO_MATCH"
+ type="int"
transient="false"
volatile="false"
- value="&quot;literal&quot;"
+ value="1"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="KEY_MEANING"
- type="java.lang.String"
+<field name="RESULT_SERVER_ERROR"
+ type="int"
transient="false"
volatile="false"
- value="&quot;meaning&quot;"
+ value="3"
static="true"
final="true"
deprecated="not deprecated"
@@ -89274,107 +93280,6 @@
>
</field>
</class>
-<class name="Recognizer.Grammar"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="Recognizer.Grammar"
- type="android.speech.srec.Recognizer.Grammar"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="g2gFileName" type="java.lang.String">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</constructor>
-<method name="addWordToSlot"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="slot" type="java.lang.String">
-</parameter>
-<parameter name="word" type="java.lang.String">
-</parameter>
-<parameter name="pron" type="java.lang.String">
-</parameter>
-<parameter name="weight" type="int">
-</parameter>
-<parameter name="tag" type="java.lang.String">
-</parameter>
-</method>
-<method name="compile"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="destroy"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="resetAllSlots"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="save"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="g2gFileName" type="java.lang.String">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="setupRecognizer"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-</class>
</package>
<package name="android.telephony"
>
@@ -91463,6 +95368,21 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="messageBody" type="java.lang.CharSequence">
+</parameter>
+<parameter name="use7bitOnly" type="boolean">
+</parameter>
+</method>
+<method name="calculateLength"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="messageBody" type="java.lang.String">
</parameter>
<parameter name="use7bitOnly" type="boolean">
@@ -96365,6 +100285,21 @@
<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
</exception>
</method>
+<method name="getLaunchIntentForPackage"
+ return="android.content.Intent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
+</exception>
+</method>
<method name="getNameForUid"
return="java.lang.String"
abstract="false"
@@ -96564,6 +100499,17 @@
<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
</exception>
</method>
+<method name="getSystemSharedLibraryNames"
+ return="java.lang.String[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getText"
return="java.lang.CharSequence"
abstract="false"
@@ -96615,6 +100561,17 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="isSafeMode"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="queryBroadcastReceivers"
return="java.util.List&lt;android.content.pm.ResolveInfo&gt;"
abstract="false"
@@ -97342,6 +101299,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="Annotation"
type="android.text.Annotation"
static="false"
@@ -97354,6 +101313,27 @@
<parameter name="value" type="java.lang.String">
</parameter>
</constructor>
+<constructor name="Annotation"
+ type="android.text.Annotation"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getKey"
return="java.lang.String"
abstract="false"
@@ -97365,6 +101345,17 @@
visibility="public"
>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getValue"
return="java.lang.String"
abstract="false"
@@ -97376,6 +101367,21 @@
visibility="public"
>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="AutoText"
extends="java.lang.Object"
@@ -98743,22 +102749,22 @@
visibility="public"
>
</field>
-<field name="TYPE_TEXT_FLAG_MULTI_LINE"
+<field name="TYPE_TEXT_FLAG_IME_MULTI_LINE"
type="int"
transient="false"
volatile="false"
- value="131072"
+ value="262144"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="TYPE_TEXT_FLAG_SEARCH"
+<field name="TYPE_TEXT_FLAG_MULTI_LINE"
type="int"
transient="false"
volatile="false"
- value="262144"
+ value="131072"
static="true"
final="true"
deprecated="not deprecated"
@@ -98776,22 +102782,33 @@
visibility="public"
>
</field>
-<field name="TYPE_TEXT_VARIATION_EMAIL_CONTENT"
+<field name="TYPE_TEXT_VARIATION_EMAIL_SUBJECT"
type="int"
transient="false"
volatile="false"
- value="64"
+ value="48"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="TYPE_TEXT_VARIATION_EMAIL_SUBJECT"
+<field name="TYPE_TEXT_VARIATION_FILTER"
type="int"
transient="false"
volatile="false"
- value="48"
+ value="176"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_TEXT_VARIATION_LONG_MESSAGE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="80"
static="true"
final="true"
deprecated="not deprecated"
@@ -98813,7 +102830,7 @@
type="int"
transient="false"
volatile="false"
- value="112"
+ value="128"
static="true"
final="true"
deprecated="not deprecated"
@@ -98824,7 +102841,18 @@
type="int"
transient="false"
volatile="false"
- value="80"
+ value="96"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_TEXT_VARIATION_PHONETIC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="192"
static="true"
final="true"
deprecated="not deprecated"
@@ -98835,18 +102863,18 @@
type="int"
transient="false"
volatile="false"
- value="96"
+ value="112"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
-<field name="TYPE_TEXT_VARIATION_SEARCH_STRING"
+<field name="TYPE_TEXT_VARIATION_SHORT_MESSAGE"
type="int"
transient="false"
volatile="false"
- value="128"
+ value="64"
static="true"
final="true"
deprecated="not deprecated"
@@ -98864,7 +102892,7 @@
visibility="public"
>
</field>
-<field name="TYPE_TEXT_VARIATION_WEB_EDIT_TEXT"
+<field name="TYPE_TEXT_VARIATION_VISIBLE_PASSWORD"
type="int"
transient="false"
volatile="false"
@@ -98875,6 +102903,17 @@
visibility="public"
>
</field>
+<field name="TYPE_TEXT_VARIATION_WEB_EDIT_TEXT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="160"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</interface>
<class name="Layout"
extends="java.lang.Object"
@@ -99784,6 +103823,54 @@
</parameter>
</method>
</class>
+<interface name="NoCopySpan"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</interface>
+<class name="NoCopySpan.Concrete"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.text.NoCopySpan">
+</implements>
+<constructor name="NoCopySpan.Concrete"
+ type="android.text.NoCopySpan.Concrete"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+</class>
+<interface name="ParcelableSpan"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
<class name="Selection"
extends="java.lang.Object"
abstract="false"
@@ -100099,6 +104186,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.NoCopySpan">
+</implements>
<method name="onSpanAdded"
return="void"
abstract="true"
@@ -101005,6 +105094,17 @@
visibility="public"
>
</field>
+<field name="SPAN_INTERMEDIATE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SPAN_MARK_MARK"
type="int"
transient="false"
@@ -102309,6 +106409,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.NoCopySpan">
+</implements>
<method name="afterTextChanged"
return="void"
abstract="true"
@@ -102701,6 +106803,21 @@
<parameter name="elapsedSeconds" type="long">
</parameter>
</method>
+<method name="formatElapsedTime"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="recycle" type="java.lang.StringBuilder">
+</parameter>
+<parameter name="elapsedSeconds" type="long">
+</parameter>
+</method>
<method name="formatSameDayTime"
return="java.lang.CharSequence"
abstract="false"
@@ -104149,6 +108266,23 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
+<method name="onKeyOther"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.widget.TextView">
+</parameter>
+<parameter name="text" type="android.text.Spannable">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
<method name="onKeyUp"
return="boolean"
abstract="false"
@@ -104257,6 +108391,23 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
+<method name="onKeyOther"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="content" type="android.text.Editable">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
</class>
<class name="CharacterPickerDialog"
extends="android.app.Dialog"
@@ -104698,6 +108849,23 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
+<method name="onKeyOther"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="text" type="android.text.Editable">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
<method name="onKeyUp"
return="boolean"
abstract="true"
@@ -104806,6 +108974,21 @@
</parameter>
</method>
<method name="clearMetaKeyState"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="content" type="android.text.Editable">
+</parameter>
+<parameter name="states" type="int">
+</parameter>
+</method>
+<method name="clearMetaKeyState"
return="long"
abstract="false"
native="false"
@@ -104925,6 +109108,21 @@
<parameter name="what" type="java.lang.Object">
</parameter>
</method>
+<method name="isSelectingMetaTracker"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="java.lang.CharSequence">
+</parameter>
+<parameter name="what" type="java.lang.Object">
+</parameter>
+</method>
<method name="onKeyDown"
return="boolean"
abstract="false"
@@ -105121,6 +109319,23 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
+<method name="onKeyOther"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.widget.TextView">
+</parameter>
+<parameter name="text" type="android.text.Spannable">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
<method name="onKeyUp"
return="boolean"
abstract="true"
@@ -105751,6 +109966,23 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
+<method name="onKeyOther"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.widget.TextView">
+</parameter>
+<parameter name="text" type="android.text.Spannable">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
<method name="onKeyUp"
return="boolean"
abstract="false"
@@ -106258,6 +110490,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="AbsoluteSizeSpan"
type="android.text.style.AbsoluteSizeSpan"
static="false"
@@ -106268,6 +110502,27 @@
<parameter name="size" type="int">
</parameter>
</constructor>
+<constructor name="AbsoluteSizeSpan"
+ type="android.text.style.AbsoluteSizeSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSize"
return="int"
abstract="false"
@@ -106279,6 +110534,17 @@
visibility="public"
>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="updateDrawState"
return="void"
abstract="false"
@@ -106305,6 +110571,21 @@
<parameter name="ds" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<interface name="AlignmentSpan"
abstract="true"
@@ -106337,6 +110618,8 @@
>
<implements name="android.text.style.AlignmentSpan">
</implements>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="AlignmentSpan.Standard"
type="android.text.style.AlignmentSpan.Standard"
static="false"
@@ -106347,6 +110630,27 @@
<parameter name="align" type="android.text.Layout.Alignment">
</parameter>
</constructor>
+<constructor name="AlignmentSpan.Standard"
+ type="android.text.style.AlignmentSpan.Standard"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getAlignment"
return="android.text.Layout.Alignment"
abstract="false"
@@ -106358,6 +110662,32 @@
visibility="public"
>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="BackgroundColorSpan"
extends="android.text.style.CharacterStyle"
@@ -106367,6 +110697,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<implements name="android.text.style.UpdateAppearance">
</implements>
<constructor name="BackgroundColorSpan"
@@ -106379,6 +110711,27 @@
<parameter name="color" type="int">
</parameter>
</constructor>
+<constructor name="BackgroundColorSpan"
+ type="android.text.style.BackgroundColorSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getBackgroundColor"
return="int"
abstract="false"
@@ -106390,6 +110743,17 @@
visibility="public"
>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="updateDrawState"
return="void"
abstract="false"
@@ -106403,6 +110767,21 @@
<parameter name="ds" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="BulletSpan"
extends="java.lang.Object"
@@ -106414,6 +110793,8 @@
>
<implements name="android.text.style.LeadingMarginSpan">
</implements>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="BulletSpan"
type="android.text.style.BulletSpan"
static="false"
@@ -106444,6 +110825,27 @@
<parameter name="color" type="int">
</parameter>
</constructor>
+<constructor name="BulletSpan"
+ type="android.text.style.BulletSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="drawLeadingMargin"
return="void"
abstract="false"
@@ -106492,6 +110894,32 @@
<parameter name="first" type="boolean">
</parameter>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
<field name="STANDARD_GAP_WIDTH"
type="int"
transient="false"
@@ -106848,6 +111276,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<implements name="android.text.style.UpdateAppearance">
</implements>
<constructor name="ForegroundColorSpan"
@@ -106860,6 +111290,27 @@
<parameter name="color" type="int">
</parameter>
</constructor>
+<constructor name="ForegroundColorSpan"
+ type="android.text.style.ForegroundColorSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getForegroundColor"
return="int"
abstract="false"
@@ -106871,6 +111322,17 @@
visibility="public"
>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="updateDrawState"
return="void"
abstract="false"
@@ -106884,6 +111346,21 @@
<parameter name="ds" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="IconMarginSpan"
extends="java.lang.Object"
@@ -107212,6 +111689,8 @@
>
<implements name="android.text.style.LeadingMarginSpan">
</implements>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="LeadingMarginSpan.Standard"
type="android.text.style.LeadingMarginSpan.Standard"
static="false"
@@ -107234,6 +111713,27 @@
<parameter name="every" type="int">
</parameter>
</constructor>
+<constructor name="LeadingMarginSpan.Standard"
+ type="android.text.style.LeadingMarginSpan.Standard"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="drawLeadingMargin"
return="void"
abstract="false"
@@ -107282,6 +111782,32 @@
<parameter name="first" type="boolean">
</parameter>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<interface name="LineBackgroundSpan"
abstract="true"
@@ -107456,6 +111982,8 @@
>
<implements name="android.text.style.LeadingMarginSpan">
</implements>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="QuoteSpan"
type="android.text.style.QuoteSpan"
static="false"
@@ -107474,6 +112002,27 @@
<parameter name="color" type="int">
</parameter>
</constructor>
+<constructor name="QuoteSpan"
+ type="android.text.style.QuoteSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="drawLeadingMargin"
return="void"
abstract="false"
@@ -107533,6 +112082,32 @@
<parameter name="first" type="boolean">
</parameter>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="RasterizerSpan"
extends="android.text.style.CharacterStyle"
@@ -107587,6 +112162,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="RelativeSizeSpan"
type="android.text.style.RelativeSizeSpan"
static="false"
@@ -107597,6 +112174,27 @@
<parameter name="proportion" type="float">
</parameter>
</constructor>
+<constructor name="RelativeSizeSpan"
+ type="android.text.style.RelativeSizeSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSizeChange"
return="float"
abstract="false"
@@ -107608,6 +112206,17 @@
visibility="public"
>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="updateDrawState"
return="void"
abstract="false"
@@ -107634,6 +112243,21 @@
<parameter name="ds" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="ReplacementSpan"
extends="android.text.style.MetricAffectingSpan"
@@ -107736,6 +112360,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="ScaleXSpan"
type="android.text.style.ScaleXSpan"
static="false"
@@ -107746,6 +112372,27 @@
<parameter name="proportion" type="float">
</parameter>
</constructor>
+<constructor name="ScaleXSpan"
+ type="android.text.style.ScaleXSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getScaleX"
return="float"
abstract="false"
@@ -107757,6 +112404,17 @@
visibility="public"
>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="updateDrawState"
return="void"
abstract="false"
@@ -107783,6 +112441,21 @@
<parameter name="ds" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="StrikethroughSpan"
extends="android.text.style.CharacterStyle"
@@ -107792,6 +112465,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<implements name="android.text.style.UpdateAppearance">
</implements>
<constructor name="StrikethroughSpan"
@@ -107802,6 +112477,38 @@
visibility="public"
>
</constructor>
+<constructor name="StrikethroughSpan"
+ type="android.text.style.StrikethroughSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="updateDrawState"
return="void"
abstract="false"
@@ -107815,6 +112522,21 @@
<parameter name="ds" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="StyleSpan"
extends="android.text.style.MetricAffectingSpan"
@@ -107824,6 +112546,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="StyleSpan"
type="android.text.style.StyleSpan"
static="false"
@@ -107834,6 +112558,38 @@
<parameter name="style" type="int">
</parameter>
</constructor>
+<constructor name="StyleSpan"
+ type="android.text.style.StyleSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getStyle"
return="int"
abstract="false"
@@ -107871,6 +112627,21 @@
<parameter name="paint" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="SubscriptSpan"
extends="android.text.style.MetricAffectingSpan"
@@ -107880,6 +112651,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="SubscriptSpan"
type="android.text.style.SubscriptSpan"
static="false"
@@ -107888,6 +112661,38 @@
visibility="public"
>
</constructor>
+<constructor name="SubscriptSpan"
+ type="android.text.style.SubscriptSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="updateDrawState"
return="void"
abstract="false"
@@ -107914,6 +112719,21 @@
<parameter name="tp" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="SuperscriptSpan"
extends="android.text.style.MetricAffectingSpan"
@@ -107923,6 +112743,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="SuperscriptSpan"
type="android.text.style.SuperscriptSpan"
static="false"
@@ -107931,6 +112753,38 @@
visibility="public"
>
</constructor>
+<constructor name="SuperscriptSpan"
+ type="android.text.style.SuperscriptSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="updateDrawState"
return="void"
abstract="false"
@@ -107957,6 +112811,21 @@
<parameter name="tp" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<interface name="TabStopSpan"
abstract="true"
@@ -108019,6 +112888,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="TextAppearanceSpan"
type="android.text.style.TextAppearanceSpan"
static="false"
@@ -108063,6 +112934,27 @@
<parameter name="linkColor" type="android.content.res.ColorStateList">
</parameter>
</constructor>
+<constructor name="TextAppearanceSpan"
+ type="android.text.style.TextAppearanceSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getFamily"
return="java.lang.String"
abstract="false"
@@ -108085,6 +112977,17 @@
visibility="public"
>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getTextColor"
return="android.content.res.ColorStateList"
abstract="false"
@@ -108144,6 +113047,21 @@
<parameter name="ds" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="TypefaceSpan"
extends="android.text.style.MetricAffectingSpan"
@@ -108153,6 +113071,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="TypefaceSpan"
type="android.text.style.TypefaceSpan"
static="false"
@@ -108163,6 +113083,27 @@
<parameter name="family" type="java.lang.String">
</parameter>
</constructor>
+<constructor name="TypefaceSpan"
+ type="android.text.style.TypefaceSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getFamily"
return="java.lang.String"
abstract="false"
@@ -108174,6 +113115,17 @@
visibility="public"
>
</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="updateDrawState"
return="void"
abstract="false"
@@ -108200,6 +113152,21 @@
<parameter name="paint" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="URLSpan"
extends="android.text.style.ClickableSpan"
@@ -108209,6 +113176,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<constructor name="URLSpan"
type="android.text.style.URLSpan"
static="false"
@@ -108219,6 +113188,38 @@
<parameter name="url" type="java.lang.String">
</parameter>
</constructor>
+<constructor name="URLSpan"
+ type="android.text.style.URLSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getURL"
return="java.lang.String"
abstract="false"
@@ -108243,6 +113244,21 @@
<parameter name="widget" type="android.view.View">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<class name="UnderlineSpan"
extends="android.text.style.CharacterStyle"
@@ -108252,6 +113268,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.text.ParcelableSpan">
+</implements>
<implements name="android.text.style.UpdateAppearance">
</implements>
<constructor name="UnderlineSpan"
@@ -108262,6 +113280,38 @@
visibility="public"
>
</constructor>
+<constructor name="UnderlineSpan"
+ type="android.text.style.UnderlineSpan"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSpanTypeId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="updateDrawState"
return="void"
abstract="false"
@@ -108275,6 +113325,21 @@
<parameter name="ds" type="android.text.TextPaint">
</parameter>
</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
</class>
<interface name="UpdateAppearance"
abstract="true"
@@ -110669,6 +115734,19 @@
<parameter name="value" type="int">
</parameter>
</method>
+<method name="removeAt"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+</method>
<method name="size"
return="int"
abstract="false"
@@ -112196,7 +117274,7 @@
type="android.view.GestureDetector"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="listener" type="android.view.GestureDetector.OnGestureListener">
@@ -112208,11 +117286,37 @@
type="android.view.GestureDetector"
static="false"
final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.view.GestureDetector.OnGestureListener">
+</parameter>
+</constructor>
+<constructor name="GestureDetector"
+ type="android.view.GestureDetector"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="listener" type="android.view.GestureDetector.OnGestureListener">
+</parameter>
+</constructor>
+<constructor name="GestureDetector"
+ type="android.view.GestureDetector"
+ static="false"
+ final="false"
deprecated="not deprecated"
visibility="public"
>
+<parameter name="context" type="android.content.Context">
+</parameter>
<parameter name="listener" type="android.view.GestureDetector.OnGestureListener">
</parameter>
+<parameter name="handler" type="android.os.Handler">
+</parameter>
</constructor>
<method name="isLongpressEnabled"
return="boolean"
@@ -112251,7 +117355,67 @@
<parameter name="isLongpressEnabled" type="boolean">
</parameter>
</method>
+<method name="setOnDoubleTapListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="onDoubleTapListener" type="android.view.GestureDetector.OnDoubleTapListener">
+</parameter>
+</method>
</class>
+<interface name="GestureDetector.OnDoubleTapListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onDoubleTap"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="android.view.MotionEvent">
+</parameter>
+</method>
+<method name="onDoubleTapEvent"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="android.view.MotionEvent">
+</parameter>
+</method>
+<method name="onSingleTapConfirmed"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="android.view.MotionEvent">
+</parameter>
+</method>
+</interface>
<interface name="GestureDetector.OnGestureListener"
abstract="true"
static="true"
@@ -112358,6 +117522,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="android.view.GestureDetector.OnDoubleTapListener">
+</implements>
<implements name="android.view.GestureDetector.OnGestureListener">
</implements>
<constructor name="GestureDetector.SimpleOnGestureListener"
@@ -112368,6 +117534,32 @@
visibility="public"
>
</constructor>
+<method name="onDoubleTap"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="android.view.MotionEvent">
+</parameter>
+</method>
+<method name="onDoubleTapEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="android.view.MotionEvent">
+</parameter>
+</method>
<method name="onDown"
return="boolean"
abstract="false"
@@ -112445,6 +117637,19 @@
<parameter name="e" type="android.view.MotionEvent">
</parameter>
</method>
+<method name="onSingleTapConfirmed"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="android.view.MotionEvent">
+</parameter>
+</method>
<method name="onSingleTapUp"
return="boolean"
abstract="false"
@@ -112818,6 +118023,48 @@
>
</field>
</class>
+<class name="HapticFeedbackConstants"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="FLAG_IGNORE_GLOBAL_SETTING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FLAG_IGNORE_VIEW_SETTING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LONG_PRESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="InflateException"
extends="java.lang.RuntimeException"
abstract="false"
@@ -112875,6 +118122,32 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="deviceHasKey"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+</method>
+<method name="deviceHasKeys"
+ return="boolean[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCodes" type="int[]">
+</parameter>
+</method>
<method name="get"
return="int"
abstract="false"
@@ -113293,6 +118566,22 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="time" type="long">
+</parameter>
+<parameter name="characters" type="java.lang.String">
+</parameter>
+<parameter name="device" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</constructor>
+<constructor name="KeyEvent"
+ type="android.view.KeyEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="origEvent" type="android.view.KeyEvent">
</parameter>
<parameter name="eventTime" type="long">
@@ -113347,6 +118636,17 @@
visibility="public"
>
</method>
+<method name="getCharacters"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getDeadChar"
return="int"
abstract="false"
@@ -113674,6 +118974,17 @@
visibility="public"
>
</field>
+<field name="FLAG_KEEP_TOUCH_MODE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_SOFT_KEYBOARD"
type="int"
transient="false"
@@ -114268,6 +119579,17 @@
visibility="public"
>
</field>
+<field name="KEYCODE_MUTE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="91"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="KEYCODE_N"
type="int"
transient="false"
@@ -116530,7 +121852,7 @@
>
</field>
</class>
-<class name="OrientationListener"
+<class name="OrientationEventListener"
extends="java.lang.Object"
abstract="true"
static="false"
@@ -116538,6 +121860,94 @@
deprecated="not deprecated"
visibility="public"
>
+<constructor name="OrientationEventListener"
+ type="android.view.OrientationEventListener"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<constructor name="OrientationEventListener"
+ type="android.view.OrientationEventListener"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="rate" type="int">
+</parameter>
+</constructor>
+<method name="canDetectOrientation"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="disable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="enable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onOrientationChanged"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="orientation" type="int">
+</parameter>
+</method>
+<field name="ORIENTATION_UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="OrientationListener"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
<implements name="android.hardware.SensorListener">
</implements>
<constructor name="OrientationListener"
@@ -117990,6 +123400,19 @@
visibility="public"
>
</method>
+<method name="checkInputConnectionProxy"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+</method>
<method name="clearAnimation"
return="void"
abstract="false"
@@ -119409,6 +124832,17 @@
visibility="public"
>
</method>
+<method name="isHapticFeedbackEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isHorizontalFadingEdgeEnabled"
return="boolean"
abstract="false"
@@ -119756,6 +125190,17 @@
visibility="protected"
>
</method>
+<method name="onFinishTemporaryDetach"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onFocusChanged"
return="void"
abstract="false"
@@ -119961,6 +125406,17 @@
<parameter name="oldh" type="int">
</parameter>
</method>
+<method name="onStartTemporaryDetach"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="onTouchEvent"
return="boolean"
abstract="false"
@@ -120024,6 +125480,34 @@
visibility="public"
>
</method>
+<method name="performHapticFeedback"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="feedbackConstant" type="int">
+</parameter>
+</method>
+<method name="performHapticFeedback"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="feedbackConstant" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
<method name="performLongClick"
return="boolean"
abstract="false"
@@ -120043,7 +125527,7 @@
static="false"
final="false"
deprecated="not deprecated"
- visibility="protected"
+ visibility="public"
>
<parameter name="soundConstant" type="int">
</parameter>
@@ -120510,6 +125994,19 @@
<parameter name="focusableInTouchMode" type="boolean">
</parameter>
</method>
+<method name="setHapticFeedbackEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="hapticFeedbackEnabled" type="boolean">
+</parameter>
+</method>
<method name="setHorizontalFadingEdgeEnabled"
return="void"
abstract="false"
@@ -121287,6 +126784,17 @@
visibility="public"
>
</field>
+<field name="HAPTIC_FEEDBACK_ENABLED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="268435456"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="INVISIBLE"
type="int"
transient="false"
@@ -121889,10 +127397,23 @@
type="android.view.ViewConfiguration"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</constructor>
+<method name="get"
+ return="android.view.ViewConfiguration"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
<method name="getEdgeSlop"
return="int"
abstract="false"
@@ -121900,7 +127421,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -121911,7 +127432,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -121955,7 +127476,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -121966,7 +127487,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -121981,6 +127502,83 @@
visibility="public"
>
</method>
+<method name="getScaledEdgeSlop"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getScaledFadingEdgeLength"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getScaledMaximumDrawingCacheSize"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getScaledMinimumFlingVelocity"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getScaledScrollBarSize"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getScaledTouchSlop"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getScaledWindowTouchSlop"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getScrollBarSize"
return="int"
abstract="false"
@@ -121988,7 +127586,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -122021,7 +127619,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -122032,7 +127630,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -125337,6 +130935,19 @@
<parameter name="streamType" type="int">
</parameter>
</method>
+<method name="setWindowAnimations"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="resId" type="int">
+</parameter>
+</method>
<method name="setWindowManager"
return="void"
abstract="false"
@@ -126454,6 +132065,28 @@
visibility="public"
>
</field>
+<field name="SCREEN_BRIGHTNESS_CHANGED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2048"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCREEN_ORIENTATION_CHANGED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1024"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SOFT_INPUT_ADJUST_PAN"
type="int"
transient="false"
@@ -126531,11 +132164,22 @@
visibility="public"
>
</field>
+<field name="SOFT_INPUT_STATE_ALWAYS_HIDDEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SOFT_INPUT_STATE_ALWAYS_VISIBLE"
type="int"
transient="false"
volatile="false"
- value="4"
+ value="5"
static="true"
final="true"
deprecated="not deprecated"
@@ -126579,7 +132223,7 @@
type="int"
transient="false"
volatile="false"
- value="3"
+ value="4"
static="true"
final="true"
deprecated="not deprecated"
@@ -126929,6 +132573,26 @@
visibility="public"
>
</field>
+<field name="screenBrightness"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="screenOrientation"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="softInputMode"
type="int"
transient="false"
@@ -127152,6 +132816,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.lang.Cloneable">
+</implements>
<constructor name="Animation"
type="android.view.animation.Animation"
static="false"
@@ -129229,7 +134895,7 @@
>
<class name="BaseInputConnection"
extends="java.lang.Object"
- abstract="true"
+ abstract="false"
static="false"
final="false"
deprecated="not deprecated"
@@ -129246,8 +134912,248 @@
>
<parameter name="targetView" type="android.view.View">
</parameter>
+<parameter name="dummyMode" type="boolean">
+</parameter>
</constructor>
-<method name="hideStatusIcon"
+<method name="beginBatchEdit"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="clearMetaKeyStates"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="states" type="int">
+</parameter>
+</method>
+<method name="commitCompletion"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="android.view.inputmethod.CompletionInfo">
+</parameter>
+</method>
+<method name="commitText"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="java.lang.CharSequence">
+</parameter>
+<parameter name="newCursorPosition" type="int">
+</parameter>
+</method>
+<method name="deleteSurroundingText"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="leftLength" type="int">
+</parameter>
+<parameter name="rightLength" type="int">
+</parameter>
+</method>
+<method name="endBatchEdit"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="finishComposingText"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getComposingSpanEnd"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="android.text.Spannable">
+</parameter>
+</method>
+<method name="getComposingSpanStart"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="android.text.Spannable">
+</parameter>
+</method>
+<method name="getCursorCapsMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="reqModes" type="int">
+</parameter>
+</method>
+<method name="getEditable"
+ return="android.text.Editable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getExtractedText"
+ return="android.view.inputmethod.ExtractedText"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="request" type="android.view.inputmethod.ExtractedTextRequest">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="getTextAfterCursor"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="length" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="getTextBeforeCursor"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="length" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="performContextMenuAction"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="performEditorAction"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="actionCode" type="int">
+</parameter>
+</method>
+<method name="performPrivateCommand"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="action" type="java.lang.String">
+</parameter>
+<parameter name="data" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="removeComposingSpans"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="android.text.Spannable">
+</parameter>
+</method>
+<method name="reportFullscreenMode"
return="boolean"
abstract="false"
native="false"
@@ -129257,6 +135163,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="enabled" type="boolean">
+</parameter>
</method>
<method name="sendKeyEvent"
return="boolean"
@@ -129271,7 +135179,20 @@
<parameter name="event" type="android.view.KeyEvent">
</parameter>
</method>
-<method name="showStatusIcon"
+<method name="setComposingSpans"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="android.text.Spannable">
+</parameter>
+</method>
+<method name="setComposingText"
return="boolean"
abstract="false"
native="false"
@@ -129281,9 +135202,24 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="packageName" type="java.lang.String">
+<parameter name="text" type="java.lang.CharSequence">
</parameter>
-<parameter name="resId" type="int">
+<parameter name="newCursorPosition" type="int">
+</parameter>
+</method>
+<method name="setSelection"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="start" type="int">
+</parameter>
+<parameter name="end" type="int">
</parameter>
</method>
</class>
@@ -129439,6 +135375,21 @@
visibility="public"
>
</method>
+<method name="dump"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pw" type="android.util.Printer">
+</parameter>
+<parameter name="prefix" type="java.lang.String">
+</parameter>
+</method>
<method name="writeToParcel"
return="void"
abstract="false"
@@ -129464,6 +135415,136 @@
visibility="public"
>
</field>
+<field name="IME_ACTION_DONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IME_ACTION_GO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IME_ACTION_NEXT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IME_ACTION_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IME_ACTION_SEARCH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IME_ACTION_SEND"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IME_ACTION_UNSPECIFIED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IME_FLAG_NO_ENTER_ACTION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1073741824"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IME_MASK_ACTION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="255"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IME_NULL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="actionId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="actionLabel"
+ type="java.lang.CharSequence"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="extras"
type="android.os.Bundle"
transient="false"
@@ -129474,6 +135555,26 @@
visibility="public"
>
</field>
+<field name="fieldId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="fieldName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="hintText"
type="java.lang.CharSequence"
transient="false"
@@ -129484,6 +135585,16 @@
visibility="public"
>
</field>
+<field name="imeOptions"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="initialCapsMode"
type="int"
transient="false"
@@ -129534,7 +135645,17 @@
visibility="public"
>
</field>
-<field name="privateContentType"
+<field name="packageName"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="privateImeOptions"
type="java.lang.String"
transient="false"
volatile="false"
@@ -129599,6 +135720,17 @@
visibility="public"
>
</field>
+<field name="FLAG_SELECTING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FLAG_SINGLE_LINE"
type="int"
transient="false"
@@ -129620,6 +135752,26 @@
visibility="public"
>
</field>
+<field name="partialEndOffset"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="partialStartOffset"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="selectionEnd"
type="int"
transient="false"
@@ -129715,6 +135867,16 @@
visibility="public"
>
</field>
+<field name="flags"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="hintMaxChars"
type="int"
transient="false"
@@ -130001,6 +136163,8 @@
>
<parameter name="n" type="int">
</parameter>
+<parameter name="flags" type="int">
+</parameter>
</method>
<method name="getTextBeforeCursor"
return="java.lang.CharSequence"
@@ -130014,8 +136178,10 @@
>
<parameter name="n" type="int">
</parameter>
+<parameter name="flags" type="int">
+</parameter>
</method>
-<method name="hideStatusIcon"
+<method name="performContextMenuAction"
return="boolean"
abstract="true"
native="false"
@@ -130025,6 +136191,21 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="performEditorAction"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="editorAction" type="int">
+</parameter>
</method>
<method name="performPrivateCommand"
return="boolean"
@@ -130041,6 +136222,19 @@
<parameter name="data" type="android.os.Bundle">
</parameter>
</method>
+<method name="reportFullscreenMode"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
<method name="sendKeyEvent"
return="boolean"
abstract="true"
@@ -130069,7 +136263,7 @@
<parameter name="newCursorPosition" type="int">
</parameter>
</method>
-<method name="showStatusIcon"
+<method name="setSelection"
return="boolean"
abstract="true"
native="false"
@@ -130079,12 +136273,23 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="packageName" type="java.lang.String">
+<parameter name="start" type="int">
</parameter>
-<parameter name="resId" type="int">
+<parameter name="end" type="int">
</parameter>
</method>
-<field name="EXTRACTED_TEXT_MONITOR"
+<field name="GET_EXTRACTED_TEXT_MONITOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="GET_TEXT_WITH_STYLES"
type="int"
transient="false"
volatile="false"
@@ -130113,7 +136318,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="base" type="android.view.inputmethod.InputConnection">
+<parameter name="target" type="android.view.inputmethod.InputConnection">
</parameter>
</constructor>
<method name="beginBatchEdit"
@@ -130245,6 +136450,8 @@
>
<parameter name="n" type="int">
</parameter>
+<parameter name="flags" type="int">
+</parameter>
</method>
<method name="getTextBeforeCursor"
return="java.lang.CharSequence"
@@ -130258,8 +136465,10 @@
>
<parameter name="n" type="int">
</parameter>
+<parameter name="flags" type="int">
+</parameter>
</method>
-<method name="hideStatusIcon"
+<method name="performContextMenuAction"
return="boolean"
abstract="false"
native="false"
@@ -130269,6 +136478,21 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="performEditorAction"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="editorAction" type="int">
+</parameter>
</method>
<method name="performPrivateCommand"
return="boolean"
@@ -130285,6 +136509,19 @@
<parameter name="data" type="android.os.Bundle">
</parameter>
</method>
+<method name="reportFullscreenMode"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="enabled" type="boolean">
+</parameter>
+</method>
<method name="sendKeyEvent"
return="boolean"
abstract="false"
@@ -130313,7 +136550,7 @@
<parameter name="newCursorPosition" type="int">
</parameter>
</method>
-<method name="showStatusIcon"
+<method name="setSelection"
return="boolean"
abstract="false"
native="false"
@@ -130323,9 +136560,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="packageName" type="java.lang.String">
+<parameter name="start" type="int">
</parameter>
-<parameter name="resId" type="int">
+<parameter name="end" type="int">
</parameter>
</method>
</class>
@@ -130385,6 +136622,10 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="flags" type="int">
+</parameter>
+<parameter name="resultReceiver" type="android.os.ResultReceiver">
+</parameter>
</method>
<method name="restartInput"
return="void"
@@ -130396,6 +136637,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="inputConnection" type="android.view.inputmethod.InputConnection">
+</parameter>
<parameter name="attribute" type="android.view.inputmethod.EditorInfo">
</parameter>
</method>
@@ -130439,6 +136682,8 @@
>
<parameter name="flags" type="int">
</parameter>
+<parameter name="resultReceiver" type="android.os.ResultReceiver">
+</parameter>
</method>
<method name="startInput"
return="void"
@@ -130450,7 +136695,9 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="attribute" type="android.view.inputmethod.EditorInfo">
+<parameter name="inputConnection" type="android.view.inputmethod.InputConnection">
+</parameter>
+<parameter name="info" type="android.view.inputmethod.EditorInfo">
</parameter>
</method>
<method name="unbindInput"
@@ -130497,6 +136744,17 @@
visibility="public"
>
</field>
+<field name="SHOW_FORCED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</interface>
<interface name="InputMethod.SessionCallback"
abstract="true"
@@ -130631,8 +136889,8 @@
visibility="public"
>
</method>
-<method name="getServiceName"
- return="java.lang.String"
+<method name="getServiceInfo"
+ return="android.content.pm.ServiceInfo"
abstract="false"
native="false"
synchronized="false"
@@ -130642,7 +136900,7 @@
visibility="public"
>
</method>
-<method name="getSettingsActivity"
+<method name="getServiceName"
return="java.lang.String"
abstract="false"
native="false"
@@ -130653,8 +136911,8 @@
visibility="public"
>
</method>
-<method name="isBuiltin"
- return="boolean"
+<method name="getSettingsActivity"
+ return="java.lang.String"
abstract="false"
native="false"
synchronized="false"
@@ -130777,7 +137035,22 @@
</parameter>
</method>
<method name="hideSoftInputFromWindow"
- return="void"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="windowToken" type="android.os.IBinder">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="hideSoftInputFromWindow"
+ return="boolean"
abstract="false"
native="false"
synchronized="false"
@@ -130790,6 +137063,21 @@
</parameter>
<parameter name="flags" type="int">
</parameter>
+<parameter name="resultReceiver" type="android.os.ResultReceiver">
+</parameter>
+</method>
+<method name="hideStatusIcon"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="imeToken" type="android.os.IBinder">
+</parameter>
</method>
<method name="isAcceptingText"
return="boolean"
@@ -130826,6 +137114,17 @@
visibility="public"
>
</method>
+<method name="isFullscreenMode"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isWatchingCursor"
return="boolean"
abstract="false"
@@ -130852,6 +137151,23 @@
<parameter name="view" type="android.view.View">
</parameter>
</method>
+<method name="sendAppPrivateCommand"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="action" type="java.lang.String">
+</parameter>
+<parameter name="data" type="android.os.Bundle">
+</parameter>
+</method>
<method name="setInputMethod"
return="void"
abstract="false"
@@ -130879,7 +137195,7 @@
>
</method>
<method name="showSoftInput"
- return="void"
+ return="boolean"
abstract="false"
native="false"
synchronized="false"
@@ -130893,6 +137209,87 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="showSoftInput"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<parameter name="resultReceiver" type="android.os.ResultReceiver">
+</parameter>
+</method>
+<method name="showSoftInputFromInputMethod"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="token" type="android.os.IBinder">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<method name="showStatusIcon"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="imeToken" type="android.os.IBinder">
+</parameter>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<parameter name="iconId" type="int">
+</parameter>
+</method>
+<method name="toggleSoftInput"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="showFlags" type="int">
+</parameter>
+<parameter name="hideFlags" type="int">
+</parameter>
+</method>
+<method name="toggleSoftInputFromWindow"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="windowToken" type="android.os.IBinder">
+</parameter>
+<parameter name="showFlags" type="int">
+</parameter>
+<parameter name="hideFlags" type="int">
+</parameter>
+</method>
<method name="updateCursor"
return="void"
abstract="false"
@@ -130952,22 +137349,51 @@
<parameter name="candidatesEnd" type="int">
</parameter>
</method>
-<method name="updateStatusIcon"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
+<field name="HIDE_IMPLICIT_ONLY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
deprecated="not deprecated"
visibility="public"
>
-<parameter name="iconId" type="int">
-</parameter>
-<parameter name="iconPackage" type="java.lang.String">
-</parameter>
-</method>
-<field name="HIDE_IMPLICIT_ONLY"
+</field>
+<field name="HIDE_NOT_ALWAYS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RESULT_HIDDEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RESULT_SHOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RESULT_UNCHANGED_HIDDEN"
type="int"
transient="false"
volatile="false"
@@ -130978,6 +137404,28 @@
visibility="public"
>
</field>
+<field name="RESULT_UNCHANGED_SHOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SHOW_FORCED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SHOW_IMPLICIT"
type="int"
transient="false"
@@ -131070,6 +137518,21 @@
visibility="public"
>
</method>
+<method name="toggleSoftInput"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="showFlags" type="int">
+</parameter>
+<parameter name="hideFlags" type="int">
+</parameter>
+</method>
<method name="updateCursor"
return="void"
abstract="true"
@@ -131145,38 +137608,6 @@
</parameter>
</method>
</interface>
-<class name="MutableInputConnectionWrapper"
- extends="android.view.inputmethod.InputConnectionWrapper"
- abstract="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<constructor name="MutableInputConnectionWrapper"
- type="android.view.inputmethod.MutableInputConnectionWrapper"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="base" type="android.view.inputmethod.InputConnection">
-</parameter>
-</constructor>
-<method name="setBaseInputConnection"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="base" type="android.view.inputmethod.InputConnection">
-</parameter>
-</method>
-</class>
</package>
<package name="android.webkit"
>
@@ -132525,6 +138956,75 @@
</parameter>
</method>
</interface>
+<class name="PluginData"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="PluginData"
+ type="android.webkit.PluginData"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="stream" type="java.io.InputStream">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<parameter name="headers" type="java.util.Map&lt;java.lang.String, java.lang.String[]&gt;">
+</parameter>
+<parameter name="code" type="int">
+</parameter>
+</constructor>
+<method name="getContentLength"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getHeaders"
+ return="java.util.Map&lt;java.lang.String, java.lang.String[]&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getInputStream"
+ return="java.io.InputStream"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStatusCode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="PluginList"
extends="java.lang.Object"
abstract="false"
@@ -132878,6 +139378,21 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="getPluginData"
+ return="android.webkit.PluginData"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="headers" type="java.util.Map&lt;java.lang.String, java.lang.String&gt;">
+</parameter>
+</method>
<method name="service"
return="android.webkit.CacheManager.CacheResult"
abstract="true"
@@ -132885,7 +139400,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="url" type="java.lang.String">
@@ -132910,6 +139425,21 @@
visibility="public"
>
</constructor>
+<method name="getPluginData"
+ return="android.webkit.PluginData"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="url" type="java.lang.String">
+</parameter>
+<parameter name="headers" type="java.util.Map&lt;java.lang.String, java.lang.String&gt;">
+</parameter>
+</method>
<method name="getSurrogate"
return="android.webkit.CacheManager.CacheResult"
abstract="false"
@@ -132917,7 +139447,7 @@
synchronized="true"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="url" type="java.lang.String">
@@ -135016,7 +141546,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
<parameter name="oldFocus" type="android.view.View">
@@ -136786,6 +143316,17 @@
<parameter name="defStyle" type="int">
</parameter>
</constructor>
+<method name="getKeyProgressIncrement"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getThumbOffset"
return="int"
abstract="false"
@@ -136797,6 +143338,19 @@
visibility="public"
>
</method>
+<method name="setKeyProgressIncrement"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="increment" type="int">
+</parameter>
+</method>
<method name="setThumb"
return="void"
abstract="false"
@@ -138123,6 +144677,19 @@
<parameter name="notifyOnChange" type="boolean">
</parameter>
</method>
+<method name="sort"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="comparator" type="java.util.Comparator&lt;? super T&gt;">
+</parameter>
+</method>
</class>
<class name="AutoCompleteTextView"
extends="android.widget.EditText"
@@ -138227,6 +144794,28 @@
visibility="public"
>
</method>
+<method name="getDropDownAnchor"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDropDownWidth"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getFilter"
return="android.widget.Filter"
abstract="false"
@@ -138315,6 +144904,17 @@
visibility="public"
>
</method>
+<method name="isPerformingCompletion"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isPopupShowing"
return="boolean"
abstract="false"
@@ -138415,6 +145015,32 @@
<parameter name="hint" type="java.lang.CharSequence">
</parameter>
</method>
+<method name="setDropDownAnchor"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
+<method name="setDropDownWidth"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="width" type="int">
+</parameter>
+</method>
<method name="setListSelection"
return="void"
abstract="false"
@@ -139132,6 +145758,17 @@
visibility="public"
>
</method>
+<method name="getOnChronometerTickListener"
+ return="android.widget.Chronometer.OnChronometerTickListener"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="setBase"
return="void"
abstract="false"
@@ -139158,6 +145795,32 @@
<parameter name="format" type="java.lang.String">
</parameter>
</method>
+<method name="setOnChronometerTickListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.widget.Chronometer.OnChronometerTickListener">
+</parameter>
+</method>
+<method name="setStarted"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="started" type="boolean">
+</parameter>
+</method>
<method name="start"
return="void"
abstract="false"
@@ -139181,6 +145844,27 @@
>
</method>
</class>
+<interface name="Chronometer.OnChronometerTickListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onChronometerTick"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="chronometer" type="android.widget.Chronometer">
+</parameter>
+</method>
+</interface>
<class name="CompoundButton"
extends="android.widget.Button"
abstract="true"
@@ -142425,6 +149109,218 @@
</parameter>
</method>
</class>
+<class name="HorizontalScrollView"
+ extends="android.widget.FrameLayout"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="HorizontalScrollView"
+ type="android.widget.HorizontalScrollView"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<constructor name="HorizontalScrollView"
+ type="android.widget.HorizontalScrollView"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+</constructor>
+<constructor name="HorizontalScrollView"
+ type="android.widget.HorizontalScrollView"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<parameter name="defStyle" type="int">
+</parameter>
+</constructor>
+<method name="arrowScroll"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="direction" type="int">
+</parameter>
+</method>
+<method name="computeScrollDeltaToGetChildRectOnScreen"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="rect" type="android.graphics.Rect">
+</parameter>
+</method>
+<method name="executeKeyEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
+<method name="fling"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="velocityX" type="int">
+</parameter>
+</method>
+<method name="fullScroll"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="direction" type="int">
+</parameter>
+</method>
+<method name="getMaxScrollAmount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isFillViewport"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isSmoothScrollingEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="pageScroll"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="direction" type="int">
+</parameter>
+</method>
+<method name="setFillViewport"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fillViewport" type="boolean">
+</parameter>
+</method>
+<method name="setSmoothScrollingEnabled"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="smoothScrollingEnabled" type="boolean">
+</parameter>
+</method>
+<method name="smoothScrollBy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dx" type="int">
+</parameter>
+<parameter name="dy" type="int">
+</parameter>
+</method>
+<method name="smoothScrollTo"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="x" type="int">
+</parameter>
+<parameter name="y" type="int">
+</parameter>
+</method>
+</class>
<class name="ImageButton"
extends="android.widget.ImageView"
abstract="false"
@@ -144340,6 +151236,21 @@
<parameter name="anchor" type="android.view.View">
</parameter>
</method>
+<method name="getMaxAvailableHeight"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="anchor" type="android.view.View">
+</parameter>
+<parameter name="yOffset" type="int">
+</parameter>
+</method>
<method name="getWidth"
return="int"
abstract="false"
@@ -144351,6 +151262,17 @@
visibility="public"
>
</method>
+<method name="isAboveAnchor"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isClippingEnabled"
return="boolean"
abstract="false"
@@ -145970,6 +152892,91 @@
<parameter name="v" type="android.view.View">
</parameter>
</method>
+<method name="setBitmap"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="android.graphics.Bitmap">
+</parameter>
+</method>
+<method name="setBoolean"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="boolean">
+</parameter>
+</method>
+<method name="setByte"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="byte">
+</parameter>
+</method>
+<method name="setChar"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="char">
+</parameter>
+</method>
+<method name="setCharSequence"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.CharSequence">
+</parameter>
+</method>
<method name="setChronometer"
return="void"
abstract="false"
@@ -145986,7 +152993,41 @@
</parameter>
<parameter name="format" type="java.lang.String">
</parameter>
-<parameter name="running" type="boolean">
+<parameter name="started" type="boolean">
+</parameter>
+</method>
+<method name="setDouble"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="double">
+</parameter>
+</method>
+<method name="setFloat"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="float">
</parameter>
</method>
<method name="setImageViewBitmap"
@@ -146034,6 +153075,40 @@
<parameter name="uri" type="android.net.Uri">
</parameter>
</method>
+<method name="setInt"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="int">
+</parameter>
+</method>
+<method name="setLong"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="long">
+</parameter>
+</method>
<method name="setOnClickPendingIntent"
return="void"
abstract="false"
@@ -146068,6 +153143,55 @@
<parameter name="indeterminate" type="boolean">
</parameter>
</method>
+<method name="setShort"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="short">
+</parameter>
+</method>
+<method name="setString"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.String">
+</parameter>
+</method>
+<method name="setTextColor"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="color" type="int">
+</parameter>
+</method>
<method name="setTextViewText"
return="void"
abstract="false"
@@ -146083,6 +153207,23 @@
<parameter name="text" type="java.lang.CharSequence">
</parameter>
</method>
+<method name="setUri"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="methodName" type="java.lang.String">
+</parameter>
+<parameter name="value" type="android.net.Uri">
+</parameter>
+</method>
<method name="setViewVisibility"
return="void"
abstract="false"
@@ -146139,6 +153280,16 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="ex" type="java.lang.Exception">
+</parameter>
+</constructor>
+<constructor name="RemoteViews.ActionException"
+ type="android.widget.RemoteViews.ActionException"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
<parameter name="message" type="java.lang.String">
</parameter>
</constructor>
@@ -147755,6 +154906,323 @@
</parameter>
</method>
</class>
+<class name="SlidingDrawer"
+ extends="android.view.ViewGroup"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="SlidingDrawer"
+ type="android.widget.SlidingDrawer"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+</constructor>
+<constructor name="SlidingDrawer"
+ type="android.widget.SlidingDrawer"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<parameter name="defStyle" type="int">
+</parameter>
+</constructor>
+<method name="animateClose"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="animateOpen"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="animateToggle"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getContent"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getHandle"
+ return="android.view.View"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isMoving"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isOpened"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="lock"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onLayout"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="changed" type="boolean">
+</parameter>
+<parameter name="l" type="int">
+</parameter>
+<parameter name="t" type="int">
+</parameter>
+<parameter name="r" type="int">
+</parameter>
+<parameter name="b" type="int">
+</parameter>
+</method>
+<method name="open"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setOnDrawerCloseListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="onDrawerCloseListener" type="android.widget.SlidingDrawer.OnDrawerCloseListener">
+</parameter>
+</method>
+<method name="setOnDrawerOpenListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="onDrawerOpenListener" type="android.widget.SlidingDrawer.OnDrawerOpenListener">
+</parameter>
+</method>
+<method name="setOnDrawerScrollListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="onDrawerScrollListener" type="android.widget.SlidingDrawer.OnDrawerScrollListener">
+</parameter>
+</method>
+<method name="toggle"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="unlock"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="ORIENTATION_HORIZONTAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ORIENTATION_VERTICAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="SlidingDrawer.OnDrawerCloseListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onDrawerClosed"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
+<interface name="SlidingDrawer.OnDrawerOpenListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onDrawerOpened"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
+<interface name="SlidingDrawer.OnDrawerScrollListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onScrollEnded"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="onScrollStarted"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</interface>
<class name="Spinner"
extends="android.widget.AbsSpinner"
abstract="false"
@@ -148856,6 +156324,41 @@
<parameter name="end" type="int">
</parameter>
</method>
+<method name="beginBatchEdit"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="bringPointIntoView"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="offset" type="int">
+</parameter>
+</method>
+<method name="clearComposingText"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="debug"
return="void"
abstract="false"
@@ -148869,6 +156372,28 @@
<parameter name="depth" type="int">
</parameter>
</method>
+<method name="didTouchFocusSelect"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="endBatchEdit"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="extractText"
return="boolean"
abstract="false"
@@ -149115,6 +156640,39 @@
visibility="public"
>
</method>
+<method name="getImeActionId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getImeActionLabel"
+ return="java.lang.CharSequence"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getImeOptions"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getInputExtras"
return="android.os.Bundle"
abstract="false"
@@ -149253,7 +156811,7 @@
visibility="public"
>
</method>
-<method name="getPrivateContentType"
+<method name="getPrivateImeOptions"
return="java.lang.String"
abstract="false"
native="false"
@@ -149450,6 +157008,17 @@
visibility="public"
>
</method>
+<method name="isInputMethodTarget"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="length"
return="int"
abstract="false"
@@ -149485,6 +157054,19 @@
<parameter name="text" type="android.view.inputmethod.CompletionInfo">
</parameter>
</method>
+<method name="onEditorAction"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="actionCode" type="int">
+</parameter>
+</method>
<method name="onEndBatchEdit"
return="void"
abstract="false"
@@ -149546,6 +157128,21 @@
visibility="public"
>
</method>
+<method name="onSelectionChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="selStart" type="int">
+</parameter>
+<parameter name="selEnd" type="int">
+</parameter>
+</method>
<method name="onTextChanged"
return="void"
abstract="false"
@@ -149565,6 +157162,19 @@
<parameter name="after" type="int">
</parameter>
</method>
+<method name="onTextContextMenuItem"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
<method name="removeTextChangedListener"
return="void"
abstract="false"
@@ -149903,6 +157513,34 @@
<parameter name="whether" type="boolean">
</parameter>
</method>
+<method name="setImeActionLabel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="label" type="java.lang.CharSequence">
+</parameter>
+<parameter name="actionId" type="int">
+</parameter>
+</method>
+<method name="setImeOptions"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="imeOptions" type="int">
+</parameter>
+</method>
<method name="setIncludeFontPadding"
return="void"
abstract="false"
@@ -150156,6 +157794,19 @@
<parameter name="movement" type="android.text.method.MovementMethod">
</parameter>
</method>
+<method name="setOnEditorActionListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="l" type="android.widget.TextView.OnEditorActionListener">
+</parameter>
+</method>
<method name="setPaintFlags"
return="void"
abstract="false"
@@ -150169,7 +157820,7 @@
<parameter name="flags" type="int">
</parameter>
</method>
-<method name="setPrivateContentType"
+<method name="setPrivateImeOptions"
return="void"
abstract="false"
native="false"
@@ -150548,6 +158199,31 @@
>
</method>
</class>
+<interface name="TextView.OnEditorActionListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onEditorAction"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="v" type="android.widget.TextView">
+</parameter>
+<parameter name="actionId" type="int">
+</parameter>
+<parameter name="event" type="android.view.KeyEvent">
+</parameter>
+</method>
+</interface>
<class name="TextView.SavedState"
extends="android.view.View.BaseSavedState"
abstract="false"
@@ -155158,6 +162834,21 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="dumpHprofData"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fileName" type="java.lang.String">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
<method name="getAllocCount"
return="int"
abstract="false"
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp
index 3d6b0b1..0f1ae8e 100644
--- a/camera/libcameraservice/CameraHardwareStub.cpp
+++ b/camera/libcameraservice/CameraHardwareStub.cpp
@@ -29,7 +29,8 @@ namespace android {
CameraHardwareStub::CameraHardwareStub()
: mParameters(),
- mHeap(0),
+ mPreviewHeap(0),
+ mRawHeap(0),
mFakeCamera(0),
mPreviewFrameSize(0),
mRawPictureCallback(0),
@@ -62,13 +63,17 @@ void CameraHardwareStub::initDefaultParameters()
void CameraHardwareStub::initHeapLocked()
{
- int width, height;
- mParameters.getPreviewSize(&width, &height);
+ // Create raw heap.
+ int picture_width, picture_height;
+ mParameters.getPictureSize(&picture_width, &picture_height);
+ mRawHeap = new MemoryHeapBase(picture_width * 2 * picture_height);
- LOGD("initHeapLocked: preview size=%dx%d", width, height);
+ int preview_width, preview_height;
+ mParameters.getPreviewSize(&preview_width, &preview_height);
+ LOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);
// Note that we enforce yuv422 in setParameters().
- int how_big = width * height * 2;
+ int how_big = preview_width * preview_height * 2;
// If we are being reinitialized to the same size as before, no
// work needs to be done.
@@ -79,15 +84,15 @@ void CameraHardwareStub::initHeapLocked()
// Make a new mmap'ed heap that can be shared across processes.
// use code below to test with pmem
- mHeap = new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
+ mPreviewHeap = new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
// Make an IMemory for each frame so that we can reuse them in callbacks.
for (int i = 0; i < kBufferCount; i++) {
- mBuffers[i] = new MemoryBase(mHeap, i * mPreviewFrameSize, mPreviewFrameSize);
+ mBuffers[i] = new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize);
}
-
+
// Recreate the fake camera to reflect the current size.
delete mFakeCamera;
- mFakeCamera = new FakeCamera(width, height);
+ mFakeCamera = new FakeCamera(preview_width, preview_height);
}
CameraHardwareStub::~CameraHardwareStub()
@@ -99,7 +104,12 @@ CameraHardwareStub::~CameraHardwareStub()
sp<IMemoryHeap> CameraHardwareStub::getPreviewHeap() const
{
- return mHeap;
+ return mPreviewHeap;
+}
+
+sp<IMemoryHeap> CameraHardwareStub::getRawHeap() const
+{
+ return mRawHeap;
}
// ---------------------------------------------------------------------------
@@ -114,7 +124,7 @@ int CameraHardwareStub::previewThread()
// Find the offset within the heap of the current buffer.
ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
- sp<MemoryHeapBase> heap = mHeap;
+ sp<MemoryHeapBase> heap = mPreviewHeap;
// this assumes the internal state of fake camera doesn't change
// (or is thread safe)
@@ -187,6 +197,24 @@ bool CameraHardwareStub::previewEnabled() {
return mPreviewThread != 0;
}
+status_t CameraHardwareStub::startRecording(recording_callback cb, void* user)
+{
+ return UNKNOWN_ERROR;
+}
+
+void CameraHardwareStub::stopRecording()
+{
+}
+
+bool CameraHardwareStub::recordingEnabled()
+{
+ return false;
+}
+
+void CameraHardwareStub::releaseRecordingFrame(const sp<IMemory>& mem)
+{
+}
+
// ---------------------------------------------------------------------------
int CameraHardwareStub::beginAutoFocusThread(void *cookie)
@@ -237,10 +265,9 @@ int CameraHardwareStub::pictureThread()
// In the meantime just make another fake camera picture.
int w, h;
mParameters.getPictureSize(&w, &h);
- sp<MemoryHeapBase> heap = new MemoryHeapBase(w * 2 * h);
- sp<MemoryBase> mem = new MemoryBase(heap, 0, w * 2 * h);
+ sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * 2 * h);
FakeCamera cam(w, h);
- cam.getNextFrameAsYuv422((uint8_t *)heap->base());
+ cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base());
if (mRawPictureCallback)
mRawPictureCallback(mem, mPictureCallbackCookie);
}
diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h
index 9f5ddf1..0d26d47 100644
--- a/camera/libcameraservice/CameraHardwareStub.h
+++ b/camera/libcameraservice/CameraHardwareStub.h
@@ -30,10 +30,17 @@ namespace android {
class CameraHardwareStub : public CameraHardwareInterface {
public:
virtual sp<IMemoryHeap> getPreviewHeap() const;
+ virtual sp<IMemoryHeap> getRawHeap() const;
virtual status_t startPreview(preview_callback cb, void* user);
virtual void stopPreview();
virtual bool previewEnabled();
+
+ virtual status_t startRecording(recording_callback cb, void* user);
+ virtual void stopRecording();
+ virtual bool recordingEnabled();
+ virtual void releaseRecordingFrame(const sp<IMemory>& mem);
+
virtual status_t autoFocus(autofocus_callback, void *user);
virtual status_t takePicture(shutter_callback,
raw_callback,
@@ -87,7 +94,8 @@ private:
CameraParameters mParameters;
- sp<MemoryHeapBase> mHeap;
+ sp<MemoryHeapBase> mPreviewHeap;
+ sp<MemoryHeapBase> mRawHeap;
sp<MemoryBase> mBuffers[kBufferCount];
FakeCamera *mFakeCamera;
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 36c5ada..15e3b21 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -86,18 +86,19 @@ sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient)
LOGD("Connect E from ICameraClient %p", cameraClient->asBinder().get());
Mutex::Autolock lock(mLock);
+ sp<Client> client;
if (mClient != 0) {
sp<Client> currentClient = mClient.promote();
if (currentClient != 0) {
sp<ICameraClient> currentCameraClient(currentClient->getCameraClient());
if (cameraClient->asBinder() == currentCameraClient->asBinder()) {
// this is the same client reconnecting...
- LOGD("Connect X same client is reconnecting...");
+ LOGD("Connect X same client (%p) is reconnecting...", cameraClient->asBinder().get());
return currentClient;
} else {
- // it's another client... boot the previous one...
- LOGD("new client connecting, booting the old one...");
- mClient.clear();
+ // it's another client... reject it
+ LOGD("new client (%p) attempting to connect - rejected", cameraClient->asBinder().get());
+ return client;
}
} else {
// can't promote, the previous client has died...
@@ -107,7 +108,7 @@ sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient)
}
// create a new Client object
- sp<Client> client = new Client(this, cameraClient, IPCThreadState::self()->getCallingPid());
+ client = new Client(this, cameraClient, IPCThreadState::self()->getCallingPid());
mClient = client;
#if DEBUG_CLIENT_REFERENCES
// Enable tracking for this object, and track increments and decrements of
@@ -151,28 +152,30 @@ void CameraService::removeClient(const sp<ICameraClient>& cameraClient)
}
CameraService::Client::Client(const sp<CameraService>& cameraService,
- const sp<ICameraClient>& cameraClient, pid_t clientPid)
+ const sp<ICameraClient>& cameraClient, pid_t clientPid)
{
LOGD("Client E constructor");
mCameraService = cameraService;
mCameraClient = cameraClient;
mClientPid = clientPid;
mHardware = openCameraHardware();
+ mUseOverlay = mHardware->useOverlay();
// Callback is disabled by default
- mFrameCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+ mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
LOGD("Client X constructor");
}
status_t CameraService::Client::checkPid()
{
if (mClientPid == IPCThreadState::self()->getCallingPid()) return NO_ERROR;
- LOGW("Attempt to use locked camera from different process");
+ LOGW("Attempt to use locked camera (%p) from different process", getCameraClient()->asBinder().get());
return -EBUSY;
}
status_t CameraService::Client::lock()
{
+ Mutex::Autolock _l(mLock);
// lock camera to this client if the the camera is unlocked
if (mClientPid == 0) {
mClientPid = IPCThreadState::self()->getCallingPid();
@@ -184,8 +187,9 @@ status_t CameraService::Client::lock()
status_t CameraService::Client::unlock()
{
+ Mutex::Autolock _l(mLock);
// allow anyone to use camera
- LOGV("unlock");
+ LOGV("unlock (%p)", getCameraClient()->asBinder().get());
status_t result = checkPid();
if (result == NO_ERROR) mClientPid = 0;
return result;
@@ -194,27 +198,40 @@ status_t CameraService::Client::unlock()
status_t CameraService::Client::connect(const sp<ICameraClient>& client)
{
// connect a new process to the camera
- LOGV("connect");
-
- // hold a reference to the old client or we will deadlock if the client is
- // in the same process and we hold the lock when we remove the reference
- sp<ICameraClient> oldClient;
+ LOGV("connect (%p)", client->asBinder().get());
+
+ // I hate this hack, but things get really ugly when the media recorder
+ // service is handing back the camera to the app. The ICameraClient
+ // destructor will be called during the same IPC, making it look like
+ // the remote client is trying to disconnect. This hack temporarily
+ // sets the mClientPid to an invalid pid to prevent the hardware from
+ // being torn down.
{
- Mutex::Autolock _l(mLock);
- if (mClientPid != 0) {
- LOGW("Tried to connect to locked camera");
- return -EBUSY;
- }
- oldClient = mCameraClient;
- // did the client actually change?
- if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR;
+ // hold a reference to the old client or we will deadlock if the client is
+ // in the same process and we hold the lock when we remove the reference
+ sp<ICameraClient> oldClient;
+ {
+ Mutex::Autolock _l(mLock);
+ if (mClientPid != 0) {
+ LOGW("Tried to connect to locked camera");
+ return -EBUSY;
+ }
+ oldClient = mCameraClient;
+
+ // did the client actually change?
+ if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR;
+
+ mCameraClient = client;
+ mClientPid = -1;
+ mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+ LOGV("connect new process (%d) to existing camera client", mClientPid);
+ }
- LOGV("connect new process to existing camera client");
- mCameraClient = client;
- mClientPid = IPCThreadState::self()->getCallingPid();
- mFrameCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
}
+ // the old client destructor is called when oldClient goes out of scope
+ // now we set the new PID to lock the interface again
+ mClientPid = IPCThreadState::self()->getCallingPid();
return NO_ERROR;
}
@@ -232,8 +249,8 @@ static void *unregister_surface(void *arg)
CameraService::Client::~Client()
{
// tear down client
- LOGD("Client E destructor");
- if (mSurface != 0) {
+ LOGD("Client (%p) E destructor", getCameraClient()->asBinder().get());
+ if (mSurface != 0 && !mUseOverlay) {
#if HAVE_ANDROID_OS
pthread_t thr;
// We unregister the buffers in a different thread because binder does
@@ -244,7 +261,7 @@ CameraService::Client::~Client()
mSurface.get());
pthread_join(thr, NULL);
#else
- mSurface->unregisterBuffers();
+ mSurface->unregisterBuffers();
#endif
}
@@ -256,16 +273,22 @@ CameraService::Client::~Client()
void CameraService::Client::disconnect()
{
- LOGD("Client E disconnect");
+ LOGD("Client (%p) E disconnect from (%d)",
+ getCameraClient()->asBinder().get(),
+ IPCThreadState::self()->getCallingPid());
Mutex::Autolock lock(mLock);
- if (mClientPid == 0) {
+ if (mClientPid <= 0) {
LOGV("camera is unlocked, don't tear down hardware");
return;
}
- if (checkPid() != NO_ERROR) return;
+ if (checkPid() != NO_ERROR) {
+ LOGV("Different client - don't disconnect");
+ return;
+ }
mCameraService->removeClient(mCameraClient);
if (mHardware != 0) {
+ LOGV("hardware teardown");
// Before destroying mHardware, we must make sure it's in the
// idle state.
mHardware->stopPreview();
@@ -288,7 +311,7 @@ status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface)
Mutex::Autolock surfaceLock(mSurfaceLock);
// asBinder() is safe on NULL (returns NULL)
if (surface->asBinder() != mSurface->asBinder()) {
- if (mSurface != 0) {
+ if (mSurface != 0 && !mUseOverlay) {
LOGD("clearing old preview surface %p", mSurface.get());
mSurface->unregisterBuffers();
}
@@ -297,19 +320,20 @@ status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface)
return NO_ERROR;
}
-// set the frame callback flag to affect how the received frames from
+// set the preview callback flag to affect how the received frames from
// preview are handled.
-void CameraService::Client::setFrameCallbackFlag(int frame_callback_flag)
+void CameraService::Client::setPreviewCallbackFlag(int callback_flag)
{
+ LOGV("setPreviewCallbackFlag");
Mutex::Autolock lock(mLock);
if (checkPid() != NO_ERROR) return;
- mFrameCallbackFlag = frame_callback_flag;
+ mPreviewCallbackFlag = callback_flag;
}
// start preview mode, must call setPreviewDisplay first
-status_t CameraService::Client::startPreview()
+status_t CameraService::Client::startCameraMode(camera_mode mode)
{
- LOGD("startPreview()");
+ LOGD("startCameraMode(%d)", mode);
/* we cannot call into mHardware with mLock held because
* mHardware has callbacks onto us which acquire this lock
@@ -325,37 +349,124 @@ status_t CameraService::Client::startPreview()
}
if (mSurface == 0) {
- LOGE("setPreviewDisplay must be called before startPreview!");
+ LOGE("setPreviewDisplay must be called before startCameraMode!");
return INVALID_OPERATION;
}
- // do nothing if preview is already started
- if (mHardware->previewEnabled()) return NO_ERROR;
+ switch(mode) {
+ case CAMERA_RECORDING_MODE:
+ return startRecordingMode();
- // XXX: This needs to be improved. remove all hardcoded stuff
+ default: // CAMERA_PREVIEW_MODE
+ return startPreviewMode();
+ }
+}
- int w, h;
- CameraParameters params(mHardware->getParameters());
- params.getPreviewSize(&w, &h);
+status_t CameraService::Client::startRecordingMode()
+{
+ LOGV("startRecordingMode");
+ status_t ret = UNKNOWN_ERROR;
+
+ // if preview has not been started, start preview first
+ if (!mHardware->previewEnabled()) {
+ ret = startPreviewMode();
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ }
+
+ // if recording has been enabled, nothing needs to be done
+ if (mHardware->recordingEnabled()) {
+ return NO_ERROR;
+ }
+
+ // start recording mode
+ ret = mHardware->startRecording(recordingCallback,
+ mCameraService.get());
+ if (ret != NO_ERROR) {
+ LOGE("mHardware->startRecording() failed with status %d", ret);
+ }
+ return ret;
+}
+
+status_t CameraService::Client::startPreviewMode()
+{
+ LOGV("startPreviewMode");
+
+ // if preview has been enabled, nothing needs to be done
+ if (mHardware->previewEnabled()) {
+ return NO_ERROR;
+ }
+
+ // start preview mode
#if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE
debug_frame_cnt = 0;
#endif
+ status_t ret = UNKNOWN_ERROR;
+ int w, h;
+ CameraParameters params(mHardware->getParameters());
+ params.getPreviewSize(&w, &h);
- status_t ret = mHardware->startPreview(previewCallback,
- mCameraService.get());
- if (ret == NO_ERROR) {
- mSurface->unregisterBuffers();
- mSurface->registerBuffers(w,h,w,h,
- PIXEL_FORMAT_YCbCr_420_SP,
- mHardware->getPreviewHeap());
- }
- else LOGE("mHardware->startPreview() failed with status %d\n",
- ret);
+ if (mUseOverlay) {
+ const char *format = params.getPreviewFormat();
+ int fmt;
+ LOGD("Use Overlays");
+ if (!strcmp(format, "yuv422i"))
+ fmt = OVERLAY_FORMAT_YCbCr_422_I;
+ else if (!strcmp(format, "rgb565"))
+ fmt = OVERLAY_FORMAT_RGB_565;
+ else {
+ LOGE("Invalid preview format for overlays");
+ return -EINVAL;
+ }
+ sp<OverlayRef> ref = mSurface->createOverlay(w, h, fmt);
+ ret = mHardware->setOverlay(new Overlay(ref));
+ if (ret != NO_ERROR) {
+ LOGE("mHardware->setOverlay() failed with status %d\n", ret);
+ return ret;
+ }
+ ret = mHardware->startPreview(NULL, mCameraService.get());
+ if (ret != NO_ERROR)
+ LOGE("mHardware->startPreview() failed with status %d\n", ret);
+
+ } else {
+ ret = mHardware->startPreview(previewCallback,
+ mCameraService.get());
+ if (ret == NO_ERROR) {
+
+ mSurface->unregisterBuffers();
+
+ uint32_t transform = 0;
+ if (params.getOrientation() ==
+ CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
+ LOGV("portrait mode");
+ transform = ISurface::BufferHeap::ROT_90;
+ }
+ ISurface::BufferHeap buffers(w, h, w, h,
+ PIXEL_FORMAT_YCbCr_420_SP,
+ transform,
+ 0,
+ mHardware->getPreviewHeap());
+ mSurface->registerBuffers(buffers);
+ } else {
+ LOGE("mHardware->startPreview() failed with status %d", ret);
+ }
+ }
return ret;
}
+status_t CameraService::Client::startPreview()
+{
+ return startCameraMode(CAMERA_PREVIEW_MODE);
+}
+
+status_t CameraService::Client::startRecording()
+{
+ return startCameraMode(CAMERA_RECORDING_MODE);
+}
+
// stop preview mode
void CameraService::Client::stopPreview()
{
@@ -372,12 +483,46 @@ void CameraService::Client::stopPreview()
mHardware->stopPreview();
LOGD("stopPreview(), hardware stopped OK");
- if (mSurface != 0) {
+ if (mSurface != 0 && !mUseOverlay) {
mSurface->unregisterBuffers();
}
mPreviewBuffer.clear();
}
+// stop recording mode
+void CameraService::Client::stopRecording()
+{
+ LOGV("stopRecording()");
+
+ Mutex::Autolock lock(mLock);
+ if (checkPid() != NO_ERROR) return;
+
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return;
+ }
+
+ mHardware->stopRecording();
+ LOGV("stopRecording(), hardware stopped OK");
+ mPreviewBuffer.clear();
+}
+
+// release a recording frame
+void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem)
+{
+ LOGV("releaseRecordingFrame()");
+
+ Mutex::Autolock lock(mLock);
+ if (checkPid() != NO_ERROR) return;
+
+ if (mHardware == 0) {
+ LOGE("mHardware is NULL, returning.");
+ return;
+ }
+
+ mHardware->releaseRecordingFrame(mem);
+}
+
bool CameraService::Client::previewEnabled()
{
Mutex::Autolock lock(mLock);
@@ -385,6 +530,13 @@ bool CameraService::Client::previewEnabled()
return mHardware->previewEnabled();
}
+bool CameraService::Client::recordingEnabled()
+{
+ Mutex::Autolock lock(mLock);
+ if (mHardware == 0) return false;
+ return mHardware->recordingEnabled();
+}
+
// Safely retrieves a strong pointer to the client during a hardware callback.
sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user)
{
@@ -476,7 +628,7 @@ void CameraService::Client::previewCallback(const sp<IMemory>& mem, void* user)
#endif
// The strong pointer guarantees the client will exist, but no lock is held.
- client->postFrame(mem);
+ client->postPreviewFrame(mem);
#if DEBUG_CLIENT_REFERENCES
//**** if the client's refcount is 1, then we are about to destroy it here,
@@ -488,6 +640,18 @@ void CameraService::Client::previewCallback(const sp<IMemory>& mem, void* user)
#endif
}
+// recording callback
+void CameraService::Client::recordingCallback(const sp<IMemory>& mem, void* user)
+{
+ LOGV("recordingCallback");
+ sp<Client> client = getClientFromCookie(user);
+ if (client == 0) {
+ return;
+ }
+ // The strong pointer guarantees the client will exist, but no lock is held.
+ client->postRecordingFrame(mem);
+}
+
// take a picture - image is returned in callback
status_t CameraService::Client::autoFocus()
{
@@ -520,9 +684,6 @@ status_t CameraService::Client::takePicture()
return INVALID_OPERATION;
}
- if (mSurface != NULL)
- mSurface->unregisterBuffers();
-
return mHardware->takePicture(shutterCallback,
yuvPictureCallback,
jpegPictureCallback,
@@ -537,7 +698,29 @@ void CameraService::Client::shutterCallback(void *user)
return;
}
+ // Screen goes black after the buffer is unregistered.
+ if (client->mSurface != 0 && !client->mUseOverlay) {
+ client->mSurface->unregisterBuffers();
+ }
+
client->postShutter();
+
+ // It takes some time before yuvPicture callback to be called.
+ // Register the buffer for raw image here to reduce latency.
+ if (client->mSurface != 0 && !client->mUseOverlay) {
+ int w, h;
+ CameraParameters params(client->mHardware->getParameters());
+ params.getPictureSize(&w, &h);
+ uint32_t transform = 0;
+ if (params.getOrientation() == CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
+ LOGV("portrait mode");
+ transform = ISurface::BufferHeap::ROT_90;
+ }
+ ISurface::BufferHeap buffers(w, h, w, h,
+ PIXEL_FORMAT_YCbCr_420_SP, transform, 0, client->mHardware->getRawHeap());
+
+ client->mSurface->registerBuffers(buffers);
+ }
}
// picture callback - raw image ready
@@ -568,15 +751,7 @@ void CameraService::Client::yuvPictureCallback(const sp<IMemory>& mem,
#endif
// Put the YUV version of the snapshot in the preview display.
- int w, h;
- CameraParameters params(client->mHardware->getParameters());
- params.getPictureSize(&w, &h);
-
-// Mutex::Autolock clientLock(client->mLock);
- if (client->mSurface != 0) {
- client->mSurface->unregisterBuffers();
- client->mSurface->registerBuffers(w,h,w,h,
- PIXEL_FORMAT_YCbCr_420_SP, heap);
+ if (client->mSurface != 0 && !client->mUseOverlay) {
client->mSurface->postBuffer(offset);
}
@@ -730,12 +905,22 @@ void CameraService::Client::copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, si
LOGE("failed to allocate space for frame callback");
return;
}
- mCameraClient->frameCallback(frame);
+ mCameraClient->previewCallback(frame);
}
-void CameraService::Client::postFrame(const sp<IMemory>& mem)
+void CameraService::Client::postRecordingFrame(const sp<IMemory>& frame)
{
- LOGV("postFrame");
+ LOGV("postRecordingFrame");
+ if (frame == 0) {
+ LOGW("frame is a null pointer");
+ return;
+ }
+ mCameraClient->recordingCallback(frame);
+}
+
+void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem)
+{
+ LOGV("postPreviewFrame");
if (mem == 0) {
LOGW("mem is a null pointer");
return;
@@ -752,31 +937,32 @@ void CameraService::Client::postFrame(const sp<IMemory>& mem)
}
// Is the callback enabled or not?
- if (!(mFrameCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
+ if (!(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
// If the enable bit is off, the copy-out and one-shot bits are ignored
LOGV("frame callback is diabled");
return;
}
// Is the received frame copied out or not?
- if (mFrameCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
+ if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
LOGV("frame is copied out");
copyFrameAndPostCopiedFrame(heap, offset, size);
} else {
LOGV("frame is directly sent out without copying");
- mCameraClient->frameCallback(mem);
+ mCameraClient->previewCallback(mem);
}
// Is this is one-shot only?
- if (mFrameCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
+ if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) {
LOGV("One-shot only, thus clear the bits and disable frame callback");
- mFrameCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
+ mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
FRAME_CALLBACK_FLAG_ENABLE_MASK);
}
}
-void CameraService::Client::postError(status_t error) {
+void CameraService::Client::postError(status_t error)
+{
mCameraClient->errorCallback(error);
}
@@ -796,6 +982,11 @@ status_t CameraService::dump(int fd, const Vector<String16>& args)
AutoMutex lock(&mLock);
if (mClient != 0) {
sp<Client> currentClient = mClient.promote();
+ sprintf(buffer, "Client (%p) PID: %d\n",
+ currentClient->getCameraClient()->asBinder().get(),
+ currentClient->mClientPid);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
currentClient->mHardware->dump(fd, args);
} else {
result.append("No camera client yet.\n");
@@ -880,5 +1071,3 @@ status_t CameraService::onTransact(
#endif // DEBUG_HEAP_LEAKS
}; // namespace android
-
-
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index cd8c1e9..d9b7927 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -82,9 +82,9 @@ private:
// pass the buffered ISurface to the camera service
virtual status_t setPreviewDisplay(const sp<ISurface>& surface);
- // set the frame callback flag to affect how the received frames from
+ // set the preview callback flag to affect how the received frames from
// preview are handled.
- virtual void setFrameCallbackFlag(int frame_callback_flag);
+ virtual void setPreviewCallbackFlag(int callback_flag);
// start preview mode, must call setPreviewDisplay first
virtual status_t startPreview();
@@ -95,6 +95,18 @@ private:
// get preview state
virtual bool previewEnabled();
+ // start recording mode
+ virtual status_t startRecording();
+
+ // stop recording mode
+ virtual void stopRecording();
+
+ // get recording state
+ virtual bool recordingEnabled();
+
+ // release a recording frame
+ virtual void releaseRecordingFrame(const sp<IMemory>& mem);
+
// auto focus
virtual status_t autoFocus();
@@ -120,6 +132,7 @@ private:
status_t checkPid();
+ static void recordingCallback(const sp<IMemory>& mem, void* user);
static void previewCallback(const sp<IMemory>& mem, void* user);
static void shutterCallback(void *user);
static void yuvPictureCallback(const sp<IMemory>& mem, void* user);
@@ -130,17 +143,28 @@ private:
void postShutter();
void postRaw(const sp<IMemory>& mem);
void postJpeg(const sp<IMemory>& mem);
- void postFrame(const sp<IMemory>& mem);
+ void postPreviewFrame(const sp<IMemory>& mem);
+ void postRecordingFrame(const sp<IMemory>& frame);
void copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size);
void postError(status_t error);
void postAutoFocus(bool focused);
- // Ensures atomicity among the public methods
+ // camera operation mode
+ enum camera_mode {
+ CAMERA_PREVIEW_MODE = 0, // frame automatically released
+ CAMERA_RECORDING_MODE = 1, // frame has to be explicitly released by releaseRecordingFrame()
+ };
+ status_t startCameraMode(camera_mode mode);
+ status_t startPreviewMode();
+ status_t startRecordingMode();
+
+ // Ensures atomicity among the public methods
mutable Mutex mLock;
+
// mSurfaceLock synchronizes access to mSurface between
- // setPreviewSurface() and postFrame(). Note that among
+ // setPreviewSurface() and postPreviewFrame(). Note that among
// the public methods, all accesses to mSurface are
- // syncrhonized by mLock. However, postFrame() is called
+ // syncrhonized by mLock. However, postPreviewFrame() is called
// by the CameraHardwareInterface callback, and needs to
// access mSurface. It cannot hold mLock, however, because
// stopPreview() may be holding that lock while attempting
@@ -152,13 +176,14 @@ private:
sp<CameraService> mCameraService;
sp<ISurface> mSurface;
sp<MemoryHeapBase> mPreviewBuffer;
- int mFrameCallbackFlag;
+ int mPreviewCallbackFlag;
// these are immutable once the object is created,
// they don't need to be protected by a lock
sp<ICameraClient> mCameraClient;
sp<CameraHardwareInterface> mHardware;
pid_t mClientPid;
+ bool mUseOverlay;
};
// ----------------------------------------------------------------------------
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index b86d40a..6d4b455 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -75,6 +75,8 @@ public class Am {
runInstrument();
} else if (op.equals("broadcast")) {
sendBroadcast();
+ } else if (op.equals("profile")) {
+ runProfile();
} else {
System.err.println("Error: Unknown command: " + op);
showUsage();
@@ -423,6 +425,49 @@ public class Am {
}
}
+ private void runProfile() {
+ String profileFile = null;
+ boolean start = false;
+
+ String process = nextArg();
+ if (process == null) {
+ System.err.println("Error: No profile process supplied");
+ showUsage();
+ return;
+ }
+
+ String cmd = nextArg();
+ if ("start".equals(cmd)) {
+ start = true;
+ profileFile = nextArg();
+ if (profileFile == null) {
+ System.err.println("Error: No profile file path supplied");
+ showUsage();
+ return;
+ }
+ } else if (!"stop".equals(cmd)) {
+ System.err.println("Error: Profile command " + cmd + " not valid");
+ showUsage();
+ return;
+ }
+
+ try {
+ if (!mAm.profileControl(process, start, profileFile)) {
+ System.out.println("PROFILE FAILED on process " + process);
+ return;
+ }
+ } catch (IllegalArgumentException e) {
+ System.out.println("PROFILE FAILED: " + e.getMessage());
+ return;
+ } catch (IllegalStateException e) {
+ System.out.println("PROFILE FAILED: " + e.getMessage());
+ return;
+ } catch (RemoteException e) {
+ System.out.println("PROFILE FAILED: activity manager gone");
+ return;
+ }
+ }
+
private String nextOption() {
if (mNextArg >= mArgs.length) {
return null;
@@ -470,11 +515,12 @@ public class Am {
}
private void showUsage() {
- System.err.println("usage: am [start|broadcast|instrument]");
+ System.err.println("usage: am [start|broadcast|instrument|profile]");
System.err.println(" am start -D INTENT");
System.err.println(" am broadcast INTENT");
System.err.println(" am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]");
System.err.println(" [-w] <COMPONENT> ");
+ System.err.println(" am profile <PROCESS> [start <PROF_FILE>|stop]");
System.err.println("");
System.err.println(" INTENT is described with:");
System.err.println(" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]");
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index dea269d..eabf98e 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -40,6 +40,18 @@ static void dumpstate(int full) {
PRINT("========================================================");
PRINT("== dumpstate");
PRINT("========================================================");
+ PRINT("------ MEMORY INFO ------");
+ DUMP("/proc/meminfo");
+ PRINT("------ CPU INFO ------");
+ EXEC7("top", "-n", "1", "-d", "1", "-m", "30", "-t");
+ PRINT("------ PROCRANK ------");
+ EXEC_XBIN("procrank");
+ PRINT("------ VIRTUAL MEMORY STATS ------");
+ DUMP("/proc/vmstat");
+ PRINT("------ SLAB INFO ------");
+ DUMP("/proc/slabinfo");
+ PRINT("------ ZONEINFO ------");
+ DUMP("/proc/zoneinfo");
PRINT("------ SYSTEM LOG ------");
EXEC4("logcat", "-v", "time", "-d", "*:v");
PRINT("------ VM TRACES ------");
@@ -67,20 +79,8 @@ static void dumpstate(int full) {
EXEC("ps");
PRINT("------ PROCESSES AND THREADS ------");
EXEC2("ps", "-t", "-p");
- PRINT("------ MEMORY INFO ------");
- DUMP("/proc/meminfo");
- PRINT("------ PSS INFO ------");
- EXEC8("top", "-n", "1", "-d", "0", "-m", "15", "-s", "pss");
- PRINT("------ PROCRANK ------");
- EXEC("procrank");
PRINT("------ LIBRANK ------");
- EXEC("librank");
- PRINT("------ VIRTUAL MEMORY STATS ------");
- DUMP("/proc/vmstat");
- PRINT("------ SLAB INFO ------");
- DUMP("/proc/slabinfo");
- PRINT("------ ZONEINFO ------");
- DUMP("/proc/zoneinfo");
+ EXEC_XBIN("librank");
PRINT("------ BINDER FAILED TRANSACTION LOG ------");
DUMP("/proc/binder/failed_transaction_log");
PRINT("");
@@ -127,7 +127,10 @@ static void dumpstate(int full) {
PRINT("========================================================");
PRINT("== dumpsys");
PRINT("========================================================");
- EXEC("dumpsys");
+ /* the full dumpsys is starting to take a long time, so we need
+ to increase its timeout. we really need to do the timeouts in
+ dumpsys itself... */
+ EXEC_TIMEOUT("dumpsys", 60);
}
}
@@ -224,6 +227,8 @@ int main(int argc, char *argv[]) {
}
if (compress)
strcat(path, ".gz");
+ else
+ strcat(path, ".txt");
/* ensure that all directories in the path exist */
create_directories(path);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index b956f99..6862e5a 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -19,8 +19,8 @@
#include <time.h>
-// Commands time out after 15 seconds
-#define TIMEOUT 15
+// Commands time out after 60 seconds
+#define TIMEOUT 60
#define PRINT(s) printf("%s\n", s)
@@ -43,6 +43,24 @@
run_command(&c, TIMEOUT); \
}
+#define EXEC_TIMEOUT(cmd, tmout)\
+{ \
+ static struct Command c = { \
+ "/system/bin/" cmd, \
+ { cmd, 0 } \
+ }; \
+ run_command(&c, tmout); \
+}
+
+#define EXEC_XBIN(cmd) \
+{ \
+ static struct Command c = { \
+ "/system/xbin/" cmd, \
+ { cmd, 0 } \
+ }; \
+ run_command(&c, TIMEOUT); \
+}
+
#define EXEC2(cmd, a1, a2) \
{ \
static struct Command c = { \
@@ -70,6 +88,15 @@
run_command(&c, TIMEOUT); \
}
+#define EXEC7(cmd, a1, a2, a3, a4, a5, a6, a7) \
+{ \
+ static struct Command c = { \
+ "/system/bin/" cmd, \
+ { cmd, a1, a2, a3, a4, a5, a6, a7, 0 } \
+ }; \
+ run_command(&c, TIMEOUT); \
+}
+
#define EXEC8(cmd, a1, a2, a3, a4, a5, a6, a7, a8) \
{ \
static struct Command c = { \
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index a3651b2..70a1206 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -413,7 +413,8 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src)
return 0;
}
-static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name)
+static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
+ const char* dexopt_flags)
{
static const char* DEX_OPT_BIN = "/system/bin/dexopt";
static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
@@ -424,7 +425,7 @@ static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name)
sprintf(odex_num, "%d", odex_fd);
execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
- (char*) NULL);
+ dexopt_flags, (char*) NULL);
LOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
}
@@ -465,6 +466,7 @@ int dexopt(const char *apk_path, uid_t uid, int is_public)
struct utimbuf ut;
struct stat apk_stat, dex_stat;
char dex_path[PKG_PATH_MAX];
+ char dexopt_flags[PROPERTY_VALUE_MAX];
char *end;
int res, zip_fd=-1, odex_fd=-1;
@@ -475,6 +477,9 @@ int dexopt(const char *apk_path, uid_t uid, int is_public)
return -1;
}
+ /* platform-specific flags affecting optimization and verification */
+ property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
+
strcpy(dex_path, apk_path);
end = strrchr(dex_path, '.');
if (end != NULL) {
@@ -533,8 +538,8 @@ int dexopt(const char *apk_path, uid_t uid, int is_public)
exit(66);
}
- run_dexopt(zip_fd, odex_fd, apk_path); /* does not return */
- exit(67);
+ run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
+ exit(67); /* only get here on exec failure */
} else {
res = wait_dexopt(pid, apk_path);
if (res != 0) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4dc4b6a..849a37d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -53,6 +53,7 @@ import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewManager;
import android.view.Window;
import android.view.WindowManager;
import android.view.ContextMenu.ContextMenuInfo;
@@ -93,11 +94,11 @@ import java.util.HashMap;
* {@link android.R.styleable#AndroidManifestActivity &lt;activity&gt;}
* declaration in their package's <code>AndroidManifest.xml</code>.</p>
*
- * <p>The Activity class is an important part of an
- * <a href="{@docRoot}intro/lifecycle.html">application's overall lifecycle</a>,
+ * <p>The Activity class is an important part of an application's overall lifecycle,
* and the way activities are launched and put together is a fundamental
- * part of the platform's
- * <a href="{@docRoot}intro/appmodel.html">application model</a>.</p>
+ * part of the platform's application model. For a detailed perspective on the structure of
+ * Android applications and lifecycles, please read the <em>Dev Guide</em> document on
+ * <a href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a>.</p>
*
* <p>Topics covered here:
* <ol>
@@ -527,7 +528,7 @@ import java.util.HashMap;
* {@link android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
* element in their own manifest to be able to start that activity.
*
- * <p>See the <a href="{@docRoot}devel/security.html">Security Model</a>
+ * <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
* document for more information on permissions and security in general.
*
* <a name="ProcessLifecycle"></a>
@@ -629,6 +630,9 @@ public class Activity extends ContextThemeWrapper
private WindowManager mWindowManager;
/*package*/ View mDecor = null;
+ /*package*/ boolean mWindowAdded = false;
+ /*package*/ boolean mVisibleFromServer = false;
+ /*package*/ boolean mVisibleFromClient = true;
private CharSequence mTitle;
private int mTitleColor = 0;
@@ -779,6 +783,8 @@ public class Activity extends ContextThemeWrapper
* @see #onPostCreate
*/
protected void onCreate(Bundle savedInstanceState) {
+ mVisibleFromClient = mWindow.getWindowStyle().getBoolean(
+ com.android.internal.R.styleable.Window_windowNoDisplay, true);
mCalled = true;
}
@@ -884,9 +890,9 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Called after {@link #onCreate} or {@link #onStop} when the current
- * activity is now being displayed to the user. It will
- * be followed by {@link #onRestart}.
+ * Called after {@link #onCreate} &mdash; or after {@link #onRestart} when
+ * the activity had been stopped, but is now again being displayed to the
+ * user. It will be followed by {@link #onResume}.
*
* <p><em>Derived classes must call through to the super class's
* implementation of this method. If they do not, an exception will be
@@ -901,9 +907,9 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Called after {@link #onStart} when the current activity is being
+ * Called after {@link #onStop} when the current activity is being
* re-displayed to the user (the user has navigated back to it). It will
- * be followed by {@link #onResume}.
+ * be followed by {@link #onStart} and then {@link #onResume}.
*
* <p>For activities that are using raw {@link Cursor} objects (instead of
* creating them through
@@ -917,6 +923,7 @@ public class Activity extends ContextThemeWrapper
* thrown.</em></p>
*
* @see #onStop
+ * @see #onStart
* @see #onResume
*/
protected void onRestart() {
@@ -1134,12 +1141,19 @@ public class Activity extends ContextThemeWrapper
/**
* Called as part of the activity lifecycle when an activity is about to go
* into the background as the result of user choice. For example, when the
- * user presses the Home key, {@link #onUserLeaving} will be called, but
+ * user presses the Home key, {@link #onUserLeaveHint} will be called, but
* when an incoming phone call causes the in-call Activity to be automatically
- * brought to the foreground, {@link #onUserLeaving} will not be called on
- * the activity being interrupted.
+ * brought to the foreground, {@link #onUserLeaveHint} will not be called on
+ * the activity being interrupted. In cases when it is invoked, this method
+ * is called right before the activity's {@link #onPause} callback.
+ *
+ * <p>This callback and {@link #onUserInteraction} are intended to help
+ * activities manage status bar notifications intelligently; specifically,
+ * for helping activities determine the proper time to cancel a notfication.
+ *
+ * @see #onUserInteraction()
*/
- protected void onUserLeaving() {
+ protected void onUserLeaveHint() {
}
/**
@@ -1207,7 +1221,7 @@ public class Activity extends ContextThemeWrapper
/**
* Called when you are no longer visible to the user. You will next
- * receive either {@link #onStart}, {@link #onDestroy}, or nothing,
+ * receive either {@link #onRestart}, {@link #onDestroy}, or nothing,
* depending on later user activity.
*
* <p>Note that this method may never be called, in low memory situations
@@ -1443,7 +1457,6 @@ public class Activity extends ContextThemeWrapper
* @return The Cursor that was returned by query().
*
* @see ContentResolver#query(android.net.Uri , String[], String, String[], String)
- * @see #managedCommitUpdates
* @see #startManagingCursor
* @hide
*/
@@ -1475,7 +1488,6 @@ public class Activity extends ContextThemeWrapper
* @return The Cursor that was returned by query().
*
* @see ContentResolver#query(android.net.Uri , String[], String, String[], String)
- * @see #managedCommitUpdates
* @see #startManagingCursor
*/
public final Cursor managedQuery(Uri uri,
@@ -1863,6 +1875,28 @@ public class Activity extends ContextThemeWrapper
return false;
}
+ /**
+ * Called whenever a key, touch, or trackball event is dispatched to the
+ * activity. Implement this method if you wish to know that the user has
+ * interacted with the device in some way while your activity is running.
+ * This callback and {@link #onUserLeaveHint} are intended to help
+ * activities manage status bar notifications intelligently; specifically,
+ * for helping activities determine the proper time to cancel a notfication.
+ *
+ * <p>All calls to your activity's {@link #onUserLeaveHint} callback will
+ * be accompanied by calls to {@link #onUserInteraction}. This
+ * ensures that your activity will be told of relevant user activity such
+ * as pulling down the notification pane and touching an item there.
+ *
+ * <p>Note that this callback will be invoked for the touch down action
+ * that begins a touch gesture, but may not be invoked for the touch-moved
+ * and touch-up actions that follow.
+ *
+ * @see #onUserLeaveHint()
+ */
+ public void onUserInteraction() {
+ }
+
public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
// Update window manager if: we have a view, that view is
// attached to its parent (which will be a RootView), and
@@ -1935,6 +1969,7 @@ public class Activity extends ContextThemeWrapper
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchKeyEvent(KeyEvent event) {
+ onUserInteraction();
if (getWindow().superDispatchKeyEvent(event)) {
return true;
}
@@ -1952,6 +1987,9 @@ public class Activity extends ContextThemeWrapper
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ onUserInteraction();
+ }
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
@@ -1969,6 +2007,7 @@ public class Activity extends ContextThemeWrapper
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchTrackballEvent(MotionEvent ev) {
+ onUserInteraction();
if (getWindow().superDispatchTrackballEvent(ev)) {
return true;
}
@@ -2865,6 +2904,35 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * Control whether this activity's main window is visible. This is intended
+ * only for the special case of an activity that is not going to show a
+ * UI itself, but can't just finish prior to onResume() because it needs
+ * to wait for a service binding or such. Setting this to false allows
+ * you to prevent your UI from being shown during that time.
+ *
+ * <p>The default value for this is taken from the
+ * {@link android.R.attr#windowNoDisplay} attribute of the activity's theme.
+ */
+ public void setVisible(boolean visible) {
+ if (mVisibleFromClient != visible) {
+ mVisibleFromClient = visible;
+ if (mVisibleFromServer) {
+ if (visible) makeVisible();
+ else mDecor.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ void makeVisible() {
+ if (!mWindowAdded) {
+ ViewManager wm = getWindowManager();
+ wm.addView(mDecor, getWindow().getAttributes());
+ mWindowAdded = true;
+ }
+ mDecor.setVisibility(View.VISIBLE);
+ }
+
+ /**
* Check to see whether this activity is in the process of finishing,
* either because you called {@link #finish} on it or someone else
* has requested that it finished. This is often used in
@@ -3482,7 +3550,8 @@ public class Activity extends ContextThemeWrapper
}
final void performUserLeaving() {
- onUserLeaving();
+ onUserInteraction();
+ onUserLeaveHint();
}
final void performStop() {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f9b9221..07520c9d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -19,16 +19,14 @@ package android.app;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.graphics.Bitmap;
import android.os.RemoteException;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.Parcelable.Creator;
import android.text.TextUtils;
-import android.util.Log;
import java.util.List;
/**
@@ -617,7 +615,59 @@ public class ActivityManager {
public String pkgList[];
+ /**
+ * Constant for {@link #importance}: this process is running the
+ * foreground UI.
+ */
+ public static final int IMPORTANCE_FOREGROUND = 100;
+
+ /**
+ * Constant for {@link #importance}: this process is running something
+ * that is considered to be actively visible to the user.
+ */
+ public static final int IMPORTANCE_VISIBLE = 200;
+
+ /**
+ * Constant for {@link #importance}: this process is contains services
+ * that should remain running.
+ */
+ public static final int IMPORTANCE_SERVICE = 300;
+
+ /**
+ * Constant for {@link #importance}: this process process contains
+ * background code that is expendable.
+ */
+ public static final int IMPORTANCE_BACKGROUND = 400;
+
+ /**
+ * Constant for {@link #importance}: this process is empty of any
+ * actively running code.
+ */
+ public static final int IMPORTANCE_EMPTY = 500;
+
+ /**
+ * The relative importance level that the system places on this
+ * process. May be one of {@link #IMPORTANCE_FOREGROUND},
+ * {@link #IMPORTANCE_VISIBLE}, {@link #IMPORTANCE_SERVICE},
+ * {@link #IMPORTANCE_BACKGROUND}, or {@link #IMPORTANCE_EMPTY}. These
+ * constants are numbered so that "more important" values are always
+ * smaller than "less important" values.
+ */
+ public int importance;
+
+ /**
+ * An additional ordering within a particular {@link #importance}
+ * category, providing finer-grained information about the relative
+ * utility of processes within a category. This number means nothing
+ * except that a smaller values are more recently used (and thus
+ * more important). Currently an LRU value is only maintained for
+ * the {@link #IMPORTANCE_BACKGROUND} category, though others may
+ * be maintained in the future.
+ */
+ public int lru;
+
public RunningAppProcessInfo() {
+ importance = IMPORTANCE_FOREGROUND;
}
public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) {
@@ -634,12 +684,16 @@ public class ActivityManager {
dest.writeString(processName);
dest.writeInt(pid);
dest.writeStringArray(pkgList);
+ dest.writeInt(importance);
+ dest.writeInt(lru);
}
public void readFromParcel(Parcel source) {
processName = source.readString();
pid = source.readInt();
pkgList = source.readStringArray();
+ importance = source.readInt();
+ lru = source.readInt();
}
public static final Creator<RunningAppProcessInfo> CREATOR =
@@ -671,4 +725,37 @@ public class ActivityManager {
return null;
}
}
+
+ /**
+ * Have the system perform a force stop of everything associated with
+ * the given application package. All processes that share its uid
+ * will be killed, all services it has running stopped, all activities
+ * removed, etc. In addition, a {@link Intent#ACTION_PACKAGE_RESTARTED}
+ * broadcast will be sent, so that any of its registered alarms can
+ * be stopped, notifications removed, etc.
+ *
+ * <p>You must hold the permission
+ * {@link android.Manifest.permission#RESTART_PACKAGES} to be able to
+ * call this method.
+ *
+ * @param packageName The name of the package to be stopped.
+ */
+ public void restartPackage(String packageName) {
+ try {
+ ActivityManagerNative.getDefault().restartPackage(packageName);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Get the device configuration attributes.
+ */
+ public ConfigurationInfo getDeviceConfigurationInfo() {
+ try {
+ return ActivityManagerNative.getDefault().getDeviceConfigurationInfo();
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index ae9f3bf..53e6f34 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.res.Configuration;
import android.graphics.Bitmap;
@@ -83,6 +84,17 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
}
/**
+ * Convenience for checking whether the system is ready. For internal use only.
+ */
+ static public boolean isSystemReady() {
+ if (!sSystemReady) {
+ sSystemReady = getDefault().testIsSystemReady();
+ }
+ return sSystemReady;
+ }
+ static boolean sSystemReady = false;
+
+ /**
* Convenience for sending a sticky broadcast. For internal use only.
* If you don't care about permission, use null.
*/
@@ -959,6 +971,34 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case GET_DEVICE_CONFIGURATION_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ ConfigurationInfo config = getDeviceConfigurationInfo();
+ reply.writeNoException();
+ config.writeToParcel(reply, 0);
+ return true;
+ }
+
+ case PROFILE_CONTROL_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ String process = data.readString();
+ boolean start = data.readInt() != 0;
+ String path = data.readString();
+ boolean res = profileControl(process, start, path);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
+ case PEEK_SERVICE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ Intent service = Intent.CREATOR.createFromParcel(data);
+ String resolvedType = data.readString();
+ IBinder binder = peekService(service, resolvedType);
+ reply.writeNoException();
+ reply.writeStrongBinder(binder);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -1604,6 +1644,20 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
+
+ public IBinder peekService(Intent service, String resolvedType) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ service.writeToParcel(data, 0);
+ data.writeString(resolvedType);
+ mRemote.transact(PEEK_SERVICE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ IBinder binder = reply.readStrongBinder();
+ reply.recycle();
+ data.recycle();
+ return binder;
+ }
public boolean startInstrumentation(ComponentName className, String profileFile,
int flags, Bundle arguments, IInstrumentationWatcher watcher)
@@ -2028,6 +2082,11 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
reply.recycle();
}
+ public boolean testIsSystemReady()
+ {
+ /* this base class version is never called */
+ return true;
+ }
public int handleApplicationError(IBinder app, int flags,
String tag, String shortMsg, String longMsg,
byte[] crashData) throws RemoteException
@@ -2071,5 +2130,35 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
+ public ConfigurationInfo getDeviceConfigurationInfo() throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(GET_DEVICE_CONFIGURATION_TRANSACTION, data, reply, 0);
+ reply.readException();
+ ConfigurationInfo res = ConfigurationInfo.CREATOR.createFromParcel(reply);
+ reply.recycle();
+ data.recycle();
+ return res;
+ }
+
+ public boolean profileControl(String process, boolean start,
+ String path) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(process);
+ data.writeInt(start ? 1 : 0);
+ data.writeString(path);
+ mRemote.transact(PROFILE_CONTROL_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean res = reply.readInt() != 0;
+ reply.recycle();
+ data.recycle();
+ return res;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e4c1057..f49005e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -144,13 +144,19 @@ public final class ActivityThread {
return sPackageManager;
}
- DisplayMetrics getDisplayMetricsLocked() {
+ DisplayMetrics getDisplayMetricsLocked(boolean forceUpdate) {
+ if (mDisplayMetrics != null && !forceUpdate) {
+ return mDisplayMetrics;
+ }
if (mDisplay == null) {
WindowManager wm = WindowManagerImpl.getDefault();
mDisplay = wm.getDefaultDisplay();
}
- DisplayMetrics metrics = new DisplayMetrics();
+ DisplayMetrics metrics = mDisplayMetrics = new DisplayMetrics();
mDisplay.getMetrics(metrics);
+ //Log.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
+ // + metrics.heightPixels + " den=" + metrics.density
+ // + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
return metrics;
}
@@ -173,7 +179,7 @@ public final class ActivityThread {
if (assets.addAssetPath(appDir) == 0) {
return null;
}
- DisplayMetrics metrics = getDisplayMetricsLocked();
+ DisplayMetrics metrics = getDisplayMetricsLocked(false);
r = new Resources(assets, metrics, getConfiguration());
//Log.i(TAG, "Created app resources " + r + ": " + r.getConfiguration());
// XXX need to remove entries when weak references go away
@@ -235,7 +241,7 @@ public final class ActivityThread {
ApplicationContext.createSystemContext(mainThread);
mSystemContext.getResources().updateConfiguration(
mainThread.getConfiguration(),
- mainThread.getDisplayMetricsLocked());
+ mainThread.getDisplayMetricsLocked(false));
//Log.i(TAG, "Created system resources "
// + mSystemContext.getResources() + ": "
// + mSystemContext.getResources().getConfiguration());
@@ -1205,7 +1211,10 @@ public final class ActivityThread {
private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
private static final String ONE_COUNT_COLUMN = "%17s %8d";
private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
-
+
+ // Formatting for checkin service - update version if row format changes
+ private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
+
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) {
queueOrSendMessage(
@@ -1440,6 +1449,10 @@ public final class ActivityThread {
}
}
+ public void profilerControl(boolean start, String path) {
+ queueOrSendMessage(H.PROFILER_CONTROL, path, start ? 1 : 0);
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
long nativeMax = Debug.getNativeHeapSize() / 1024;
@@ -1462,7 +1475,101 @@ public final class ActivityThread {
long dalvikMax = runtime.totalMemory() / 1024;
long dalvikFree = runtime.freeMemory() / 1024;
long dalvikAllocated = dalvikMax - dalvikFree;
-
+ long viewInstanceCount = ViewDebug.getViewInstanceCount();
+ long viewRootInstanceCount = ViewDebug.getViewRootInstanceCount();
+ long appContextInstanceCount = ApplicationContext.getInstanceCount();
+ long activityInstanceCount = Activity.getInstanceCount();
+ int globalAssetCount = AssetManager.getGlobalAssetCount();
+ int globalAssetManagerCount = AssetManager.getGlobalAssetManagerCount();
+ int binderLocalObjectCount = Debug.getBinderLocalObjectCount();
+ int binderProxyObjectCount = Debug.getBinderProxyObjectCount();
+ int binderDeathObjectCount = Debug.getBinderDeathObjectCount();
+ int openSslSocketCount = OpenSSLSocketImpl.getInstanceCount();
+ long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024;
+ SQLiteDebug.PagerStats stats = new SQLiteDebug.PagerStats();
+ SQLiteDebug.getPagerStats(stats);
+
+ // Check to see if we were called by checkin server. If so, print terse format.
+ boolean doCheckinFormat = false;
+ if (args != null) {
+ for (String arg : args) {
+ if ("-c".equals(arg)) doCheckinFormat = true;
+ }
+ }
+
+ // For checkin, we print one long comma-separated list of values
+ if (doCheckinFormat) {
+ // NOTE: if you change anything significant below, also consider changing
+ // ACTIVITY_THREAD_CHECKIN_VERSION.
+ String processName = (mBoundApplication != null)
+ ? mBoundApplication.processName : "unknown";
+
+ // Header
+ pw.print(ACTIVITY_THREAD_CHECKIN_VERSION); pw.print(',');
+ pw.print(Process.myPid()); pw.print(',');
+ pw.print(processName); pw.print(',');
+
+ // Heap info - max
+ pw.print(nativeMax); pw.print(',');
+ pw.print(dalvikMax); pw.print(',');
+ pw.print("N/A,");
+ pw.print(nativeMax + dalvikMax); pw.print(',');
+
+ // Heap info - allocated
+ pw.print(nativeAllocated); pw.print(',');
+ pw.print(dalvikAllocated); pw.print(',');
+ pw.print("N/A,");
+ pw.print(nativeAllocated + dalvikAllocated); pw.print(',');
+
+ // Heap info - free
+ pw.print(nativeFree); pw.print(',');
+ pw.print(dalvikFree); pw.print(',');
+ pw.print("N/A,");
+ pw.print(nativeFree + dalvikFree); pw.print(',');
+
+ // Heap info - proportional set size
+ pw.print(memInfo.nativePss); pw.print(',');
+ pw.print(memInfo.dalvikPss); pw.print(',');
+ pw.print(memInfo.otherPss); pw.print(',');
+ pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
+
+ // Heap info - shared
+ pw.print(nativeShared); pw.print(',');
+ pw.print(dalvikShared); pw.print(',');
+ pw.print(otherShared); pw.print(',');
+ pw.print(nativeShared + dalvikShared + otherShared); pw.print(',');
+
+ // Heap info - private
+ pw.print(nativePrivate); pw.print(',');
+ pw.print(dalvikPrivate); pw.print(',');
+ pw.print(otherPrivate); pw.print(',');
+ pw.print(nativePrivate + dalvikPrivate + otherPrivate); pw.print(',');
+
+ // Object counts
+ pw.print(viewInstanceCount); pw.print(',');
+ pw.print(viewRootInstanceCount); pw.print(',');
+ pw.print(appContextInstanceCount); pw.print(',');
+ pw.print(activityInstanceCount); pw.print(',');
+
+ pw.print(globalAssetCount); pw.print(',');
+ pw.print(globalAssetManagerCount); pw.print(',');
+ pw.print(binderLocalObjectCount); pw.print(',');
+ pw.print(binderProxyObjectCount); pw.print(',');
+
+ pw.print(binderDeathObjectCount); pw.print(',');
+ pw.print(openSslSocketCount); pw.print(',');
+
+ // SQL
+ pw.print(sqliteAllocated); pw.print(',');
+ pw.print(stats.databaseBytes / 1024); pw.print(',');
+ pw.print(stats.numPagers); pw.print(',');
+ pw.print((stats.totalBytes - stats.referencedBytes) / 1024); pw.print(',');
+ pw.print(stats.referencedBytes / 1024); pw.print('\n');
+
+ return;
+ }
+
+ // otherwise, show human-readable format
printRow(pw, HEAP_COLUMN, "", "native", "dalvik", "other", "total");
printRow(pw, HEAP_COLUMN, "size:", nativeMax, dalvikMax, "N/A", nativeMax + dalvikMax);
printRow(pw, HEAP_COLUMN, "allocated:", nativeAllocated, dalvikAllocated, "N/A",
@@ -1480,26 +1587,22 @@ public final class ActivityThread {
pw.println(" ");
pw.println(" Objects");
- printRow(pw, TWO_COUNT_COLUMNS, "Views:", ViewDebug.getViewInstanceCount(), "ViewRoots:",
- ViewDebug.getViewRootInstanceCount());
+ printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewRoots:",
+ viewRootInstanceCount);
- printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", ApplicationContext.getInstanceCount(),
- "Activities:", Activity.getInstanceCount());
+ printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", appContextInstanceCount,
+ "Activities:", activityInstanceCount);
- printRow(pw, TWO_COUNT_COLUMNS, "Assets:", AssetManager.getGlobalAssetCount(),
- "AssetManagers:", AssetManager.getGlobalAssetManagerCount());
+ printRow(pw, TWO_COUNT_COLUMNS, "Assets:", globalAssetCount,
+ "AssetManagers:", globalAssetManagerCount);
- printRow(pw, TWO_COUNT_COLUMNS, "Local Binders:", Debug.getBinderLocalObjectCount(),
- "Proxy Binders:", Debug.getBinderProxyObjectCount());
- printRow(pw, ONE_COUNT_COLUMN, "Death Recipients:", Debug.getBinderDeathObjectCount());
-
- printRow(pw, ONE_COUNT_COLUMN, "OpenSSL Sockets:", OpenSSLSocketImpl.getInstanceCount());
+ printRow(pw, TWO_COUNT_COLUMNS, "Local Binders:", binderLocalObjectCount,
+ "Proxy Binders:", binderProxyObjectCount);
+ printRow(pw, ONE_COUNT_COLUMN, "Death Recipients:", binderDeathObjectCount);
+ printRow(pw, ONE_COUNT_COLUMN, "OpenSSL Sockets:", openSslSocketCount);
+
// SQLite mem info
- long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024;
- SQLiteDebug.PagerStats stats = new SQLiteDebug.PagerStats();
- SQLiteDebug.getPagerStats(stats);
-
pw.println(" ");
pw.println(" SQL");
printRow(pw, TWO_COUNT_COLUMNS, "heap:", sqliteAllocated, "dbFiles:",
@@ -1542,6 +1645,7 @@ public final class ActivityThread {
public static final int LOW_MEMORY = 124;
public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
public static final int RELAUNCH_ACTIVITY = 126;
+ public static final int PROFILER_CONTROL = 127;
String codeToString(int code) {
if (localLOGV) {
switch (code) {
@@ -1572,6 +1676,7 @@ public final class ActivityThread {
case LOW_MEMORY: return "LOW_MEMORY";
case ACTIVITY_CONFIGURATION_CHANGED: return "ACTIVITY_CONFIGURATION_CHANGED";
case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
+ case PROFILER_CONTROL: return "PROFILER_CONTROL";
}
}
return "(unknown)";
@@ -1671,6 +1776,9 @@ public final class ActivityThread {
case ACTIVITY_CONFIGURATION_CHANGED:
handleActivityConfigurationChanged((IBinder)msg.obj);
break;
+ case PROFILER_CONTROL:
+ handleProfilerControl(msg.arg1 != 0, (String)msg.obj);
+ break;
}
}
}
@@ -1751,6 +1859,7 @@ public final class ActivityThread {
final HashMap<String, WeakReference<PackageInfo>> mResourcePackages
= new HashMap<String, WeakReference<PackageInfo>>();
Display mDisplay = null;
+ DisplayMetrics mDisplayMetrics = null;
HashMap<String, WeakReference<Resources> > mActiveResources
= new HashMap<String, WeakReference<Resources> >();
@@ -1918,7 +2027,7 @@ public final class ActivityThread {
PackageInfo info = new PackageInfo(this, "android", context);
context.init(info, null, this);
context.getResources().updateConfiguration(
- getConfiguration(), getDisplayMetricsLocked());
+ getConfiguration(), getDisplayMetricsLocked(false));
mSystemContext = context;
//Log.i(TAG, "Created system resources " + context.getResources()
// + ": " + context.getResources().getConfiguration());
@@ -2557,7 +2666,10 @@ public final class ActivityThread {
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
- wm.addView(decor, l);
+ if (a.mVisibleFromClient) {
+ a.mWindowAdded = true;
+ wm.addView(decor, l);
+ }
// If the window has already been added, but during resume
// we started another activity, then don't yet make the
@@ -2576,7 +2688,8 @@ public final class ActivityThread {
performConfigurationChanged(r.activity, r.newConfig);
r.newConfig = null;
}
- Log.v(TAG, "Resuming " + r + " with isForward=" + isForward);
+ if (localLOGV) Log.v(TAG, "Resuming " + r + " with isForward="
+ + isForward);
WindowManager.LayoutParams l = r.window.getAttributes();
if ((l.softInputMode
& WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
@@ -2588,8 +2701,11 @@ public final class ActivityThread {
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);
}
- r.activity.mDecor.setVisibility(View.VISIBLE);
+ r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
+ if (r.activity.mVisibleFromClient) {
+ r.activity.makeVisible();
+ }
}
r.nextIdle = mNewActivities;
@@ -2800,18 +2916,22 @@ public final class ActivityThread {
View v = r.activity.mDecor;
if (v != null) {
if (show) {
- if (v.getVisibility() != View.VISIBLE) {
- v.setVisibility(View.VISIBLE);
+ if (!r.activity.mVisibleFromServer) {
+ r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
+ if (r.activity.mVisibleFromClient) {
+ r.activity.makeVisible();
+ }
}
if (r.newConfig != null) {
performConfigurationChanged(r.activity, r.newConfig);
r.newConfig = null;
}
} else {
- if (v.getVisibility() == View.VISIBLE) {
- v.setVisibility(View.INVISIBLE);
+ if (r.activity.mVisibleFromServer) {
+ r.activity.mVisibleFromServer = false;
mNumVisibleActivities--;
+ v.setVisibility(View.INVISIBLE);
}
}
}
@@ -3037,11 +3157,13 @@ public final class ActivityThread {
WindowManager wm = r.activity.getWindowManager();
View v = r.activity.mDecor;
if (v != null) {
- if (v.getVisibility() == View.VISIBLE) {
+ if (r.activity.mVisibleFromServer) {
mNumVisibleActivities--;
}
IBinder wtoken = v.getWindowToken();
- wm.removeViewImmediate(v);
+ if (r.activity.mWindowAdded) {
+ wm.removeViewImmediate(v);
+ }
if (wtoken != null) {
WindowManagerImpl.getDefault().closeAll(wtoken,
r.activity.getClass().getName(), "Activity");
@@ -3271,6 +3393,7 @@ public final class ActivityThread {
mConfiguration = new Configuration();
}
mConfiguration.updateFrom(config);
+ DisplayMetrics dm = getDisplayMetricsLocked(true);
// set it for java, this also affects newly created Resources
if (config.locale != null) {
@@ -3290,7 +3413,7 @@ public final class ActivityThread {
WeakReference<Resources> v = it.next();
Resources r = v.get();
if (r != null) {
- r.updateConfiguration(config, null);
+ r.updateConfiguration(config, dm);
//Log.i(TAG, "Updated app resources " + v.getKey()
// + " " + r + ": " + r.getConfiguration());
} else {
@@ -3318,6 +3441,21 @@ public final class ActivityThread {
performConfigurationChanged(r.activity, mConfiguration);
}
+ final void handleProfilerControl(boolean start, String path) {
+ if (start) {
+ File file = new File(path);
+ file.getParentFile().mkdirs();
+ try {
+ Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Profiling failed on path " + path
+ + " -- can the process access this path?");
+ }
+ } else {
+ Debug.stopMethodTracing();
+ }
+ }
+
final void handleLowMemory() {
ArrayList<ComponentCallbacks> callbacks
= new ArrayList<ComponentCallbacks>();
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 4236a00..3b5ad86 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -1487,7 +1487,7 @@ class ApplicationContext extends Context {
static final class ApplicationPackageManager extends PackageManager {
@Override
public PackageInfo getPackageInfo(String packageName, int flags)
- throws NameNotFoundException {
+ throws NameNotFoundException {
try {
PackageInfo pi = mPM.getPackageInfo(packageName, flags);
if (pi != null) {
@@ -1500,6 +1500,43 @@ class ApplicationContext extends Context {
throw new NameNotFoundException(packageName);
}
+ public Intent getLaunchIntentForPackage(String packageName)
+ throws NameNotFoundException {
+ // First see if the package has an INFO activity; the existence of
+ // such an activity is implied to be the desired front-door for the
+ // overall package (such as if it has multiple launcher entries).
+ Intent intent = getLaunchIntentForPackageCategory(this, packageName,
+ Intent.CATEGORY_INFO);
+ if (intent != null) {
+ return intent;
+ }
+
+ // Otherwise, try to find a main launcher activity.
+ return getLaunchIntentForPackageCategory(this, packageName,
+ Intent.CATEGORY_LAUNCHER);
+ }
+
+ // XXX This should be implemented as a call to the package manager,
+ // to reduce the work needed.
+ static Intent getLaunchIntentForPackageCategory(PackageManager pm,
+ String packageName, String category) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Intent intentToResolve = new Intent(Intent.ACTION_MAIN, null);
+ intentToResolve.addCategory(category);
+ final List<ResolveInfo> apps =
+ pm.queryIntentActivities(intentToResolve, 0);
+ // I wish there were a way to directly get the "main" activity of a
+ // package but ...
+ for (ResolveInfo app : apps) {
+ if (app.activityInfo.packageName.equals(packageName)) {
+ intent.setClassName(packageName, app.activityInfo.name);
+ return intent;
+ }
+ }
+ return null;
+ }
+
@Override
public int[] getPackageGids(String packageName)
throws NameNotFoundException {
@@ -1630,6 +1667,15 @@ class ApplicationContext extends Context {
}
@Override
+ public String[] getSystemSharedLibraryNames() {
+ try {
+ return mPM.getSystemSharedLibraryNames();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
+ @Override
public int checkPermission(String permName, String pkgName) {
try {
return mPM.checkPermission(permName, pkgName);
@@ -1974,6 +2020,18 @@ class ApplicationContext extends Context {
getApplicationInfo(appPackageName, 0));
}
+ int mCachedSafeMode = -1;
+ @Override public boolean isSafeMode() {
+ try {
+ if (mCachedSafeMode < 0) {
+ mCachedSafeMode = mPM.isSafeMode() ? 1 : 0;
+ }
+ return mCachedSafeMode != 0;
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+
static void configurationChanged() {
synchronized (sSync) {
sIconCache.clear();
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index d2cf55a..bcc9302 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -322,6 +322,15 @@ public abstract class ApplicationThreadNative extends Binder
requestPss();
return true;
}
+
+ case PROFILER_CONTROL_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ boolean start = data.readInt() != 0;
+ String path = data.readString();
+ profilerControl(start, path);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -654,5 +663,14 @@ class ApplicationThreadProxy implements IApplicationThread {
data.recycle();
}
+ public void profilerControl(boolean start, String path) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeInt(start ? 1 : 0);
+ data.writeString(path);
+ mRemote.transact(PROFILER_CONTROL_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 951b48d..b09a57f 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -122,7 +122,7 @@ public class Dialog implements DialogInterface, Window.Callback,
* uses the window manager and theme from this context to
* present its UI.
* @param theme A style resource describing the theme to use for the
- * window. See <a href="{@docRoot}reference/available-resources.html#stylesandthemes">Style
+ * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style
* and Theme Resources</a> for more information about defining and using
* styles. This theme is applied on top of the current theme in
* <var>context</var>. If 0, the default dialog theme will be used.
@@ -518,7 +518,7 @@ public class Dialog implements DialogInterface, Window.Callback,
private boolean isOutOfBounds(MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
- final int slop = ViewConfiguration.getWindowTouchSlop();
+ final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop();
final View decorView = getWindow().getDecorView();
return (x < -slop) || (y < -slop)
|| (x > (decorView.getWidth()+slop))
diff --git a/core/java/android/app/ExpandableListActivity.java b/core/java/android/app/ExpandableListActivity.java
index 75dfcae..a2e048f 100644
--- a/core/java/android/app/ExpandableListActivity.java
+++ b/core/java/android/app/ExpandableListActivity.java
@@ -63,21 +63,21 @@ import java.util.Map;
*
* <pre>
* &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
- * &lt;LinearLayout
+ * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:orientation=&quot;vertical&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
- * android:paddingLeft=&quot;8&quot;
- * android:paddingRight=&quot;8&quot;&gt;
+ * android:paddingLeft=&quot;8dp&quot;
+ * android:paddingRight=&quot;8dp&quot;&gt;
*
- * &lt;ExpandableListView id=&quot;android:list&quot;
+ * &lt;ExpandableListView android:id=&quot;@id/android:list&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
* android:background=&quot;#00FF00&quot;
* android:layout_weight=&quot;1&quot;
* android:drawSelectorOnTop=&quot;false&quot;/&gt;
*
- * &lt;TextView id=&quot;android:empty&quot;
+ * &lt;TextView android:id=&quot;@id/android:empty&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
* android:background=&quot;#FF0000&quot;
@@ -113,19 +113,19 @@ import java.util.Map;
*
* <pre>
* &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
- * &lt;LinearLayout
+ * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;
* android:orientation=&quot;vertical&quot;&gt;
*
- * &lt;TextView id=&quot;text1&quot;
- * android:textSize=&quot;16&quot;
+ * &lt;TextView android:id=&quot;@+id/text1&quot;
+ * android:textSize=&quot;16sp&quot;
* android:textStyle=&quot;bold&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;/&gt;
*
- * &lt;TextView id=&quot;text2&quot;
- * android:textSize=&quot;16&quot;
+ * &lt;TextView android:id=&quot;@+id/text2&quot;
+ * android:textSize=&quot;16sp&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;/&gt;
* &lt;/LinearLayout&gt;
@@ -162,7 +162,8 @@ public class ExpandableListActivity extends Activity implements
/**
* Override this to populate the context menu when an item is long pressed. menuInfo
- * will contain a {@link AdapterContextMenuInfo} whose position is a packed position
+ * will contain an {@link android.widget.ExpandableListView.ExpandableListContextMenuInfo}
+ * whose packedPosition is a packed position
* that should be used with {@link ExpandableListView#getPackedPositionType(long)} and
* the other similar methods.
* <p>
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 353500e..2ac6160 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -22,6 +22,7 @@ import android.content.ContentProviderNative;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.ProviderInfo;
import android.content.res.Configuration;
@@ -127,7 +128,8 @@ public interface IActivityManager extends IInterface {
boolean doRebind) throws RemoteException;
/* oneway */
public void serviceDoneExecuting(IBinder token) throws RemoteException;
-
+ public IBinder peekService(Intent service, String resolvedType) throws RemoteException;
+
public boolean startInstrumentation(ComponentName className, String profileFile,
int flags, Bundle arguments, IInstrumentationWatcher watcher)
throws RemoteException;
@@ -216,6 +218,17 @@ public interface IActivityManager extends IInterface {
// Retrieve running application processes in the system
public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses()
throws RemoteException;
+ // Get device configuration
+ public ConfigurationInfo getDeviceConfigurationInfo() throws RemoteException;
+
+ // Turn on/off profiling in a particular process.
+ public boolean profileControl(String process, boolean start,
+ String path) throws RemoteException;
+
+ /*
+ * Private non-Binder interfaces
+ */
+ /* package */ boolean testIsSystemReady();
/** Information you can retrieve about a particular application. */
public static class ContentProviderHolder implements Parcelable {
@@ -354,4 +367,7 @@ public interface IActivityManager extends IInterface {
int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80;
int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81;
int GET_RUNNING_APP_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+82;
+ int GET_DEVICE_CONFIGURATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+83;
+ int PEEK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+84;
+ int PROFILE_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+85;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 47476b5..9f3534b 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -86,6 +86,7 @@ public interface IApplicationThread extends IInterface {
void scheduleLowMemory() throws RemoteException;
void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
void requestPss() throws RemoteException;
+ void profilerControl(boolean start, String path) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -115,4 +116,5 @@ public interface IApplicationThread extends IInterface {
int SCHEDULE_ACTIVITY_CONFIGURATION_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+24;
int SCHEDULE_RELAUNCH_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+25;
int REQUEST_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+26;
+ int PROFILER_CONTROL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+27;
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index f96d787..f6a28b2 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1267,7 +1267,7 @@ public class Instrumentation {
}
/**
- * Perform calling of an activity's {@link Activity#onUserLeaving} method.
+ * Perform calling of an activity's {@link Activity#onUserLeaveHint} method.
* The default implementation simply calls through to that method.
*
* @param activity The activity being notified that the user has navigated away
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
new file mode 100644
index 0000000..2b12a2a
--- /dev/null
+++ b/core/java/android/app/IntentService.java
@@ -0,0 +1,74 @@
+package android.app;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * An abstract {@link Service} that serializes the handling of the Intents passed upon service
+ * start and handles them on a handler thread.
+ *
+ * <p>To use this class extend it and implement {@link #onHandleIntent}. The {@link Service} will
+ * automatically be stopped when the last enqueued {@link Intent} is handled.
+ */
+public abstract class IntentService extends Service {
+ private volatile Looper mServiceLooper;
+ private volatile ServiceHandler mServiceHandler;
+ private String mName;
+
+ private final class ServiceHandler extends Handler {
+ public ServiceHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ onHandleIntent((Intent)msg.obj);
+ stopSelf(msg.arg1);
+ }
+ }
+
+ public IntentService(String name) {
+ super();
+ mName = name;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
+ thread.start();
+
+ mServiceLooper = thread.getLooper();
+ mServiceHandler = new ServiceHandler(mServiceLooper);
+ }
+
+ @Override
+ public void onStart(Intent intent, int startId) {
+ super.onStart(intent, startId);
+ Message msg = mServiceHandler.obtainMessage();
+ msg.arg1 = startId;
+ msg.obj = intent;
+ mServiceHandler.sendMessage(msg);
+ }
+
+ @Override
+ public void onDestroy() {
+ mServiceLooper.quit();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ /**
+ * Invoked on the Handler thread with the {@link Intent} that is passed to {@link #onStart}.
+ * Note that this will be invoked from a different thread than the one that handles the
+ * {@link #onStart} call.
+ */
+ protected abstract void onHandleIntent(Intent intent);
+}
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 8f0a4f5..d6fcbb1 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -18,14 +18,23 @@ package android.app;
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.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.PaintDrawable;
import android.os.Bundle;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.Window;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
@@ -43,33 +52,59 @@ import java.util.List;
*
*/
public abstract class LauncherActivity extends ListActivity {
+
+ Intent mIntent;
+ PackageManager mPackageManager;
/**
+ * An item in the list
+ */
+ public static class ListItem {
+ public CharSequence label;
+ //public CharSequence description;
+ public Drawable icon;
+ public String packageName;
+ public String className;
+
+ ListItem(PackageManager pm, ResolveInfo resolveInfo, IconResizer resizer) {
+ label = resolveInfo.loadLabel(pm);
+ if (label == null && resolveInfo.activityInfo != null) {
+ label = resolveInfo.activityInfo.name;
+ }
+
+ /*
+ if (resolveInfo.activityInfo != null &&
+ resolveInfo.activityInfo.applicationInfo != null) {
+ description = resolveInfo.activityInfo.applicationInfo.loadDescription(pm);
+ }
+ */
+
+ icon = resizer.createIconThumbnail(resolveInfo.loadIcon(pm));
+ packageName = resolveInfo.activityInfo.applicationInfo.packageName;
+ className = resolveInfo.activityInfo.name;
+ }
+
+ public ListItem() {
+ }
+ }
+
+ /**
* Adapter which shows the set of activities that can be performed for a given intent.
*/
private class ActivityAdapter extends BaseAdapter implements Filterable {
private final Object lock = new Object();
- private ArrayList<ResolveInfo> mOriginalValues;
+ private ArrayList<ListItem> mOriginalValues;
- protected final Context mContext;
- protected final Intent mIntent;
protected final LayoutInflater mInflater;
- protected List<ResolveInfo> mActivitiesList;
+ protected List<ListItem> mActivitiesList;
private Filter mFilter;
-
- public ActivityAdapter(Context context, Intent intent) {
- mContext = context;
- mIntent = new Intent(intent);
- mIntent.setComponent(null);
- mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- PackageManager pm = context.getPackageManager();
- mActivitiesList = pm.queryIntentActivities(intent, 0);
- if (mActivitiesList != null) {
- Collections.sort(mActivitiesList, new ResolveInfo.DisplayNameComparator(pm));
- }
+
+ public ActivityAdapter() {
+ mInflater = (LayoutInflater) LauncherActivity.this.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ mActivitiesList = makeListItems();
}
public Intent intentForPosition(int position) {
@@ -78,8 +113,8 @@ public abstract class LauncherActivity extends ListActivity {
}
Intent intent = new Intent(mIntent);
- ActivityInfo ai = mActivitiesList.get(position).activityInfo;
- intent.setClassName(ai.applicationInfo.packageName, ai.name);
+ ListItem item = mActivitiesList.get(position);
+ intent.setClassName(item.packageName, item.className);
return intent;
}
@@ -99,7 +134,7 @@ public abstract class LauncherActivity extends ListActivity {
View view;
if (convertView == null) {
view = mInflater.inflate(
- com.android.internal.R.layout.simple_list_item_1, parent, false);
+ com.android.internal.R.layout.activity_list_item_2, parent, false);
} else {
view = convertView;
}
@@ -107,35 +142,22 @@ public abstract class LauncherActivity extends ListActivity {
return view;
}
- private char getCandidateLetter(ResolveInfo info) {
- PackageManager pm = mContext.getPackageManager();
- CharSequence label = info.loadLabel(pm);
-
- if (label == null) {
- label = info.activityInfo.name;
- }
-
- return Character.toLowerCase(label.charAt(0));
+ private void bindView(View view, ListItem item) {
+ TextView text = (TextView) view;
+ text.setText(item.label);
+ text.setCompoundDrawablesWithIntrinsicBounds(item.icon, null, null, null);
}
-
- private void bindView(View view, ResolveInfo info) {
- TextView text = (TextView) view.findViewById(com.android.internal.R.id.text1);
-
- PackageManager pm = mContext.getPackageManager();
- CharSequence label = info.loadLabel(pm);
- text.setText(label != null ? label : info.activityInfo.name);
- }
-
+
public Filter getFilter() {
if (mFilter == null) {
mFilter = new ArrayFilter();
}
return mFilter;
}
-
+
/**
- * <p>An array filters constrains the content of the array adapter with a prefix. Each item that
- * does not start with the supplied prefix is removed from the list.</p>
+ * An array filters constrains the content of the array adapter with a prefix. Each
+ * item that does not start with the supplied prefix is removed from the list.
*/
private class ArrayFilter extends Filter {
@Override
@@ -144,39 +166,35 @@ public abstract class LauncherActivity extends ListActivity {
if (mOriginalValues == null) {
synchronized (lock) {
- mOriginalValues = new ArrayList<ResolveInfo>(mActivitiesList);
+ mOriginalValues = new ArrayList<ListItem>(mActivitiesList);
}
}
if (prefix == null || prefix.length() == 0) {
synchronized (lock) {
- ArrayList<ResolveInfo> list = new ArrayList<ResolveInfo>(mOriginalValues);
+ ArrayList<ListItem> list = new ArrayList<ListItem>(mOriginalValues);
results.values = list;
results.count = list.size();
}
} else {
- final PackageManager pm = mContext.getPackageManager();
final String prefixString = prefix.toString().toLowerCase();
- ArrayList<ResolveInfo> values = mOriginalValues;
+ ArrayList<ListItem> values = mOriginalValues;
int count = values.size();
- ArrayList<ResolveInfo> newValues = new ArrayList<ResolveInfo>(count);
+ ArrayList<ListItem> newValues = new ArrayList<ListItem>(count);
for (int i = 0; i < count; i++) {
- ResolveInfo value = values.get(i);
+ ListItem item = values.get(i);
- final CharSequence label = value.loadLabel(pm);
- final CharSequence name = label != null ? label : value.activityInfo.name;
-
- String[] words = name.toString().toLowerCase().split(" ");
+ String[] words = item.label.toString().toLowerCase().split(" ");
int wordCount = words.length;
for (int k = 0; k < wordCount; k++) {
final String word = words[k];
if (word.startsWith(prefixString)) {
- newValues.add(value);
+ newValues.add(item);
break;
}
}
@@ -192,7 +210,7 @@ public abstract class LauncherActivity extends ListActivity {
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
//noinspection unchecked
- mActivitiesList = (List<ResolveInfo>) results.values;
+ mActivitiesList = (List<ListItem>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
@@ -201,19 +219,119 @@ public abstract class LauncherActivity extends ListActivity {
}
}
}
-
-
+
+ /**
+ * Utility class to resize icons to match default icon size.
+ */
+ public class IconResizer {
+ // Code is borrowed from com.android.launcher.Utilities.
+ private int mIconWidth = -1;
+ private int mIconHeight = -1;
+
+ private final Rect mOldBounds = new Rect();
+ private Canvas mCanvas = new Canvas();
+
+ public IconResizer() {
+ mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
+ Paint.FILTER_BITMAP_FLAG));
+
+ final Resources resources = LauncherActivity.this.getResources();
+ mIconWidth = mIconHeight = (int) resources.getDimension(
+ android.R.dimen.app_icon_size);
+ }
+
+ /**
+ * Returns a Drawable representing the thumbnail of the specified Drawable.
+ * The size of the thumbnail is defined by the dimension
+ * android.R.dimen.launcher_application_icon_size.
+ *
+ * This method is not thread-safe and should be invoked on the UI thread only.
+ *
+ * @param icon The icon to get a thumbnail of.
+ *
+ * @return A thumbnail for the specified icon or the icon itself if the
+ * thumbnail could not be created.
+ */
+ public Drawable createIconThumbnail(Drawable icon) {
+ int width = mIconWidth;
+ int height = mIconHeight;
+
+ final int iconWidth = icon.getIntrinsicWidth();
+ final int iconHeight = icon.getIntrinsicHeight();
+
+ if (icon instanceof PaintDrawable) {
+ PaintDrawable painter = (PaintDrawable) icon;
+ painter.setIntrinsicWidth(width);
+ painter.setIntrinsicHeight(height);
+ }
+
+ if (width > 0 && height > 0) {
+ if (width < iconWidth || height < iconHeight) {
+ final float ratio = (float) iconWidth / iconHeight;
+
+ if (iconWidth > iconHeight) {
+ height = (int) (width / ratio);
+ } else if (iconHeight > iconWidth) {
+ width = (int) (height * ratio);
+ }
+
+ final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ?
+ Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
+ final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
+ final Canvas canvas = mCanvas;
+ canvas.setBitmap(thumb);
+ // Copy the old bounds to restore them later
+ // If we were to do oldBounds = icon.getBounds(),
+ // the call to setBounds() that follows would
+ // change the same instance and we would lose the
+ // old bounds
+ mOldBounds.set(icon.getBounds());
+ final int x = (mIconWidth - width) / 2;
+ final int y = (mIconHeight - height) / 2;
+ icon.setBounds(x, y, x + width, y + height);
+ icon.draw(canvas);
+ icon.setBounds(mOldBounds);
+ icon = new BitmapDrawable(thumb);
+ } else if (iconWidth < width && iconHeight < height) {
+ final Bitmap.Config c = Bitmap.Config.ARGB_8888;
+ final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
+ final Canvas canvas = mCanvas;
+ canvas.setBitmap(thumb);
+ mOldBounds.set(icon.getBounds());
+ final int x = (width - iconWidth) / 2;
+ final int y = (height - iconHeight) / 2;
+ icon.setBounds(x, y, x + iconWidth, y + iconHeight);
+ icon.draw(canvas);
+ icon.setBounds(mOldBounds);
+ icon = new BitmapDrawable(thumb);
+ }
+ }
+
+ return icon;
+ }
+ }
+
@Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mPackageManager = getPackageManager();
+
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ setProgressBarIndeterminateVisibility(true);
+ setContentView(com.android.internal.R.layout.activity_list);
- mAdapter = new ActivityAdapter(this, getTargetIntent());
+
+ mIntent = new Intent(getTargetIntent());
+ mIntent.setComponent(null);
+ mAdapter = new ActivityAdapter();
setListAdapter(mAdapter);
getListView().setTextFilterEnabled(true);
+
+ setProgressBarIndeterminateVisibility(false);
}
-
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = ((ActivityAdapter)mAdapter).intentForPosition(position);
@@ -221,6 +339,42 @@ public abstract class LauncherActivity extends ListActivity {
startActivity(intent);
}
- protected abstract Intent getTargetIntent();
-
+ /**
+ * Return the actual Intent for a specific position in our
+ * {@link android.widget.ListView}.
+ * @param position The item whose Intent to return
+ */
+ protected Intent intentForPosition(int position) {
+ ActivityAdapter adapter = (ActivityAdapter) mAdapter;
+ return adapter.intentForPosition(position);
+ }
+
+ /**
+ * Get the base intent to use when running
+ * {@link PackageManager#queryIntentActivities(Intent, int)}.
+ */
+ protected Intent getTargetIntent() {
+ return new Intent();
+ }
+
+ /**
+ * Perform the query to determine which results to show and return a list of them.
+ */
+ public List<ListItem> makeListItems() {
+ // Load all matching activities and sort correctly
+ List<ResolveInfo> list = mPackageManager.queryIntentActivities(mIntent,
+ /* no flags */ 0);
+ Collections.sort(list, new ResolveInfo.DisplayNameComparator(mPackageManager));
+
+ IconResizer resizer = new IconResizer();
+
+ ArrayList<ListItem> result = new ArrayList<ListItem>(list.size());
+ int listSize = list.size();
+ for (int i = 0; i < listSize; i++) {
+ ResolveInfo resolveInfo = list.get(i);
+ result.add(new ListItem(mPackageManager, resolveInfo, resizer));
+ }
+
+ return result;
+ }
}
diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java
index 2818937..5523c18 100644
--- a/core/java/android/app/ListActivity.java
+++ b/core/java/android/app/ListActivity.java
@@ -53,22 +53,22 @@ import android.widget.ListView;
* </p>
*
* <pre>
- * &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
- * &lt;LinearLayout
+ * &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+ * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:orientation=&quot;vertical&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
- * android:paddingLeft=&quot;8&quot;
- * android:paddingRight=&quot;8&quot;&gt;
+ * android:paddingLeft=&quot;8dp&quot;
+ * android:paddingRight=&quot;8dp&quot;&gt;
*
- * &lt;ListView id=&quot;android:list&quot;
+ * &lt;ListView android:id=&quot;@id/android:list&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
* android:background=&quot;#00FF00&quot;
* android:layout_weight=&quot;1&quot;
* android:drawSelectorOnTop=&quot;false&quot;/&gt;
*
- * &lt;TextView id=&quot;android:empty&quot;
+ * &lt;TextView id=&quot;@id/android:empty&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;fill_parent&quot;
* android:background=&quot;#FF0000&quot;
@@ -99,19 +99,19 @@ import android.widget.ListView;
*
* <pre>
* &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
- * &lt;LinearLayout
+ * &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;
* android:orientation=&quot;vertical&quot;&gt;
*
- * &lt;TextView id=&quot;text1&quot;
- * android:textSize=&quot;16&quot;
+ * &lt;TextView android:id=&quot;@+id/text1&quot;
+ * android:textSize=&quot;16sp&quot;
* android:textStyle=&quot;bold&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;/&gt;
*
- * &lt;TextView id=&quot;text2&quot;
- * android:textSize=&quot;16&quot;
+ * &lt;TextView android:id=&quot;@+id/text2&quot;
+ * android:textSize=&quot;16sp&quot;
* android:layout_width=&quot;fill_parent&quot;
* android:layout_height=&quot;wrap_content&quot;/&gt;
* &lt;/LinearLayout&gt;
@@ -142,8 +142,8 @@ import android.widget.ListView;
* public class MyListAdapter extends ListActivity {
*
* &#064;Override
- * protected void onCreate(Bundle icicle){
- * super.onCreate(icicle);
+ * protected void onCreate(Bundle savedInstanceState){
+ * super.onCreate(savedInstanceState);
*
* // We'll define a custom screen layout here (the one shown above), but
* // typically, you could just use the standard ListActivity layout.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ea67cdb..51fddb1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -90,8 +90,9 @@ public class Notification implements Parcelable
* The intent to execute when the expanded status entry is clicked. If
* this is an activity, it must include the
* {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
- * that you take care of task management as described in the
- * <a href="{@docRoot}intro/appmodel.html">application model</a> document.
+ * that you take care of task management as described in the <em>Activities and Tasks</em>
+ * section of the <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application
+ * Fundamentals</a> document.
*/
public PendingIntent contentIntent;
@@ -420,8 +421,8 @@ public class Notification implements Parcelable
* @param contentIntent The intent to launch when the user clicks the expanded notification.
* If this is an activity, it must include the
* {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
- * that you take care of task management as described in the
- * <a href="{@docRoot}intro/appmodel.html">application model</a> document.
+ * that you take care of task management as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application Fundamentals: Activities and Tasks</a>.
*/
public void setLatestEventInfo(Context context,
CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index afb3827..39edab7 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -82,9 +82,7 @@ public class NotificationManager
* @param id An identifier for this notification unique within your
* application.
* @param notification A {@link Notification} object describing how to
- * notify the user, other than the view you're providing. If you
- * pass null, there will be no persistent notification and no
- * flashing, vibration, etc.
+ * notify the user, other than the view you're providing. Must not be null.
*/
public void notify(int id, Notification notification)
{
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index b59e9dc..1bed706 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -426,13 +426,9 @@ public final class PendingIntent implements Parcelable {
*/
@Override
public boolean equals(Object otherObj) {
- if (otherObj == null) {
- return false;
- }
- try {
+ if (otherObj instanceof PendingIntent) {
return mTarget.asBinder().equals(((PendingIntent)otherObj)
.mTarget.asBinder());
- } catch (ClassCastException e) {
}
return false;
}
@@ -442,6 +438,13 @@ public final class PendingIntent implements Parcelable {
return mTarget.asBinder().hashCode();
}
+ @Override
+ public String toString() {
+ return "PendingIntent{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " target " + (mTarget != null ? mTarget.asBinder() : null) + "}";
+ }
+
public int describeContents() {
return 0;
}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 2e2a1a1..64288d2 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -16,11 +16,14 @@
package android.app;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
@@ -29,11 +32,11 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
-import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.server.search.SearchableInfo;
+import android.speech.RecognizerIntent;
import android.text.Editable;
import android.text.InputType;
import android.text.TextUtils;
@@ -50,6 +53,7 @@ import android.widget.AdapterView;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CursorAdapter;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
@@ -94,6 +98,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
private TextView mBadgeLabel;
private AutoCompleteTextView mSearchTextField;
private Button mGoButton;
+ private ImageButton mVoiceButton;
// interaction with searchable application
private ComponentName mLaunchComponent;
@@ -115,10 +120,13 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
private Uri mSuggestionData = null;
private String mSuggestionQuery = null;
+ // For voice searching
+ private Intent mVoiceWebSearchIntent;
+ private Intent mVoiceAppSearchIntent;
+
// support for AutoCompleteTextView suggestions display
private SuggestionsAdapter mSuggestionsAdapter;
-
/**
* Constructor - fires it up and makes it look like the search UI.
*
@@ -153,12 +161,15 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
mSearchTextField = (AutoCompleteTextView)
findViewById(com.android.internal.R.id.search_src_text);
mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn);
+ mVoiceButton = (ImageButton) findViewById(com.android.internal.R.id.search_voice_btn);
// attach listeners
mSearchTextField.addTextChangedListener(mTextWatcher);
mSearchTextField.setOnKeyListener(mTextKeyListener);
mGoButton.setOnClickListener(mGoButtonClickListener);
mGoButton.setOnKeyListener(mButtonsKeyListener);
+ mVoiceButton.setOnClickListener(mVoiceButtonClickListener);
+ mVoiceButton.setOnKeyListener(mButtonsKeyListener);
// pre-hide all the extraneous elements
mBadgeLabel.setVisibility(View.GONE);
@@ -169,13 +180,19 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
setCanceledOnTouchOutside(true);
// Set up broadcast filters
- mCloseDialogsFilter = new
- IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ mCloseDialogsFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mPackageFilter = new IntentFilter();
mPackageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
mPackageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
mPackageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
mPackageFilter.addDataScheme("package");
+
+ // Save voice intent for later queries/launching
+ mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
+ mVoiceWebSearchIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
+ RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
+
+ mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
}
/**
@@ -236,7 +253,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
mSearchTextField.setAdapter(mSuggestionsAdapter);
mSearchTextField.setText(initialQuery);
} else {
- mSuggestionsAdapter = new SuggestionsAdapter(getContext(), mSearchable);
+ mSuggestionsAdapter = new SuggestionsAdapter(getContext(), mSearchable,
+ mSearchTextField);
mSearchTextField.setAdapter(mSuggestionsAdapter);
// finally, load the user's initial text (which may trigger suggestions)
@@ -261,16 +279,15 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
/**
- * Dismiss the search dialog.
+ * The search dialog is being dismissed, so handle all of the local shutdown operations.
*
- * This function is designed to be idempotent so it can be safely called at any time
+ * This function is designed to be idempotent so that dismiss() can be safely called at any time
* (even if already closed) and more likely to really dump any memory. No leaks!
*/
@Override
- public void dismiss() {
- if (isShowing()) {
- super.dismiss();
- }
+ public void onStop() {
+ super.onStop();
+
setOnCancelListener(null);
setOnDismissListener(null);
@@ -281,6 +298,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// This is OK - it just means we didn't have any registered
}
+ // close any leftover cursor
+ if (mSuggestionsAdapter != null) {
+ mSuggestionsAdapter.changeCursor(null);
+ }
+
// dump extra memory we're hanging on to
mLaunchComponent = null;
mAppSearchData = null;
@@ -408,6 +430,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
updateSearchButton();
updateSearchBadge();
updateQueryHint();
+ updateVoiceButton();
// In order to properly configure the input method (if one is being used), we
// need to let it know if we'll be providing suggestions. Although it would be
@@ -426,6 +449,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
}
mSearchTextField.setInputType(inputType);
+ mSearchTextField.setImeOptions(mSearchable.getImeOptions());
}
}
@@ -500,6 +524,30 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
/**
+ * Update the visibility of the voice button. There are actually two voice search modes,
+ * either of which will activate the button.
+ */
+ private void updateVoiceButton() {
+ int visibility = View.GONE;
+ if (mSearchable.getVoiceSearchEnabled()) {
+ Intent testIntent = null;
+ if (mSearchable.getVoiceSearchLaunchWebSearch()) {
+ testIntent = mVoiceWebSearchIntent;
+ } else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
+ testIntent = mVoiceAppSearchIntent;
+ }
+ if (testIntent != null) {
+ ResolveInfo ri = getContext().getPackageManager().
+ resolveActivity(testIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (ri != null) {
+ visibility = View.VISIBLE;
+ }
+ }
+ }
+ mVoiceButton.setVisibility(visibility);
+ }
+
+ /**
* Listeners of various types
*/
@@ -642,11 +690,97 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
};
/**
+ * React to a click in the voice search button.
+ */
+ View.OnClickListener mVoiceButtonClickListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ try {
+ if (mSearchable.getVoiceSearchLaunchWebSearch()) {
+ getContext().startActivity(mVoiceWebSearchIntent);
+ dismiss();
+ } else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
+ Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent);
+ getContext().startActivity(appSearchIntent);
+ dismiss();
+ }
+ } catch (ActivityNotFoundException e) {
+ // Should not happen, since we check the availability of
+ // voice search before showing the button. But just in case...
+ Log.w(LOG_TAG, "Could not find voice search activity");
+ }
+ }
+ };
+
+ /**
+ * Create and return an Intent that can launch the voice search activity, perform a specific
+ * voice transcription, and forward the results to the searchable activity.
+ *
+ * @param baseIntent The voice app search intent to start from
+ * @return A completely-configured intent ready to send to the voice search activity
+ */
+ private Intent createVoiceAppSearchIntent(Intent baseIntent) {
+ // create the necessary intent to set up a search-and-forward operation
+ // in the voice search system. We have to keep the bundle separate,
+ // because it becomes immutable once it enters the PendingIntent
+ Intent queryIntent = new Intent(Intent.ACTION_SEARCH);
+ queryIntent.setComponent(mSearchable.mSearchActivity);
+ PendingIntent pending = PendingIntent.getActivity(
+ getContext(), 0, queryIntent, PendingIntent.FLAG_ONE_SHOT);
+
+ // Now set up the bundle that will be inserted into the pending intent
+ // when it's time to do the search. We always build it here (even if empty)
+ // because the voice search activity will always need to insert "QUERY" into
+ // it anyway.
+ Bundle queryExtras = new Bundle();
+ if (mAppSearchData != null) {
+ queryExtras.putBundle(SearchManager.APP_DATA, mAppSearchData);
+ }
+
+ // Now build the intent to launch the voice search. Add all necessary
+ // extras to launch the voice recognizer, and then all the necessary extras
+ // to forward the results to the searchable activity
+ Intent voiceIntent = new Intent(baseIntent);
+
+ // Add all of the configuration options supplied by the searchable's metadata
+ String languageModel = RecognizerIntent.LANGUAGE_MODEL_FREE_FORM;
+ String prompt = null;
+ String language = null;
+ int maxResults = 1;
+ Resources resources = mActivityContext.getResources();
+ if (mSearchable.getVoiceLanguageModeId() != 0) {
+ languageModel = resources.getString(mSearchable.getVoiceLanguageModeId());
+ }
+ if (mSearchable.getVoicePromptTextId() != 0) {
+ prompt = resources.getString(mSearchable.getVoicePromptTextId());
+ }
+ if (mSearchable.getVoiceLanguageId() != 0) {
+ language = resources.getString(mSearchable.getVoiceLanguageId());
+ }
+ if (mSearchable.getVoiceMaxResults() != 0) {
+ maxResults = mSearchable.getVoiceMaxResults();
+ }
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel);
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt);
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language);
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults);
+
+ // Add the values that configure forwarding the results
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, pending);
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT_BUNDLE, queryExtras);
+
+ return voiceIntent;
+ }
+
+ /**
* React to the user typing "enter" or other hardwired keys while typing in the search box.
* This handles these special keys while the edit box has focus.
*/
View.OnKeyListener mTextKeyListener = new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ cancel();
+ return true;
+ }
// also guard against possible race conditions (late arrival after dismiss)
if (mSearchable != null &&
TextUtils.getTrimmedLength(mSearchTextField.getText()) > 0) {
@@ -661,7 +795,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// otherwise, dispatch an "edit view" key
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
if (event.getAction() == KeyEvent.ACTION_UP) {
v.cancelLongPress();
launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null);
@@ -700,9 +833,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// also guard against possible race conditions (late arrival after dismiss)
if (mSearchable != null) {
handled = doSuggestionsKey(v, keyCode, event);
- if (!handled) {
- handled = refocusingKeyListener(v, keyCode, event);
- }
}
return handled;
}
@@ -793,24 +923,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
};
/**
- * UI-thread handling of dialog dismiss. Called by mBroadcastReceiver.onReceive().
- *
- * TODO: This is a really heavyweight solution for something that should be so simple.
- * For example, we already have a handler, in our superclass, why aren't we sharing that?
- * I think we need to investigate simplifying this entire methodology, or perhaps boosting
- * it up into the Dialog class.
- */
- private static final int MESSAGE_DISMISS = 0;
- private Handler mDismissHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == MESSAGE_DISMISS) {
- dismiss();
- }
- }
- };
-
- /**
* Various ways to launch searches
*/
@@ -907,6 +1019,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
* @param jamQuery True means to set the query, false means to reset it to the user's choice
*/
private void jamSuggestionQuery(boolean jamQuery, AdapterView<?> parent, int position) {
+ // quick check against race conditions
+ if (mSearchable == null) {
+ return;
+ }
+
mSuggestionsAdapter.setNonUserQuery(true); // disables any suggestions processing
if (jamQuery) {
CursorAdapter ca = getSuggestionsAdapter(parent);
@@ -1180,10 +1297,13 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// These private variables are shared by the filter thread and must be protected
private WeakReference<Cursor> mRecentCursor = new WeakReference<Cursor>(null);
private boolean mNonUserQuery = false;
+ private AutoCompleteTextView mParentView;
- public SuggestionsAdapter(Context context, SearchableInfo searchable) {
+ public SuggestionsAdapter(Context context, SearchableInfo searchable,
+ AutoCompleteTextView actv) {
super(context, -1, null, null, null);
mSearchable = searchable;
+ mParentView = actv;
// set up provider resources (gives us icons, etc.)
Context activityContext = mSearchable.getActivityContext(mContext);
@@ -1296,9 +1416,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
to = ONE_LINE_TO;
}
}
+ // Force the underlying ListView to discard and reload all layouts
+ // (Note, this should be optimized for cases where layout/cursor remain same)
+ mParentView.resetListAndClearViews();
// Now actually set up the cursor, columns, and the list view
changeCursorAndColumns(c, from, to);
- setViewResource(layout);
+ setViewResource(layout);
} else {
// Provide some help for developers instead of just silently discarding
Log.w(LOG_TAG, "Suggestions cursor discarded due to missing required columns.");
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 0a37e81..c1d66f4 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -168,7 +168,8 @@ import android.view.KeyEvent;
* <p><b>Managing focus and knowing if Search is active.</b> The search UI is not a separate
* activity, and when the UI is invoked or dismissed, your activity will not typically be paused,
* resumed, or otherwise notified by the methods defined in
- * <a href="android.app.Activity#ActivityLifecycle">Activity Lifecycle</a>. The search UI is
+ * <a href="{@docRoot}guide/topics/fundamentals.html#actlife">Application Fundamentals:
+ * Activity Lifecycle</a>. The search UI is
* handled in the same way as other system UI elements which may appear from time to time, such as
* notifications, screen locks, or other system alerts:
* <p>When the search UI appears, your activity will lose input focus.
@@ -212,11 +213,11 @@ import android.view.KeyEvent;
* {@link #QUERY getStringExtra(SearchManager.QUERY)}.</li>
* <li>To identify and support your searchable activity, you'll need to
* provide an XML file providing searchability configuration parameters, a reference to that
- * in your searchable activity's <a href="../../../devel/bblocks-manifest.html">manifest</a>
+ * in your searchable activity's <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a>
* entry, and an intent-filter declaring that you can
* receive ACTION_SEARCH intents. This is described in more detail in the
* <a href="#SearchabilityMetadata">Searchability Metadata</a> section.</li>
- * <li>Your <a href="../../../devel/bblocks-manifest.html">manifest</a> also needs a metadata entry
+ * <li>Your <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> also needs a metadata entry
* providing a global reference to the searchable activity. This is the "glue" directing the search
* UI, when invoked from any of your <i>other</i> activities, to use your application as the
* default search context. This is also described in more detail in the
@@ -359,7 +360,7 @@ import android.view.KeyEvent;
* <li>Implement a Content Provider that provides suggestions. If you already have one, and it
* has access to your suggestions data. If not, you'll have to create one.
* You'll also provide information about your Content Provider in your
- * package's <a href="../../../devel/bblocks-manifest.html">manifest</a>.</li>
+ * package's <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a>.</li>
* <li>Update your searchable activity's XML configuration file. There are two categories of
* information used for suggestions:
* <ul><li>The first is (required) data that the search manager will
@@ -634,7 +635,7 @@ import android.view.KeyEvent;
*
* <p><b>Metadata for searchable activity.</b> As with your search implementations described
* above, you must first identify which of your activities is searchable. In the
- * <a href="../../../devel/bblocks-manifest.html">manifest</a> entry for this activity, you must
+ * <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> entry for this activity, you must
* provide two elements:
* <ul><li>An intent-filter specifying that you can receive and process the
* {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} {@link android.content.Intent Intent}.
@@ -643,7 +644,7 @@ import android.view.KeyEvent;
* remaining configuration information for how your application implements search.</li></ul>
*
* <p>Here is a snippet showing the necessary elements in the
- * <a href="../../../devel/bblocks-manifest.html">manifest</a> entry for your searchable activity.
+ * <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> entry for your searchable activity.
* <pre class="prettyprint">
* &lt;!-- Search Activity - searchable --&gt;
* &lt;activity android:name="MySearchActivity"
@@ -746,6 +747,14 @@ import android.view.KeyEvent;
* <a href="../R.attr.html#inputType">inputType</a> attribute.</td>
* <td align="center">No</td>
* </tr>
+ * <tr><th>android:imeOptions</th>
+ * <td>If provided, supplies additional options for the input method.
+ * For most searches, in which free form text is expected, this attribute
+ * need not be provided, and will default to "actionSearch".
+ * Suitable values for this attribute are described in the
+ * <a href="../R.attr.html#imeOptions">imeOptions</a> attribute.</td>
+ * <td align="center">No</td>
+ * </tr>
*
* </tbody>
* </table>
@@ -765,9 +774,8 @@ import android.view.KeyEvent;
* <li>.../res/values/strings.xml</li></ul>
*
* <p>For more complete documentation on this capability, see
- * <a href="../../../devel/resources-i18n.html#AlternateResources">Resources and
- * Internationalization: Supporting Alternate Resources for Alternate Languages and Configurations
- * </a>.
+ * <a href="{@docRoot}guide/topics/resources/resources-i18n.html#AlternateResources">Resources and
+ * Internationalization: Alternate Resources</a>.
*
* <p><b>Metadata for non-searchable activities.</b> Activities which are part of a searchable
* application, but don't implement search itself, require a bit of "glue" in order to cause
@@ -775,7 +783,7 @@ import android.view.KeyEvent;
* provided, then searches from these activities will use the system default search context.
*
* <p>The simplest way to specify this is to add a <i>search reference</i> element to the
- * application entry in the <a href="../../../devel/bblocks-manifest.html">manifest</a> file.
+ * application entry in the <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> file.
* The value of this reference can be either of:
* <ul><li>The name of your searchable activity.
* It is typically prefixed by '.' to indicate that it's in the same package.</li>
@@ -803,7 +811,7 @@ import android.view.KeyEvent;
* to generate search suggestions, you'll need to publish it to the system, and you'll need to
* provide a bit of additional XML metadata in order to configure communications with it.
*
- * <p>First, in your <a href="../../../devel/bblocks-manifest.html">manifest</a>, you'll add the
+ * <p>First, in your <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a>, you'll add the
* following lines.
* <pre class="prettyprint">
* &lt;!-- Content provider for search suggestions --&gt;
@@ -832,7 +840,7 @@ import android.view.KeyEvent;
* <tbody>
* <tr><th>android:searchSuggestAuthority</th>
* <td>This value must match the authority string provided in the <i>provider</i> section
- * of your <a href="../../../devel/bblocks-manifest.html">manifest</a>.</td>
+ * of your <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a>.</td>
* <td align="center">Yes</td>
* </tr>
*
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 6c08e75..a6a436f 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -42,12 +42,12 @@ import java.io.PrintWriter;
* thread of their hosting process. This means that, if your service is going
* to do any CPU intensive (such as MP3 playback) or blocking (such as
* networking) operations, it should spawn its own thread in which to do that
- * work. More information on this can be found in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of the
- * Application Model overview</a>.</p>
+ * work. More information on this can be found in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.</p>
*
* <p>The Service class is an important part of an
- * <a href="{@docRoot}intro/lifecycle.html">application's overall lifecycle</a>.</p>
+ * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">application's overall lifecycle</a>.</p>
*
* <p>Topics covered here:
* <ol>
@@ -79,7 +79,7 @@ import java.io.PrintWriter;
* to the service. The service will remain running as long as the connection
* is established (whether or not the client retains a reference on the
* service's IBinder). Usually the IBinder returned is for a complex
- * interface that has been <a href="{@docRoot}reference/aidl.html">written
+ * interface that has been <a href="{@docRoot}guide/developing/tools/aidl.html">written
* in aidl</a>.
*
* <p>A service can be both started and have connections bound to it. In such
@@ -106,7 +106,7 @@ import java.io.PrintWriter;
* {@link #checkCallingPermission}
* method before executing the implementation of that call.
*
- * <p>See the <a href="{@docRoot}devel/security.html">Security Model</a>
+ * <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
* document for more information on permissions and security in general.
*
* <a name="ProcessLifecycle"></a>
@@ -201,14 +201,14 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
* Return the communication channel to the service. May return null if
* clients can not bind to the service. The returned
* {@link android.os.IBinder} is usually for a complex interface
- * that has been <a href="{@docRoot}reference/aidl.html">described using
+ * that has been <a href="{@docRoot}guide/developing/tools/aidl.html">described using
* aidl</a>.
*
* <p><em>Note that unlike other application components, calls on to the
* IBinder interface returned here may not happen on the main thread
* of the process</em>. More information about this can be found
- * in the <a href="{@docRoot}intro/appmodel.html#Threads">Threading section
- * of the Application Model overview</a>.</p>
+ * in <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.</p>
*
* @param intent The Intent that was used to bind to this service,
* as given to {@link android.content.Context#bindService
@@ -327,11 +327,15 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
}
/**
- * Print the Service's state into the given stream.
+ * Print the Service's state into the given stream. This gets invoked if
+ * you run "adb shell dumpsys activity service <yourservicename>".
+ * This is distinct from "dumpsys <servicename>", which only works for
+ * named system services and which invokes the {@link IBinder#dump} method
+ * on the {@link IBinder} interface registered with ServiceManager.
*
* @param fd The raw file descriptor that the dump is being sent to.
* @param writer The PrintWriter to which you should dump your state. This will be
- * closed for you after you return.
+ * closed for you after you return.
* @param args additional arguments to the dump request.
*/
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
new file mode 100644
index 0000000..10c2b02
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -0,0 +1,248 @@
+/*
+ *
+ * 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 android.appwidget;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.widget.RemoteViews;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import com.android.internal.appwidget.IAppWidgetHost;
+import com.android.internal.appwidget.IAppWidgetService;
+
+/**
+ * AppWidgetHost provides the interaction with the AppWidget service for apps,
+ * like the home screen, that want to embed AppWidgets in their UI.
+ */
+public class AppWidgetHost {
+
+ static final int HANDLE_UPDATE = 1;
+ static final int HANDLE_PROVIDER_CHANGED = 2;
+
+ static Object sServiceLock = new Object();
+ static IAppWidgetService sService;
+
+ Context mContext;
+ String mPackageName;
+
+ class Callbacks extends IAppWidgetHost.Stub {
+ public void updateAppWidget(int appWidgetId, RemoteViews views) {
+ Message msg = mHandler.obtainMessage(HANDLE_UPDATE);
+ msg.arg1 = appWidgetId;
+ msg.obj = views;
+ msg.sendToTarget();
+ }
+
+ public void providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
+ Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);
+ msg.arg1 = appWidgetId;
+ msg.obj = info;
+ msg.sendToTarget();
+ }
+ }
+
+ class UpdateHandler extends Handler {
+ public UpdateHandler(Looper looper) {
+ super(looper);
+ }
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case HANDLE_UPDATE: {
+ updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj);
+ break;
+ }
+ case HANDLE_PROVIDER_CHANGED: {
+ onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj);
+ break;
+ }
+ }
+ }
+ }
+
+ Handler mHandler;
+
+ int mHostId;
+ Callbacks mCallbacks = new Callbacks();
+ HashMap<Integer,AppWidgetHostView> mViews = new HashMap();
+
+ public AppWidgetHost(Context context, int hostId) {
+ mContext = context;
+ mHostId = hostId;
+ mHandler = new UpdateHandler(context.getMainLooper());
+ synchronized (sServiceLock) {
+ if (sService == null) {
+ IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
+ sService = IAppWidgetService.Stub.asInterface(b);
+ }
+ }
+ }
+
+ /**
+ * Start receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity
+ * becomes visible, i.e. from onStart() in your Activity.
+ */
+ public void startListening() {
+ int[] updatedIds = null;
+ ArrayList<RemoteViews> updatedViews = new ArrayList();
+
+ try {
+ if (mPackageName == null) {
+ mPackageName = mContext.getPackageName();
+ }
+ updatedIds = sService.startListening(mCallbacks, mPackageName, mHostId, updatedViews);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+
+ final int N = updatedIds.length;
+ for (int i=0; i<N; i++) {
+ updateAppWidgetView(updatedIds[i], updatedViews.get(i));
+ }
+ }
+
+ /**
+ * Stop receiving onAppWidgetChanged calls for your AppWidgets. Call this when your activity is
+ * no longer visible, i.e. from onStop() in your Activity.
+ */
+ public void stopListening() {
+ try {
+ sService.stopListening(mHostId);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Get a appWidgetId for a host in the calling process.
+ *
+ * @return a appWidgetId
+ */
+ public int allocateAppWidgetId() {
+ try {
+ if (mPackageName == null) {
+ mPackageName = mContext.getPackageName();
+ }
+ return sService.allocateAppWidgetId(mPackageName, mHostId);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Stop listening to changes for this AppWidget.
+ */
+ public void deleteAppWidgetId(int appWidgetId) {
+ synchronized (mViews) {
+ mViews.remove(appWidgetId);
+ try {
+ sService.deleteAppWidgetId(appWidgetId);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+ }
+
+ /**
+ * Remove all records about this host from the AppWidget manager.
+ * <ul>
+ * <li>Call this when initializing your database, as it might be because of a data wipe.</li>
+ * <li>Call this to have the AppWidget manager release all resources associated with your
+ * host. Any future calls about this host will cause the records to be re-allocated.</li>
+ * </ul>
+ */
+ public void deleteHost() {
+ try {
+ sService.deleteHost(mHostId);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Remove all records about all hosts for your package.
+ * <ul>
+ * <li>Call this when initializing your database, as it might be because of a data wipe.</li>
+ * <li>Call this to have the AppWidget manager release all resources associated with your
+ * host. Any future calls about this host will cause the records to be re-allocated.</li>
+ * </ul>
+ */
+ public static void deleteAllHosts() {
+ try {
+ sService.deleteAllHosts();
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ public final AppWidgetHostView createView(Context context, int appWidgetId,
+ AppWidgetProviderInfo appWidget) {
+ AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
+ view.setAppWidget(appWidgetId, appWidget);
+ synchronized (mViews) {
+ mViews.put(appWidgetId, view);
+ }
+ RemoteViews views = null;
+ try {
+ views = sService.getAppWidgetViews(appWidgetId);
+ } catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ view.updateAppWidget(views);
+ return view;
+ }
+
+ /**
+ * Called to create the AppWidgetHostView. Override to return a custom subclass if you
+ * need it. {@more}
+ */
+ protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
+ AppWidgetProviderInfo appWidget) {
+ return new AppWidgetHostView(context);
+ }
+
+ /**
+ * Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
+ */
+ protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
+ }
+
+ void updateAppWidgetView(int appWidgetId, RemoteViews views) {
+ AppWidgetHostView v;
+ synchronized (mViews) {
+ v = mViews.get(appWidgetId);
+ }
+ if (v != null) {
+ v.updateAppWidget(views);
+ }
+ }
+}
+
+
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
new file mode 100644
index 0000000..be0f96e
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -0,0 +1,312 @@
+/*
+ * 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 android.appwidget;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.Config;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Animation;
+import android.widget.FrameLayout;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+/**
+ * Provides the glue to show AppWidget views. This class offers automatic animation
+ * between updates, and will try recycling old views for each incoming
+ * {@link RemoteViews}.
+ */
+public class AppWidgetHostView extends FrameLayout {
+ static final String TAG = "AppWidgetHostView";
+ static final boolean LOGD = false;
+ static final boolean CROSSFADE = false;
+
+ static final int VIEW_MODE_NOINIT = 0;
+ static final int VIEW_MODE_CONTENT = 1;
+ static final int VIEW_MODE_ERROR = 2;
+ static final int VIEW_MODE_DEFAULT = 3;
+
+ static final int FADE_DURATION = 1000;
+
+ // When we're inflating the initialLayout for a AppWidget, we only allow
+ // views that are allowed in RemoteViews.
+ static final LayoutInflater.Filter sInflaterFilter = new LayoutInflater.Filter() {
+ public boolean onLoadClass(Class clazz) {
+ return clazz.isAnnotationPresent(RemoteViews.RemoteView.class);
+ }
+ };
+
+ Context mContext;
+
+ int mAppWidgetId;
+ AppWidgetProviderInfo mInfo;
+ View mView;
+ int mViewMode = VIEW_MODE_NOINIT;
+ int mLayoutId = -1;
+ long mFadeStartTime = -1;
+ Bitmap mOld;
+ Paint mOldPaint = new Paint();
+
+ /**
+ * Create a host view. Uses default fade animations.
+ */
+ public AppWidgetHostView(Context context) {
+ this(context, android.R.anim.fade_in, android.R.anim.fade_out);
+ }
+
+ /**
+ * Create a host view. Uses specified animations when pushing
+ * {@link #updateAppWidget(RemoteViews)}.
+ *
+ * @param animationIn Resource ID of in animation to use
+ * @param animationOut Resource ID of out animation to use
+ */
+ public AppWidgetHostView(Context context, int animationIn, int animationOut) {
+ super(context);
+ mContext = context;
+ }
+
+ /**
+ * Set the AppWidget that will be displayed by this view.
+ */
+ public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
+ mAppWidgetId = appWidgetId;
+ mInfo = info;
+ }
+
+ public int getAppWidgetId() {
+ return mAppWidgetId;
+ }
+
+ public AppWidgetProviderInfo getAppWidgetInfo() {
+ return mInfo;
+ }
+
+ /**
+ * Process a set of {@link RemoteViews} coming in as an update from the
+ * AppWidget provider. Will animate into these new views as needed.
+ */
+ public void updateAppWidget(RemoteViews remoteViews) {
+ if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld);
+
+ boolean recycled = false;
+ View content = null;
+ Exception exception = null;
+
+ // Capture the old view into a bitmap so we can do the crossfade.
+ if (CROSSFADE) {
+ if (mFadeStartTime < 0) {
+ if (mView != null) {
+ final int width = mView.getWidth();
+ final int height = mView.getHeight();
+ try {
+ mOld = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ } catch (OutOfMemoryError e) {
+ // we just won't do the fade
+ mOld = null;
+ }
+ if (mOld != null) {
+ //mView.drawIntoBitmap(mOld);
+ }
+ }
+ }
+ }
+
+ if (remoteViews == null) {
+ if (mViewMode == VIEW_MODE_DEFAULT) {
+ // We've already done this -- nothing to do.
+ return;
+ }
+ content = getDefaultView();
+ mLayoutId = -1;
+ mViewMode = VIEW_MODE_DEFAULT;
+ } else {
+ int layoutId = remoteViews.getLayoutId();
+
+ // If our stale view has been prepared to match active, and the new
+ // layout matches, try recycling it
+ if (content == null && layoutId == mLayoutId) {
+ try {
+ remoteViews.reapply(mContext, mView);
+ content = mView;
+ recycled = true;
+ if (LOGD) Log.d(TAG, "was able to recycled existing layout");
+ } catch (RuntimeException e) {
+ exception = e;
+ }
+ }
+
+ // Try normal RemoteView inflation
+ if (content == null) {
+ try {
+ content = remoteViews.apply(mContext, this);
+ if (LOGD) Log.d(TAG, "had to inflate new layout");
+ } catch (RuntimeException e) {
+ exception = e;
+ }
+ }
+
+ mLayoutId = layoutId;
+ mViewMode = VIEW_MODE_CONTENT;
+ }
+
+ if (content == null) {
+ if (mViewMode == VIEW_MODE_ERROR) {
+ // We've already done this -- nothing to do.
+ return ;
+ }
+ Log.w(TAG, "updateAppWidget couldn't find any view, using error view", exception);
+ content = getErrorView();
+ mViewMode = VIEW_MODE_ERROR;
+ }
+
+ if (!recycled) {
+ prepareView(content);
+ addView(content);
+ }
+
+ if (mView != content) {
+ removeView(mView);
+ mView = content;
+ }
+
+ if (CROSSFADE) {
+ if (mFadeStartTime < 0) {
+ // if there is already an animation in progress, don't do anything --
+ // the new view will pop in on top of the old one during the cross fade,
+ // and that looks okay.
+ mFadeStartTime = SystemClock.uptimeMillis();
+ invalidate();
+ }
+ }
+ }
+
+ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+ if (CROSSFADE) {
+ int alpha;
+ int l = child.getLeft();
+ int t = child.getTop();
+ if (mFadeStartTime > 0) {
+ alpha = (int)(((drawingTime-mFadeStartTime)*255)/FADE_DURATION);
+ if (alpha > 255) {
+ alpha = 255;
+ }
+ Log.d(TAG, "drawChild alpha=" + alpha + " l=" + l + " t=" + t
+ + " w=" + child.getWidth());
+ if (alpha != 255 && mOld != null) {
+ mOldPaint.setAlpha(255-alpha);
+ //canvas.drawBitmap(mOld, l, t, mOldPaint);
+ }
+ } else {
+ alpha = 255;
+ }
+ int restoreTo = canvas.saveLayerAlpha(l, t, child.getWidth(), child.getHeight(), alpha,
+ Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+ boolean rv = super.drawChild(canvas, child, drawingTime);
+ canvas.restoreToCount(restoreTo);
+ if (alpha < 255) {
+ invalidate();
+ } else {
+ mFadeStartTime = -1;
+ if (mOld != null) {
+ mOld.recycle();
+ mOld = null;
+ }
+ }
+ return rv;
+ } else {
+ return super.drawChild(canvas, child, drawingTime);
+ }
+ }
+
+ /**
+ * Prepare the given view to be shown. This might include adjusting
+ * {@link FrameLayout.LayoutParams} before inserting.
+ */
+ protected void prepareView(View view) {
+ // Take requested dimensions from parent, but apply default gravity.
+ ViewGroup.LayoutParams requested = view.getLayoutParams();
+ if (requested == null) {
+ requested = new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,
+ LayoutParams.FILL_PARENT);
+ }
+
+ FrameLayout.LayoutParams params =
+ new FrameLayout.LayoutParams(requested.width, requested.height);
+ params.gravity = Gravity.CENTER;
+ view.setLayoutParams(params);
+ }
+
+ /**
+ * Inflate and return the default layout requested by AppWidget provider.
+ */
+ protected View getDefaultView() {
+ View defaultView = null;
+ Exception exception = null;
+
+ try {
+ if (mInfo != null) {
+ Context theirContext = mContext.createPackageContext(
+ mInfo.provider.getPackageName(), 0 /* no flags */);
+ LayoutInflater inflater = (LayoutInflater)
+ theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater = inflater.cloneInContext(theirContext);
+ inflater.setFilter(sInflaterFilter);
+ defaultView = inflater.inflate(mInfo.initialLayout, this, false);
+ } else {
+ Log.w(TAG, "can't inflate defaultView because mInfo is missing");
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ exception = e;
+ } catch (RuntimeException e) {
+ exception = e;
+ }
+
+ if (exception != null && LOGD) {
+ Log.w(TAG, "Error inflating AppWidget " + mInfo, exception);
+ }
+
+ if (defaultView == null) {
+ if (LOGD) Log.d(TAG, "getDefaultView couldn't find any view, so inflating error");
+ defaultView = getErrorView();
+ }
+
+ return defaultView;
+ }
+
+ /**
+ * Inflate and return a view that represents an error state.
+ */
+ protected View getErrorView() {
+ TextView tv = new TextView(mContext);
+ tv.setText(com.android.internal.R.string.gadget_host_error_inflating);
+ // TODO: get this color from somewhere.
+ tv.setBackgroundColor(Color.argb(127, 0, 0, 0));
+ return tv;
+ }
+}
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
new file mode 100644
index 0000000..3b10ed2
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2006 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 android.appwidget;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+import com.android.internal.appwidget.IAppWidgetService;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.WeakHashMap;
+
+/**
+ * Updates AppWidget state; gets information about installed AppWidget providers and other
+ * AppWidget related state.
+ */
+public class AppWidgetManager {
+ static final String TAG = "AppWidgetManager";
+
+ /**
+ * Send this from your {@link AppWidgetHost} activity when you want to pick an AppWidget to display.
+ * The AppWidget picker activity will be launched.
+ * <p>
+ * You must supply the following extras:
+ * <table>
+ * <tr>
+ * <td>{@link #EXTRA_APPWIDGET_ID}</td>
+ * <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
+ * once the user has selected one.</td>
+ * </tr>
+ * </table>
+ *
+ * <p>
+ * The system will respond with an onActivityResult call with the following extras in
+ * the intent:
+ * <table>
+ * <tr>
+ * <td>{@link #EXTRA_APPWIDGET_ID}</td>
+ * <td>The appWidgetId that you supplied in the original intent.</td>
+ * </tr>
+ * </table>
+ * <p>
+ * When you receive the result from the AppWidget pick activity, if the resultCode is
+ * {@link android.app.Activity#RESULT_OK}, an AppWidget has been selected. You should then
+ * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its configuration
+ * activity. If {@link android.app.Activity#RESULT_CANCELED} is returned, you should delete
+ * the appWidgetId.
+ *
+ * @see #ACTION_APPWIDGET_CONFIGURE
+ */
+ public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
+
+ /**
+ * Sent when it is time to configure your AppWidget while it is being added to a host.
+ * This action is not sent as a broadcast to the AppWidget provider, but as a startActivity
+ * to the activity specified in the {@link AppWidgetProviderInfo AppWidgetProviderInfo meta-data}.
+ *
+ * <p>
+ * The intent will contain the following extras:
+ * <table>
+ * <tr>
+ * <td>{@link #EXTRA_APPWIDGET_ID}</td>
+ * <td>The appWidgetId to configure.</td>
+ * </tr>
+ * </table>
+ *
+ * <p>If you return {@link android.app.Activity#RESULT_OK} using
+ * {@link android.app.Activity#setResult Activity.setResult()}, the AppWidget will be added,
+ * and you will receive an {@link #ACTION_APPWIDGET_UPDATE} broadcast for this AppWidget.
+ * If you return {@link android.app.Activity#RESULT_CANCELED}, the host will cancel the add
+ * and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED} broadcast.
+ */
+ public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
+
+ /**
+ * An intent extra that contains one appWidgetId.
+ * <p>
+ * The value will be an int that can be retrieved like this:
+ * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
+ */
+ public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
+
+ /**
+ * An intent extra that contains multiple appWidgetIds.
+ * <p>
+ * The value will be an int array that can be retrieved like this:
+ * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
+ */
+ public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
+
+ /**
+ * A sentiel value that the AppWidget manager will never return as a appWidgetId.
+ */
+ public static final int INVALID_APPWIDGET_ID = 0;
+
+ /**
+ * Sent when it is time to update your AppWidget.
+ *
+ * <p>This may be sent in response to a new instance for this AppWidget provider having
+ * been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval}
+ * having lapsed, or the system booting.
+ *
+ * <p>
+ * The intent will contain the following extras:
+ * <table>
+ * <tr>
+ * <td>{@link #EXTRA_APPWIDGET_IDS}</td>
+ * <td>The appWidgetIds to update. This may be all of the AppWidgets created for this
+ * provider, or just a subset. The system tries to send updates for as few AppWidget
+ * instances as possible.</td>
+ * </tr>
+ * </table>
+ *
+ * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
+ */
+ public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
+
+ /**
+ * Sent when an instance of an AppWidget is deleted from its host.
+ *
+ * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
+ */
+ public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
+
+ /**
+ * Sent when an instance of an AppWidget is removed from the last host.
+ *
+ * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
+ */
+ public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
+
+ /**
+ * Sent when an instance of an AppWidget is added to a host for the first time.
+ * This broadcast is sent at boot time if there is a AppWidgetHost installed with
+ * an instance for this provider.
+ *
+ * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
+ */
+ public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
+
+ /**
+ * Field for the manifest meta-data tag.
+ *
+ * @see AppWidgetProviderInfo
+ */
+ public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
+
+ static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache = new WeakHashMap();
+ static IAppWidgetService sService;
+
+ Context mContext;
+
+ /**
+ * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
+ * Context} object.
+ */
+ public static AppWidgetManager getInstance(Context context) {
+ synchronized (sManagerCache) {
+ if (sService == null) {
+ IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
+ sService = IAppWidgetService.Stub.asInterface(b);
+ }
+
+ WeakReference<AppWidgetManager> ref = sManagerCache.get(context);
+ AppWidgetManager result = null;
+ if (ref != null) {
+ result = ref.get();
+ }
+ if (result == null) {
+ result = new AppWidgetManager(context);
+ sManagerCache.put(context, new WeakReference(result));
+ }
+ return result;
+ }
+ }
+
+ private AppWidgetManager(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Set the RemoteViews to use for the specified appWidgetIds.
+ *
+ * <p>
+ * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
+ * and outside of the handler.
+ * This method will only work when called from the uid that owns the AppWidget provider.
+ *
+ * @param appWidgetIds The AppWidget instances for which to set the RemoteViews.
+ * @param views The RemoteViews object to show.
+ */
+ public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
+ try {
+ sService.updateAppWidgetIds(appWidgetIds, views);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Set the RemoteViews to use for the specified appWidgetId.
+ *
+ * <p>
+ * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
+ * and outside of the handler.
+ * This method will only work when called from the uid that owns the AppWidget provider.
+ *
+ * @param appWidgetId The AppWidget instance for which to set the RemoteViews.
+ * @param views The RemoteViews object to show.
+ */
+ public void updateAppWidget(int appWidgetId, RemoteViews views) {
+ updateAppWidget(new int[] { appWidgetId }, views);
+ }
+
+ /**
+ * Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider.
+ *
+ * <p>
+ * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
+ * and outside of the handler.
+ * This method will only work when called from the uid that owns the AppWidget provider.
+ *
+ * @param provider The {@link ComponentName} for the {@link
+ * android.content.BroadcastReceiver BroadcastReceiver} provider
+ * for your AppWidget.
+ * @param views The RemoteViews object to show.
+ */
+ public void updateAppWidget(ComponentName provider, RemoteViews views) {
+ try {
+ sService.updateAppWidgetProvider(provider, views);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Return a list of the AppWidget providers that are currently installed.
+ */
+ public List<AppWidgetProviderInfo> getInstalledProviders() {
+ try {
+ return sService.getInstalledProviders();
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Get the available info about the AppWidget.
+ *
+ * @return A appWidgetId. If the appWidgetId has not been bound to a provider yet, or
+ * you don't have access to that appWidgetId, null is returned.
+ */
+ public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
+ try {
+ return sService.getAppWidgetInfo(appWidgetId);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Set the component for a given appWidgetId.
+ *
+ * <p class="note">You need the APPWIDGET_LIST permission. This method is to be used by the
+ * AppWidget picker.
+ *
+ * @param appWidgetId The AppWidget instance for which to set the RemoteViews.
+ * @param provider The {@link android.content.BroadcastReceiver} that will be the AppWidget
+ * provider for this AppWidget.
+ */
+ public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
+ try {
+ sService.bindAppWidgetId(appWidgetId, provider);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+
+ /**
+ * Get the list of appWidgetIds that have been bound to the given AppWidget
+ * provider.
+ *
+ * @param provider The {@link android.content.BroadcastReceiver} that is the
+ * AppWidget provider to find appWidgetIds for.
+ */
+ public int[] getAppWidgetIds(ComponentName provider) {
+ try {
+ return sService.getAppWidgetIds(provider);
+ }
+ catch (RemoteException e) {
+ throw new RuntimeException("system server dead?", e);
+ }
+ }
+}
+
diff --git a/core/java/android/appwidget/AppWidgetProvider.java b/core/java/android/appwidget/AppWidgetProvider.java
new file mode 100755
index 0000000..f70de9c
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetProvider.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2006 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 android.appwidget;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * A conveience class to aid in implementing an AppWidget provider.
+ * Everything you can do with AppWidgetProvider, you can do with a regular {@link BroadcastReceiver}.
+ * AppWidgetProvider merely parses the relevant fields out of the Intent that is received in
+ * {@link #onReceive(Context,Intent) onReceive(Context,Intent)}, and calls hook methods
+ * with the received extras.
+ *
+ * <p>Extend this class and override one or more of the {@link #onUpdate}, {@link #onDeleted},
+ * {@link #onEnabled} or {@link #onDisabled} methods to implement your own AppWidget functionality.
+ *
+ * <h3>Sample Code</h3>
+ * For an example of how to write a AppWidget provider, see the
+ * <a href="{@toroot}reference/android/appwidget/package-descr.html#providers">android.appwidget
+ * package overview</a>.
+ */
+public class AppWidgetProvider extends BroadcastReceiver {
+ /**
+ * Constructor to initialize AppWidgetProvider.
+ */
+ public AppWidgetProvider() {
+ }
+
+ /**
+ * Implements {@link BroadcastReceiver#onReceive} to dispatch calls to the various
+ * other methods on AppWidgetProvider.
+ *
+ * @param context The Context in which the receiver is running.
+ * @param intent The Intent being received.
+ */
+ // BEGIN_INCLUDE(onReceive)
+ public void onReceive(Context context, Intent intent) {
+ // Protect against rogue update broadcasts (not really a security issue,
+ // just filter bad broacasts out so subclasses are less likely to crash).
+ String action = intent.getAction();
+ if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
+ if (appWidgetIds != null && appWidgetIds.length > 0) {
+ this.onUpdate(context, AppWidgetManager.getInstance(context), appWidgetIds);
+ }
+ }
+ }
+ else if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
+ if (appWidgetIds != null && appWidgetIds.length > 0) {
+ this.onDeleted(context, appWidgetIds);
+ }
+ }
+ }
+ else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
+ this.onEnabled(context);
+ }
+ else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
+ this.onDisabled(context);
+ }
+ }
+ // END_INCLUDE(onReceive)
+
+ /**
+ * Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_UPDATE} broadcast when
+ * this AppWidget provider is being asked to provide {@link android.widget.RemoteViews RemoteViews}
+ * for a set of AppWidgets. Override this method to implement your own AppWidget functionality.
+ *
+ * {@more}
+ *
+ * @param context The {@link android.content.Context Context} in which this receiver is
+ * running.
+ * @param appWidgetManager A {@link AppWidgetManager} object you can call {@link
+ * AppWidgetManager#updateAppWidget} on.
+ * @param appWidgetIds The appWidgetIds for which an update is needed. Note that this
+ * may be all of the AppWidget instances for this provider, or just
+ * a subset of them.
+ *
+ * @see AppWidgetManager#ACTION_APPWIDGET_UPDATE
+ */
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+ }
+
+ /**
+ * Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_DELETED} broadcast when
+ * one or more AppWidget instances have been deleted. Override this method to implement
+ * your own AppWidget functionality.
+ *
+ * {@more}
+ *
+ * @param context The {@link android.content.Context Context} in which this receiver is
+ * running.
+ * @param appWidgetIds The appWidgetIds that have been deleted from their host.
+ *
+ * @see AppWidgetManager#ACTION_APPWIDGET_DELETED
+ */
+ public void onDeleted(Context context, int[] appWidgetIds) {
+ }
+
+ /**
+ * Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_ENABLED} broadcast when
+ * the a AppWidget for this provider is instantiated. Override this method to implement your
+ * own AppWidget functionality.
+ *
+ * {@more}
+ * When the last AppWidget for this provider is deleted,
+ * {@link AppWidgetManager#ACTION_APPWIDGET_DISABLED} is sent by the AppWidget manager, and
+ * {@link #onDisabled} is called. If after that, an AppWidget for this provider is created
+ * again, onEnabled() will be called again.
+ *
+ * @param context The {@link android.content.Context Context} in which this receiver is
+ * running.
+ *
+ * @see AppWidgetManager#ACTION_APPWIDGET_ENABLED
+ */
+ public void onEnabled(Context context) {
+ }
+
+ /**
+ * Called in response to the {@link AppWidgetManager#ACTION_APPWIDGET_DISABLED} broadcast, which
+ * is sent when the last AppWidget instance for this provider is deleted. Override this method
+ * to implement your own AppWidget functionality.
+ *
+ * {@more}
+ *
+ * @param context The {@link android.content.Context Context} in which this receiver is
+ * running.
+ *
+ * @see AppWidgetManager#ACTION_APPWIDGET_DISABLED
+ */
+ public void onDisabled(Context context) {
+ }
+}
diff --git a/core/java/android/os/HandlerInterface.java b/core/java/android/appwidget/AppWidgetProviderInfo.aidl
index 62dc273..82b3ada 100644
--- a/core/java/android/os/HandlerInterface.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.aidl
@@ -1,27 +1,19 @@
/*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (c) 2007, 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
+ * 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
+ * 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
+ * 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 android.os;
-
-/**
- * @hide
- * @deprecated
- */
-public interface HandlerInterface
-{
- void handleMessage(Message msg);
-}
+package android.appwidget;
+parcelable AppWidgetProviderInfo;
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
new file mode 100644
index 0000000..8530c35
--- /dev/null
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2006 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 android.appwidget;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.content.ComponentName;
+
+/**
+ * Describes the meta data for an installed AppWidget provider. The fields in this class
+ * correspond to the fields in the <code>&lt;appwidget-provider&gt;</code> xml tag.
+ */
+public class AppWidgetProviderInfo implements Parcelable {
+ /**
+ * Identity of this AppWidget component. This component should be a {@link
+ * android.content.BroadcastReceiver}, and it will be sent the AppWidget intents
+ * {@link android.appwidget as described in the AppWidget package documentation}.
+ *
+ * <p>This field corresponds to the <code>android:name</code> attribute in
+ * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+ */
+ public ComponentName provider;
+
+ /**
+ * Minimum width of the AppWidget, in dp.
+ *
+ * <p>This field corresponds to the <code>android:minWidth</code> attribute in
+ * the AppWidget meta-data file.
+ */
+ public int minWidth;
+
+ /**
+ * Minimum height of the AppWidget, in dp.
+ *
+ * <p>This field corresponds to the <code>android:minHeight</code> attribute in
+ * the AppWidget meta-data file.
+ */
+ public int minHeight;
+
+ /**
+ * How often, in milliseconds, that this AppWidget wants to be updated.
+ * The AppWidget manager may place a limit on how often a AppWidget is updated.
+ *
+ * <p>This field corresponds to the <code>android:updatePeriodMillis</code> attribute in
+ * the AppWidget meta-data file.
+ */
+ public int updatePeriodMillis;
+
+ /**
+ * The resource id of the initial layout for this AppWidget. This should be
+ * displayed until the RemoteViews for the AppWidget is available.
+ *
+ * <p>This field corresponds to the <code>android:initialLayout</code> attribute in
+ * the AppWidget meta-data file.
+ */
+ public int initialLayout;
+
+ /**
+ * The activity to launch that will configure the AppWidget.
+ *
+ * <p>This class name of field corresponds to the <code>android:configure</code> attribute in
+ * the AppWidget meta-data file. The package name always corresponds to the package containing
+ * the AppWidget provider.
+ */
+ public ComponentName configure;
+
+ /**
+ * The label to display to the user in the AppWidget picker. If not supplied in the
+ * xml, the application label will be used.
+ *
+ * <p>This field corresponds to the <code>android:label</code> attribute in
+ * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+ */
+ public String label;
+
+ /**
+ * The icon to display for this AppWidget in the AppWidget picker. If not supplied in the
+ * xml, the application icon will be used.
+ *
+ * <p>This field corresponds to the <code>android:icon</code> attribute in
+ * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
+ */
+ public int icon;
+
+ public AppWidgetProviderInfo() {
+ }
+
+ /**
+ * Unflatten the AppWidgetProviderInfo from a parcel.
+ */
+ public AppWidgetProviderInfo(Parcel in) {
+ if (0 != in.readInt()) {
+ this.provider = new ComponentName(in);
+ }
+ this.minWidth = in.readInt();
+ this.minHeight = in.readInt();
+ this.updatePeriodMillis = in.readInt();
+ this.initialLayout = in.readInt();
+ if (0 != in.readInt()) {
+ this.configure = new ComponentName(in);
+ }
+ this.label = in.readString();
+ this.icon = in.readInt();
+ }
+
+
+ public void writeToParcel(android.os.Parcel out, int flags) {
+ if (this.provider != null) {
+ out.writeInt(1);
+ this.provider.writeToParcel(out, flags);
+ } else {
+ out.writeInt(0);
+ }
+ out.writeInt(this.minWidth);
+ out.writeInt(this.minHeight);
+ out.writeInt(this.updatePeriodMillis);
+ out.writeInt(this.initialLayout);
+ if (this.configure != null) {
+ out.writeInt(1);
+ this.configure.writeToParcel(out, flags);
+ } else {
+ out.writeInt(0);
+ }
+ out.writeString(this.label);
+ out.writeInt(this.icon);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Parcelable.Creator that instantiates AppWidgetProviderInfo objects
+ */
+ public static final Parcelable.Creator<AppWidgetProviderInfo> CREATOR
+ = new Parcelable.Creator<AppWidgetProviderInfo>()
+ {
+ public AppWidgetProviderInfo createFromParcel(Parcel parcel)
+ {
+ return new AppWidgetProviderInfo(parcel);
+ }
+
+ public AppWidgetProviderInfo[] newArray(int size)
+ {
+ return new AppWidgetProviderInfo[size];
+ }
+ };
+
+ public String toString() {
+ return "AppWidgetProviderInfo(provider=" + this.provider + ")";
+ }
+}
+
+
diff --git a/core/java/android/appwidget/package.html b/core/java/android/appwidget/package.html
new file mode 100644
index 0000000..b6cd9c7
--- /dev/null
+++ b/core/java/android/appwidget/package.html
@@ -0,0 +1,136 @@
+<body>
+<p>Android allows applications to publish views to be embedded in other applications. These
+views are called widgets, and are published by "AppWidget providers." The component that can
+contain widgets is called a "AppWidget host."
+</p>
+<h3><a href="package-descr.html#providers">AppWidget Providers</a></h3>
+<ul>
+ <li><a href="package-descr.html#provider_manifest">Declaring a widget in the AndroidManifest</a></li>
+ <li><a href="package-descr.html#provider_meta_data">Adding the AppWidgetProviderInfo meta-data</a></li>
+ <li><a href="package-descr.html#provider_AppWidgetProvider">Using the AppWidgetProvider class</a></li>
+ <li><a href="package-descr.html#provider_configuration">AppWidget Configuration UI</a></li>
+ <li><a href="package-descr.html#provider_broadcasts">AppWidget Broadcast Intents</a></li>
+</ul>
+<h3><a href="package-descr.html#">AppWidget Hosts</a></h3>
+
+
+{@more}
+
+
+<h2><a name="providers"></a>AppWidget Providers</h2>
+<p>
+Any application can publish widgets. All an application needs to do to publish a widget is
+to have a {@link android.content.BroadcastReceiver} that receives the {@link
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} intent,
+and provide some meta-data about the widget. Android provides the
+{@link android.appwidget.AppWidgetProvider} class, which extends BroadcastReceiver, as a convenience
+class to aid in handling the broadcasts.
+
+<h3><a name="provider_manifest"></a>Declaring a widget in the AndroidManifest</h3>
+
+<p>
+First, declare the {@link android.content.BroadcastReceiver} in your application's
+<code>AndroidManifest.xml</code> file.
+
+{@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml AppWidgetProvider}
+
+<p>
+The <b><code>&lt;receiver&gt;</b> element has the following attributes:
+<ul>
+ <li><b><code>android:name</code> -</b> which specifies the
+ {@link android.content.BroadcastReceiver} or {@link android.appwidget.AppWidgetProvider}
+ class.</li>
+ <li><b><code>android:label</code> -</b> which specifies the string resource that
+ will be shown by the widget picker as the label.</li>
+ <li><b><code>android:icon</code> -</b> which specifies the drawable resource that
+ will be shown by the widget picker as the icon.</li>
+</ul>
+
+<p>
+The <b><code>&lt;intent-filter&gt;</b> element tells the {@link android.content.pm.PackageManager}
+that this {@link android.content.BroadcastReceiver} receives the {@link
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} broadcast.
+The widget manager will send other broadcasts directly to your widget provider as required.
+It is only necessary to explicitly declare that you accept the {@link
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE AppWidgetManager.ACTION_APPWIDGET_UPDATE} broadcast.
+
+<p>
+The <b><code>&lt;meta-data&gt;</code></b> element tells the widget manager which xml resource to
+read to find the {@link android.appwidget.AppWidgetProviderInfo} for your widget provider. It has the following
+attributes:
+<ul>
+ <li><b><code>android:name="android.appwidget.provider"</code> -</b> identifies this meta-data
+ as the {@link android.appwidget.AppWidgetProviderInfo} descriptor.</li>
+ <li><b><code>android:resource</code> -</b> is the xml resource to use as that descriptor.</li>
+</ul>
+
+
+<h3><a name="provider_meta_data"></a>Adding the {@link android.appwidget.AppWidgetProviderInfo AppWidgetProviderInfo} meta-data</h3>
+
+<p>
+For a widget, the values in the {@link android.appwidget.AppWidgetProviderInfo} structure are supplied
+in an XML resource. In the example above, the xml resource is referenced with
+<code>android:resource="@xml/appwidget_info"</code>. That XML file would go in your application's
+directory at <code>res/xml/appwidget_info.xml</code>. Here is a simple example.
+
+{@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/res/xml/appwidget_info.xml AppWidgetProviderInfo}
+
+<p>
+The attributes are as documented in the {@link android.appwidget.AppWidgetProviderInfo GagetInfo} class. (86400000 milliseconds means once per day)
+
+
+<h3><a name="provider_AppWidgetProvider"></a>Using the {@link android.appwidget.AppWidgetProvider AppWidgetProvider} class</h3>
+
+<p>The AppWidgetProvider class is the easiest way to handle the widget provider intent broadcasts.
+See the <code>src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.java</code>
+sample class in ApiDemos for an example.
+
+<p class="note">Keep in mind that since the the AppWidgetProvider is a BroadcastReceiver,
+your process is not guaranteed to keep running after the callback methods return. See
+<a href="../../../guide/topics/fundamentals.html#broadlife">Application Fundamentals &gt;
+Broadcast Receiver Lifecycle</a> for more information.
+
+
+
+<h3><a name="provider_configuration"></a>AppWidget Configuration UI</h3>
+
+<p>
+Widget hosts have the ability to start a configuration activity when a widget is instantiated.
+The activity should be declared as normal in AndroidManifest.xml, and it should be listed in
+the AppWidgetProviderInfo XML file in the <code>android:configure</code> attribute.
+
+<p>The activity you specified will be launched with the {@link
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE} action. See the documentation for that
+action for more info.
+
+<p>See the <code>src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.java</code>
+sample class in ApiDemos for an example.
+
+
+
+<h3><a name="providers_broadcasts"></a>AppWidget Broadcast Intents</h3>
+
+<p>{@link android.appwidget.AppWidgetProvider} is just a convenience class. If you would like
+to receive the widget broadcasts directly, you can. The four intents you need to care about are:
+<ul>
+ <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE}</li>
+ <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DELETED}</li>
+ <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_ENABLED}</li>
+ <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DISABLED}</li>
+</ul>
+
+<p>By way of example, the implementation of
+{@link android.appwidget.AppWidgetProvider#onReceive} is quite simple:</p>
+
+{@sample frameworks/base/core/java/android/appwidget/AppWidgetProvider.java onReceive}
+
+
+<h2>AppWidget Hosts</h3>
+<p>Widget hosts are the containers in which widgets can be placed. Most of the look and feel
+details are left up to the widget hosts. For example, the home screen has one way of viewing
+widgets, but the lock screen could also contain widgets, and it would have a different way of
+adding, removing and otherwise managing widgets.</p>
+<p>For more information on implementing your own widget host, see the
+{@link android.appwidget.AppWidgetHost AppWidgetHost} class.</p>
+</body>
+
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index b0b0154..2ea45d5 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -49,6 +49,7 @@ import java.util.List;
*/
public class BluetoothA2dp {
private static final String TAG = "BluetoothA2dp";
+ private static final boolean DBG = false;
/** int extra for SINK_STATE_CHANGED_ACTION */
public static final String SINK_STATE =
@@ -103,6 +104,7 @@ public class BluetoothA2dp {
* @hide
*/
public int connectSink(String address) {
+ if (DBG) log("connectSink(" + address + ")");
try {
return mService.connectSink(address);
} catch (RemoteException e) {
@@ -119,6 +121,7 @@ public class BluetoothA2dp {
* @hide
*/
public int disconnectSink(String address) {
+ if (DBG) log("disconnectSink(" + address + ")");
try {
return mService.disconnectSink(address);
} catch (RemoteException e) {
@@ -133,6 +136,7 @@ public class BluetoothA2dp {
* @hide
*/
public boolean isSinkConnected(String address) {
+ if (DBG) log("isSinkConnected(" + address + ")");
int state = getSinkState(address);
return state == STATE_CONNECTED || state == STATE_PLAYING;
}
@@ -142,6 +146,7 @@ public class BluetoothA2dp {
* @hide
*/
public List<String> listConnectedSinks() {
+ if (DBG) log("listConnectedSinks()");
try {
return mService.listConnectedSinks();
} catch (RemoteException e) {
@@ -156,6 +161,7 @@ public class BluetoothA2dp {
* @hide
*/
public int getSinkState(String address) {
+ if (DBG) log("getSinkState(" + address + ")");
try {
return mService.getSinkState(address);
} catch (RemoteException e) {
@@ -177,6 +183,7 @@ public class BluetoothA2dp {
* @return Result code, negative indicates an error
*/
public int setSinkPriority(String address, int priority) {
+ if (DBG) log("setSinkPriority(" + address + ", " + priority + ")");
try {
return mService.setSinkPriority(address, priority);
} catch (RemoteException e) {
@@ -191,6 +198,7 @@ public class BluetoothA2dp {
* @return non-negative priority, or negative error code on error.
*/
public int getSinkPriority(String address) {
+ if (DBG) log("getSinkPriority(" + address + ")");
try {
return mService.getSinkPriority(address);
} catch (RemoteException e) {
@@ -244,4 +252,8 @@ public class BluetoothA2dp {
return "<unknown state " + state + ">";
}
}
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index d613e1c..1ba1c1e 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -31,10 +31,15 @@ import java.io.UnsupportedEncodingException;
* @hide
*/
public class BluetoothDevice {
- public static final int MODE_UNKNOWN = -1;
- public static final int MODE_OFF = 0;
- public static final int MODE_CONNECTABLE = 1;
- public static final int MODE_DISCOVERABLE = 2;
+ /** Inquiry scan and page scan are both off.
+ * Device is neither discoverable nor connectable */
+ public static final int SCAN_MODE_NONE = 0;
+ /** Page scan is on, inquiry scan is off.
+ * Device is connectable, but not discoverable */
+ public static final int SCAN_MODE_CONNECTABLE = 1;
+ /** Page scan and inquiry scan are on.
+ * Device is connectable and discoverable */
+ public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3;
public static final int RESULT_FAILURE = -1;
public static final int RESULT_SUCCESS = 0;
@@ -54,12 +59,14 @@ public class BluetoothDevice {
/** A bond attempt failed because the other side explicilty rejected
* bonding */
public static final int UNBOND_REASON_AUTH_REJECTED = 2;
- /** A bond attempt failed because we cancelled the bonding process */
- public static final int UNBOND_REASON_CANCELLED = 3;
+ /** A bond attempt failed because we canceled the bonding process */
+ public static final int UNBOND_REASON_AUTH_CANCELED = 3;
/** A bond attempt failed because we could not contact the remote device */
- public static final int UNBOND_REASON_AUTH_REMOTE_DEVICE_DOWN = 4;
+ public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
+ /** A bond attempt failed because a discovery is in progress */
+ public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
/** An existing bond was explicitly revoked */
- public static final int UNBOND_REASON_REMOVED = 5;
+ public static final int UNBOND_REASON_REMOVED = 6;
private static final String TAG = "BluetoothDevice";
@@ -174,18 +181,6 @@ public class BluetoothDevice {
return false;
}
- public String getMajorClass() {
- try {
- return mService.getMajorClass();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getMinorClass() {
- try {
- return mService.getMinorClass();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
public String getVersion() {
try {
return mService.getVersion();
@@ -211,15 +206,26 @@ public class BluetoothDevice {
return null;
}
- public int getMode() {
+ /**
+ * Get the current scan mode.
+ * Used to determine if the local device is connectable and/or discoverable
+ * @return Scan mode, one of SCAN_MODE_* or an error code
+ */
+ public int getScanMode() {
try {
- return mService.getMode();
+ return mService.getScanMode();
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return MODE_UNKNOWN;
+ return BluetoothError.ERROR_IPC;
}
- public void setMode(int mode) {
+
+ /**
+ * Set the current scan mode.
+ * Used to make the local device connectable and/or discoverable
+ * @param scanMode One of SCAN_MODE_*
+ */
+ public void setScanMode(int scanMode) {
try {
- mService.setMode(mode);
+ mService.setScanMode(scanMode);
} catch (RemoteException e) {Log.e(TAG, "", e);}
}
@@ -435,24 +441,6 @@ public class BluetoothDevice {
return null;
}
- public String getRemoteAlias(String address) {
- try {
- return mService.getRemoteAlias(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public boolean setRemoteAlias(String address, String alias) {
- try {
- return mService.setRemoteAlias(address, alias);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
- public boolean clearRemoteAlias(String address) {
- try {
- return mService.clearRemoteAlias(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
public String getRemoteVersion(String address) {
try {
return mService.getRemoteVersion(address);
@@ -477,24 +465,6 @@ public class BluetoothDevice {
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
- public String getRemoteMajorClass(String address) {
- try {
- return mService.getRemoteMajorClass(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getRemoteMinorClass(String address) {
- try {
- return mService.getRemoteMinorClass(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String[] getRemoteServiceClasses(String address) {
- try {
- return mService.getRemoteServiceClasses(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
/**
* Returns the RFCOMM channel associated with the 16-byte UUID on
@@ -512,12 +482,19 @@ public class BluetoothDevice {
return false;
}
+ /**
+ * Get the major, minor and servics classes of a remote device.
+ * These classes are encoded as a 32-bit integer. See BluetoothClass.
+ * @param address remote device
+ * @return 32-bit class suitable for use with BluetoothClass.
+ */
public int getRemoteClass(String address) {
try {
return mService.getRemoteClass(address);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return BluetoothClass.ERROR;
}
+
public byte[] getRemoteFeatures(String address) {
try {
return mService.getRemoteFeatures(address);
@@ -576,8 +553,8 @@ public class BluetoothDevice {
}
- /* Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */
private static final int ADDRESS_LENGTH = 17;
+ /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */
public static boolean checkBluetoothAddress(String address) {
if (address == null || address.length() != ADDRESS_LENGTH) {
return false;
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index c315271..1dbe0cc 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -67,10 +67,15 @@ public class BluetoothHeadset {
/** A headset is currently connected */
public static final int STATE_CONNECTED = 2;
+ /** A SCO audio channel is not established */
+ public static final int AUDIO_STATE_DISCONNECTED = 0;
+ /** A SCO audio channel is established */
+ public static final int AUDIO_STATE_CONNECTED = 1;
+
public static final int RESULT_FAILURE = 0;
public static final int RESULT_SUCCESS = 1;
- /** Connection cancelled before completetion. */
- public static final int RESULT_CANCELLED = 2;
+ /** Connection canceled before completetion. */
+ public static final int RESULT_CANCELED = 2;
/** Default priority for headsets that should be auto-connected */
public static final int PRIORITY_AUTO = 100;
@@ -126,6 +131,7 @@ public class BluetoothHeadset {
* are ok.
*/
public synchronized void close() {
+ if (DBG) log("close()");
if (mConnection != null) {
mContext.unbindService(mConnection);
mConnection = null;
@@ -138,6 +144,7 @@ public class BluetoothHeadset {
* object is currently not connected to the Headset service.
*/
public int getState() {
+ if (DBG) log("getState()");
if (mService != null) {
try {
return mService.getState();
@@ -156,6 +163,7 @@ public class BluetoothHeadset {
* service.
*/
public String getHeadsetAddress() {
+ if (DBG) log("getHeadsetAddress()");
if (mService != null) {
try {
return mService.getHeadsetAddress();
@@ -180,6 +188,7 @@ public class BluetoothHeadset {
* will be expected.
*/
public boolean connectHeadset(String address) {
+ if (DBG) log("connectHeadset(" + address + ")");
if (mService != null) {
try {
if (mService.connectHeadset(address)) {
@@ -199,6 +208,7 @@ public class BluetoothHeadset {
* if not currently connected to the headset service.
*/
public boolean isConnected(String address) {
+ if (DBG) log("isConnected(" + address + ")");
if (mService != null) {
try {
return mService.isConnected(address);
@@ -216,6 +226,7 @@ public class BluetoothHeadset {
* not currently connected to the Headset service.
*/
public boolean disconnectHeadset() {
+ if (DBG) log("disconnectHeadset()");
if (mService != null) {
try {
mService.disconnectHeadset();
@@ -235,6 +246,7 @@ public class BluetoothHeadset {
* error.
*/
public boolean startVoiceRecognition() {
+ if (DBG) log("startVoiceRecognition()");
if (mService != null) {
try {
return mService.startVoiceRecognition();
@@ -252,6 +264,7 @@ public class BluetoothHeadset {
* headset is not in voice recognition mode, or on error.
*/
public boolean stopVoiceRecognition() {
+ if (DBG) log("stopVoiceRecognition()");
if (mService != null) {
try {
return mService.stopVoiceRecognition();
@@ -282,6 +295,7 @@ public class BluetoothHeadset {
* @return True if successful, false if there was some error.
*/
public boolean setPriority(String address, int priority) {
+ if (DBG) log("setPriority(" + address + ", " + priority + ")");
if (mService != null) {
try {
return mService.setPriority(address, priority);
@@ -299,6 +313,7 @@ public class BluetoothHeadset {
* @return non-negative priority, or negative error code on error.
*/
public int getPriority(String address) {
+ if (DBG) log("getPriority(" + address + ")");
if (mService != null) {
try {
return mService.getPriority(address);
@@ -318,6 +333,12 @@ public class BluetoothHeadset {
* @return True if this device might support HSP or HFP.
*/
public static boolean doesClassMatch(int btClass) {
+ // The render service class is required by the spec for HFP, so is a
+ // pretty good signal
+ if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
+ return true;
+ }
+ // Just in case they forgot the render service class
switch (BluetoothClass.Device.getDevice(btClass)) {
case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
@@ -344,4 +365,8 @@ public class BluetoothHeadset {
}
}
};
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothIntent.java b/core/java/android/bluetooth/BluetoothIntent.java
index 57c46f9..9273d0d 100644
--- a/core/java/android/bluetooth/BluetoothIntent.java
+++ b/core/java/android/bluetooth/BluetoothIntent.java
@@ -29,8 +29,8 @@ import android.annotation.SdkConstant.SdkConstantType;
* @hide
*/
public interface BluetoothIntent {
- public static final String MODE =
- "android.bluetooth.intent.MODE";
+ public static final String SCAN_MODE =
+ "android.bluetooth.intent.SCAN_MODE";
public static final String ADDRESS =
"android.bluetooth.intent.ADDRESS";
public static final String NAME =
@@ -45,6 +45,8 @@ public interface BluetoothIntent {
"android.bluetooth.intent.HEADSET_STATE";
public static final String HEADSET_PREVIOUS_STATE =
"android.bluetooth.intent.HEADSET_PREVIOUS_STATE";
+ public static final String HEADSET_AUDIO_STATE =
+ "android.bluetooth.intent.HEADSET_AUDIO_STATE";
public static final String BOND_STATE =
"android.bluetooth.intent.BOND_STATE";
public static final String BOND_PREVIOUS_STATE =
@@ -62,9 +64,14 @@ public interface BluetoothIntent {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String NAME_CHANGED_ACTION =
"android.bluetooth.intent.action.NAME_CHANGED";
+
+ /**
+ * Broadcast when the scan mode changes. Always contains an int extra
+ * named SCAN_MODE that contains the new scan mode.
+ */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String MODE_CHANGED_ACTION =
- "android.bluetooth.intent.action.MODE_CHANGED";
+ public static final String SCAN_MODE_CHANGED_ACTION =
+ "android.bluetooth.intent.action.SCAN_MODE_CHANGED";
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String DISCOVERY_STARTED_ACTION =
@@ -104,12 +111,6 @@ public interface BluetoothIntent {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String REMOTE_NAME_FAILED_ACTION =
"android.bluetooth.intent.action.REMOTE_NAME_FAILED";
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String REMOTE_ALIAS_CHANGED_ACTION =
- "android.bluetooth.intent.action.REMOTE_ALIAS_CHANGED";
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String REMOTE_ALIAS_CLEARED_ACTION =
- "android.bluetooth.intent.action.REMOTE_ALIAS_CLEARED";
/**
* Broadcast when the bond state of a remote device changes.
@@ -123,7 +124,18 @@ public interface BluetoothIntent {
public static final String BOND_STATE_CHANGED_ACTION =
"android.bluetooth.intent.action.BOND_STATE_CHANGED_ACTION";
+ /**
+ * TODO(API release): Move into BluetoothHeadset
+ */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String HEADSET_STATE_CHANGED_ACTION =
"android.bluetooth.intent.action.HEADSET_STATE_CHANGED";
+
+ /**
+ * TODO(API release): Consider incorporating as new state in
+ * HEADSET_STATE_CHANGED
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String HEADSET_AUDIO_STATE_CHANGED_ACTION =
+ "android.bluetooth.intent.action.HEADSET_ADUIO_STATE_CHANGED";
}
diff --git a/core/java/android/bluetooth/HeadsetBase.java b/core/java/android/bluetooth/HeadsetBase.java
index bce3388..fd2d2ab 100644
--- a/core/java/android/bluetooth/HeadsetBase.java
+++ b/core/java/android/bluetooth/HeadsetBase.java
@@ -21,13 +21,10 @@ import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
-import java.io.IOException;
-import java.lang.Thread;
-
/**
* The Android Bluetooth API is not finalized, and *will* change. Use at your
* own risk.
- *
+ *
* The base RFCOMM (service) connection for a headset or handsfree device.
*
* In the future this class will be removed.
@@ -90,7 +87,7 @@ public class HeadsetBase {
/* Create from an already exisiting rfcomm connection */
public HeadsetBase(PowerManager pm, BluetoothDevice bluetooth, String address, int socketFd,
- int rfcommChannel, Handler handler) {
+ int rfcommChannel, Handler handler) {
mDirection = DIRECTION_INCOMING;
mConnectTimestamp = System.currentTimeMillis();
mBluetooth = bluetooth;
@@ -132,30 +129,8 @@ public class HeadsetBase {
*/
protected void initializeAtParser() {
mAtParser = new AtParser();
-
- // Microphone Gain
- mAtParser.register("+VGM", new AtCommandHandler() {
- @Override
- public AtCommandResult handleSetCommand(Object[] args) {
- // AT+VGM=<gain> in range [0,15]
- // Headset/Handsfree is reporting its current gain setting
- //TODO: sync to android UI
- //TODO: Send unsolicited +VGM when volume changed on AG
- return new AtCommandResult(AtCommandResult.OK);
- }
- });
-
- // Speaker Gain
- mAtParser.register("+VGS", new AtCommandHandler() {
- @Override
- public AtCommandResult handleSetCommand(Object[] args) {
- // AT+VGS=<gain> in range [0,15]
- // Headset/Handsfree is reporting its current gain to Android
- //TODO: sync to AG UI
- //TODO: Send unsolicited +VGS when volume changed on AG
- return new AtCommandResult(AtCommandResult.OK);
- }
- });
+ //TODO(): Get rid of this as there are no parsers registered. But because of dependencies,
+ //it needs to be done as part of refactoring HeadsetBase and BluetoothHandsfree
}
public AtParser getAtParser() {
diff --git a/core/java/android/bluetooth/IBluetoothDevice.aidl b/core/java/android/bluetooth/IBluetoothDevice.aidl
index 59f679f..4351d2e 100644
--- a/core/java/android/bluetooth/IBluetoothDevice.aidl
+++ b/core/java/android/bluetooth/IBluetoothDevice.aidl
@@ -32,15 +32,13 @@ interface IBluetoothDevice
String getAddress();
String getName();
boolean setName(in String name);
- String getMajorClass();
- String getMinorClass();
String getVersion();
String getRevision();
String getManufacturer();
String getCompany();
- int getMode();
- boolean setMode(int mode);
+ int getScanMode();
+ boolean setScanMode(int mode);
int getDiscoverableTimeout();
boolean setDiscoverableTimeout(int timeout);
@@ -64,17 +62,11 @@ interface IBluetoothDevice
int getBondState(in String address);
String getRemoteName(in String address);
- String getRemoteAlias(in String address);
- boolean setRemoteAlias(in String address, in String alias);
- boolean clearRemoteAlias(in String address);
String getRemoteVersion(in String address);
String getRemoteRevision(in String address);
int getRemoteClass(in String address);
String getRemoteManufacturer(in String address);
String getRemoteCompany(in String address);
- String getRemoteMajorClass(in String address);
- String getRemoteMinorClass(in String address);
- String[] getRemoteServiceClasses(in String address);
boolean getRemoteServiceChannel(in String address, int uuid16, in IBluetoothDeviceCallback callback);
byte[] getRemoteFeatures(in String adddress);
String lastSeen(in String address);
diff --git a/core/java/android/bluetooth/ScoSocket.java b/core/java/android/bluetooth/ScoSocket.java
index 75b3329..a43a08b 100644
--- a/core/java/android/bluetooth/ScoSocket.java
+++ b/core/java/android/bluetooth/ScoSocket.java
@@ -16,17 +16,12 @@
package android.bluetooth;
-import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
-import java.io.IOException;
-import java.lang.Thread;
-
-
/**
* The Android Bluetooth API is not finalized, and *will* change. Use at your
* own risk.
@@ -56,7 +51,7 @@ public class ScoSocket {
private int mConnectedCode;
private int mClosedCode;
- private WakeLock mWakeLock; // held while STATE_CONNECTING or STATE_CONNECTED
+ private WakeLock mWakeLock; // held while in STATE_CONNECTING
static {
classInitNative();
@@ -130,6 +125,7 @@ public class ScoSocket {
public synchronized void close() {
if (DBG) log(this + " SCO OBJECT close() mState = " + mState);
+ acquireWakeLock();
mState = STATE_CLOSED;
closeNative();
releaseWakeLock();
@@ -152,19 +148,16 @@ public class ScoSocket {
mState = STATE_CLOSED;
}
mHandler.obtainMessage(mConnectedCode, mState, -1, this).sendToTarget();
- if (result < 0) {
- releaseWakeLock();
- }
+ releaseWakeLock();
}
private synchronized void onAccepted(int result) {
if (VDBG) log("onAccepted() " + this);
if (mState != STATE_ACCEPT) {
- if (DBG) log("Strange state" + this);
+ if (DBG) log("Strange state " + this);
return;
}
if (result >= 0) {
- acquireWakeLock();
mState = STATE_CONNECTED;
} else {
mState = STATE_CLOSED;
@@ -184,13 +177,13 @@ public class ScoSocket {
private void acquireWakeLock() {
if (!mWakeLock.isHeld()) {
mWakeLock.acquire();
- if (VDBG) log("mWakeLock.acquire()" + this);
+ if (VDBG) log("mWakeLock.acquire() " + this);
}
}
private void releaseWakeLock() {
if (mWakeLock.isHeld()) {
- if (VDBG) log("mWakeLock.release()" + this);
+ if (VDBG) log("mWakeLock.release() " + this);
mWakeLock.release();
}
}
diff --git a/core/java/android/content/AsyncQueryHandler.java b/core/java/android/content/AsyncQueryHandler.java
index 2d651a7..ac851cc 100644
--- a/core/java/android/content/AsyncQueryHandler.java
+++ b/core/java/android/content/AsyncQueryHandler.java
@@ -146,6 +146,20 @@ public abstract class AsyncQueryHandler extends Handler {
* @param token A token passed into {@link #onQueryComplete} to identify
* the query.
* @param cookie An object that gets passed into {@link #onQueryComplete}
+ * @param uri The URI, using the content:// scheme, for the content to
+ * retrieve.
+ * @param projection A list of which columns to return. Passing null will
+ * return all columns, which is discouraged to prevent reading data
+ * from storage that isn't going to be used.
+ * @param selection A filter declaring which rows to return, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself). Passing null will
+ * return all rows for the given URI.
+ * @param selectionArgs You may include ?s in selection, which will be
+ * replaced by the values from selectionArgs, in the order that they
+ * appear in the selection. The values will be bound as Strings.
+ * @param orderBy How to order the rows, formatted as an SQL ORDER BY
+ * clause (excluding the ORDER BY itself). Passing null will use the
+ * default sort order, which may be unordered.
*/
public void startQuery(int token, Object cookie, Uri uri,
String[] projection, String selection, String[] selectionArgs,
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index cd92002..08f6191 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -16,7 +16,11 @@
package android.content;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.util.Log;
/**
@@ -75,7 +79,7 @@ import android.util.Log;
* <p>The BroadcastReceiver class (when launched as a component through
* a manifest's {@link android.R.styleable#AndroidManifestReceiver &lt;receiver&gt;}
* tag) is an important part of an
- * <a href="{@docRoot}intro/lifecycle.html">application's overall lifecycle</a>.</p>
+ * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">application's overall lifecycle</a>.</p>
*
* <p>Topics covered here:
* <ol>
@@ -131,7 +135,7 @@ import android.util.Log;
* tag in their <code>AndroidManifest.xml</code>) will be able to send an
* Intent to the receiver.
*
- * <p>See the <a href="{@docRoot}devel/security.html">Security Model</a>
+ * <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
* document for more information on permissions and security in general.
*
* <a name="ProcessLifecycle"></a>
@@ -175,7 +179,9 @@ public abstract class BroadcastReceiver {
* return a result to you asynchronously -- in particular, for interacting
* with services, you should use
* {@link Context#startService(Intent)} instead of
- * {@link Context#bindService(Intent, ServiceConnection, int)}.
+ * {@link Context#bindService(Intent, ServiceConnection, int)}. If you wish
+ * to interact with a service that is already running, you can use
+ * {@link #peekService}.
*
* @param context The Context in which the receiver is running.
* @param intent The Intent being received.
@@ -183,6 +189,26 @@ public abstract class BroadcastReceiver {
public abstract void onReceive(Context context, Intent intent);
/**
+ * Provide a binder to an already-running service. This method is synchronous
+ * and will not start the target service if it is not present, so it is safe
+ * to call from {@link #onReceive}.
+ *
+ * @param myContext The Context that had been passed to {@link #onReceive(Context, Intent)}
+ * @param service The Intent indicating the service you wish to use. See {@link
+ * Context#startService(Intent)} for more information.
+ */
+ public IBinder peekService(Context myContext, Intent service) {
+ IActivityManager am = ActivityManagerNative.getDefault();
+ IBinder binder = null;
+ try {
+ binder = am.peekService(service, service.resolveTypeIfNeeded(
+ myContext.getContentResolver()));
+ } catch (RemoteException e) {
+ }
+ return binder;
+ }
+
+ /**
* Change the current result code of this broadcast; only works with
* broadcasts sent through
* {@link Context#sendOrderedBroadcast(Intent, String)
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 226c5ab..25544de 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -18,6 +18,7 @@ package android.content;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
+import android.content.res.AssetFileDescriptor;
import android.content.res.Configuration;
import android.database.Cursor;
import android.database.CursorToBulkCursorAdaptor;
@@ -41,8 +42,8 @@ import java.io.FileNotFoundException;
* multiple applications you can use a database directly via
* {@link android.database.sqlite.SQLiteDatabase}.
*
- * <p>See <a href="{@docRoot}devel/data/contentproviders.html">this page</a> for more information on
- * content providers.</p>
+ * <p>For more information, read <a href="{@docRoot}guide/topics/providers/content-providers.html">Content
+ * Providers</a>.</p>
*
* <p>When a request is made via
* a {@link ContentResolver} the system inspects the authority of the given URI and passes the
@@ -162,6 +163,13 @@ public abstract class ContentProvider implements ComponentCallbacks {
return ContentProvider.this.openFile(uri, mode);
}
+ public AssetFileDescriptor openAssetFile(Uri uri, String mode)
+ throws FileNotFoundException {
+ if (mode != null && mode.startsWith("rw")) checkWritePermission(uri);
+ else checkReadPermission(uri);
+ return ContentProvider.this.openAssetFile(uri, mode);
+ }
+
public ISyncAdapter getSyncAdapter() {
checkWritePermission(null);
return ContentProvider.this.getSyncAdapter().getISyncAdapter();
@@ -226,9 +234,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
/**
* Return the name of the permission required for read-only access to
* this content provider. This method can be called from multiple
- * threads, as described in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
- * the Application Model overview</a>.
+ * threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
*/
public final String getReadPermission() {
return mReadPermission;
@@ -248,9 +256,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
/**
* Return the name of the permission required for read/write access to
* this content provider. This method can be called from multiple
- * threads, as described in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
- * the Application Model overview</a>.
+ * threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
*/
public final String getWritePermission() {
return mWritePermission;
@@ -273,9 +281,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
* Receives a query request from a client in a local process, and
* returns a Cursor. This is called internally by the {@link ContentResolver}.
* This method can be called from multiple
- * threads, as described in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
- * the Application Model overview</a>.
+ * threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
* <p>
* Example client call:<p>
* <pre>// Request a specific record.
@@ -330,9 +338,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
* <code>vnd.android.cursor.item</code> for a single record,
* or <code>vnd.android.cursor.dir/</code> for multiple items.
* This method can be called from multiple
- * threads, as described in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
- * the Application Model overview</a>.
+ * threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
*
* @param uri the URI to query.
* @return a MIME type string, or null if there is no type.
@@ -344,9 +352,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
* As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
* after inserting.
* This method can be called from multiple
- * threads, as described in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of the
- * Application Model overview</a>.
+ * threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
* @param uri The content:// URI of the insertion request.
* @param values A set of column_name/value pairs to add to the database.
* @return The URI for the newly inserted item.
@@ -359,9 +367,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
* As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
* after inserting.
* This method can be called from multiple
- * threads, as described in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
- * the Application Model overview</a>.
+ * threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
*
* @param uri The content:// URI of the insertion request.
* @param values An array of sets of column_name/value pairs to add to the database.
@@ -382,9 +390,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
* As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyDelete()}
* after deleting.
* This method can be called from multiple
- * threads, as described in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of the
- * Application Model overview</a>.
+ * threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
*
* <p>The implementation is responsible for parsing out a row ID at the end
* of the URI, if a specific row is being deleted. That is, the client would
@@ -405,9 +413,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
* As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
* after updating.
* This method can be called from multiple
- * threads, as described in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of the
- * Application Model overview</a>.
+ * threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
*
* @param uri The URI to query. This can potentially have a record ID if this
* is an update request for a specific record.
@@ -422,9 +430,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
/**
* Open a file blob associated with a content URI.
* This method can be called from multiple
- * threads, as described in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of the
- * Application Model overview</a>.
+ * threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
*
* <p>Returns a
* ParcelFileDescriptor, from which you can obtain a
@@ -438,8 +446,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
* of this method should create a new ParcelFileDescriptor for each call.
*
* @param uri The URI whose file is to be opened.
- * @param mode Access mode for the file. May be "r" for read-only access
- * or "rw" for read and write access.
+ * @param mode Access mode for the file. May be "r" for read-only access,
+ * "rw" for read and write access, or "rwt" for read and write access
+ * that truncates any existing file.
*
* @return Returns a new ParcelFileDescriptor which you can use to access
* the file.
@@ -448,19 +457,66 @@ public abstract class ContentProvider implements ComponentCallbacks {
* no file associated with the given URI or the mode is invalid.
* @throws SecurityException Throws SecurityException if the caller does
* not have permission to access the file.
- */
+ *
+ * @see #openAssetFile(Uri, String)
+ * @see #openFileHelper(Uri, String)
+ */
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
throw new FileNotFoundException("No files supported by provider at "
+ uri);
}
+
+ /**
+ * This is like {@link #openFile}, but can be implemented by providers
+ * that need to be able to return sub-sections of files, often assets
+ * inside of their .apk. Note that when implementing this your clients
+ * must be able to deal with such files, either directly with
+ * {@link ContentResolver#openAssetFileDescriptor
+ * ContentResolver.openAssetFileDescriptor}, or by using the higher-level
+ * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
+ * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
+ * methods.
+ *
+ * <p><em>Note: if you are implementing this to return a full file, you
+ * should create the AssetFileDescriptor with
+ * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
+ * applications that can not handle sub-sections of files.</em></p>
+ *
+ * @param uri The URI whose file is to be opened.
+ * @param mode Access mode for the file. May be "r" for read-only access,
+ * "w" for write-only access (erasing whatever data is currently in
+ * the file), "wa" for write-only access to append to any existing data,
+ * "rw" for read and write access on any existing data, and "rwt" for read
+ * and write access that truncates any existing file.
+ *
+ * @return Returns a new AssetFileDescriptor which you can use to access
+ * the file.
+ *
+ * @throws FileNotFoundException Throws FileNotFoundException if there is
+ * no file associated with the given URI or the mode is invalid.
+ * @throws SecurityException Throws SecurityException if the caller does
+ * not have permission to access the file.
+ *
+ * @see #openFile(Uri, String)
+ * @see #openFileHelper(Uri, String)
+ */
+ public AssetFileDescriptor openAssetFile(Uri uri, String mode)
+ throws FileNotFoundException {
+ ParcelFileDescriptor fd = openFile(uri, mode);
+ return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
+ }
/**
* Convenience for subclasses that wish to implement {@link #openFile}
* by looking up a column named "_data" at the given URI.
*
* @param uri The URI to be opened.
- * @param mode The file mode.
+ * @param mode The file mode. May be "r" for read-only access,
+ * "w" for write-only access (erasing whatever data is currently in
+ * the file), "wa" for write-only access to append to any existing data,
+ * "rw" for read and write access on any existing data, and "rwt" for read
+ * and write access that truncates any existing file.
*
* @return Returns a new ParcelFileDescriptor that can be used by the
* client to access the file.
@@ -489,16 +545,7 @@ public abstract class ContentProvider implements ComponentCallbacks {
throw new FileNotFoundException("Column _data not found.");
}
- int modeBits;
- if ("r".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
- } else if ("rw".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_READ_WRITE
- | ParcelFileDescriptor.MODE_CREATE;
- } else {
- throw new FileNotFoundException("Bad mode for " + uri + ": "
- + mode);
- }
+ int modeBits = ContentResolver.modeToMode(uri, mode);
return ParcelFileDescriptor.open(new File(path), modeBits);
}
@@ -507,9 +554,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
* This is intended for use by the sync system. If null then this
* content provider is considered not syncable.
* This method can be called from multiple
- * threads, as described in the
- * <a href="{@docRoot}intro/appmodel.html#Threads">Threading section of
- * the Application Model overview</a>.
+ * threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
*
* @return the SyncAdapter that is to be used by this ContentProvider, or null
* if this ContentProvider is not syncable
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index ede2c9b..e5e3f74 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -16,6 +16,7 @@
package android.content;
+import android.content.res.AssetFileDescriptor;
import android.database.BulkCursorNative;
import android.database.BulkCursorToCursorAdaptor;
import android.database.Cursor;
@@ -187,6 +188,25 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
return true;
}
+ case OPEN_ASSET_FILE_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ Uri url = Uri.CREATOR.createFromParcel(data);
+ String mode = data.readString();
+
+ AssetFileDescriptor fd;
+ fd = openAssetFile(url, mode);
+ reply.writeNoException();
+ if (fd != null) {
+ reply.writeInt(1);
+ fd.writeToParcel(reply,
+ Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ } else {
+ reply.writeInt(0);
+ }
+ return true;
+ }
+
case GET_SYNC_ADAPTER_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
@@ -413,6 +433,29 @@ final class ContentProviderProxy implements IContentProvider
return fd;
}
+ public AssetFileDescriptor openAssetFile(Uri url, String mode)
+ throws RemoteException, FileNotFoundException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+
+ data.writeInterfaceToken(IContentProvider.descriptor);
+
+ url.writeToParcel(data, 0);
+ data.writeString(mode);
+
+ mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
+ int has = reply.readInt();
+ AssetFileDescriptor fd = has != 0
+ ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
+
+ data.recycle();
+ reply.recycle();
+
+ return fd;
+ }
+
public ISyncAdapter getSyncAdapter() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 52f55b6..0d886ee 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -17,6 +17,7 @@
package android.content;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
@@ -28,6 +29,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.text.TextUtils;
+import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -170,119 +172,100 @@ public abstract class ContentResolver {
* <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
* <li>file ({@link #SCHEME_FILE})</li>
* </ul>
- * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
- * <p>
- * A Uri object can be used to reference a resource in an APK file. The
- * Uri should be one of the following formats:
- * <ul>
- * <li><code>android.resource://package_name/id_number</code><br/>
- * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
- * For example <code>com.example.myapp</code><br/>
- * <code>id_number</code> is the int form of the ID.<br/>
- * The easiest way to construct this form is
- * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
- * </li>
- * <li><code>android.resource://package_name/type/name</code><br/>
- * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
- * For example <code>com.example.myapp</code><br/>
- * <code>type</code> is the string form of the resource type. For example, <code>raw</code>
- * or <code>drawable</code>.
- * <code>name</code> is the string form of the resource name. That is, whatever the file
- * name was in your res directory, without the type extension.
- * The easiest way to construct this form is
- * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
- * </li>
- * </ul>
- * @param uri The desired "content:" URI.
+ *
+ * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
+ * on these schemes.
+ *
+ * @param uri The desired URI.
* @return InputStream
* @throws FileNotFoundException if the provided URI could not be opened.
+ * @see #openAssetFileDescriptor(Uri, String)
*/
public final InputStream openInputStream(Uri uri)
throws FileNotFoundException {
String scheme = uri.getScheme();
- if (SCHEME_CONTENT.equals(scheme)) {
- ParcelFileDescriptor fd = openFileDescriptor(uri, "r");
- return fd != null ? new ParcelFileDescriptor.AutoCloseInputStream(fd) : null;
- } else if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
- String authority = uri.getAuthority();
- Resources r;
- if (TextUtils.isEmpty(authority)) {
- throw new FileNotFoundException("No authority: " + uri);
- } else {
- try {
- r = mContext.getPackageManager().getResourcesForApplication(authority);
- } catch (NameNotFoundException ex) {
- throw new FileNotFoundException("No package found for authority: " + uri);
- }
- }
- List<String> path = uri.getPathSegments();
- if (path == null) {
- throw new FileNotFoundException("No path: " + uri);
- }
- int len = path.size();
- int id;
- if (len == 1) {
- try {
- id = Integer.parseInt(path.get(0));
- } catch (NumberFormatException e) {
- throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
- }
- } else if (len == 2) {
- id = r.getIdentifier(path.get(1), path.get(0), authority);
- } else {
- throw new FileNotFoundException("More than two path segments: " + uri);
- }
- if (id == 0) {
- throw new FileNotFoundException("No resource found for: " + uri);
- }
+ if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
+ // Note: left here to avoid breaking compatibility. May be removed
+ // with sufficient testing.
+ OpenResourceIdResult r = getResourceId(uri);
try {
- InputStream stream = r.openRawResource(id);
+ InputStream stream = r.r.openRawResource(r.id);
return stream;
} catch (Resources.NotFoundException ex) {
- throw new FileNotFoundException("Resource ID does not exist: " + uri);
+ throw new FileNotFoundException("Resource does not exist: " + uri);
}
} else if (SCHEME_FILE.equals(scheme)) {
+ // Note: left here to avoid breaking compatibility. May be removed
+ // with sufficient testing.
return new FileInputStream(uri.getPath());
} else {
- throw new FileNotFoundException("Unknown scheme: " + uri);
+ AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r");
+ try {
+ return fd != null ? fd.createInputStream() : null;
+ } catch (IOException e) {
+ throw new FileNotFoundException("Unable to create stream");
+ }
}
}
/**
+ * Synonym for {@link #openOutputStream(Uri, String)
+ * openOutputStream(uri, "w")}.
+ * @throws FileNotFoundException if the provided URI could not be opened.
+ */
+ public final OutputStream openOutputStream(Uri uri)
+ throws FileNotFoundException {
+ return openOutputStream(uri, "w");
+ }
+
+ /**
* Open a stream on to the content associated with a content URI. If there
* is no data associated with the URI, FileNotFoundException is thrown.
*
* <h5>Accepts the following URI schemes:</h5>
* <ul>
* <li>content ({@link #SCHEME_CONTENT})</li>
+ * <li>file ({@link #SCHEME_FILE})</li>
* </ul>
*
- * @param uri The desired "content:" URI.
+ * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
+ * on these schemes.
+ *
+ * @param uri The desired URI.
+ * @param mode May be "w", "wa", "rw", or "rwt".
* @return OutputStream
+ * @throws FileNotFoundException if the provided URI could not be opened.
+ * @see #openAssetFileDescriptor(Uri, String)
*/
- public final OutputStream openOutputStream(Uri uri)
+ public final OutputStream openOutputStream(Uri uri, String mode)
throws FileNotFoundException {
- String scheme = uri.getScheme();
- if (SCHEME_CONTENT.equals(scheme)) {
- ParcelFileDescriptor fd = openFileDescriptor(uri, "rw");
- return fd != null
- ? new ParcelFileDescriptor.AutoCloseOutputStream(fd) : null;
- } else {
- throw new FileNotFoundException("Unknown scheme: " + uri);
+ AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode);
+ try {
+ return fd != null ? fd.createOutputStream() : null;
+ } catch (IOException e) {
+ throw new FileNotFoundException("Unable to create stream");
}
}
/**
* Open a raw file descriptor to access data under a "content:" URI. This
- * interacts with the underlying {@link ContentProvider#openFile}
- * ContentProvider.openFile()} method of the provider associated with the
- * given URI, to retrieve any file stored there.
+ * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
+ * underlying {@link ContentProvider#openFile}
+ * ContentProvider.openFile()} method, so will <em>not</em> work with
+ * providers that return sub-sections of files. If at all possible,
+ * you should use {@link #openAssetFileDescriptor(Uri, String)}. You
+ * will receive a FileNotFoundException exception if the provider returns a
+ * sub-section of a file.
*
* <h5>Accepts the following URI schemes:</h5>
* <ul>
* <li>content ({@link #SCHEME_CONTENT})</li>
+ * <li>file ({@link #SCHEME_FILE})</li>
* </ul>
*
+ * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
+ * on these schemes.
+ *
* @param uri The desired URI to open.
* @param mode The file mode to use, as per {@link ContentProvider#openFile
* ContentProvider.openFile}.
@@ -290,32 +273,189 @@ public abstract class ContentResolver {
* own this descriptor and are responsible for closing it when done.
* @throws FileNotFoundException Throws FileNotFoundException of no
* file exists under the URI or the mode is invalid.
+ * @see #openAssetFileDescriptor(Uri, String)
*/
public final ParcelFileDescriptor openFileDescriptor(Uri uri,
String mode) throws FileNotFoundException {
- IContentProvider provider = acquireProvider(uri);
- if (provider == null) {
- throw new FileNotFoundException("No content provider: " + uri);
+ AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode);
+ if (afd == null) {
+ return null;
+ }
+
+ if (afd.getDeclaredLength() < 0) {
+ // This is a full file!
+ return afd.getParcelFileDescriptor();
}
+
+ // Client can't handle a sub-section of a file, so close what
+ // we got and bail with an exception.
try {
- ParcelFileDescriptor fd = provider.openFile(uri, mode);
- if(fd == null) {
+ afd.close();
+ } catch (IOException e) {
+ }
+
+ throw new FileNotFoundException("Not a whole file");
+ }
+
+ /**
+ * Open a raw file descriptor to access data under a "content:" URI. This
+ * interacts with the underlying {@link ContentProvider#openAssetFile}
+ * ContentProvider.openAssetFile()} method of the provider associated with the
+ * given URI, to retrieve any file stored there.
+ *
+ * <h5>Accepts the following URI schemes:</h5>
+ * <ul>
+ * <li>content ({@link #SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
+ * <li>file ({@link #SCHEME_FILE})</li>
+ * </ul>
+ * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
+ * <p>
+ * A Uri object can be used to reference a resource in an APK file. The
+ * Uri should be one of the following formats:
+ * <ul>
+ * <li><code>android.resource://package_name/id_number</code><br/>
+ * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
+ * For example <code>com.example.myapp</code><br/>
+ * <code>id_number</code> is the int form of the ID.<br/>
+ * The easiest way to construct this form is
+ * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
+ * </li>
+ * <li><code>android.resource://package_name/type/name</code><br/>
+ * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
+ * For example <code>com.example.myapp</code><br/>
+ * <code>type</code> is the string form of the resource type. For example, <code>raw</code>
+ * or <code>drawable</code>.
+ * <code>name</code> is the string form of the resource name. That is, whatever the file
+ * name was in your res directory, without the type extension.
+ * The easiest way to construct this form is
+ * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
+ * </li>
+ * </ul>
+ *
+ * @param uri The desired URI to open.
+ * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
+ * ContentProvider.openAssetFile}.
+ * @return Returns a new ParcelFileDescriptor pointing to the file. You
+ * own this descriptor and are responsible for closing it when done.
+ * @throws FileNotFoundException Throws FileNotFoundException of no
+ * file exists under the URI or the mode is invalid.
+ */
+ public final AssetFileDescriptor openAssetFileDescriptor(Uri uri,
+ String mode) throws FileNotFoundException {
+ String scheme = uri.getScheme();
+ if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
+ if (!"r".equals(mode)) {
+ throw new FileNotFoundException("Can't write resources: " + uri);
+ }
+ OpenResourceIdResult r = getResourceId(uri);
+ try {
+ return r.r.openRawResourceFd(r.id);
+ } catch (Resources.NotFoundException ex) {
+ throw new FileNotFoundException("Resource does not exist: " + uri);
+ }
+ } else if (SCHEME_FILE.equals(scheme)) {
+ ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+ new File(uri.getPath()), modeToMode(uri, mode));
+ return new AssetFileDescriptor(pfd, 0, -1);
+ } else {
+ IContentProvider provider = acquireProvider(uri);
+ if (provider == null) {
+ throw new FileNotFoundException("No content provider: " + uri);
+ }
+ try {
+ AssetFileDescriptor fd = provider.openAssetFile(uri, mode);
+ if(fd == null) {
+ releaseProvider(provider);
+ return null;
+ }
+ ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
+ fd.getParcelFileDescriptor(), provider);
+ return new AssetFileDescriptor(pfd, fd.getStartOffset(),
+ fd.getDeclaredLength());
+ } catch (RemoteException e) {
releaseProvider(provider);
- return null;
+ throw new FileNotFoundException("Dead content provider: " + uri);
+ } catch (FileNotFoundException e) {
+ releaseProvider(provider);
+ throw e;
+ } catch (RuntimeException e) {
+ releaseProvider(provider);
+ throw e;
}
- return new ParcelFileDescriptorInner(fd, provider);
- } catch (RemoteException e) {
- releaseProvider(provider);
- throw new FileNotFoundException("Dead content provider: " + uri);
- } catch (FileNotFoundException e) {
- releaseProvider(provider);
- throw e;
- } catch (RuntimeException e) {
- releaseProvider(provider);
- throw e;
}
}
+ class OpenResourceIdResult {
+ Resources r;
+ int id;
+ }
+
+ OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
+ String authority = uri.getAuthority();
+ Resources r;
+ if (TextUtils.isEmpty(authority)) {
+ throw new FileNotFoundException("No authority: " + uri);
+ } else {
+ try {
+ r = mContext.getPackageManager().getResourcesForApplication(authority);
+ } catch (NameNotFoundException ex) {
+ throw new FileNotFoundException("No package found for authority: " + uri);
+ }
+ }
+ List<String> path = uri.getPathSegments();
+ if (path == null) {
+ throw new FileNotFoundException("No path: " + uri);
+ }
+ int len = path.size();
+ int id;
+ if (len == 1) {
+ try {
+ id = Integer.parseInt(path.get(0));
+ } catch (NumberFormatException e) {
+ throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
+ }
+ } else if (len == 2) {
+ id = r.getIdentifier(path.get(1), path.get(0), authority);
+ } else {
+ throw new FileNotFoundException("More than two path segments: " + uri);
+ }
+ if (id == 0) {
+ throw new FileNotFoundException("No resource found for: " + uri);
+ }
+ OpenResourceIdResult res = new OpenResourceIdResult();
+ res.r = r;
+ res.id = id;
+ return res;
+ }
+
+ /** @hide */
+ static public int modeToMode(Uri uri, String mode) throws FileNotFoundException {
+ int modeBits;
+ if ("r".equals(mode)) {
+ modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
+ } else if ("w".equals(mode) || "wt".equals(mode)) {
+ modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
+ | ParcelFileDescriptor.MODE_CREATE
+ | ParcelFileDescriptor.MODE_TRUNCATE;
+ } else if ("wa".equals(mode)) {
+ modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
+ | ParcelFileDescriptor.MODE_CREATE
+ | ParcelFileDescriptor.MODE_APPEND;
+ } else if ("rw".equals(mode)) {
+ modeBits = ParcelFileDescriptor.MODE_READ_WRITE
+ | ParcelFileDescriptor.MODE_CREATE;
+ } else if ("rwt".equals(mode)) {
+ modeBits = ParcelFileDescriptor.MODE_READ_WRITE
+ | ParcelFileDescriptor.MODE_CREATE
+ | ParcelFileDescriptor.MODE_TRUNCATE;
+ } else {
+ throw new FileNotFoundException("Bad mode for " + uri + ": "
+ + mode);
+ }
+ return modeBits;
+ }
+
/**
* Inserts a row into a table at the given URL.
*
diff --git a/core/java/android/content/ContentServiceNative.java b/core/java/android/content/ContentServiceNative.java
index f050501..364f9ee 100644
--- a/core/java/android/content/ContentServiceNative.java
+++ b/core/java/android/content/ContentServiceNative.java
@@ -75,6 +75,13 @@ abstract class ContentServiceNative extends Binder implements IContentService
{
try {
switch (code) {
+ case 5038: {
+ data.readString(); // ignore the interface token that service generated
+ Uri uri = Uri.parse(data.readString());
+ notifyChange(uri, null, false, false);
+ return true;
+ }
+
case REGISTER_CONTENT_OBSERVER_TRANSACTION: {
Uri uri = Uri.CREATOR.createFromParcel(data);
boolean notifyForDescendents = data.readInt() != 0;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 3908aa1..9a0dc9f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -127,7 +127,7 @@ public abstract class Context {
* current process.
*/
public abstract Context getApplicationContext();
-
+
/**
* Return a localized, styled CharSequence from the application's package's
* default string table.
@@ -428,7 +428,7 @@ public abstract class Context {
* cursor when query is called.
*
* @return The contents of a newly created database with the given name.
- * @throws SQLiteException if the database file could not be opened.
+ * @throws android.database.sqlite.SQLiteException if the database file could not be opened.
*
* @see #MODE_PRIVATE
* @see #MODE_WORLD_READABLE
@@ -1064,7 +1064,7 @@ public abstract class Context {
* @see #AUDIO_SERVICE
* @see android.media.AudioManager
* @see #TELEPHONY_SERVICE
- * @see android.internal.TelephonyManager
+ * @see android.telephony.TelephonyManager
* @see #INPUT_METHOD_SERVICE
* @see android.view.inputmethod.InputMethodManager
*/
@@ -1250,12 +1250,12 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
- * {@blink android.gadget.GadgetManager} for accessing wallpapers.
+ * {@blink android.appwidget.AppWidgetManager} for accessing AppWidgets.
*
* @hide
* @see #getSystemService
*/
- public static final String GADGET_SERVICE = "gadget";
+ public static final String APPWIDGET_SERVICE = "appwidget";
/**
* Determine whether the given permission is allowed for a particular
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index a6ef46f..0606956 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -16,6 +16,7 @@
package android.content;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.IBulkCursor;
@@ -52,6 +53,8 @@ public interface IContentProvider extends IInterface {
String[] selectionArgs) throws RemoteException;
public ParcelFileDescriptor openFile(Uri url, String mode)
throws RemoteException, FileNotFoundException;
+ public AssetFileDescriptor openAssetFile(Uri url, String mode)
+ throws RemoteException, FileNotFoundException;
public ISyncAdapter getSyncAdapter() throws RemoteException;
/* IPC constants */
@@ -65,4 +68,5 @@ public interface IContentProvider extends IInterface {
static final int GET_SYNC_ADAPTER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 10;
static final int BULK_INSERT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 12;
static final int OPEN_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 13;
+ static final int OPEN_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 14;
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 23fd171..c47b72f 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -504,6 +504,8 @@ import java.util.Set;
* <li> {@link #ACTION_PACKAGE_ADDED}
* <li> {@link #ACTION_PACKAGE_CHANGED}
* <li> {@link #ACTION_PACKAGE_REMOVED}
+ * <li> {@link #ACTION_PACKAGE_RESTARTED}
+ * <li> {@link #ACTION_PACKAGE_DATA_CLEARED}
* <li> {@link #ACTION_UID_REMOVED}
* <li> {@link #ACTION_BATTERY_CHANGED}
* <li> {@link #ACTION_POWER_CONNECTED}
@@ -522,9 +524,9 @@ import java.util.Set;
* <li> {@link #CATEGORY_ALTERNATIVE}
* <li> {@link #CATEGORY_SELECTED_ALTERNATIVE}
* <li> {@link #CATEGORY_LAUNCHER}
+ * <li> {@link #CATEGORY_INFO}
* <li> {@link #CATEGORY_HOME}
* <li> {@link #CATEGORY_PREFERENCE}
- * <li> {@link #CATEGORY_GADGET}
* <li> {@link #CATEGORY_TEST}
* </ul>
*
@@ -1026,6 +1028,15 @@ public class Intent implements Parcelable {
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
+
+ /**
+ * Activity Action: Start action associated with long pressing on the
+ * search key.
+ * <p>Input: Nothing.
+ * <p>Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SEARCH_LONG_PRESS = "android.intent.action.SEARCH_LONG_PRESS";
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
@@ -1041,6 +1052,14 @@ public class Intent implements Parcelable {
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
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
+ * keyguard is gone).
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USER_PRESENT= "android.intent.action.USER_PRESENT";
+
/**
* Broadcast Action: The current time has changed. Sent every
* minute. You can <em>not</em> receive this through components declared
@@ -1109,6 +1128,12 @@ public class Intent implements Parcelable {
/**
* Broadcast Action: A new application package has been installed on the
* device. The data contains the name of the package.
+ * <p>My include the following extras:
+ * <ul>
+ * <li> {@link #EXTRA_UID} containing the integer uid assigned to the new package.
+ * <li> {@link #EXTRA_REPLACING} is set to true if this is following
+ * an {@link #ACTION_PACKAGE_REMOVED} broadcast for the same package.
+ * </ul>
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
@@ -1116,23 +1141,49 @@ public class Intent implements Parcelable {
* Broadcast Action: An existing application package has been removed from
* the device. The data contains the name of the package. The package
* that is being installed does <em>not</em> receive this Intent.
+ * <ul>
+ * <li> {@link #EXTRA_UID} containing the integer uid previously assigned
+ * to the package.
+ * <li> {@link #EXTRA_DATA_REMOVED} is set to true if the entire
+ * application -- data and code -- is being removed.
+ * <li> {@link #EXTRA_REPLACING} is set to true if this will be followed
+ * by an {@link #ACTION_PACKAGE_ADDED} broadcast for the same package.
+ * </ul>
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
/**
* Broadcast Action: An existing application package has been changed (e.g. a component has been
* enabled or disabled. The data contains the name of the package.
+ * <ul>
+ * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
+ * </ul>
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
/**
- * Broadcast Action: The user has restarted a package, all runtime state
+ * Broadcast Action: The user has restarted a package, and all of its
+ * processes have been killed. All runtime state
* associated with it (processes, alarms, notifications, etc) should
- * be remove. The data contains the name of the package.
+ * be removed. The data contains the name of the package.
+ * <ul>
+ * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
+ * </ul>
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
/**
+ * Broadcast Action: The user has cleared the data of a package. This should
+ * be preceded by {@link #ACTION_PACKAGE_RESTARTED}, after which all of
+ * its persistent data is erased and this broadcast sent. The data contains
+ * the name of the package.
+ * <ul>
+ * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
+ /**
* Broadcast Action: A user ID has been removed from the system. The user
* ID number is stored in the extra data under {@link #EXTRA_UID}.
*/
@@ -1248,7 +1299,6 @@ public class Intent implements Parcelable {
/**
* Broadcast Action: External media is present, and being disk-checked
* The path to the mount point for the checking media is contained in the Intent.mData field.
- * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_MEDIA_CHECKING = "android.intent.action.MEDIA_CHECKING";
@@ -1256,7 +1306,6 @@ public class Intent implements Parcelable {
/**
* Broadcast Action: External media is present, but is using an incompatible fs (or is blank)
* The path to the mount point for the checking media is contained in the Intent.mData field.
- * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_MEDIA_NOFS = "android.intent.action.MEDIA_NOFS";
@@ -1524,16 +1573,17 @@ public class Intent implements Parcelable {
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_TAB = "android.intent.category.TAB";
/**
- * This activity can be embedded inside of another activity that is hosting
- * gadgets.
+ * Should be displayed in the top-level launcher.
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
- public static final String CATEGORY_GADGET = "android.intent.category.GADGET";
+ public static final String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER";
/**
- * Should be displayed in the top-level launcher.
+ * Provides information about the package it is in; typically used if
+ * a package does not contain a {@link #CATEGORY_LAUNCHER} to provide
+ * a front-door to the user without having to be shown in the all apps list.
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
- public static final String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER";
+ public static final String CATEGORY_INFO = "android.intent.category.INFO";
/**
* This is the home activity, that is the first activity that is displayed
* when the device boots.
@@ -1552,9 +1602,6 @@ public class Intent implements Parcelable {
public static final String CATEGORY_DEVELOPMENT_PREFERENCE = "android.intent.category.DEVELOPMENT_PREFERENCE";
/**
* Capable of running inside a parent activity container.
- *
- * <p>Note: being removed in favor of more explicit categories such as
- * CATEGORY_GADGET
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_EMBED = "android.intent.category.EMBED";
@@ -1677,6 +1724,22 @@ public class Intent implements Parcelable {
public static final String EXTRA_UID = "android.intent.extra.UID";
/**
+ * Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
+ * intents to indicate whether this represents a full uninstall (removing
+ * both the code and its data) or a partial uninstall (leaving its data,
+ * 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
+ * broadcast will immediately be followed by an add broadcast for a
+ * 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
* delievered with the intent. For one-shot alarms this will always be 1.
@@ -1739,9 +1802,9 @@ 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
- * <a href="{@docRoot}intro/appmodel.html">Application Model</a>
- * documentation for more details on tasks.
+ * the same order. See
+ * <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application Fundamentals:
+ * Activities and Tasks</a> for more details on tasks.
*
* <p>This flag is generally used by activities that want
* to present a "launcher" style behavior: they give the user a list of
@@ -1774,9 +1837,8 @@ public class Intent implements Parcelable {
* <p>This flag is ignored if
* {@link #FLAG_ACTIVITY_NEW_TASK} is not set.
*
- * <p>See the
- * <a href="{@docRoot}intro/appmodel.html">Application Model</a>
- * documentation for more details on tasks.
+ * <p>See <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application Fundamentals:
+ * Activities and Tasks</a> for more details on tasks.
*/
public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 0x08000000;
/**
@@ -1791,8 +1853,8 @@ public class Intent implements Parcelable {
* Intent, resulting in the stack now being: A, B.
*
* <p>The currently running instance of task B in the above example will
- * either receiving the new intent you are starting here in its
- * onNewIntent() method, or be itself finished and restarting with the
+ * either receive the new intent you are starting here in its
+ * onNewIntent() method, or be itself finished and restarted with the
* new intent. If it has declared its launch mode to be "multiple" (the
* default) it will be finished and re-created; for all other launch modes
* it will receive the Intent in the current instance.
@@ -1804,9 +1866,8 @@ public class Intent implements Parcelable {
* especially useful, for example, when launching an activity from the
* notification manager.
*
- * <p>See the
- * <a href="{@docRoot}intro/appmodel.html">Application Model</a>
- * documentation for more details on tasks.
+ * <p>See <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application Fundamentals:
+ * Activities and Tasks</a> for more details on tasks.
*/
public static final int FLAG_ACTIVITY_CLEAR_TOP = 0x04000000;
/**
@@ -1876,7 +1937,7 @@ public class Intent implements Parcelable {
*/
public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 0x00080000;
/**
- * If set, this flag will prevent the normal {@link android.app.Activity#onUserLeaving}
+ * 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.
*
@@ -1892,12 +1953,39 @@ public class Intent implements Parcelable {
* 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.
+ *
+ * <p>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.
+ */
+ public static final int FLAG_ACTIVITY_REORDER_TO_FRONT = 0X00020000;
/**
* If set, when sending a broadcast only registered receivers will be
* called -- no BroadcastReceiver components will be launched.
*/
public static final int FLAG_RECEIVER_REGISTERED_ONLY = 0x40000000;
+ /**
+ * If set, when sending a broadcast <i>before boot has completed</i> only
+ * registered receivers will be called -- no BroadcastReceiver components
+ * 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.
+ *
+ * <p>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;
// ---------------------------------------------------------------------
@@ -3865,8 +3953,8 @@ public class Intent implements Parcelable {
* FLAG_RECEIVER_* flags are all for use with
* {@link Context#sendBroadcast(Intent) Context.sendBroadcast()}.
*
- * <p>See the <a href="{@docRoot}intro/appmodel.html">Application Model</a>
- * documentation for important information on how some of these options impact
+ * <p>See the <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application Fundamentals:
+ * Activities and Tasks</a> documentation for important information on how some of these options impact
* the behavior of your application.
*
* @param flags The desired flags.
@@ -4141,14 +4229,11 @@ public class Intent implements Parcelable {
@Override
public boolean equals(Object obj) {
- Intent other;
- try {
- other = ((FilterComparison)obj).mIntent;
- } catch (ClassCastException e) {
- return false;
+ if (obj instanceof FilterComparison) {
+ Intent other = ((FilterComparison)obj).mIntent;
+ return mIntent.filterEquals(other);
}
-
- return mIntent.filterEquals(other);
+ return false;
}
@Override
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 6bc3774..96470c3 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -123,7 +123,7 @@ class SyncManager {
private static final String SYNC_WAKE_LOCK = "SyncManagerSyncWakeLock";
private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarmWakeLock";
-
+
private Context mContext;
private ContentResolver mContentResolver;
@@ -249,7 +249,7 @@ class SyncManager {
mSyncQueue = new SyncQueue(mSyncStorageEngine);
mContext = context;
-
+
mSyncThread = new HandlerThread("SyncHandlerThread", Process.THREAD_PRIORITY_BACKGROUND);
mSyncThread.start();
mSyncHandler = new SyncHandler(mSyncThread.getLooper());
@@ -489,7 +489,7 @@ class SyncManager {
// Require the precise value "yes" to discourage accidental activation.
return "yes".equals(SystemProperties.get("ro.config.sync"));
}
-
+
/**
* Initiate a sync. This can start a sync for all providers
* (pass null to url, set onlyTicklable to false), only those
@@ -515,7 +515,7 @@ class SyncManager {
* syncs of a specific provider. Can be null. Is ignored
* if the url is null.
* @param delay how many milliseconds in the future to wait before performing this
- * sync. -1 means to make this the next sync to perform.
+ * sync. -1 means to make this the next sync to perform.
*/
public void scheduleSync(Uri url, Bundle extras, long delay) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
@@ -694,7 +694,7 @@ class SyncManager {
class SyncHandlerMessagePayload {
public final ActiveSyncContext activeSyncContext;
public final SyncResult syncResult;
-
+
SyncHandlerMessagePayload(ActiveSyncContext syncContext, SyncResult syncResult) {
this.activeSyncContext = syncContext;
this.syncResult = syncResult;
@@ -740,7 +740,7 @@ class SyncManager {
if (newDelayInMs > maxSyncRetryTimeInSeconds * 1000) {
newDelayInMs = maxSyncRetryTimeInSeconds * 1000;
}
-
+
SyncOperation rescheduledSyncOperation = new SyncOperation(syncOperation);
rescheduledSyncOperation.setDelay(newDelayInMs);
scheduleSyncOperation(rescheduledSyncOperation);
@@ -786,7 +786,7 @@ class SyncManager {
// key than the one we are scheduling.
if (!activeIsExpedited && !hasSameKey) {
rescheduleImmediately(activeSyncContext.mSyncOperation);
- sendSyncFinishedOrCanceledMessage(activeSyncContext,
+ sendSyncFinishedOrCanceledMessage(activeSyncContext,
null /* no result since this is a cancel */);
}
}
@@ -1323,7 +1323,7 @@ class SyncManager {
public SyncHandler(Looper looper) {
super(looper);
}
-
+
public void handleMessage(Message msg) {
handleSyncHandlerMessage(msg);
}
@@ -1462,6 +1462,9 @@ class SyncManager {
// start it, otherwise just get out.
SyncOperation syncOperation;
final Sync.Settings.QueryMap syncSettings = getSyncSettings();
+ final ConnectivityManager connManager = (ConnectivityManager)
+ mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ final boolean backgroundDataSetting = connManager.getBackgroundDataSetting();
synchronized (mSyncQueue) {
while (true) {
syncOperation = mSyncQueue.head();
@@ -1484,10 +1487,10 @@ class SyncManager {
// skip the sync if it isn't a force and the settings are off for this provider
final boolean force = syncOperation.extras.getBoolean(
ContentResolver.SYNC_EXTRAS_FORCE, false);
- if (!force && (!syncSettings.getBackgroundData()
+ if (!force && (!backgroundDataSetting
|| !syncSettings.getListenForNetworkTickles()
|| !syncSettings.getSyncProviderAutomatically(
- syncOperation.authority))) {
+ syncOperation.authority))) {
if (isLoggable) {
Log.v(TAG, "runStateIdle: sync off, dropping " + syncOperation);
}
@@ -1669,7 +1672,7 @@ class SyncManager {
* @param syncResult the SyncResult from which to read
* @return the most "serious" error set in the SyncResult
* @throws IllegalStateException if the SyncResult does not indicate any errors.
- * If SyncResult.error() is true then it is safe to call this.
+ * If SyncResult.error() is true then it is safe to call this.
*/
private int syncResultToErrorNumber(SyncResult syncResult) {
if (syncResult.syncAlreadyInProgress) return History.ERROR_SYNC_ALREADY_IN_PROGRESS;
@@ -1679,7 +1682,8 @@ class SyncManager {
if (syncResult.stats.numConflictDetectedExceptions > 0) return History.ERROR_CONFLICT;
if (syncResult.tooManyDeletions) return History.ERROR_TOO_MANY_DELETIONS;
if (syncResult.tooManyRetries) return History.ERROR_TOO_MANY_RETRIES;
- throw new IllegalStateException("we are not in an error state, " + toString());
+ if (syncResult.databaseError) return History.ERROR_INTERNAL;
+ throw new IllegalStateException("we are not in an error state, " + syncResult);
}
private void manageSyncNotification() {
@@ -1717,7 +1721,7 @@ class SyncManager {
if (mSyncNotificationInfo.isActive) {
shouldInstall = shouldCancel;
} else {
- final boolean timeToShowNotification =
+ final boolean timeToShowNotification =
now > mSyncNotificationInfo.startTime + SYNC_NOTIFICATION_DELAY;
final boolean syncIsForced = syncOperation.extras
.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false);
@@ -1769,7 +1773,7 @@ class SyncManager {
if (!mDataConnectionIsConnected) return;
if (mAccounts == null) return;
if (mStorageIsLow) return;
-
+
// Compute the alarm fire time:
// - not syncing: time of the next sync operation
// - syncing, no notification: time from sync start to notification create time
@@ -1850,12 +1854,12 @@ class SyncManager {
clickIntent.putExtra("account", account);
clickIntent.putExtra("provider", authority);
clickIntent.putExtra("numDeletes", numDeletes);
-
+
if (!isActivityAvailable(clickIntent)) {
Log.w(TAG, "No activity found to handle too many deletes.");
return;
}
-
+
final PendingIntent pendingIntent = PendingIntent
.getActivity(mContext, 0, clickIntent, PendingIntent.FLAG_CANCEL_CURRENT);
@@ -1877,7 +1881,7 @@ class SyncManager {
/**
* Checks whether an activity exists on the system image for the given intent.
- *
+ *
* @param intent The intent for an activity.
* @return Whether or not an activity exists.
*/
@@ -1892,10 +1896,10 @@ class SyncManager {
return true;
}
}
-
+
return false;
}
-
+
public long insertStartSyncEvent(SyncOperation syncOperation) {
final int source = syncOperation.syncSource;
final long now = System.currentTimeMillis();
diff --git a/core/java/android/content/TempProviderSyncAdapter.java b/core/java/android/content/TempProviderSyncAdapter.java
index 78510aa..eb3a5da 100644
--- a/core/java/android/content/TempProviderSyncAdapter.java
+++ b/core/java/android/content/TempProviderSyncAdapter.java
@@ -1,11 +1,11 @@
package android.content;
-import com.google.android.net.NetStats;
-
import android.database.SQLException;
import android.os.Bundle;
import android.os.Debug;
+import android.os.NetStat;
import android.os.Parcelable;
+import android.os.Process;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Config;
@@ -177,7 +177,8 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
private final Bundle mExtras;
private final SyncContext mSyncContext;
private volatile boolean mIsCanceled = false;
- private long[] mNetStats;
+ private long mInitialTxBytes;
+ private long mInitialRxBytes;
private final SyncResult mResult;
SyncThread(SyncContext syncContext, String account, Bundle extras) {
@@ -193,15 +194,18 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
if (mAdapterSyncStarted) onSyncCanceled();
if (mProviderSyncStarted) mProvider.onSyncCanceled();
// We may lose the last few sync events when canceling. Oh well.
- long[] newNetStats = NetStats.getStats();
- logSyncDetails(newNetStats[0] - mNetStats[0], newNetStats[1] - mNetStats[1], mResult);
+ int uid = Process.myUid();
+ logSyncDetails(NetStat.getUidTxBytes(uid) - mInitialTxBytes,
+ NetStat.getUidRxBytes(uid) - mInitialRxBytes, mResult);
}
@Override
public void run() {
- android.os.Process.setThreadPriority(android.os.Process.myTid(),
- android.os.Process.THREAD_PRIORITY_BACKGROUND);
- mNetStats = NetStats.getStats();
+ Process.setThreadPriority(Process.myTid(),
+ Process.THREAD_PRIORITY_BACKGROUND);
+ int uid = Process.myUid();
+ mInitialTxBytes = NetStat.getUidTxBytes(uid);
+ mInitialRxBytes = NetStat.getUidRxBytes(uid);
try {
sync(mSyncContext, mAccount, mExtras);
} catch (SQLException e) {
@@ -210,8 +214,8 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter {
} finally {
mSyncThread = null;
if (!mIsCanceled) {
- long[] newNetStats = NetStats.getStats();
- logSyncDetails(newNetStats[0] - mNetStats[0], newNetStats[1] - mNetStats[1], mResult);
+ logSyncDetails(NetStat.getUidTxBytes(uid) - mInitialTxBytes,
+ NetStat.getUidRxBytes(uid) - mInitialRxBytes, mResult);
mSyncContext.onFinished(mResult);
}
}
diff --git a/core/java/android/content/package.html b/core/java/android/content/package.html
index 7b3e8cf..dd5360f 100644
--- a/core/java/android/content/package.html
+++ b/core/java/android/content/package.html
@@ -50,9 +50,9 @@ an application's resources and transfer data between applications.</p>
<p>This topic includes a terminology list associated with resources, and a series
of examples of using resources in code. For a complete guide on creating and
- using resources, see the document on <a href="{@docRoot}devel/resources-i18n.html">Resources
+ using resources, see the document on <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources
and Internationalization</a>. For a reference on the supported Android resource types,
- see <a href="{@docRoot}reference/available-resources.html">Available Resource Types</a>.</p>
+ see <a href="{@docRoot}guide/topics/resources/available-resources.html">Available Resource Types</a>.</p>
<p>The Android resource system keeps track of all non-code
assets associated with an application. You use the
{@link android.content.res.Resources Resources} class to access your
@@ -175,7 +175,8 @@ download files with new appearances.</p>
<p>This section gives a few quick examples you can use to make your own resources.
For more details on how to define and use resources, see <a
- href="{@docRoot}devel/resources-i18n.html">Resources</a>. </p>
+ href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources and
+ Internationalization</a>. </p>
<a name="UsingSystemResources"></a>
<h4>Using System Resources</h4>
diff --git a/core/java/android/content/pm/ConfigurationInfo.java b/core/java/android/content/pm/ConfigurationInfo.java
index 9115225..dcc7463 100755
--- a/core/java/android/content/pm/ConfigurationInfo.java
+++ b/core/java/android/content/pm/ConfigurationInfo.java
@@ -16,7 +16,6 @@
package android.content.pm;
-import android.content.res.Configuration;
import android.os.Parcel;
import android.os.Parcelable;
@@ -60,12 +59,12 @@ public class ConfigurationInfo implements Parcelable {
/**
* Value for {@link #reqInputFeatures}: if set, indicates that the application
- * requires a hard keyboard
+ * requires a five way navigation device
*/
public static final int INPUT_FEATURE_FIVE_WAY_NAV = 0x00000002;
/**
- * Flags associated with the application. Any combination of
+ * Flags associated with the input features. Any combination of
* {@link #INPUT_FEATURE_HARD_KEYBOARD},
* {@link #INPUT_FEATURE_FIVE_WAY_NAV}
*/
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index ea86188..d3f6f3c 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -255,8 +255,15 @@ interface IPackageManager {
* retrieval of information is complete.
*/
void getPackageSizeInfo(in String packageName, IPackageStatsObserver observer);
+
+ /**
+ * Get a list of shared libraries that are available on the
+ * system.
+ */
+ String[] getSystemSharedLibraryNames();
void enterSafeMode();
+ boolean isSafeMode();
void systemReady();
boolean hasSystemUidErrors();
}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 994afc8..d9326f2 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -29,6 +29,20 @@ public class PackageInfo implements Parcelable {
public String versionName;
/**
+ * The shared user ID name of this package, as specified by the &lt;manifest&gt;
+ * tag's {@link android.R.styleable#AndroidManifest_sharedUserId sharedUserId}
+ * attribute.
+ */
+ public String sharedUserId;
+
+ /**
+ * The shared user ID label of this package, as specified by the &lt;manifest&gt;
+ * tag's {@link android.R.styleable#AndroidManifest_sharedUserLabel sharedUserLabel}
+ * attribute.
+ */
+ public int sharedUserLabel;
+
+ /**
* Information collected from the &lt;application&gt; tag, or null if
* there was none.
*/
@@ -130,6 +144,8 @@ public class PackageInfo implements Parcelable {
dest.writeString(packageName);
dest.writeInt(versionCode);
dest.writeString(versionName);
+ dest.writeString(sharedUserId);
+ dest.writeInt(sharedUserLabel);
if (applicationInfo != null) {
dest.writeInt(1);
applicationInfo.writeToParcel(dest, parcelableFlags);
@@ -163,6 +179,8 @@ public class PackageInfo implements Parcelable {
packageName = source.readString();
versionCode = source.readInt();
versionName = source.readString();
+ sharedUserId = source.readString();
+ sharedUserLabel = source.readInt();
int hasApp = source.readInt();
if (hasApp != 0) {
applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4b902e9..7287d9c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -480,6 +480,26 @@ public abstract class PackageManager {
throws NameNotFoundException;
/**
+ * Return a "good" intent to launch a front-door activity in a package,
+ * for use for example to implement an "open" button when browsing through
+ * packages. The current implementation will look first for a main
+ * activity in the category {@link Intent#CATEGORY_INFO}, next for a
+ * main activity in the category {@link Intent#CATEGORY_LAUNCHER}, or return
+ * null if neither are found.
+ *
+ * <p>Throws {@link NameNotFoundException} if a package with the given
+ * name can not be found on the system.
+ *
+ * @param packageName The name of the package to inspect.
+ *
+ * @return Returns either a fully-qualified Intent that can be used to
+ * launch the main activity in the package, or null if the package does
+ * not contain such an activity.
+ */
+ public abstract Intent getLaunchIntentForPackage(String packageName)
+ throws NameNotFoundException;
+
+ /**
* Return an array of all of the secondary group-ids that have been
* assigned to a package.
*
@@ -851,6 +871,16 @@ public abstract class PackageManager {
* @see #GET_UNINSTALLED_PACKAGES
*/
public abstract List<ApplicationInfo> getInstalledApplications(int flags);
+
+ /**
+ * Get a list of shared libraries that are available on the
+ * system.
+ *
+ * @return An array of shared library names that are
+ * available on the system, or null if none are installed.
+ *
+ */
+ public abstract String[] getSystemSharedLibraryNames();
/**
* Determine the best action to perform for a given Intent. This is how
@@ -1608,4 +1638,9 @@ public abstract class PackageManager {
* the manifest as found in {@link ComponentInfo}.
*/
public abstract int getApplicationEnabledSetting(String packageName);
+
+ /**
+ * Return whether the device has been booted into safe mode.
+ */
+ public abstract boolean isSafeMode();
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e08f1d1..2dcb483 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -101,6 +101,8 @@ public class PackageParser {
pi.packageName = p.packageName;
pi.versionCode = p.mVersionCode;
pi.versionName = p.mVersionName;
+ pi.sharedUserId = p.mSharedUserId;
+ pi.sharedUserLabel = p.mSharedUserLabel;
pi.applicationInfo = p.applicationInfo;
if ((flags&PackageManager.GET_GIDS) != 0) {
pi.gids = gids;
@@ -258,8 +260,9 @@ public class PackageParser {
boolean assetError = true;
try {
assmgr = new AssetManager();
- if(assmgr.addAssetPath(mArchiveSourcePath) != 0) {
- parser = assmgr.openXmlResourceParser("AndroidManifest.xml");
+ int cookie = assmgr.addAssetPath(mArchiveSourcePath);
+ if(cookie != 0) {
+ parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
assetError = false;
} else {
Log.w(TAG, "Failed adding asset path:"+mArchiveSourcePath);
@@ -585,6 +588,8 @@ public class PackageParser {
return null;
}
pkg.mSharedUserId = str.intern();
+ pkg.mSharedUserLabel = sa.getResourceId(
+ com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
sa.recycle();
@@ -2045,6 +2050,9 @@ public class PackageParser {
// The shared user id that this package wants to use.
public String mSharedUserId;
+ // The shared user label that this package wants to use.
+ public int mSharedUserLabel;
+
// Signatures that were read from the package.
public Signature mSignatures[];
diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java
index 4a073f7..231e3e2 100644
--- a/core/java/android/content/res/AssetFileDescriptor.java
+++ b/core/java/android/content/res/AssetFileDescriptor.java
@@ -16,9 +16,13 @@
package android.content.res;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
/**
@@ -26,16 +30,32 @@ import java.io.IOException;
* opened FileDescriptor that can be used to read the data, as well as the
* offset and length of that entry's data in the file.
*/
-public class AssetFileDescriptor {
+public class AssetFileDescriptor implements Parcelable {
+ /**
+ * Length used with {@link #AssetFileDescriptor(ParcelFileDescriptor, long, long)}
+ * and {@link #getDeclaredLength} when a length has not been declared. This means
+ * the data extends to the end of the file.
+ */
+ public static final long UNKNOWN_LENGTH = -1;
+
private final ParcelFileDescriptor mFd;
private final long mStartOffset;
private final long mLength;
/**
* Create a new AssetFileDescriptor from the given values.
+ * @param fd The underlying file descriptor.
+ * @param startOffset The location within the file that the asset starts.
+ * This must be 0 if length is UNKNOWN_LENGTH.
+ * @param length The number of bytes of the asset, or
+ * {@link #UNKNOWN_LENGTH if it extends to the end of the file.
*/
public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset,
long length) {
+ if (length < 0 && startOffset != 0) {
+ throw new IllegalArgumentException(
+ "startOffset must be 0 when using UNKNOWN_LENGTH");
+ }
mFd = fd;
mStartOffset = startOffset;
mLength = length;
@@ -66,9 +86,33 @@ public class AssetFileDescriptor {
}
/**
- * Returns the total number of bytes of this asset entry's data.
+ * Returns the total number of bytes of this asset entry's data. May be
+ * {@link #UNKNOWN_LENGTH} if the asset extends to the end of the file.
+ * If the AssetFileDescriptor was constructed with {@link #UNKNOWN_LENGTH},
+ * this will use {@link ParcelFileDescriptor#getStatSize()
+ * ParcelFileDescriptor.getStatSize()} to find the total size of the file,
+ * returning that number if found or {@link #UNKNOWN_LENGTH} if it could
+ * not be determined.
+ *
+ * @see #getDeclaredLength()
*/
public long getLength() {
+ if (mLength >= 0) {
+ return mLength;
+ }
+ long len = mFd.getStatSize();
+ return len >= 0 ? len : UNKNOWN_LENGTH;
+ }
+
+ /**
+ * Return the actual number of bytes that were declared when the
+ * AssetFileDescriptor was constructed. Will be
+ * {@link #UNKNOWN_LENGTH} if the length was not declared, meaning data
+ * should be read to the end of the file.
+ *
+ * @see #getDeclaredLength()
+ */
+ public long getDeclaredLength() {
return mLength;
}
@@ -78,4 +122,227 @@ public class AssetFileDescriptor {
public void close() throws IOException {
mFd.close();
}
+
+ /**
+ * Create and return a new auto-close input stream for this asset. This
+ * will either return a full asset {@link AutoCloseInputStream}, or
+ * an underlying {@link ParcelFileDescriptor.AutoCloseInputStream
+ * ParcelFileDescriptor.AutoCloseInputStream} depending on whether the
+ * the object represents a complete file or sub-section of a file. You
+ * should only call this once for a particular asset.
+ */
+ public FileInputStream createInputStream() throws IOException {
+ if (mLength < 0) {
+ return new ParcelFileDescriptor.AutoCloseInputStream(mFd);
+ }
+ return new AutoCloseInputStream(this);
+ }
+
+ /**
+ * Create and return a new auto-close output stream for this asset. This
+ * will either return a full asset {@link AutoCloseOutputStream}, or
+ * an underlying {@link ParcelFileDescriptor.AutoCloseOutputStream
+ * ParcelFileDescriptor.AutoCloseOutputStream} depending on whether the
+ * the object represents a complete file or sub-section of a file. You
+ * should only call this once for a particular asset.
+ */
+ public FileOutputStream createOutputStream() throws IOException {
+ if (mLength < 0) {
+ return new ParcelFileDescriptor.AutoCloseOutputStream(mFd);
+ }
+ return new AutoCloseOutputStream(this);
+ }
+
+ @Override
+ public String toString() {
+ return "{AssetFileDescriptor: " + mFd
+ + " start=" + mStartOffset + " len=" + mLength + "}";
+ }
+
+ /**
+ * An InputStream you can create on a ParcelFileDescriptor, which will
+ * take care of calling {@link ParcelFileDescriptor#close
+ * ParcelFileDescritor.close()} for you when the stream is closed.
+ */
+ public static class AutoCloseInputStream
+ extends ParcelFileDescriptor.AutoCloseInputStream {
+ private long mRemaining;
+
+ public AutoCloseInputStream(AssetFileDescriptor fd) throws IOException {
+ super(fd.getParcelFileDescriptor());
+ super.skip(fd.getStartOffset());
+ mRemaining = (int)fd.getLength();
+ }
+
+ @Override
+ public int available() throws IOException {
+ return mRemaining >= 0
+ ? (mRemaining < 0x7fffffff ? (int)mRemaining : 0x7fffffff)
+ : super.available();
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (mRemaining >= 0) {
+ if (mRemaining == 0) return -1;
+ int res = super.read();
+ if (res >= 0) mRemaining--;
+ return res;
+ }
+
+ return super.read();
+ }
+
+ @Override
+ public int read(byte[] buffer, int offset, int count) throws IOException {
+ if (mRemaining >= 0) {
+ if (mRemaining == 0) return -1;
+ if (count > mRemaining) count = (int)mRemaining;
+ int res = super.read(buffer, offset, count);
+ if (res >= 0) mRemaining -= res;
+ return res;
+ }
+
+ return super.read(buffer, offset, count);
+ }
+
+ @Override
+ public int read(byte[] buffer) throws IOException {
+ if (mRemaining >= 0) {
+ if (mRemaining == 0) return -1;
+ int count = buffer.length;
+ if (count > mRemaining) count = (int)mRemaining;
+ int res = super.read(buffer, 0, count);
+ if (res >= 0) mRemaining -= res;
+ return res;
+ }
+
+ return super.read(buffer);
+ }
+
+ @Override
+ public long skip(long count) throws IOException {
+ if (mRemaining >= 0) {
+ if (mRemaining == 0) return -1;
+ if (count > mRemaining) count = mRemaining;
+ long res = super.skip(count);
+ if (res >= 0) mRemaining -= res;
+ return res;
+ }
+
+ // TODO Auto-generated method stub
+ return super.skip(count);
+ }
+
+ @Override
+ public void mark(int readlimit) {
+ if (mRemaining >= 0) {
+ // Not supported.
+ return;
+ }
+ super.mark(readlimit);
+ }
+
+ @Override
+ public boolean markSupported() {
+ if (mRemaining >= 0) {
+ return false;
+ }
+ return super.markSupported();
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ if (mRemaining >= 0) {
+ // Not supported.
+ return;
+ }
+ super.reset();
+ }
+ }
+
+ /**
+ * An OutputStream you can create on a ParcelFileDescriptor, which will
+ * take care of calling {@link ParcelFileDescriptor#close
+ * ParcelFileDescritor.close()} for you when the stream is closed.
+ */
+ public static class AutoCloseOutputStream
+ extends ParcelFileDescriptor.AutoCloseOutputStream {
+ private long mRemaining;
+
+ public AutoCloseOutputStream(AssetFileDescriptor fd) throws IOException {
+ super(fd.getParcelFileDescriptor());
+ if (fd.getParcelFileDescriptor().seekTo(fd.getStartOffset()) < 0) {
+ throw new IOException("Unable to seek");
+ }
+ mRemaining = (int)fd.getLength();
+ }
+
+ @Override
+ public void write(byte[] buffer, int offset, int count) throws IOException {
+ if (mRemaining >= 0) {
+ if (mRemaining == 0) return;
+ if (count > mRemaining) count = (int)mRemaining;
+ super.write(buffer, offset, count);
+ mRemaining -= count;
+ return;
+ }
+
+ super.write(buffer, offset, count);
+ }
+
+ @Override
+ public void write(byte[] buffer) throws IOException {
+ if (mRemaining >= 0) {
+ if (mRemaining == 0) return;
+ int count = buffer.length;
+ if (count > mRemaining) count = (int)mRemaining;
+ super.write(buffer);
+ mRemaining -= count;
+ return;
+ }
+
+ super.write(buffer);
+ }
+
+ @Override
+ public void write(int oneByte) throws IOException {
+ if (mRemaining >= 0) {
+ if (mRemaining == 0) return;
+ super.write(oneByte);
+ mRemaining--;
+ return;
+ }
+
+ super.write(oneByte);
+ }
+ }
+
+
+ /* Parcelable interface */
+ public int describeContents() {
+ return mFd.describeContents();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ mFd.writeToParcel(out, flags);
+ out.writeLong(mStartOffset);
+ out.writeLong(mLength);
+ }
+
+ AssetFileDescriptor(Parcel src) {
+ mFd = ParcelFileDescriptor.CREATOR.createFromParcel(src);
+ mStartOffset = src.readLong();
+ mLength = src.readLong();
+ }
+
+ public static final Parcelable.Creator<AssetFileDescriptor> CREATOR
+ = new Parcelable.Creator<AssetFileDescriptor>() {
+ public AssetFileDescriptor createFromParcel(Parcel in) {
+ return new AssetFileDescriptor(in);
+ }
+ public AssetFileDescriptor[] newArray(int size) {
+ return new AssetFileDescriptor[size];
+ }
+ };
}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index fadcb35..1c91736 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -567,8 +567,8 @@ public final class AssetManager {
/**
* Add an additional set of assets to the asset manager. This can be
- * either a directory or ZIP file. Not for use by applications. A
- * zero return value indicates failure.
+ * either a directory or ZIP file. Not for use by applications. Returns
+ * the cookie of the added asset, or 0 on failure.
* {@hide}
*/
public native final int addAssetPath(String path);
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 4b1e678..453a83d 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -16,8 +16,6 @@
package android.content.res;
-import com.google.android.collect.Lists;
-
import com.android.internal.util.ArrayUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -113,7 +111,8 @@ public class ColorStateList implements Parcelable {
* Create a ColorStateList from an XML document, given a set of {@link Resources}.
*/
public static ColorStateList createFromXml(Resources r, XmlPullParser parser)
- throws XmlPullParserException, IOException {
+ throws XmlPullParserException, IOException {
+
AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
@@ -125,19 +124,16 @@ public class ColorStateList implements Parcelable {
throw new XmlPullParserException("No start tag found");
}
- final ColorStateList colorStateList = createFromXmlInner(r, parser, attrs);
-
- return colorStateList;
+ return createFromXmlInner(r, parser, attrs);
}
/* Create from inside an XML document. Called on a parser positioned at
* a tag in an XML document, tries to create a ColorStateList from that tag.
* Returns null if the tag is not a valid ColorStateList.
*/
- private static ColorStateList createFromXmlInner(Resources r,
- XmlPullParser parser,
- AttributeSet attrs)
- throws XmlPullParserException, IOException {
+ private static ColorStateList createFromXmlInner(Resources r, XmlPullParser parser,
+ AttributeSet attrs) throws XmlPullParserException, IOException {
+
ColorStateList colorStateList;
final String name = parser.getName();
@@ -146,8 +142,7 @@ public class ColorStateList implements Parcelable {
colorStateList = new ColorStateList();
} else {
throw new XmlPullParserException(
- parser.getPositionDescription() + ": invalid drawable tag "
- + name);
+ parser.getPositionDescription() + ": invalid drawable tag " + name);
}
colorStateList.inflate(r, parser, attrs);
@@ -304,7 +299,11 @@ public class ColorStateList implements Parcelable {
}
public void writeToParcel(Parcel dest, int flags) {
- dest.writeArray(mStateSpecs);
+ final int N = mStateSpecs.length;
+ dest.writeInt(N);
+ for (int i=0; i<N; i++) {
+ dest.writeIntArray(mStateSpecs[i]);
+ }
dest.writeIntArray(mColors);
}
@@ -315,14 +314,11 @@ public class ColorStateList implements Parcelable {
}
public ColorStateList createFromParcel(Parcel source) {
- Object[] o = source.readArray(
- ColorStateList.class.getClassLoader());
- int[][] stateSpecs = new int[o.length][];
-
- for (int i = 0; i < o.length; i++) {
- stateSpecs[i] = (int[]) o[i];
+ final int N = source.readInt();
+ int[][] stateSpecs = new int[N][];
+ for (int i=0; i<N; i++) {
+ stateSpecs[i] = source.createIntArray();
}
-
int[] colors = source.createIntArray();
return new ColorStateList(stateSpecs, colors);
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 10eced6..1a963f6 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -22,7 +22,6 @@ import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import android.content.Intent;
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ColorDrawable;
@@ -47,6 +46,7 @@ public class Resources {
static final String TAG = "Resources";
private static final boolean DEBUG_LOAD = false;
private static final boolean DEBUG_CONFIG = false;
+ private static final boolean TRACE_FOR_PRELOAD = false;
private static final int sSdkVersion = SystemProperties.getInt(
"ro.build.version.sdk", 0);
@@ -58,6 +58,8 @@ public class Resources {
// single-threaded, and after that these are immutable.
private static final SparseArray<Drawable.ConstantState> mPreloadedDrawables
= new SparseArray<Drawable.ConstantState>();
+ private static final SparseArray<ColorStateList> mPreloadedColorStateLists
+ = new SparseArray<ColorStateList>();
private static boolean mPreloaded;
/*package*/ final TypedValue mTmpValue = new TypedValue();
@@ -79,7 +81,7 @@ public class Resources {
private final Configuration mConfiguration = new Configuration();
/*package*/ final DisplayMetrics mMetrics = new DisplayMetrics();
PluralRules mPluralRule;
-
+
/**
* This exception is thrown by the resource APIs when a requested resource
* can not be found.
@@ -91,7 +93,7 @@ public class Resources {
public NotFoundException(String name) {
super(name);
}
- };
+ }
/**
* Create a new Resources object on top of an existing set of assets in an
@@ -399,7 +401,6 @@ public class Resources {
*
* @throws NotFoundException Throws NotFoundException if the given ID does not exist.
*
- * @return CharSequence The string data associated with the resource, plus
* @see #getDimensionPixelOffset
* @see #getDimensionPixelSize
*/
@@ -432,7 +433,6 @@ public class Resources {
*
* @throws NotFoundException Throws NotFoundException if the given ID does not exist.
*
- * @return CharSequence The string data associated with the resource, plus
* @see #getDimension
* @see #getDimensionPixelSize
*/
@@ -467,7 +467,6 @@ public class Resources {
*
* @throws NotFoundException Throws NotFoundException if the given ID does not exist.
*
- * @return CharSequence The string data associated with the resource, plus
* @see #getDimension
* @see #getDimensionPixelOffset
*/
@@ -486,6 +485,36 @@ public class Resources {
}
/**
+ * Retrieve a fractional unit for a particular resource ID.
+ *
+ * @param id The desired resource identifier, as generated by the aapt
+ * tool. This integer encodes the package, type, and resource
+ * entry. The value 0 is an invalid identifier.
+ * @param base The base value of this fraction. In other words, a
+ * standard fraction is multiplied by this value.
+ * @param pbase The parent base value of this fraction. In other
+ * words, a parent fraction (nn%p) is multiplied by this
+ * value.
+ *
+ * @return Attribute fractional value multiplied by the appropriate
+ * base value.
+ *
+ * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
+ */
+ public float getFraction(int id, int base, int pbase) {
+ synchronized (mTmpValue) {
+ TypedValue value = mTmpValue;
+ getValue(id, value, true);
+ if (value.type == TypedValue.TYPE_FRACTION) {
+ return TypedValue.complexToFraction(value.data, base, pbase);
+ }
+ throw new NotFoundException(
+ "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
+ + Integer.toHexString(value.type) + " is not valid");
+ }
+ }
+
+ /**
* Return a drawable object associated with a particular resource ID.
* Various types of objects will be returned depending on the underlying
* resource -- for example, a solid color, PNG image, scalable image, etc.
@@ -721,22 +750,36 @@ public class Resources {
*/
public InputStream openRawResource(int id) throws NotFoundException {
synchronized (mTmpValue) {
- TypedValue value = mTmpValue;
- getValue(id, value, true);
+ return openRawResource(id, mTmpValue);
+ }
+ }
- try {
- return mAssets.openNonAsset(
- value.assetCookie, value.string.toString(),
- AssetManager.ACCESS_STREAMING);
- } catch (Exception e) {
- NotFoundException rnf = new NotFoundException(
- "File " + value.string.toString()
- + " from drawable resource ID #0x"
- + Integer.toHexString(id));
- rnf.initCause(e);
- throw rnf;
- }
+ /**
+ * Open a data stream for reading a raw resource. This can only be used
+ * with resources whose value is the name of an asset files -- that is, it can be
+ * used to open drawable, sound, and raw resources; it will fail on string
+ * and color resources.
+ *
+ * @param id The resource identifier to open, as generated by the appt tool.
+ * @param value The TypedValue object to hold the resource information.
+ *
+ * @return InputStream Access to the resource data.
+ *
+ * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
+ *
+ * @hide Pending API council approval
+ */
+ public InputStream openRawResource(int id, TypedValue value) throws NotFoundException {
+ getValue(id, value, true);
+ try {
+ return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
+ AssetManager.ACCESS_STREAMING);
+ } catch (Exception e) {
+ NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
+ " from drawable resource ID #0x" + Integer.toHexString(id));
+ rnf.initCause(e);
+ throw rnf;
}
}
@@ -1189,7 +1232,9 @@ public class Resources {
width = mMetrics.widthPixels;
height = mMetrics.heightPixels;
} else {
+ //noinspection SuspiciousNameCombination
width = mMetrics.heightPixels;
+ //noinspection SuspiciousNameCombination
height = mMetrics.widthPixels;
}
int keyboardHidden = mConfiguration.keyboardHidden;
@@ -1302,6 +1347,7 @@ public class Resources {
try {
return Integer.parseInt(name);
} catch (Exception e) {
+ // Ignore
}
return mAssets.getResourceIdentifier(name, defType, defPackage);
}
@@ -1535,21 +1581,18 @@ public class Resources {
/*package*/ Drawable loadDrawable(TypedValue value, int id)
throws NotFoundException {
- if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
- && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
- // Should we be caching these? If we use constant colors much
- // at all, most likely...
- //System.out.println("Creating drawable for color: #" +
- // Integer.toHexString(value.data));
- Drawable dr = new ColorDrawable(value.data);
- dr.setChangingConfigurations(value.changingConfigurations);
- return dr;
+
+ if (TRACE_FOR_PRELOAD) {
+ // Log only framework resources
+ if ((id >>> 24) == 0x1) {
+ final String name = getResourceName(id);
+ if (name != null) android.util.Log.d("PreloadDrawable", name);
+ }
}
- final int key = (value.assetCookie<<24)|value.data;
+ final int key = (value.assetCookie << 24) | value.data;
Drawable dr = getCachedDrawable(key);
- //System.out.println("Cached drawable @ #" +
- // Integer.toHexString(key.intValue()) + ": " + dr);
+
if (dr != null) {
return dr;
}
@@ -1557,46 +1600,52 @@ public class Resources {
Drawable.ConstantState cs = mPreloadedDrawables.get(key);
if (cs != null) {
dr = cs.newDrawable();
-
} else {
- if (value.string == null) {
- throw new NotFoundException(
- "Resource is not a Drawable (color or path): " + value);
+ if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
+ value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+ dr = new ColorDrawable(value.data);
}
-
- String file = value.string.toString();
-
- if (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie "
- + value.assetCookie + ": " + file);
-
- if (file.endsWith(".xml")) {
- try {
- XmlResourceParser rp = loadXmlResourceParser(
- file, id, value.assetCookie, "drawable");
- dr = Drawable.createFromXml(this, rp);
- rp.close();
- } catch (Exception e) {
- NotFoundException rnf = new NotFoundException(
- "File " + file + " from drawable resource ID #0x"
- + Integer.toHexString(id));
- rnf.initCause(e);
- throw rnf;
+
+ if (dr == null) {
+ if (value.string == null) {
+ throw new NotFoundException(
+ "Resource is not a Drawable (color or path): " + value);
}
-
- } else {
- try {
- InputStream is = mAssets.openNonAsset(
- value.assetCookie, file, AssetManager.ACCESS_BUFFER);
- // System.out.println("Opened file " + file + ": " + is);
- dr = Drawable.createFromStream(is, file);
- is.close();
- // System.out.println("Created stream: " + dr);
- } catch (Exception e) {
- NotFoundException rnf = new NotFoundException(
- "File " + file + " from drawable resource ID #0x"
- + Integer.toHexString(id));
- rnf.initCause(e);
- throw rnf;
+
+ String file = value.string.toString();
+
+ if (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie "
+ + value.assetCookie + ": " + file);
+
+ if (file.endsWith(".xml")) {
+ try {
+ XmlResourceParser rp = loadXmlResourceParser(
+ file, id, value.assetCookie, "drawable");
+ dr = Drawable.createFromXml(this, rp);
+ rp.close();
+ } catch (Exception e) {
+ NotFoundException rnf = new NotFoundException(
+ "File " + file + " from drawable resource ID #0x"
+ + Integer.toHexString(id));
+ rnf.initCause(e);
+ throw rnf;
+ }
+
+ } else {
+ try {
+ InputStream is = mAssets.openNonAsset(
+ value.assetCookie, file, AssetManager.ACCESS_BUFFER);
+ // System.out.println("Opened file " + file + ": " + is);
+ dr = Drawable.createFromResourceStream(this, value, is, file);
+ is.close();
+ // System.out.println("Created stream: " + dr);
+ } catch (Exception e) {
+ NotFoundException rnf = new NotFoundException(
+ "File " + file + " from drawable resource ID #0x"
+ + Integer.toHexString(id));
+ rnf.initCause(e);
+ throw rnf;
+ }
}
}
}
@@ -1607,13 +1656,13 @@ public class Resources {
if (cs != null) {
if (mPreloading) {
mPreloadedDrawables.put(key, cs);
- }
- synchronized (mTmpValue) {
- //Log.i(TAG, "Saving cached drawable @ #" +
- // Integer.toHexString(key.intValue())
- // + " in " + this + ": " + cs);
- mDrawableCache.put(
- key, new WeakReference<Drawable.ConstantState>(cs));
+ } else {
+ synchronized (mTmpValue) {
+ //Log.i(TAG, "Saving cached drawable @ #" +
+ // Integer.toHexString(key.intValue())
+ // + " in " + this + ": " + cs);
+ mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
+ }
}
}
}
@@ -1621,7 +1670,7 @@ public class Resources {
return dr;
}
- private final Drawable getCachedDrawable(int key) {
+ private Drawable getCachedDrawable(int key) {
synchronized (mTmpValue) {
WeakReference<Drawable.ConstantState> wr = mDrawableCache.get(key);
if (wr != null) { // we have the key
@@ -1642,13 +1691,40 @@ public class Resources {
/*package*/ ColorStateList loadColorStateList(TypedValue value, int id)
throws NotFoundException {
- if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
- && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
- return ColorStateList.valueOf(value.data);
+ if (TRACE_FOR_PRELOAD) {
+ // Log only framework resources
+ if ((id >>> 24) == 0x1) {
+ final String name = getResourceName(id);
+ if (name != null) android.util.Log.d("PreloadColorStateList", name);
+ }
}
- final int key = (value.assetCookie<<24)|value.data;
- ColorStateList csl = getCachedColorStateList(key);
+ final int key = (value.assetCookie << 24) | value.data;
+
+ ColorStateList csl;
+
+ if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
+ value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+
+ csl = mPreloadedColorStateLists.get(key);
+ if (csl != null) {
+ return csl;
+ }
+
+ csl = ColorStateList.valueOf(value.data);
+ if (mPreloading) {
+ mPreloadedColorStateLists.put(key, csl);
+ }
+
+ return csl;
+ }
+
+ csl = getCachedColorStateList(key);
+ if (csl != null) {
+ return csl;
+ }
+
+ csl = mPreloadedColorStateLists.get(key);
if (csl != null) {
return csl;
}
@@ -1680,12 +1756,16 @@ public class Resources {
}
if (csl != null) {
- synchronized (mTmpValue) {
- //Log.i(TAG, "Saving cached color state list @ #" +
- // Integer.toHexString(key.intValue())
- // + " in " + this + ": " + csl);
- mColorStateListCache.put(
- key, new WeakReference<ColorStateList>(csl));
+ if (mPreloading) {
+ mPreloadedColorStateLists.put(key, csl);
+ } else {
+ synchronized (mTmpValue) {
+ //Log.i(TAG, "Saving cached color state list @ #" +
+ // Integer.toHexString(key.intValue())
+ // + " in " + this + ": " + csl);
+ mColorStateListCache.put(
+ key, new WeakReference<ColorStateList>(csl));
+ }
}
}
diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java
index 3df7708..e684cb8 100644
--- a/core/java/android/content/res/StringBlock.java
+++ b/core/java/android/content/res/StringBlock.java
@@ -141,6 +141,8 @@ final class StringBlock {
int type = style[i];
if (localLOGV) Log.v(TAG, "Applying style span id=" + type
+ ", start=" + style[i+1] + ", end=" + style[i+2]);
+
+
if (type == ids.boldId) {
buffer.setSpan(new StyleSpan(Typeface.BOLD),
style[i+1], style[i+2]+1,
@@ -178,9 +180,8 @@ final class StringBlock {
style[i+1], style[i+2]+1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if (type == ids.listItemId) {
- buffer.setSpan(new BulletSpan(10),
- style[i+1], style[i+2]+1,
- Spannable.SPAN_PARAGRAPH);
+ addParagraphSpan(buffer, new BulletSpan(10),
+ style[i+1], style[i+2]+1);
} else if (type == ids.marqueeId) {
buffer.setSpan(TextUtils.TruncateAt.MARQUEE,
style[i+1], style[i+2]+1,
@@ -194,9 +195,8 @@ final class StringBlock {
sub = subtag(tag, ";height=");
if (sub != null) {
int size = Integer.parseInt(sub);
- buffer.setSpan(new Height(size),
- style[i+1], style[i+2]+1,
- Spannable.SPAN_PARAGRAPH);
+ addParagraphSpan(buffer, new Height(size),
+ style[i+1], style[i+2]+1);
}
sub = subtag(tag, ";size=");
@@ -231,6 +231,28 @@ final class StringBlock {
style[i+1], style[i+2]+1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
+ } else if (tag.startsWith("annotation;")) {
+ int len = tag.length();
+ int next;
+
+ for (int t = tag.indexOf(';'); t < len; t = next) {
+ int eq = tag.indexOf('=', t);
+ if (eq < 0) {
+ break;
+ }
+
+ next = tag.indexOf(';', eq);
+ if (next < 0) {
+ next = len;
+ }
+
+ String key = tag.substring(t + 1, eq);
+ String value = tag.substring(eq + 1, next);
+
+ buffer.setSpan(new Annotation(key, value),
+ style[i+1], style[i+2]+1,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
}
}
@@ -239,6 +261,34 @@ final class StringBlock {
return new SpannedString(buffer);
}
+ /**
+ * If a translator has messed up the edges of paragraph-level markup,
+ * fix it to actually cover the entire paragraph that it is attached to
+ * instead of just whatever range they put it on.
+ */
+ private static void addParagraphSpan(Spannable buffer, Object what,
+ int start, int end) {
+ int len = buffer.length();
+
+ if (start != 0 && start != len && buffer.charAt(start - 1) != '\n') {
+ for (start--; start > 0; start--) {
+ if (buffer.charAt(start - 1) == '\n') {
+ break;
+ }
+ }
+ }
+
+ if (end != 0 && end != len && buffer.charAt(end - 1) != '\n') {
+ for (end++; end < len; end++) {
+ if (buffer.charAt(end - 1) == '\n') {
+ break;
+ }
+ }
+ }
+
+ buffer.setSpan(what, start, end, Spannable.SPAN_PARAGRAPH);
+ }
+
private static String subtag(String full, String attribute) {
int start = full.indexOf(attribute);
if (start < 0) {
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 82a57dd..3a32c03 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -438,6 +438,34 @@ public class TypedArray {
throw new RuntimeException(getPositionDescription()
+ ": You must supply a " + name + " attribute.");
}
+
+ /**
+ * Special version of {@link #getDimensionPixelSize} for retrieving
+ * {@link android.view.ViewGroup}'s layout_width and layout_height
+ * attributes. This is only here for performance reasons; applications
+ * should use {@link #getDimensionPixelSize}.
+ *
+ * @param index Index of the attribute to retrieve.
+ * @param defValue The default value to return if this attribute is not
+ * default or contains the wrong type of data.
+ *
+ * @return Attribute dimension value multiplied by the appropriate
+ * metric and truncated to integer pixels.
+ */
+ public int getLayoutDimension(int index, int defValue) {
+ index *= AssetManager.STYLE_NUM_ENTRIES;
+ final int[] data = mData;
+ final int type = data[index+AssetManager.STYLE_TYPE];
+ if (type >= TypedValue.TYPE_FIRST_INT
+ && type <= TypedValue.TYPE_LAST_INT) {
+ return data[index+AssetManager.STYLE_DATA];
+ } else if (type == TypedValue.TYPE_DIMENSION) {
+ return TypedValue.complexToDimensionPixelSize(
+ data[index+AssetManager.STYLE_DATA], mResources.mMetrics);
+ }
+
+ return defValue;
+ }
/**
* Retrieve a fractional unit attribute at <var>index</var>.
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 2ff7294..10f3806 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -84,6 +84,7 @@ public class DatabaseUtils {
code = 9;
} else {
reply.writeException(e);
+ Log.e(TAG, "Writing exception to parcel", e);
return;
}
reply.writeInt(code);
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index fa062c8..2af080a 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -25,6 +25,7 @@ import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Config;
import android.util.Log;
+import android.util.EventLog;
import java.io.File;
import java.util.HashMap;
@@ -51,7 +52,8 @@ import java.util.concurrent.locks.ReentrantLock;
* is the Unicode Collation Algorithm and not tailored to the current locale.
*/
public class SQLiteDatabase extends SQLiteClosable {
- private final static String TAG = "Database";
+ private static final String TAG = "Database";
+ private static final int DB_OPERATION_EVENT = 52000;
/**
* Algorithms used in ON CONFLICT clause
@@ -207,6 +209,11 @@ public class SQLiteDatabase extends SQLiteClosable {
private WeakHashMap<SQLiteClosable, Object> mPrograms;
private final RuntimeException mLeakedException;
+
+ // package visible, since callers will access directly to minimize overhead in the case
+ // that logging is not enabled.
+ /* package */ final boolean mLogStats;
+
/**
* @param closable
*/
@@ -436,7 +443,14 @@ public class SQLiteDatabase extends SQLiteClosable {
if (mTransactionIsSuccessful) {
execSQL("COMMIT;");
} else {
- execSQL("ROLLBACK;");
+ try {
+ execSQL("ROLLBACK;");
+ } catch (SQLException e) {
+ if (Config.LOGD) {
+ Log.d(TAG, "exception during rollback, maybe the DB previously "
+ + "performed an auto-rollback");
+ }
+ }
}
} finally {
unlockForced();
@@ -764,9 +778,9 @@ public class SQLiteDatabase extends SQLiteClosable {
}
/**
- * Returns the maximum size the database may grow to.
+ * Returns the current database page size, in bytes.
*
- * @return the new maximum database size
+ * @return the database page size, in bytes
*/
public long getPageSize() {
SQLiteStatement prog = null;
@@ -1472,10 +1486,8 @@ public class SQLiteDatabase extends SQLiteClosable {
* @throws SQLException If the SQL string is invalid for some reason
*/
public void execSQL(String sql) throws SQLException {
- long timeStart = 0;
- if (Config.LOGV) {
- timeStart = System.currentTimeMillis();
- }
+ boolean logStats = mLogStats;
+ long timeStart = logStats ? SystemClock.elapsedRealtime() : 0;
lock();
try {
native_execSQL(sql);
@@ -1485,9 +1497,8 @@ public class SQLiteDatabase extends SQLiteClosable {
} finally {
unlock();
}
- if (Config.LOGV) {
- long timeEnd = System.currentTimeMillis();
- Log.v(TAG, "Executed (" + (timeEnd - timeStart) + " ms):" + sql);
+ if (logStats) {
+ logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime());
}
}
@@ -1504,10 +1515,9 @@ public class SQLiteDatabase extends SQLiteClosable {
if (bindArgs == null) {
throw new IllegalArgumentException("Empty bindArgs");
}
- long timeStart = 0;
- if (Config.LOGV) {
- timeStart = System.currentTimeMillis();
- }
+
+ boolean logStats = mLogStats;
+ long timeStart = logStats ? SystemClock.elapsedRealtime() : 0;
lock();
SQLiteStatement statement = null;
try {
@@ -1528,9 +1538,8 @@ public class SQLiteDatabase extends SQLiteClosable {
}
unlock();
}
- if (Config.LOGV) {
- long timeEnd = System.currentTimeMillis();
- Log.v(TAG, "Executed (" + (timeEnd - timeStart) + " ms):" + sql);
+ if (logStats) {
+ logTimeStat(false /* not a read */, timeStart, SystemClock.elapsedRealtime());
}
}
@@ -1550,7 +1559,7 @@ public class SQLiteDatabase extends SQLiteClosable {
}
/**
- * Private constructor. See {@link createDatabase} and {@link openDatabase}.
+ * Private constructor. See {@link #create} and {@link #openDatabase}.
*
* @param path The full path to the database
* @param factory The factory to use when creating cursors, may be NULL.
@@ -1563,6 +1572,8 @@ public class SQLiteDatabase extends SQLiteClosable {
}
mFlags = flags;
mPath = path;
+ mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats"));
+
mLeakedException = new IllegalStateException(path +
" SQLiteDatabase created and never closed");
mFactory = factory;
@@ -1605,6 +1616,10 @@ public class SQLiteDatabase extends SQLiteClosable {
return mPath;
}
+ /* package */ void logTimeStat(boolean read, long begin, long end) {
+ EventLog.writeEvent(DB_OPERATION_EVENT, mPath, read ? 0 : 1, end - begin);
+ }
+
/**
* Sets the locale for this database. Does nothing if this database has
* the NO_LOCALIZED_COLLATORS flag set or was opened read only.
@@ -1629,7 +1644,7 @@ public class SQLiteDatabase extends SQLiteClosable {
private native void dbopen(String path, int flags);
/**
- * Native call to execute a raw SQL statement. {@link mLock} must be held
+ * Native call to execute a raw SQL statement. {@link #lock} must be held
* when calling this method.
*
* @param sql The raw SQL string
@@ -1638,7 +1653,7 @@ public class SQLiteDatabase extends SQLiteClosable {
/* package */ native void native_execSQL(String sql) throws SQLException;
/**
- * Native call to set the locale. {@link mLock} must be held when calling
+ * Native call to set the locale. {@link #lock} must be held when calling
* this method.
* @throws SQLException
*/
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 35bf645..52aac3a 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -26,6 +26,8 @@ import android.util.Log;
* optionally {@link #onOpen}, and this class takes care of opening the database
* if it exists, creating it if it does not, and upgrading it as necessary.
* Transactions are used to make sure the database is always in a sensible state.
+ * <p>For an example, see the NotePadProvider class in the NotePad sample application,
+ * in the <em>samples/</em> directory of the SDK.</p>
*/
public abstract class SQLiteOpenHelper {
private static final String TAG = SQLiteOpenHelper.class.getSimpleName();
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index f89c87d..9e85452 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -22,7 +22,7 @@ import android.util.Log;
* A base class for compiled SQLite programs.
*/
public abstract class SQLiteProgram extends SQLiteClosable {
- static final String TAG = "SQLiteProgram";
+ private static final String TAG = "SQLiteProgram";
/** The database this program is compiled against. */
protected SQLiteDatabase mDatabase;
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index 22c53ab..1386a0d 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -17,13 +17,15 @@
package android.database.sqlite;
import android.database.CursorWindow;
+import android.os.SystemClock;
+import android.util.Log;
/**
* A SQLite program that represents a query that reads the resulting rows into a CursorWindow.
* This class is used by SQLiteCursor and isn't useful itself.
*/
public class SQLiteQuery extends SQLiteProgram {
- //private static final String TAG = "Cursor";
+ private static final String TAG = "Cursor";
/** The index of the unbound OFFSET parameter */
private int mOffsetIndex;
@@ -55,12 +57,14 @@ public class SQLiteQuery extends SQLiteProgram {
* Reads rows into a buffer. This method acquires the database lock.
*
* @param window The window to fill into
- * @param startPos The position to start reading rows from
* @return number of total rows in the query
*/
/* package */ int fillWindow(CursorWindow window,
int maxRead, int lastPos) {
mDatabase.lock();
+
+ boolean logStats = mDatabase.mLogStats;
+ long startTime = logStats ? SystemClock.elapsedRealtime() : 0;
try {
acquireReference();
try {
@@ -68,8 +72,18 @@ public class SQLiteQuery extends SQLiteProgram {
// if the start pos is not equal to 0, then most likely window is
// too small for the data set, loading by another thread
// is not safe in this situation. the native code will ignore maxRead
- return native_fill_window(window, window.getStartPosition(), mOffsetIndex,
+ int numRows = native_fill_window(window, window.getStartPosition(), mOffsetIndex,
maxRead, lastPos);
+
+ // Logging
+ if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
+ Log.d(TAG, "fillWindow(): " + mQuery);
+ }
+ if (logStats) {
+ mDatabase.logTimeStat(true /* read */, startTime,
+ SystemClock.elapsedRealtime());
+ }
+ return numRows;
} catch (IllegalStateException e){
// simply ignore it
return 0;
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index bf9361d..5889ad9 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -16,6 +16,9 @@
package android.database.sqlite;
+import android.os.SystemClock;
+import android.util.Log;
+
/**
* A pre-compiled statement against a {@link SQLiteDatabase} that can be reused.
* The statement cannot return multiple rows, but 1x1 result sets are allowed.
@@ -24,6 +27,10 @@ package android.database.sqlite;
*/
public class SQLiteStatement extends SQLiteProgram
{
+ private static final String TAG = "SQLiteStatement";
+
+ private final String mSql;
+
/**
* Don't use SQLiteStatement constructor directly, please use
* {@link SQLiteDatabase#compileStatement(String)}
@@ -32,6 +39,11 @@ public class SQLiteStatement extends SQLiteProgram
*/
/* package */ SQLiteStatement(SQLiteDatabase db, String sql) {
super(db, sql);
+ if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
+ mSql = sql;
+ } else {
+ mSql = null;
+ }
}
/**
@@ -43,10 +55,19 @@ public class SQLiteStatement extends SQLiteProgram
*/
public void execute() {
mDatabase.lock();
+ boolean logStats = mDatabase.mLogStats;
+ long startTime = logStats ? SystemClock.elapsedRealtime() : 0;
+
acquireReference();
try {
+ if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
+ Log.v(TAG, "execute() for [" + mSql + "]");
+ }
native_execute();
- } finally {
+ if (logStats) {
+ mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime());
+ }
+ } finally {
releaseReference();
mDatabase.unlock();
}
@@ -64,9 +85,18 @@ public class SQLiteStatement extends SQLiteProgram
*/
public long executeInsert() {
mDatabase.lock();
+ boolean logStats = mDatabase.mLogStats;
+ long startTime = logStats ? SystemClock.elapsedRealtime() : 0;
+
acquireReference();
try {
+ if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
+ Log.v(TAG, "executeInsert() for [" + mSql + "]");
+ }
native_execute();
+ if (logStats) {
+ mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime());
+ }
return mDatabase.lastInsertRow();
} finally {
releaseReference();
@@ -84,9 +114,19 @@ public class SQLiteStatement extends SQLiteProgram
*/
public long simpleQueryForLong() {
mDatabase.lock();
+ boolean logStats = mDatabase.mLogStats;
+ long startTime = logStats ? SystemClock.elapsedRealtime() : 0;
+
acquireReference();
try {
- return native_1x1_long();
+ if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
+ Log.v(TAG, "simpleQueryForLong() for [" + mSql + "]");
+ }
+ long retValue = native_1x1_long();
+ if (logStats) {
+ mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime());
+ }
+ return retValue;
} finally {
releaseReference();
mDatabase.unlock();
@@ -103,9 +143,19 @@ public class SQLiteStatement extends SQLiteProgram
*/
public String simpleQueryForString() {
mDatabase.lock();
+ boolean logStats = mDatabase.mLogStats;
+ long startTime = logStats ? SystemClock.elapsedRealtime() : 0;
+
acquireReference();
try {
- return native_1x1_string();
+ if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
+ Log.v(TAG, "simpleQueryForString() for [" + mSql + "]");
+ }
+ String retValue = native_1x1_string();
+ if (logStats) {
+ mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime());
+ }
+ return retValue;
} finally {
releaseReference();
mDatabase.unlock();
diff --git a/core/java/android/database/sqlite/package.html b/core/java/android/database/sqlite/package.html
index c03a8dc..ff0f9f5 100644
--- a/core/java/android/database/sqlite/package.html
+++ b/core/java/android/database/sqlite/package.html
@@ -6,7 +6,7 @@ classes that an application would use to manage its own private database.
Applications use these classes to maange private databases. If creating a
content provider, you will probably have to use these classes to create and
manage your own database to store content. See <a
-href="{@docRoot}devel/data.html">Storing, Retrieving and Exposing Data</a> to learn
+href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> to learn
the conventions for implementing a content provider. See the
NotePadProvider class in the NotePad sample application in the SDK for an
example of a content provider. Android ships with SQLite version 3.4.0
diff --git a/core/java/android/emoji/EmojiFactory.java b/core/java/android/emoji/EmojiFactory.java
new file mode 100644
index 0000000..389bd07
--- /dev/null
+++ b/core/java/android/emoji/EmojiFactory.java
@@ -0,0 +1,273 @@
+/*
+ * 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 android.emoji;
+
+import android.graphics.Bitmap;
+
+import java.lang.ref.WeakReference;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * A class for the factories which produce Emoji (pictgram) images.
+ * This is intended to be used by IME, Email app, etc.
+ * There's no plan to make this public for now.
+ * @hide
+ */
+public final class EmojiFactory {
+ // private static final String LOG_TAG = "EmojiFactory";
+
+ private int sCacheSize = 100;
+
+ // HashMap for caching Bitmap object. In order not to make an cache object
+ // blow up, we use LinkedHashMap with size limit.
+ private class CustomLinkedHashMap<K, V> extends LinkedHashMap<K, V> {
+ public CustomLinkedHashMap() {
+ // These magic numbers are gotten from the source code of
+ // LinkedHashMap.java and HashMap.java.
+ super(16, 0.75f, true);
+ }
+
+ /*
+ * If size() becomes more than sCacheSize, least recently used cache
+ * is erased.
+ * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry)
+ */
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+ return size() > sCacheSize;
+ }
+ }
+
+ // A pointer to native EmojiFactory object.
+ private int mNativeEmojiFactory;
+ private String mName;
+ // Cache.
+ private Map<Integer, WeakReference<Bitmap>> mCache;
+
+ /**
+ * @noinspection UnusedDeclaration
+ */
+ /*
+ * Private constructor that must received an already allocated native
+ * EmojiFactory int (pointer).
+ *
+ * This can be called from JNI code.
+ */
+ private EmojiFactory(int nativeEmojiFactory, String name) {
+ mNativeEmojiFactory = nativeEmojiFactory;
+ mName = name;
+ mCache = new CustomLinkedHashMap<Integer, WeakReference<Bitmap>>();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ nativeDestructor(mNativeEmojiFactory);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ public String name() {
+ return mName;
+ }
+
+ /**
+ * Returns Bitmap object corresponding to the AndroidPua.
+ *
+ * Note that each Bitmap is cached by this class, which means that, if you modify a
+ * Bitmap object (using setPos() method), all same emoji Bitmap will be modified.
+ * If it is unacceptable, please copy the object before modifying it.
+ *
+ * @param pua A unicode codepoint.
+ * @return Bitmap object when this factory knows the Bitmap relevant to the codepoint.
+ * Otherwise null is returned.
+ */
+ public synchronized Bitmap getBitmapFromAndroidPua(int pua) {
+ WeakReference<Bitmap> cache = mCache.get(pua);
+ if (cache == null) {
+ Bitmap ret = nativeGetBitmapFromAndroidPua(mNativeEmojiFactory, pua);
+ // There is no need to cache returned null, since in most cases it means there
+ // is no map from the AndroidPua to a specific image. In other words, it usually does
+ // not include the cost of creating Bitmap object.
+ if (ret != null) {
+ mCache.put(pua, new WeakReference<Bitmap>(ret));
+ }
+ return ret;
+ } else {
+ Bitmap tmp = cache.get();
+ if (tmp == null) {
+ Bitmap ret = nativeGetBitmapFromAndroidPua(mNativeEmojiFactory, pua);
+ mCache.put(pua, new WeakReference<Bitmap>(ret));
+ return ret;
+ } else {
+ return tmp;
+ }
+ }
+ }
+
+ /**
+ * Returns Bitmap object corresponding to the vendor specified sjis.
+ *
+ * See comments in getBitmapFromAndroidPua().
+ *
+ * @param sjis sjis code specific to each career(vendor)
+ * @return Bitmap object when this factory knows the Bitmap relevant to the code. Otherwise
+ * null is returned.
+ */
+ public synchronized Bitmap getBitmapFromVendorSpecificSjis(char sjis) {
+ return getBitmapFromAndroidPua(getAndroidPuaFromVendorSpecificSjis(sjis));
+ }
+
+ /**
+ * Returns Bitmap object corresponding to the vendor specific Unicode.
+ *
+ * See comments in getBitmapFromAndroidPua().
+ *
+ * @param vsp vendor specific PUA.
+ * @return Bitmap object when this factory knows the Bitmap relevant to the code. Otherwise
+ * null is returned.
+ */
+ public synchronized Bitmap getBitmapFromVendorSpecificPua(int vsp) {
+ return getBitmapFromAndroidPua(getAndroidPuaFromVendorSpecificPua(vsp));
+ }
+
+ /**
+ * Returns Unicode PUA for Android corresponding to the vendor specific sjis.
+ *
+ * @param sjis vendor specific sjis
+ * @return Unicode PUA for Android, or -1 if there's no map for the sjis.
+ */
+ public int getAndroidPuaFromVendorSpecificSjis(char sjis) {
+ return nativeGetAndroidPuaFromVendorSpecificSjis(mNativeEmojiFactory, sjis);
+ }
+
+ /**
+ * Returns vendor specific sjis corresponding to the Unicode AndroidPua.
+ *
+ * @param pua Unicode PUA for Android,
+ * @return vendor specific sjis, or -1 if there's no map for the AndroidPua.
+ */
+ public int getVendorSpecificSjisFromAndroidPua(int pua) {
+ return nativeGetVendorSpecificSjisFromAndroidPua(mNativeEmojiFactory, pua);
+ }
+
+ /**
+ * Returns Unicode PUA for Android corresponding to the vendor specific Unicode.
+ *
+ * @param vsp vendor specific PUA.
+ * @return Unicode PUA for Android, or -1 if there's no map for the
+ * Unicode.
+ */
+ public int getAndroidPuaFromVendorSpecificPua(int vsp) {
+ return nativeGetAndroidPuaFromVendorSpecificPua(mNativeEmojiFactory, vsp);
+ }
+
+ public String getAndroidPuaFromVendorSpecificPua(String vspString) {
+ if (vspString == null) {
+ return null;
+ }
+ int minVsp = nativeGetMinimumVendorSpecificPua(mNativeEmojiFactory);
+ int maxVsp = nativeGetMaximumVendorSpecificPua(mNativeEmojiFactory);
+ int len = vspString.length();
+ int[] codePoints = new int[vspString.codePointCount(0, len)];
+
+ int new_len = 0;
+ for (int i = 0; i < len; i = vspString.offsetByCodePoints(i, 1), new_len++) {
+ int codePoint = vspString.codePointAt(i);
+ if (minVsp <= codePoint && codePoint <= maxVsp) {
+ int newCodePoint = getAndroidPuaFromVendorSpecificPua(codePoint);
+ if (newCodePoint > 0) {
+ codePoints[new_len] = newCodePoint;
+ continue;
+ }
+ }
+ codePoints[new_len] = codePoint;
+ }
+ return new String(codePoints, 0, new_len);
+ }
+
+ /**
+ * Returns vendor specific Unicode corresponding to the Unicode AndroidPua.
+ *
+ * @param pua Unicode PUA for Android,
+ * @return vendor specific sjis, or -1 if there's no map for the AndroidPua.
+ */
+ public int getVendorSpecificPuaFromAndroidPua(int pua) {
+ return nativeGetVendorSpecificPuaFromAndroidPua(mNativeEmojiFactory, pua);
+ }
+
+ public String getVendorSpecificPuaFromAndroidPua(String puaString) {
+ if (puaString == null) {
+ return null;
+ }
+ int minVsp = nativeGetMinimumAndroidPua(mNativeEmojiFactory);
+ int maxVsp = nativeGetMaximumAndroidPua(mNativeEmojiFactory);
+ int len = puaString.length();
+ int[] codePoints = new int[puaString.codePointCount(0, len)];
+
+ int new_len = 0;
+ for (int i = 0; i < len; i = puaString.offsetByCodePoints(i, 1), new_len++) {
+ int codePoint = puaString.codePointAt(i);
+ if (minVsp <= codePoint && codePoint <= maxVsp) {
+ int newCodePoint = getVendorSpecificPuaFromAndroidPua(codePoint);
+ if (newCodePoint > 0) {
+ codePoints[new_len] = newCodePoint;
+ continue;
+ }
+ }
+ codePoints[new_len] = codePoint;
+ }
+ return new String(codePoints, 0, new_len);
+ }
+
+ /**
+ * Constructs an instance of EmojiFactory corresponding to the name.
+ *
+ * @param class_name Name of the factory. This must include complete package name.
+ * @return A concrete EmojiFactory instance corresponding to factory_name.
+ * If factory_name is invalid, null is returned.
+ */
+ public static native EmojiFactory newInstance(String class_name);
+
+ /**
+ * Constructs an instance of available EmojiFactory.
+ *
+ * @return A concrete EmojiFactory instance. If there are several available
+ * EmojiFactory class, preferred one is chosen by the system. If there isn't, null
+ * is returned.
+ */
+ public static native EmojiFactory newAvailableInstance();
+
+ // native methods
+
+ private native void nativeDestructor(int factory);
+ private native Bitmap nativeGetBitmapFromAndroidPua(int nativeEmojiFactory, int AndroidPua);
+ private native int nativeGetAndroidPuaFromVendorSpecificSjis(int nativeEmojiFactory,
+ char sjis);
+ private native int nativeGetVendorSpecificSjisFromAndroidPua(int nativeEmojiFactory,
+ int pua);
+ private native int nativeGetAndroidPuaFromVendorSpecificPua(int nativeEmojiFactory,
+ int vsp);
+ private native int nativeGetVendorSpecificPuaFromAndroidPua(int nativeEmojiFactory,
+ int pua);
+ private native int nativeGetMaximumVendorSpecificPua(int nativeEmojiFactory);
+ private native int nativeGetMinimumVendorSpecificPua(int nativeEmojiFactory);
+ private native int nativeGetMaximumAndroidPua(int nativeEmojiFactory);
+ private native int nativeGetMinimumAndroidPua(int nativeEmojiFactory);
+}
diff --git a/core/java/android/gadget/GadgetHost.java b/core/java/android/gadget/GadgetHost.java
deleted file mode 100644
index 418f2aa..0000000
--- a/core/java/android/gadget/GadgetHost.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2006 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 android.gadget;
-
-import android.content.Context;
-import android.widget.RemoteViews;
-
-/**
- * GadgetHost provides the interaction with the Gadget Service for apps,
- * like the home screen, that want to embed gadgets in their UI.
- */
-public class GadgetHost {
- public GadgetHost(Context context, int hostId) {
- }
-
- /**
- * Start receiving onGadgetChanged calls for your gadgets. Call this when your activity
- * becomes visible, i.e. from onStart() in your Activity.
- */
- public void startListening() {
- }
-
- /**
- * Stop receiving onGadgetChanged calls for your gadgets. Call this when your activity is
- * no longer visible, i.e. from onStop() in your Activity.
- */
- public void stopListening() {
- }
-
- /**
- * Stop listening to changes for this gadget.
- */
- public void gadgetRemoved(int gadgetId) {
- }
-
- /**
- * Remove all records about gadget instances from the gadget manager. Call this when
- * initializing your database, as it might be because of a data wipe.
- */
- public void clearGadgets() {
- }
-
- public final GadgetHostView createView(Context context, int gadgetId, GadgetInfo gadget) {
- GadgetHostView view = onCreateView(context, gadgetId, gadget);
- view.setGadget(gadgetId, gadget);
- view.updateGadget(null);
- return view;
- }
-
- /**
- * Called to create the GadgetHostView. Override to return a custom subclass if you
- * need it. {@more}
- */
- protected GadgetHostView onCreateView(Context context, int gadgetId, GadgetInfo gadget) {
- return new GadgetHostView(context);
- }
-}
-
diff --git a/core/java/android/gadget/GadgetHostView.java b/core/java/android/gadget/GadgetHostView.java
deleted file mode 100644
index e2bef8c..0000000
--- a/core/java/android/gadget/GadgetHostView.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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 android.gadget;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.gadget.GadgetInfo;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.RemoteViews;
-import android.widget.TextView;
-
-public class GadgetHostView extends FrameLayout {
- static final String TAG = "GadgetHostView";
-
- // When we're inflating the initialLayout for a gadget, we only allow
- // views that are allowed in RemoteViews.
- static final LayoutInflater.Filter sInflaterFilter = new LayoutInflater.Filter() {
- public boolean onLoadClass(Class clazz) {
- return clazz.isAnnotationPresent(RemoteViews.RemoteView.class);
- }
- };
-
- int mGadgetId;
- GadgetInfo mInfo;
- View mContentView;
-
- public GadgetHostView(Context context) {
- super(context);
- }
-
- public void setGadget(int gadgetId, GadgetInfo info) {
- if (mInfo != null) {
- // TODO: remove the old view, or whatever
- }
- mGadgetId = gadgetId;
- mInfo = info;
- }
-
- public void updateGadget(RemoteViews remoteViews) {
- Context context = getContext();
-
- View contentView = null;
- Exception exception = null;
- try {
- if (remoteViews == null) {
- // there is no remoteViews (yet), so use the initial layout
- Context theirContext = context.createPackageContext(mInfo.provider.getPackageName(),
- 0);
- LayoutInflater inflater = (LayoutInflater)theirContext.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- inflater = inflater.cloneInContext(theirContext);
- inflater.setFilter(sInflaterFilter);
- contentView = inflater.inflate(mInfo.initialLayout, this, false);
- } else {
- // use the RemoteViews
- contentView = remoteViews.apply(mContext, this);
- }
- }
- catch (PackageManager.NameNotFoundException e) {
- exception = e;
- }
- catch (RuntimeException e) {
- exception = e;
- }
- if (contentView == null) {
- Log.w(TAG, "Error inflating gadget " + mInfo, exception);
- // TODO: Should we throw an exception here for the host activity to catch?
- // Maybe we should show a generic error widget.
- TextView tv = new TextView(context);
- tv.setText("Error inflating gadget");
- contentView = tv;
- }
-
- FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- FrameLayout.LayoutParams.WRAP_CONTENT);
-
- mContentView = contentView;
- this.addView(contentView, lp);
-
- // TODO: do an animation (maybe even one provided by the gadget).
- }
-}
-
diff --git a/core/java/android/gadget/GadgetInfo.java b/core/java/android/gadget/GadgetInfo.java
deleted file mode 100644
index 1a7a9a0..0000000
--- a/core/java/android/gadget/GadgetInfo.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2006 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 android.gadget;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.content.ComponentName;
-
-/**
- * Describes the meta data for an installed gadget.
- */
-public class GadgetInfo implements Parcelable {
- /**
- * Identity of this gadget component. This component should be a {@link
- * android.content.BroadcastReceiver}, and it will be sent the Gadget intents
- * {@link android.gadget as described in the gadget package documentation}.
- */
- public ComponentName provider;
-
- /**
- * Minimum width of the gadget, in dp.
- */
- public int minWidth;
-
- /**
- * Minimum height of the gadget, in dp.
- */
- public int minHeight;
-
- /**
- * How often, in milliseconds, that this gadget wants to be updated.
- * The gadget manager may place a limit on how often a gadget is updated.
- */
- public int updatePeriodMillis;
-
- /**
- * The resource id of the initial layout for this gadget. This should be
- * displayed until the RemoteViews for the gadget is available.
- */
- public int initialLayout;
-
- /**
- * The activity to launch that will configure the gadget.
- */
- public ComponentName configure;
-
- public GadgetInfo() {
- }
-
- /**
- * Unflatten the GadgetInfo from a parcel.
- */
- public GadgetInfo(Parcel in) {
- if (0 != in.readInt()) {
- this.provider = new ComponentName(in);
- }
- this.minWidth = in.readInt();
- this.minHeight = in.readInt();
- this.updatePeriodMillis = in.readInt();
- this.initialLayout = in.readInt();
- if (0 != in.readInt()) {
- this.configure = new ComponentName(in);
- }
- }
-
-
- public void writeToParcel(android.os.Parcel out, int flags) {
- if (this.provider != null) {
- out.writeInt(1);
- this.provider.writeToParcel(out, flags);
- } else {
- out.writeInt(0);
- }
- out.writeInt(this.minWidth);
- out.writeInt(this.minHeight);
- out.writeInt(this.updatePeriodMillis);
- out.writeInt(this.initialLayout);
- if (this.configure != null) {
- out.writeInt(1);
- this.configure.writeToParcel(out, flags);
- } else {
- out.writeInt(0);
- }
- }
-
- public int describeContents() {
- return 0;
- }
-
- /**
- * Parcelable.Creator that instantiates GadgetInfo objects
- */
- public static final Parcelable.Creator<GadgetInfo> CREATOR
- = new Parcelable.Creator<GadgetInfo>()
- {
- public GadgetInfo createFromParcel(Parcel parcel)
- {
- return new GadgetInfo(parcel);
- }
-
- public GadgetInfo[] newArray(int size)
- {
- return new GadgetInfo[size];
- }
- };
-
- public String toString() {
- return "GadgetInfo(provider=" + this.provider + ")";
- }
-}
-
-
diff --git a/core/java/android/gadget/GadgetManager.java b/core/java/android/gadget/GadgetManager.java
deleted file mode 100644
index 088dc86..0000000
--- a/core/java/android/gadget/GadgetManager.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2006 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 android.gadget;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-import android.widget.RemoteViews;
-
-import com.android.internal.gadget.IGadgetService;
-
-import java.lang.ref.WeakReference;
-import java.util.List;
-import java.util.WeakHashMap;
-
-public class GadgetManager {
- static final String TAG = "GadgetManager";
-
- /**
- * Send this when you want to pick a gadget to display.
- *
- * <p>
- * The system will respond with an onActivityResult call with the following extras in
- * the intent:
- * <ul>
- * <li><b>gadgetId</b></li>
- * <li><b>gadgetId</b></li>
- * <li><b>gadgetId</b></li>
- * </ul>
- * TODO: Add constants for these.
- * TODO: Where does this go?
- */
- public static final String GADGET_PICK_ACTION = "android.gadget.action.PICK_GADGET";
-
- public static final String EXTRA_GADGET_ID = "gadgetId";
-
- /**
- * Sent when it is time to update your gadget.
- */
- public static final String GADGET_UPDATE_ACTION = "android.gadget.action.GADGET_UPDATE";
-
- /**
- * Sent when the gadget is added to a host for the first time. TODO: Maybe we don't want this.
- */
- public static final String GADGET_ENABLE_ACTION = "android.gadget.action.GADGET_ENABLE";
-
- /**
- * Sent when the gadget is removed from the last host. TODO: Maybe we don't want this.
- */
- public static final String GADGET_DISABLE_ACTION = "android.gadget.action.GADGET_DISABLE";
-
- /**
- * Field for the manifest meta-data tag.
- */
- public static final String GADGET_PROVIDER_META_DATA = "android.gadget.provider";
-
- static WeakHashMap<Context, WeakReference<GadgetManager>> sManagerCache = new WeakHashMap();
- static IGadgetService sService;
-
- Context mContext;
-
- public static GadgetManager getInstance(Context context) {
- synchronized (sManagerCache) {
- if (sService == null) {
- IBinder b = ServiceManager.getService(Context.GADGET_SERVICE);
- sService = IGadgetService.Stub.asInterface(b);
- }
-
- WeakReference<GadgetManager> ref = sManagerCache.get(context);
- GadgetManager result = null;
- if (ref != null) {
- result = ref.get();
- }
- if (result == null) {
- result = new GadgetManager(context);
- sManagerCache.put(context, new WeakReference(result));
- }
- return result;
- }
- }
-
- private GadgetManager(Context context) {
- mContext = context;
- }
-
- /**
- * Call this with the new RemoteViews for your gadget whenever you need to.
- *
- * <p>
- * This method will only work when called from the uid that owns the gadget provider.
- *
- * @param gadgetId The gadget instance for which to set the RemoteViews.
- * @param views The RemoteViews object to show.
- */
- public void updateGadget(int gadgetId, RemoteViews views) {
- }
-
- /**
- * Return a list of the gadget providers that are currently installed.
- */
- public List<GadgetInfo> getInstalledProviders() {
- try {
- return sService.getInstalledProviders();
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
- }
- }
-
- /**
- * Get the available info about the gadget. If the gadgetId has not been bound yet,
- * this method will return null.
- *
- * TODO: throws GadgetNotFoundException ??? if not valid
- */
- public GadgetInfo getGadgetInfo(int gadgetId) {
- try {
- return sService.getGadgetInfo(gadgetId);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
- }
- }
-
- /**
- * Get a gadgetId for a host in the calling process.
- *
- * @return a gadgetId
- */
- public int allocateGadgetId(String hostPackage) {
- try {
- return sService.allocateGadgetId(hostPackage);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
- }
- }
-
- /**
- * Delete the gadgetId. Same as removeGadget on GadgetHost.
- */
- public void deleteGadgetId(int gadgetId) {
- try {
- sService.deleteGadgetId(gadgetId);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
- }
- }
-
- /**
- * Set the component for a given gadgetId. You need the GADGET_LIST permission.
- */
- public void bindGadgetId(int gadgetId, ComponentName provider) {
- try {
- sService.bindGadgetId(gadgetId, provider);
- }
- catch (RemoteException e) {
- throw new RuntimeException("system server dead?", e);
- }
- }
-}
-
diff --git a/core/java/android/gadget/package.html b/core/java/android/gadget/package.html
deleted file mode 100644
index 280ccfb..0000000
--- a/core/java/android/gadget/package.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<body>
-@hide
-</body>
-
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index c09567c..106c920 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -18,6 +18,7 @@ package android.hardware;
import java.lang.ref.WeakReference;
import java.util.HashMap;
+import java.util.StringTokenizer;
import java.io.IOException;
import android.util.Log;
@@ -47,7 +48,6 @@ public class Camera {
private static final int ERROR_CALLBACK = 5;
private int mNativeContext; // accessed by native methods
- private int mListenerContext;
private EventHandler mEventHandler;
private ShutterCallback mShutterCallback;
private PictureCallback mRawImageCallback;
@@ -494,11 +494,17 @@ public class Camera {
*/
public void unflatten(String flattened) {
mMap.clear();
- String[] pairs = flattened.split(";");
- for (String p : pairs) {
- String[] kv = p.split("=");
- if (kv.length == 2)
- mMap.put(kv[0], kv[1]);
+
+ StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
+ while (tokenizer.hasMoreElements()) {
+ String kv = tokenizer.nextToken();
+ int pos = kv.indexOf('=');
+ if (pos == -1) {
+ continue;
+ }
+ String k = kv.substring(0, pos);
+ String v = kv.substring(pos + 1);
+ mMap.put(k, v);
}
}
diff --git a/core/java/android/hardware/GeomagneticField.java b/core/java/android/hardware/GeomagneticField.java
new file mode 100644
index 0000000..b4c04b1
--- /dev/null
+++ b/core/java/android/hardware/GeomagneticField.java
@@ -0,0 +1,409 @@
+/*
+ * 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 android.hardware;
+
+import java.util.GregorianCalendar;
+
+/**
+ * This class is used to estimated estimate magnetic field at a given point on
+ * Earth, and in particular, to compute the magnetic declination from true
+ * north.
+ *
+ * <p>This uses the World Magnetic Model produced by the United States National
+ * Geospatial-Intelligence Agency. More details about the model can be found at
+ * <a href="http://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml">http://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml</a>.
+ * This class currently uses WMM-2005 which is valid until 2010, but should
+ * produce acceptable results for several years after that.
+ */
+public class GeomagneticField {
+ // The magnetic field at a given point, in nonoteslas in geodetic
+ // coordinates.
+ private float mX;
+ private float mY;
+ private float mZ;
+
+ // Geocentric coordinates -- set by computeGeocentricCoordinates.
+ private float mGcLatitudeRad;
+ private float mGcLongitudeRad;
+ private float mGcRadiusKm;
+
+ // Constants from WGS84 (the coordinate system used by GPS)
+ static private final float EARTH_SEMI_MAJOR_AXIS_KM = 6378.137f;
+ static private final float EARTH_SEMI_MINOR_AXIS_KM = 6356.7523f;
+ static private final float EARTH_REFERENCE_RADIUS_KM = 6371.2f;
+
+ // These coefficients and the formulae used below are from:
+ // NOAA Technical Report: The US/UK World Magnetic Model for 2005-2010
+ static private final float[][] G_COEFF = new float[][] {
+ { 0f },
+ { -29556.8f, -1671.7f },
+ { -2340.6f, 3046.9f, 1657.0f },
+ { 1335.4f, -2305.1f, 1246.7f, 674.0f },
+ { 919.8f, 798.1f, 211.3f, -379.4f, 100.0f },
+ { -227.4f, 354.6f, 208.7f, -136.5f, -168.3f, -14.1f },
+ { 73.2f, 69.7f, 76.7f, -151.2f, -14.9f, 14.6f, -86.3f },
+ { 80.1f, -74.5f, -1.4f, 38.5f, 12.4f, 9.5f, 5.7f, 1.8f },
+ { 24.9f, 7.7f, -11.6f, -6.9f, -18.2f, 10.0f, 9.2f, -11.6f, -5.2f },
+ { 5.6f, 9.9f, 3.5f, -7.0f, 5.1f, -10.8f, -1.3f, 8.8f, -6.7f, -9.1f },
+ { -2.3f, -6.3f, 1.6f, -2.6f, 0.0f, 3.1f, 0.4f, 2.1f, 3.9f, -0.1f, -2.3f },
+ { 2.8f, -1.6f, -1.7f, 1.7f, -0.1f, 0.1f, -0.7f, 0.7f, 1.8f, 0.0f, 1.1f, 4.1f },
+ { -2.4f, -0.4f, 0.2f, 0.8f, -0.3f, 1.1f, -0.5f, 0.4f, -0.3f, -0.3f, -0.1f,
+ -0.3f, -0.1f } };
+
+ static private final float[][] H_COEFF = new float[][] {
+ { 0f },
+ { 0.0f, 5079.8f },
+ { 0.0f, -2594.7f, -516.7f },
+ { 0.0f, -199.9f, 269.3f, -524.2f },
+ { 0.0f, 281.5f, -226.0f, 145.8f, -304.7f },
+ { 0.0f, 42.4f, 179.8f, -123.0f, -19.5f, 103.6f },
+ { 0.0f, -20.3f, 54.7f, 63.6f, -63.4f, -0.1f, 50.4f },
+ { 0.0f, -61.5f, -22.4f, 7.2f, 25.4f, 11.0f, -26.4f, -5.1f },
+ { 0.0f, 11.2f, -21.0f, 9.6f, -19.8f, 16.1f, 7.7f, -12.9f, -0.2f },
+ { 0.0f, -20.1f, 12.9f, 12.6f, -6.7f, -8.1f, 8.0f, 2.9f, -7.9f, 6.0f },
+ { 0.0f, 2.4f, 0.2f, 4.4f, 4.8f, -6.5f, -1.1f, -3.4f, -0.8f, -2.3f, -7.9f },
+ { 0.0f, 0.3f, 1.2f, -0.8f, -2.5f, 0.9f, -0.6f, -2.7f, -0.9f, -1.3f, -2.0f, -1.2f },
+ { 0.0f, -0.4f, 0.3f, 2.4f, -2.6f, 0.6f, 0.3f, 0.0f, 0.0f, 0.3f, -0.9f, -0.4f,
+ 0.8f } };
+
+ static private final float[][] DELTA_G = new float[][] {
+ { 0f },
+ { 8.0f, 10.6f },
+ { -15.1f, -7.8f, -0.8f },
+ { 0.4f, -2.6f, -1.2f, -6.5f },
+ { -2.5f, 2.8f, -7.0f, 6.2f, -3.8f },
+ { -2.8f, 0.7f, -3.2f, -1.1f, 0.1f, -0.8f },
+ { -0.7f, 0.4f, -0.3f, 2.3f, -2.1f, -0.6f, 1.4f },
+ { 0.2f, -0.1f, -0.3f, 1.1f, 0.6f, 0.5f, -0.4f, 0.6f },
+ { 0.1f, 0.3f, -0.4f, 0.3f, -0.3f, 0.2f, 0.4f, -0.7f, 0.4f },
+ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } };
+
+ static private final float[][] DELTA_H = new float[][] {
+ { 0f },
+ { 0.0f, -20.9f },
+ { 0.0f, -23.2f, -14.6f },
+ { 0.0f, 5.0f, -7.0f, -0.6f },
+ { 0.0f, 2.2f, 1.6f, 5.8f, 0.1f },
+ { 0.0f, 0.0f, 1.7f, 2.1f, 4.8f, -1.1f },
+ { 0.0f, -0.6f, -1.9f, -0.4f, -0.5f, -0.3f, 0.7f },
+ { 0.0f, 0.6f, 0.4f, 0.2f, 0.3f, -0.8f, -0.2f, 0.1f },
+ { 0.0f, -0.2f, 0.1f, 0.3f, 0.4f, 0.1f, -0.2f, 0.4f, 0.4f },
+ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f } };
+
+ static private final long BASE_TIME =
+ new GregorianCalendar(2005, 1, 1).getTimeInMillis();
+
+ // The ratio between the Gauss-normalized associated Legendre functions and
+ // the Schmid quasi-normalized ones. Compute these once staticly since they
+ // don't depend on input variables at all.
+ static private final float[][] SCHMIDT_QUASI_NORM_FACTORS =
+ computeSchmidtQuasiNormFactors(G_COEFF.length);
+
+ /**
+ * Estimate the magnetic field at a given point and time.
+ *
+ * @param gdLatitudeDeg
+ * Latitude in WGS84 geodetic coordinates -- positive is east.
+ * @param gdLongitudeDeg
+ * Longitude in WGS84 geodetic coordinates -- positive is north.
+ * @param altitudeMeters
+ * Altitude in WGS84 geodetic coordinates, in meters.
+ * @param timeMillis
+ * Time at which to evaluate the declination, in milliseconds
+ * since January 1, 1970. (approximate is fine -- the declination
+ * changes very slowly).
+ */
+ public GeomagneticField(float gdLatitudeDeg,
+ float gdLongitudeDeg,
+ float altitudeMeters,
+ long timeMillis) {
+ final int MAX_N = G_COEFF.length; // Maximum degree of the coefficients.
+
+ // We don't handle the north and south poles correctly -- pretend that
+ // we're not quite at them to avoid crashing.
+ gdLatitudeDeg = Math.min(90.0f - 1e-5f,
+ Math.max(-90.0f + 1e-5f, gdLatitudeDeg));
+ computeGeocentricCoordinates(gdLatitudeDeg,
+ gdLongitudeDeg,
+ altitudeMeters);
+
+ assert G_COEFF.length == H_COEFF.length;
+
+ // Note: LegendreTable computes associated Legendre functions for
+ // cos(theta). We want the associated Legendre functions for
+ // sin(latitude), which is the same as cos(PI/2 - latitude), except the
+ // derivate will be negated.
+ LegendreTable legendre =
+ new LegendreTable(MAX_N - 1,
+ (float) (Math.PI / 2.0 - mGcLatitudeRad));
+
+ // Compute a table of (EARTH_REFERENCE_RADIUS_KM / radius)^n for i in
+ // 0..MAX_N-2 (this is much faster than calling Math.pow MAX_N+1 times).
+ float[] relativeRadiusPower = new float[MAX_N + 2];
+ relativeRadiusPower[0] = 1.0f;
+ relativeRadiusPower[1] = EARTH_REFERENCE_RADIUS_KM / mGcRadiusKm;
+ for (int i = 2; i < relativeRadiusPower.length; ++i) {
+ relativeRadiusPower[i] = relativeRadiusPower[i - 1] *
+ relativeRadiusPower[1];
+ }
+
+ // Compute tables of sin(lon * m) and cos(lon * m) for m = 0..MAX_N --
+ // this is much faster than calling Math.sin and Math.com MAX_N+1 times.
+ float[] sinMLon = new float[MAX_N];
+ float[] cosMLon = new float[MAX_N];
+ sinMLon[0] = 0.0f;
+ cosMLon[0] = 1.0f;
+ sinMLon[1] = (float) Math.sin(mGcLongitudeRad);
+ cosMLon[1] = (float) Math.cos(mGcLongitudeRad);
+
+ for (int m = 2; m < MAX_N; ++m) {
+ // Standard expansions for sin((m-x)*theta + x*theta) and
+ // cos((m-x)*theta + x*theta).
+ int x = m >> 1;
+ sinMLon[m] = sinMLon[m-x] * cosMLon[x] + cosMLon[m-x] * sinMLon[x];
+ cosMLon[m] = cosMLon[m-x] * cosMLon[x] - sinMLon[m-x] * sinMLon[x];
+ }
+
+ float inverseCosLatitude = 1.0f / (float) Math.cos(mGcLatitudeRad);
+ float yearsSinceBase =
+ (timeMillis - BASE_TIME) / (365f * 24f * 60f * 60f * 1000f);
+
+ // We now compute the magnetic field strength given the geocentric
+ // location. The magnetic field is the derivative of the potential
+ // function defined by the model. See NOAA Technical Report: The US/UK
+ // World Magnetic Model for 2005-2010 for the derivation.
+ float gcX = 0.0f; // Geocentric northwards component.
+ float gcY = 0.0f; // Geocentric eastwards component.
+ float gcZ = 0.0f; // Geocentric downwards component.
+
+ for (int n = 1; n < MAX_N; n++) {
+ for (int m = 0; m <= n; m++) {
+ // Adjust the coefficients for the current date.
+ float g = G_COEFF[n][m] + yearsSinceBase * DELTA_G[n][m];
+ float h = H_COEFF[n][m] + yearsSinceBase * DELTA_H[n][m];
+
+ // Negative derivative with respect to latitude, divided by
+ // radius. This looks like the negation of the version in the
+ // NOAA Techincal report because that report used
+ // P_n^m(sin(theta)) and we use P_n^m(cos(90 - theta)), so the
+ // derivative with respect to theta is negated.
+ gcX += relativeRadiusPower[n+2]
+ * (g * cosMLon[m] + h * sinMLon[m])
+ * legendre.mPDeriv[n][m]
+ * SCHMIDT_QUASI_NORM_FACTORS[n][m];
+
+ // Negative derivative with respect to longitude, divided by
+ // radius.
+ gcY += relativeRadiusPower[n+2] * m
+ * (g * sinMLon[m] - h * cosMLon[m])
+ * legendre.mP[n][m]
+ * SCHMIDT_QUASI_NORM_FACTORS[n][m]
+ * inverseCosLatitude;
+
+ // Negative derivative with respect to radius.
+ gcZ -= (n + 1) * relativeRadiusPower[n+2]
+ * (g * cosMLon[m] + h * sinMLon[m])
+ * legendre.mP[n][m]
+ * SCHMIDT_QUASI_NORM_FACTORS[n][m];
+ }
+ }
+
+ // Convert back to geodetic coordinates. This is basically just a
+ // rotation around the Y-axis by the difference in latitudes between the
+ // geocentric frame and the geodetic frame.
+ double latDiffRad = Math.toRadians(gdLatitudeDeg) - mGcLatitudeRad;
+ mX = (float) (gcX * Math.cos(latDiffRad)
+ + gcZ * Math.sin(latDiffRad));
+ mY = gcY;
+ mZ = (float) (- gcX * Math.sin(latDiffRad)
+ + gcZ * Math.cos(latDiffRad));
+ }
+
+ /**
+ * @return The X (northward) component of the magnetic field in nanoteslas.
+ */
+ public float getX() {
+ return mX;
+ }
+
+ /**
+ * @return The Y (eastward) component of the magnetic field in nanoteslas.
+ */
+ public float getY() {
+ return mY;
+ }
+
+ /**
+ * @return The Z (downward) component of the magnetic field in nanoteslas.
+ */
+ public float getZ() {
+ return mZ;
+ }
+
+ /**
+ * @return The declination of the horizontal component of the magnetic
+ * field from true north, in degrees (i.e. positive means the
+ * magnetic field is rotated east that much from true north).
+ */
+ public float getDeclination() {
+ return (float) Math.toDegrees(Math.atan2(mY, mX));
+ }
+
+ /**
+ * @return The inclination of the magnetic field in degrees -- positive
+ * means the magnetic field is rotated downwards.
+ */
+ public float getInclination() {
+ return (float) Math.toDegrees(Math.atan2(mZ,
+ getHorizontalStrength()));
+ }
+
+ /**
+ * @return Horizontal component of the field strength in nonoteslas.
+ */
+ public float getHorizontalStrength() {
+ return (float) Math.sqrt(mX * mX + mY * mY);
+ }
+
+ /**
+ * @return Total field strength in nanoteslas.
+ */
+ public float getFieldStrength() {
+ return (float) Math.sqrt(mX * mX + mY * mY + mZ * mZ);
+ }
+
+ /**
+ * @param gdLatitudeDeg
+ * Latitude in WGS84 geodetic coordinates.
+ * @param gdLongitudeDeg
+ * Longitude in WGS84 geodetic coordinates.
+ * @param altitudeMeters
+ * Altitude above sea level in WGS84 geodetic coordinates.
+ * @return Geocentric latitude (i.e. angle between closest point on the
+ * equator and this point, at the center of the earth.
+ */
+ private void computeGeocentricCoordinates(float gdLatitudeDeg,
+ float gdLongitudeDeg,
+ float altitudeMeters) {
+ float altitudeKm = altitudeMeters / 1000.0f;
+ float a2 = EARTH_SEMI_MAJOR_AXIS_KM * EARTH_SEMI_MAJOR_AXIS_KM;
+ float b2 = EARTH_SEMI_MINOR_AXIS_KM * EARTH_SEMI_MINOR_AXIS_KM;
+ double gdLatRad = Math.toRadians(gdLatitudeDeg);
+ float clat = (float) Math.cos(gdLatRad);
+ float slat = (float) Math.sin(gdLatRad);
+ float tlat = slat / clat;
+ float latRad =
+ (float) Math.sqrt(a2 * clat * clat + b2 * slat * slat);
+
+ mGcLatitudeRad = (float) Math.atan(tlat * (latRad * altitudeKm + b2)
+ / (latRad * altitudeKm + a2));
+
+ mGcLongitudeRad = (float) Math.toRadians(gdLongitudeDeg);
+
+ float radSq = altitudeKm * altitudeKm
+ + 2 * altitudeKm * (float) Math.sqrt(a2 * clat * clat +
+ b2 * slat * slat)
+ + (a2 * a2 * clat * clat + b2 * b2 * slat * slat)
+ / (a2 * clat * clat + b2 * slat * slat);
+ mGcRadiusKm = (float) Math.sqrt(radSq);
+ }
+
+
+ /**
+ * Utility class to compute a table of Gauss-normalized associated Legendre
+ * functions P_n^m(cos(theta))
+ */
+ static private class LegendreTable {
+ // These are the Gauss-normalized associated Legendre functions -- that
+ // is, they are normal Legendre functions multiplied by
+ // (n-m)!/(2n-1)!! (where (2n-1)!! = 1*3*5*...*2n-1)
+ public final float[][] mP;
+
+ // Derivative of mP, with respect to theta.
+ public final float[][] mPDeriv;
+
+ /**
+ * @param maxN
+ * The maximum n- and m-values to support
+ * @param thetaRad
+ * Returned functions will be Gauss-normalized
+ * P_n^m(cos(thetaRad)), with thetaRad in radians.
+ */
+ public LegendreTable(int maxN, float thetaRad) {
+ // Compute the table of Gauss-normalized associated Legendre
+ // functions using standard recursion relations. Also compute the
+ // table of derivatives using the derivative of the recursion
+ // relations.
+ float cos = (float) Math.cos(thetaRad);
+ float sin = (float) Math.sin(thetaRad);
+
+ mP = new float[maxN + 1][];
+ mPDeriv = new float[maxN + 1][];
+ mP[0] = new float[] { 1.0f };
+ mPDeriv[0] = new float[] { 0.0f };
+ for (int n = 1; n <= maxN; n++) {
+ mP[n] = new float[n + 1];
+ mPDeriv[n] = new float[n + 1];
+ for (int m = 0; m <= n; m++) {
+ if (n == m) {
+ mP[n][m] = sin * mP[n - 1][m - 1];
+ mPDeriv[n][m] = cos * mP[n - 1][m - 1]
+ + sin * mPDeriv[n - 1][m - 1];
+ } else if (n == 1 || m == n - 1) {
+ mP[n][m] = cos * mP[n - 1][m];
+ mPDeriv[n][m] = -sin * mP[n - 1][m]
+ + cos * mPDeriv[n - 1][m];
+ } else {
+ assert n > 1 && m < n - 1;
+ float k = ((n - 1) * (n - 1) - m * m)
+ / (float) ((2 * n - 1) * (2 * n - 3));
+ mP[n][m] = cos * mP[n - 1][m] - k * mP[n - 2][m];
+ mPDeriv[n][m] = -sin * mP[n - 1][m]
+ + cos * mPDeriv[n - 1][m] - k * mPDeriv[n - 2][m];
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Compute the ration between the Gauss-normalized associated Legendre
+ * functions and the Schmidt quasi-normalized version. This is equivalent to
+ * sqrt((m==0?1:2)*(n-m)!/(n+m!))*(2n-1)!!/(n-m)!
+ */
+ private static float[][] computeSchmidtQuasiNormFactors(int maxN) {
+ float[][] schmidtQuasiNorm = new float[maxN + 1][];
+ schmidtQuasiNorm[0] = new float[] { 1.0f };
+ for (int n = 1; n <= maxN; n++) {
+ schmidtQuasiNorm[n] = new float[n + 1];
+ schmidtQuasiNorm[n][0] =
+ schmidtQuasiNorm[n - 1][0] * (2 * n - 1) / (float) n;
+ for (int m = 1; m <= n; m++) {
+ schmidtQuasiNorm[n][m] = schmidtQuasiNorm[n][m - 1]
+ * (float) Math.sqrt((n - m + 1) * (m == 1 ? 2 : 1)
+ / (float) (n + m));
+ }
+ }
+ return schmidtQuasiNorm;
+ }
+} \ No newline at end of file
diff --git a/core/java/android/hardware/ISensorService.aidl b/core/java/android/hardware/ISensorService.aidl
index 8aad9b4..04af2ae 100644
--- a/core/java/android/hardware/ISensorService.aidl
+++ b/core/java/android/hardware/ISensorService.aidl
@@ -25,5 +25,5 @@ import android.os.ParcelFileDescriptor;
interface ISensorService
{
ParcelFileDescriptor getDataChanel();
- boolean enableSensor(IBinder listener, int sensor, int enable);
+ boolean enableSensor(IBinder listener, String name, int sensor, int enable);
}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index f02094e..e232c2c 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -620,6 +620,9 @@ public class SensorManager extends IRotationWatcher.Stub
*/
@Deprecated
public boolean registerListener(SensorListener listener, int sensors, int rate) {
+ if (listener == null) {
+ return false;
+ }
boolean result = false;
result = registerLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
listener, sensors, rate) || result;
@@ -638,6 +641,9 @@ public class SensorManager extends IRotationWatcher.Stub
private boolean registerLegacyListener(int legacyType, int type,
SensorListener listener, int sensors, int rate)
{
+ if (listener == null) {
+ return false;
+ }
boolean result = false;
// Are we activating this legacy sensor?
if ((sensors & legacyType) != 0) {
@@ -693,6 +699,9 @@ public class SensorManager extends IRotationWatcher.Stub
private void unregisterLegacyListener(int legacyType, int type,
SensorListener listener, int sensors)
{
+ if (listener == null) {
+ return;
+ }
// do we know about this listener?
LegacyListener legacyListener = null;
synchronized (mLegacyListenersMap) {
@@ -741,7 +750,7 @@ public class SensorManager extends IRotationWatcher.Stub
*/
@Deprecated
public void unregisterListener(SensorListener listener) {
- unregisterListener(listener, SENSOR_ALL);
+ unregisterListener(listener, SENSOR_ALL | SENSOR_ORIENTATION_RAW);
}
/**
@@ -800,6 +809,9 @@ public class SensorManager extends IRotationWatcher.Stub
*/
public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate,
Handler handler) {
+ if (listener == null || sensor == null) {
+ return false;
+ }
boolean result;
int delay = -1;
switch (rate) {
@@ -829,9 +841,11 @@ public class SensorManager extends IRotationWatcher.Stub
}
}
+ String name = sensor.getName();
+ int handle = sensor.getHandle();
if (l == null) {
l = new ListenerDelegate(listener, sensor, handler);
- result = mSensorService.enableSensor(l, sensor.getHandle(), delay);
+ result = mSensorService.enableSensor(l, name, handle, delay);
if (result) {
sListeners.add(l);
sListeners.notify();
@@ -840,7 +854,7 @@ public class SensorManager extends IRotationWatcher.Stub
sSensorThread.startLocked(mSensorService);
}
} else {
- result = mSensorService.enableSensor(l, sensor.getHandle(), delay);
+ result = mSensorService.enableSensor(l, name, handle, delay);
if (result) {
l.addSensor(sensor);
}
@@ -854,6 +868,9 @@ public class SensorManager extends IRotationWatcher.Stub
}
private void unregisterListener(Object listener, Sensor sensor) {
+ if (listener == null || sensor == null) {
+ return;
+ }
try {
synchronized (sListeners) {
final int size = sListeners.size();
@@ -861,8 +878,9 @@ public class SensorManager extends IRotationWatcher.Stub
ListenerDelegate l = sListeners.get(i);
if (l.getListener() == listener) {
// disable these sensors
+ String name = sensor.getName();
int handle = sensor.getHandle();
- mSensorService.enableSensor(l, handle, SENSOR_DISABLE);
+ mSensorService.enableSensor(l, name, handle, SENSOR_DISABLE);
// if we have no more sensors enabled on this listener,
// take it off the list.
if (l.removeSensor(sensor) == 0) {
@@ -878,6 +896,9 @@ public class SensorManager extends IRotationWatcher.Stub
}
private void unregisterListener(Object listener) {
+ if (listener == null) {
+ return;
+ }
try {
synchronized (sListeners) {
final int size = sListeners.size();
@@ -886,7 +907,9 @@ public class SensorManager extends IRotationWatcher.Stub
if (l.getListener() == listener) {
// disable all sensors for this listener
for (Sensor sensor : l.getSensors()) {
- mSensorService.enableSensor(l, sensor.getHandle(), SENSOR_DISABLE);
+ String name = sensor.getName();
+ int handle = sensor.getHandle();
+ mSensorService.enableSensor(l, name, handle, SENSOR_DISABLE);
}
sListeners.remove(i);
break;
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 7d02f65..eedcc35 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -24,6 +24,9 @@ import android.view.MotionEvent;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* AbstractInputMethodService provides a abstract base class for input methods.
* Normal input method implementations will not derive from this directly,
@@ -156,6 +159,13 @@ public abstract class AbstractInputMethodService extends Service
*/
public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
+ /**
+ * Implement this to handle {@link android.os.Binder#dump Binder.dump()}
+ * calls on your input method.
+ */
+ protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ }
+
@Override
final public IBinder onBind(Intent intent) {
if (mInputMethod == null) {
diff --git a/core/java/android/inputmethodservice/ExtractButton.java b/core/java/android/inputmethodservice/ExtractButton.java
new file mode 100644
index 0000000..d6fe38d
--- /dev/null
+++ b/core/java/android/inputmethodservice/ExtractButton.java
@@ -0,0 +1,30 @@
+package android.inputmethodservice;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+/***
+ * Specialization of {@link Button} that ignores the window not being focused.
+ */
+class ExtractButton extends Button {
+ public ExtractButton(Context context) {
+ super(context, null);
+ }
+
+ public ExtractButton(Context context, AttributeSet attrs) {
+ super(context, attrs, com.android.internal.R.attr.buttonStyle);
+ }
+
+ public ExtractButton(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Pretend like the window this view is in always has focus, so it will
+ * highlight when selected.
+ */
+ @Override public boolean hasWindowFocus() {
+ return this.isEnabled() ? true : false;
+ }
+}
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index e59f38b..0295f69 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -2,6 +2,7 @@ package android.inputmethodservice;
import android.content.Context;
import android.util.AttributeSet;
+import android.view.inputmethod.ExtractedText;
import android.widget.EditText;
/***
@@ -9,6 +10,9 @@ import android.widget.EditText;
* extracted text in a full-screen input method.
*/
public class ExtractEditText extends EditText {
+ private InputMethodService mIME;
+ private int mSettingExtractedText;
+
public ExtractEditText(Context context) {
super(context, null);
}
@@ -20,4 +24,107 @@ public class ExtractEditText extends EditText {
public ExtractEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
+
+ void setIME(InputMethodService ime) {
+ mIME = ime;
+ }
+
+ /**
+ * Start making changes that will not be reported to the client. That
+ * is, {@link #onSelectionChanged(int, int)} will not result in sending
+ * the new selection to the client
+ */
+ public void startInternalChanges() {
+ mSettingExtractedText += 1;
+ }
+
+ /**
+ * Finish making changes that will not be reported to the client. That
+ * is, {@link #onSelectionChanged(int, int)} will not result in sending
+ * the new selection to the client
+ */
+ public void finishInternalChanges() {
+ mSettingExtractedText -= 1;
+ }
+
+ /**
+ * Implement just to keep track of when we are setting text from the
+ * client (vs. seeing changes in ourself from the user).
+ */
+ @Override public void setExtractedText(ExtractedText text) {
+ try {
+ mSettingExtractedText++;
+ super.setExtractedText(text);
+ } finally {
+ mSettingExtractedText--;
+ }
+ }
+
+ /**
+ * Report to the underlying text editor about selection changes.
+ */
+ @Override protected void onSelectionChanged(int selStart, int selEnd) {
+ if (mSettingExtractedText == 0 && mIME != null && selStart >= 0 && selEnd >= 0) {
+ mIME.onExtractedSelectionChanged(selStart, selEnd);
+ }
+ }
+
+ /**
+ * Redirect clicks to the IME for handling there. First allows any
+ * on click handler to run, though.
+ */
+ @Override public boolean performClick() {
+ if (!super.performClick() && mIME != null) {
+ mIME.onExtractedTextClicked();
+ return true;
+ }
+ return false;
+ }
+
+ @Override public boolean onTextContextMenuItem(int id) {
+ if (mIME != null) {
+ if (mIME.onExtractTextContextMenuItem(id)) {
+ return true;
+ }
+ }
+ return super.onTextContextMenuItem(id);
+ }
+
+ /**
+ * We are always considered to be an input method target.
+ */
+ public boolean isInputMethodTarget() {
+ return true;
+ }
+
+ /**
+ * Return true if the edit text is currently showing a scroll bar.
+ */
+ public boolean hasVerticalScrollBar() {
+ return computeVerticalScrollRange() > computeVerticalScrollExtent();
+ }
+
+ /**
+ * Pretend like the window this view is in always has focus, so its
+ * highlight and cursor will be displayed.
+ */
+ @Override public boolean hasWindowFocus() {
+ return this.isEnabled() ? true : false;
+ }
+
+ /**
+ * Pretend like this view always has focus, so its
+ * highlight and cursor will be displayed.
+ */
+ @Override public boolean isFocused() {
+ return this.isEnabled() ? true : false;
+ }
+
+ /**
+ * Pretend like this view always has focus, so its
+ * highlight and cursor will be displayed.
+ */
+ @Override public boolean hasFocus() {
+ return this.isEnabled() ? true : false;
+ }
}
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 5a85c66..6cf90d6 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -30,6 +30,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
private static final int DO_UPDATE_SELECTION = 90;
private static final int DO_UPDATE_CURSOR = 95;
private static final int DO_APP_PRIVATE_COMMAND = 100;
+ private static final int DO_TOGGLE_SOFT_INPUT = 105;
final HandlerCaller mCaller;
final InputMethodSession mInputMethodSession;
@@ -106,6 +107,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
mCaller.recycleArgs(args);
return;
}
+ case DO_TOGGLE_SOFT_INPUT: {
+ mInputMethodSession.toggleSoftInput(msg.arg1, msg.arg2);
+ return;
+ }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
@@ -149,4 +154,8 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
public void appPrivateCommand(String action, Bundle data) {
mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action, data));
}
+
+ public void toggleSoftInput(int showFlags, int hideFlags) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags));
+ }
}
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 9abc23b..20a05a5 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -8,9 +8,12 @@ import com.android.internal.view.IInputMethodSession;
import com.android.internal.view.InputConnectionWrapper;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputBinding;
@@ -18,6 +21,11 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
* Implements the internal IInputMethod interface to convert incoming calls
* on to it back to calls on the public InputMethod interface, scheduling
@@ -28,6 +36,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
private static final String TAG = "InputMethodWrapper";
private static final boolean DEBUG = false;
+ private static final int DO_DUMP = 1;
private static final int DO_ATTACH_TOKEN = 10;
private static final int DO_SET_INPUT_CONTEXT = 20;
private static final int DO_UNSET_INPUT_CONTEXT = 30;
@@ -39,9 +48,14 @@ class IInputMethodWrapper extends IInputMethod.Stub
private static final int DO_SHOW_SOFT_INPUT = 60;
private static final int DO_HIDE_SOFT_INPUT = 70;
+ final AbstractInputMethodService mTarget;
final HandlerCaller mCaller;
final InputMethod mInputMethod;
+ static class Notifier {
+ boolean notified;
+ }
+
// NOTE: we should have a cache of these.
static class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback {
final Context mContext;
@@ -64,7 +78,9 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
}
- public IInputMethodWrapper(Context context, InputMethod inputMethod) {
+ public IInputMethodWrapper(AbstractInputMethodService context,
+ InputMethod inputMethod) {
+ mTarget = context;
mCaller = new HandlerCaller(context, this);
mInputMethod = inputMethod;
}
@@ -75,6 +91,20 @@ class IInputMethodWrapper extends IInputMethod.Stub
public void executeMessage(Message msg) {
switch (msg.what) {
+ case DO_DUMP: {
+ HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
+ try {
+ mTarget.dump((FileDescriptor)args.arg1,
+ (PrintWriter)args.arg2, (String[])args.arg3);
+ } catch (RuntimeException e) {
+ ((PrintWriter)args.arg2).println("Exception: " + e);
+ }
+ synchronized (args.arg4) {
+ ((CountDownLatch)args.arg4).countDown();
+ }
+ return;
+ }
+
case DO_ATTACH_TOKEN: {
mInputMethod.attachToken((IBinder)msg.obj);
return;
@@ -86,12 +116,22 @@ class IInputMethodWrapper extends IInputMethod.Stub
case DO_UNSET_INPUT_CONTEXT:
mInputMethod.unbindInput();
return;
- case DO_START_INPUT:
- mInputMethod.startInput((EditorInfo)msg.obj);
+ case DO_START_INPUT: {
+ HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
+ IInputContext inputContext = (IInputContext)args.arg1;
+ InputConnection ic = inputContext != null
+ ? new InputConnectionWrapper(inputContext) : null;
+ mInputMethod.startInput(ic, (EditorInfo)args.arg2);
return;
- case DO_RESTART_INPUT:
- mInputMethod.restartInput((EditorInfo)msg.obj);
+ }
+ case DO_RESTART_INPUT: {
+ HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
+ IInputContext inputContext = (IInputContext)args.arg1;
+ InputConnection ic = inputContext != null
+ ? new InputConnectionWrapper(inputContext) : null;
+ mInputMethod.restartInput(ic, (EditorInfo)args.arg2);
return;
+ }
case DO_CREATE_SESSION: {
mInputMethod.createSession(new InputMethodSessionCallbackWrapper(
mCaller.mContext, (IInputMethodCallback)msg.obj));
@@ -105,16 +145,37 @@ class IInputMethodWrapper extends IInputMethod.Stub
mInputMethod.revokeSession((InputMethodSession)msg.obj);
return;
case DO_SHOW_SOFT_INPUT:
- mInputMethod.showSoftInput(
- msg.arg1 != 0 ? InputMethod.SHOW_EXPLICIT : 0);
+ mInputMethod.showSoftInput(msg.arg1, (ResultReceiver)msg.obj);
return;
case DO_HIDE_SOFT_INPUT:
- mInputMethod.hideSoftInput();
+ mInputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj);
return;
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
+ @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ if (mTarget.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ fout.println("Permission Denial: can't dump InputMethodManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ CountDownLatch latch = new CountDownLatch(1);
+ mCaller.executeOrSendMessage(mCaller.obtainMessageOOOO(DO_DUMP,
+ fd, fout, args, latch));
+ try {
+ if (!latch.await(5, TimeUnit.SECONDS)) {
+ fout.println("Timeout waiting for dump");
+ }
+ } catch (InterruptedException e) {
+ fout.println("Interrupted waiting for dump");
+ }
+ }
+
public void attachToken(IBinder token) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_ATTACH_TOKEN, token));
}
@@ -130,12 +191,14 @@ class IInputMethodWrapper extends IInputMethod.Stub
mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_UNSET_INPUT_CONTEXT));
}
- public void startInput(EditorInfo attribute) {
- mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_START_INPUT, attribute));
+ public void startInput(IInputContext inputContext, EditorInfo attribute) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_START_INPUT,
+ inputContext, attribute));
}
- public void restartInput(EditorInfo attribute) {
- mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RESTART_INPUT, attribute));
+ public void restartInput(IInputContext inputContext, EditorInfo attribute) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_RESTART_INPUT,
+ inputContext, attribute));
}
public void createSession(IInputMethodCallback callback) {
@@ -163,12 +226,13 @@ class IInputMethodWrapper extends IInputMethod.Stub
}
}
- public void showSoftInput(boolean explicit) {
- mCaller.executeOrSendMessage(mCaller.obtainMessageI(DO_SHOW_SOFT_INPUT,
- explicit ? 1 : 0));
+ public void showSoftInput(int flags, ResultReceiver resultReceiver) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_SHOW_SOFT_INPUT,
+ flags, resultReceiver));
}
- public void hideSoftInput() {
- mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_HIDE_SOFT_INPUT));
+ public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_HIDE_SOFT_INPUT,
+ flags, resultReceiver));
}
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 3a9b26a..32270c4 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -26,7 +26,16 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.ResultReceiver;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.InputType;
+import android.text.Layout;
+import android.text.Spannable;
+import android.text.method.MovementMethod;
import android.util.Log;
+import android.util.PrintWriterPrinter;
+import android.util.Printer;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -43,7 +52,10 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
import android.widget.FrameLayout;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
/**
* InputMethodService provides a standard implementation of an InputMethod,
@@ -51,6 +63,22 @@ import android.widget.FrameLayout;
* base class {@link AbstractInputMethodService} and the {@link InputMethod}
* interface for more information on the basics of writing input methods.
*
+ * <p>In addition to the normal Service lifecycle methods, this class
+ * introduces some new specific callbacks that most subclasses will want
+ * to make use of:</p>
+ * <ul>
+ * <li> {@link #onInitializeInterface()} for user-interface initialization,
+ * in particular to deal with configuration changes while the service is
+ * running.
+ * <li> {@link #onBindInput} to find out about switching to a new client.
+ * <li> {@link #onStartInput} to deal with an input session starting with
+ * the client.
+ * <li> {@link #onCreateInputView()}, {@link #onCreateCandidatesView()},
+ * and {@link #onCreateExtractTextView()} for non-demand generation of the UI.
+ * <li> {@link #onStartInputView(EditorInfo, boolean)} to deal with input
+ * starting within the input area of the IME.
+ * </ul>
+ *
* <p>An input method has significant discretion in how it goes about its
* work: the {@link android.inputmethodservice.InputMethodService} provides
* a basic framework for standard UI elements (input view, candidates view,
@@ -181,9 +209,12 @@ public class InputMethodService extends AbstractInputMethodService {
static final String TAG = "InputMethodService";
static final boolean DEBUG = false;
+ InputMethodManager mImm;
+
LayoutInflater mInflater;
View mRootView;
SoftInputWindow mWindow;
+ boolean mInitialized;
boolean mWindowCreated;
boolean mWindowAdded;
boolean mWindowVisible;
@@ -196,16 +227,25 @@ public class InputMethodService extends AbstractInputMethodService {
InputBinding mInputBinding;
InputConnection mInputConnection;
boolean mInputStarted;
+ boolean mInputViewStarted;
+ boolean mCandidatesViewStarted;
+ InputConnection mStartedInputConnection;
EditorInfo mInputEditorInfo;
+ int mShowInputFlags;
boolean mShowInputRequested;
boolean mLastShowInputRequested;
- boolean mShowCandidatesRequested;
+ int mCandidatesVisibility;
+ CompletionInfo[] mCurCompletions;
+
+ boolean mShowInputForced;
boolean mFullscreenApplied;
boolean mIsFullscreen;
View mExtractView;
ExtractEditText mExtractEditText;
+ ViewGroup mExtractAccessories;
+ Button mExtractAction;
ExtractedText mExtractedText;
int mExtractedToken;
@@ -236,6 +276,21 @@ public class InputMethodService extends AbstractInputMethodService {
}
};
+ final View.OnClickListener mActionClickListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ final EditorInfo ei = getCurrentInputEditorInfo();
+ final InputConnection ic = getCurrentInputConnection();
+ if (ei != null && ic != null) {
+ if (ei.actionId != 0) {
+ ic.performEditorAction(ei.actionId);
+ } else if ((ei.imeOptions&EditorInfo.IME_MASK_ACTION)
+ != EditorInfo.IME_ACTION_NONE) {
+ ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
+ }
+ }
+ }
+ };
+
/**
* Concrete implementation of
* {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides
@@ -262,6 +317,9 @@ public class InputMethodService extends AbstractInputMethodService {
mInputConnection = binding.getConnection();
if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
+ " ic=" + mInputConnection);
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) ic.reportFullscreenMode(mIsFullscreen);
+ initialize();
onBindInput();
}
@@ -277,31 +335,50 @@ public class InputMethodService extends AbstractInputMethodService {
mInputConnection = null;
}
- public void startInput(EditorInfo attribute) {
+ public void startInput(InputConnection ic, EditorInfo attribute) {
if (DEBUG) Log.v(TAG, "startInput(): editor=" + attribute);
- doStartInput(attribute, false);
+ doStartInput(ic, attribute, false);
}
- public void restartInput(EditorInfo attribute) {
+ public void restartInput(InputConnection ic, EditorInfo attribute) {
if (DEBUG) Log.v(TAG, "restartInput(): editor=" + attribute);
- doStartInput(attribute, true);
+ doStartInput(ic, attribute, true);
}
/**
* Handle a request by the system to hide the soft input area.
*/
- public void hideSoftInput() {
+ public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
if (DEBUG) Log.v(TAG, "hideSoftInput()");
+ boolean wasVis = isInputViewShown();
+ mShowInputFlags = 0;
mShowInputRequested = false;
+ mShowInputForced = false;
hideWindow();
+ if (resultReceiver != null) {
+ resultReceiver.send(wasVis != isInputViewShown()
+ ? InputMethodManager.RESULT_HIDDEN
+ : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
+ : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
+ }
}
/**
* Handle a request by the system to show the soft input area.
*/
- public void showSoftInput(int flags) {
+ public void showSoftInput(int flags, ResultReceiver resultReceiver) {
if (DEBUG) Log.v(TAG, "showSoftInput()");
- onShowRequested(flags);
+ boolean wasVis = isInputViewShown();
+ mShowInputFlags = 0;
+ if (onShowInputRequested(flags, false)) {
+ showWindow(true);
+ }
+ if (resultReceiver != null) {
+ resultReceiver.send(wasVis != isInputViewShown()
+ ? InputMethodManager.RESULT_SHOWN
+ : (wasVis ? InputMethodManager.RESULT_UNCHANGED_SHOWN
+ : InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
+ }
}
}
@@ -316,8 +393,7 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
if (DEBUG) Log.v(TAG, "finishInput() in " + this);
- onFinishInput();
- mInputStarted = false;
+ doFinishInput();
}
/**
@@ -328,6 +404,7 @@ public class InputMethodService extends AbstractInputMethodService {
if (!isEnabled()) {
return;
}
+ mCurCompletions = completions;
onDisplayCompletions(completions);
}
@@ -377,6 +454,13 @@ public class InputMethodService extends AbstractInputMethodService {
}
InputMethodService.this.onAppPrivateCommand(action, data);
}
+
+ /**
+ *
+ */
+ public void toggleSoftInput(int showFlags, int hideFlags) {
+ InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
+ }
}
/**
@@ -391,7 +475,7 @@ public class InputMethodService extends AbstractInputMethodService {
* of the application behind. This value is relative to the top edge
* of the input method window.
*/
- int contentTopInsets;
+ public int contentTopInsets;
/**
* This is the top part of the UI that is visibly covering the
@@ -404,7 +488,7 @@ public class InputMethodService extends AbstractInputMethodService {
* needed to make the focus visible. This value is relative to the top edge
* of the input method window.
*/
- int visibleTopInsets;
+ public int visibleTopInsets;
/**
* Option for {@link #touchableInsets}: the entire window frame
@@ -437,6 +521,7 @@ public class InputMethodService extends AbstractInputMethodService {
@Override public void onCreate() {
super.onCreate();
+ mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
mInflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mWindow = new SoftInputWindow(this);
@@ -444,20 +529,42 @@ public class InputMethodService extends AbstractInputMethodService {
mWindow.getWindow().setLayout(FILL_PARENT, WRAP_CONTENT);
}
+ /**
+ * This is a hook that subclasses can use to perform initialization of
+ * their interface. It is called for you prior to any of your UI objects
+ * being created, both after the service is first created and after a
+ * configuration change happens.
+ */
+ public void onInitializeInterface() {
+ }
+
+ void initialize() {
+ if (!mInitialized) {
+ mInitialized = true;
+ onInitializeInterface();
+ }
+ }
+
void initViews() {
- mWindowVisible = false;
+ mInitialized = false;
mWindowCreated = false;
mShowInputRequested = false;
- mShowCandidatesRequested = false;
+ mShowInputForced = false;
mRootView = mInflater.inflate(
com.android.internal.R.layout.input_method, null);
mWindow.setContentView(mRootView);
mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
-
+ if (Settings.System.getInt(getContentResolver(),
+ Settings.System.FANCY_IME_ANIMATIONS, 0) != 0) {
+ mWindow.getWindow().setWindowAnimations(
+ com.android.internal.R.style.Animation_InputMethodFancy);
+ }
mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea);
mExtractView = null;
mExtractEditText = null;
+ mExtractAccessories = null;
+ mExtractAction = null;
mFullscreenApplied = false;
mCandidatesFrame = (FrameLayout)mRootView.findViewById(android.R.id.candidatesArea);
@@ -466,7 +573,8 @@ public class InputMethodService extends AbstractInputMethodService {
mIsInputViewShown = false;
mExtractFrame.setVisibility(View.GONE);
- mCandidatesFrame.setVisibility(View.INVISIBLE);
+ mCandidatesVisibility = getCandidatesHiddenVisibility();
+ mCandidatesFrame.setVisibility(mCandidatesVisibility);
mInputFrame.setVisibility(View.GONE);
}
@@ -486,26 +594,48 @@ public class InputMethodService extends AbstractInputMethodService {
* regenerating the input method UI as a result of the configuration
* change, so you can rely on your {@link #onCreateInputView} and
* other methods being called as appropriate due to a configuration change.
+ *
+ * <p>When a configuration change does happen,
+ * {@link #onInitializeInterface()} is guaranteed to be called the next
+ * time prior to any of the other input or UI creation callbacks. The
+ * following will be called immediately depending if appropriate for current
+ * state: {@link #onStartInput} if input is active, and
+ * {@link #onCreateInputView} and {@link #onStartInputView} and related
+ * appropriate functions if the UI is displayed.
*/
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
boolean visible = mWindowVisible;
+ int showFlags = mShowInputFlags;
boolean showingInput = mShowInputRequested;
- boolean showingCandidates = mShowCandidatesRequested;
+ CompletionInfo[] completions = mCurCompletions;
initViews();
+ mInputViewStarted = false;
+ mCandidatesViewStarted = false;
+ if (mInputStarted) {
+ doStartInput(getCurrentInputConnection(),
+ getCurrentInputEditorInfo(), true);
+ }
if (visible) {
- if (showingCandidates) {
- setCandidatesViewShown(true);
- }
if (showingInput) {
- // If we are showing the full soft keyboard, then go through
- // this path to take care of current decisions about fullscreen
- // etc.
- onShowRequested(InputMethod.SHOW_EXPLICIT);
- } else {
- // Otherwise just put it back for its candidates.
+ // If we were last showing the soft keyboard, try to do so again.
+ if (onShowInputRequested(showFlags, true)) {
+ showWindow(true);
+ if (completions != null) {
+ mCurCompletions = completions;
+ onDisplayCompletions(completions);
+ }
+ } else {
+ hideWindow();
+ }
+ } else if (mCandidatesVisibility == View.VISIBLE) {
+ // If the candidates are currently visible, make sure the
+ // window is shown for them.
showWindow(false);
+ } else {
+ // Otherwise hide the window.
+ hideWindow();
}
}
}
@@ -568,6 +698,10 @@ public class InputMethodService extends AbstractInputMethodService {
* the input method, or null if there is none.
*/
public InputConnection getCurrentInputConnection() {
+ InputConnection ic = mStartedInputConnection;
+ if (ic != null) {
+ return ic;
+ }
return mInputConnection;
}
@@ -593,7 +727,10 @@ public class InputMethodService extends AbstractInputMethodService {
if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
changed = true;
mIsFullscreen = isFullscreen;
+ InputConnection ic = getCurrentInputConnection();
+ 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
@@ -609,7 +746,7 @@ public class InputMethodService extends AbstractInputMethodService {
setExtractView(v);
}
}
- startExtractingText();
+ startExtractingText(false);
}
}
@@ -708,6 +845,7 @@ public class InputMethodService extends AbstractInputMethodService {
mIsInputViewShown = isShown;
mInputFrame.setVisibility(isShown ? View.VISIBLE : View.GONE);
if (mInputView == null) {
+ initialize();
View v = onCreateInputView();
if (v != null) {
setInputView(v);
@@ -717,12 +855,19 @@ public class InputMethodService extends AbstractInputMethodService {
}
/**
+ * Returns true if we have been asked to show our input view.
+ */
+ public boolean isShowInputRequested() {
+ return mShowInputRequested;
+ }
+
+ /**
* Return whether the soft input view is <em>currently</em> shown to the
* user. This is the state that was last determined and
* applied by {@link #updateInputViewShown()}.
*/
public boolean isInputViewShown() {
- return mIsInputViewShown;
+ return mIsInputViewShown && mWindowVisible;
}
/**
@@ -744,9 +889,10 @@ public class InputMethodService extends AbstractInputMethodService {
* it is hidden.
*/
public void setCandidatesViewShown(boolean shown) {
- if (mShowCandidatesRequested != shown) {
- mCandidatesFrame.setVisibility(shown ? View.VISIBLE : View.INVISIBLE);
- mShowCandidatesRequested = shown;
+ int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
+ if (mCandidatesVisibility != vis) {
+ mCandidatesFrame.setVisibility(vis);
+ mCandidatesVisibility = vis;
}
if (!mShowInputRequested && mWindowVisible != shown) {
// If we are being asked to show the candidates view while the app
@@ -760,11 +906,27 @@ public class InputMethodService extends AbstractInputMethodService {
}
}
- public void setStatusIcon(int iconResId) {
+ /**
+ * 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,
+ * 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;
+ }
+
+ public void showStatusIcon(int iconResId) {
mStatusIcon = iconResId;
- if (mInputConnection != null && mWindowVisible) {
- mInputConnection.showStatusIcon(getPackageName(), iconResId);
- }
+ mImm.showStatusIcon(mToken, getPackageName(), iconResId);
+ }
+
+ public void hideStatusIcon() {
+ mStatusIcon = 0;
+ mImm.hideStatusIcon(mToken);
}
/**
@@ -775,22 +937,30 @@ public class InputMethodService extends AbstractInputMethodService {
* @param id Unique identifier of the new input method ot start.
*/
public void switchInputMethod(String id) {
- ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE))
- .setInputMethod(mToken, id);
+ mImm.setInputMethod(mToken, id);
}
public void setExtractView(View view) {
mExtractFrame.removeAllViews();
mExtractFrame.addView(view, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
+ ViewGroup.LayoutParams.FILL_PARENT));
mExtractView = view;
if (view != null) {
mExtractEditText = (ExtractEditText)view.findViewById(
com.android.internal.R.id.inputExtractEditText);
- startExtractingText();
+ mExtractEditText.setIME(this);
+ mExtractAction = (Button)view.findViewById(
+ com.android.internal.R.id.inputExtractAction);
+ if (mExtractAction != null) {
+ mExtractAccessories = (ViewGroup)view.findViewById(
+ com.android.internal.R.id.inputExtractAccessories);
+ }
+ startExtractingText(false);
} else {
mExtractEditText = null;
+ mExtractAccessories = null;
+ mExtractAction = null;
}
}
@@ -890,27 +1060,111 @@ public class InputMethodService extends AbstractInputMethodService {
}
/**
+ * Called when the input view is being hidden from the user. This will
+ * be called either prior to hiding the window, or prior to switching to
+ * another target for editing.
+ *
+ * <p>The default
+ * implementation uses the InputConnection to clear any active composing
+ * text; you can override this (not calling the base class implementation)
+ * to perform whatever behavior you would like.
+ *
+ * @param finishingInput If true, {@link #onFinishInput} will be
+ * called immediately after.
+ */
+ public void onFinishInputView(boolean finishingInput) {
+ if (!finishingInput) {
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) {
+ ic.finishComposingText();
+ }
+ }
+ }
+
+ /**
+ * Called when only the candidates view has been shown for showing
+ * processing as the user enters text through a hard keyboard.
+ * This will always be called after {@link #onStartInput},
+ * allowing you to do your general setup there and just view-specific
+ * setup here. You are guaranteed that {@link #onCreateCandidatesView()}
+ * will have been called some time before this function is called.
+ *
+ * <p>Note that this will <em>not</em> be called when the input method
+ * is running in full editing mode, and thus receiving
+ * {@link #onStartInputView} to initiate that operation. This is only
+ * for the case when candidates are being shown while the input method
+ * editor is hidden but wants to show its candidates UI as text is
+ * entered through some other mechanism.
+ *
+ * @param info Description of the type of text being edited.
+ * @param restarting Set to true if we are restarting input on the
+ * same text field as before.
+ */
+ public void onStartCandidatesView(EditorInfo info, boolean restarting) {
+ }
+
+ /**
+ * Called when the candidates view is being hidden from the user. This will
+ * be called either prior to hiding the window, or prior to switching to
+ * another target for editing.
+ *
+ * <p>The default
+ * implementation uses the InputConnection to clear any active composing
+ * text; you can override this (not calling the base class implementation)
+ * to perform whatever behavior you would like.
+ *
+ * @param finishingInput If true, {@link #onFinishInput} will be
+ * called immediately after.
+ */
+ public void onFinishCandidatesView(boolean finishingInput) {
+ if (!finishingInput) {
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) {
+ ic.finishComposingText();
+ }
+ }
+ }
+
+ /**
* The system has decided that it may be time to show your input method.
* This is called due to a corresponding call to your
- * {@link InputMethod#showSoftInput(int) InputMethod.showSoftInput(int)}
- * method. The default implementation simply calls
- * {@link #showWindow(boolean)}, except if the
- * {@link InputMethod#SHOW_EXPLICIT InputMethod.SHOW_EXPLICIT} flag is
- * not set and the input method is running in fullscreen mode.
+ * {@link InputMethod#showSoftInput InputMethod.showSoftInput()}
+ * method. The default implementation uses
+ * {@link #onEvaluateInputViewShown()}, {@link #onEvaluateFullscreenMode()},
+ * and the current configuration to decide whether the input view should
+ * be shown at this point.
*
* @param flags Provides additional information about the show request,
- * as per {@link InputMethod#showSoftInput(int) InputMethod.showSoftInput(int)}.
+ * as per {@link InputMethod#showSoftInput InputMethod.showSoftInput()}.
+ * @param configChange This is true if we are re-showing due to a
+ * configuration change.
+ * @return Returns true to indicate that the window should be shown.
*/
- public void onShowRequested(int flags) {
+ public boolean onShowInputRequested(int flags, boolean configChange) {
if (!onEvaluateInputViewShown()) {
- return;
+ return false;
}
- if ((flags&InputMethod.SHOW_EXPLICIT) == 0 && onEvaluateFullscreenMode()) {
- // Don't show if this is not explicit requested by the user and
- // the input method is fullscreen. That would be too disruptive.
- return;
+ if ((flags&InputMethod.SHOW_EXPLICIT) == 0) {
+ if (!configChange && onEvaluateFullscreenMode()) {
+ // Don't show if this is not explicitly requested by the user and
+ // the input method is fullscreen. That would be too disruptive.
+ // However, we skip this change for a config change, since if
+ // the IME is already shown we do want to go into fullscreen
+ // mode at this point.
+ return false;
+ }
+ Configuration config = getResources().getConfiguration();
+ if (config.keyboard != Configuration.KEYBOARD_NOKEYS) {
+ // And if the device has a hard keyboard, even if it is
+ // currently hidden, don't show the input method implicitly.
+ // These kinds of devices don't need it that much.
+ return false;
+ }
}
- showWindow(true);
+ if ((flags&InputMethod.SHOW_FORCED) != 0) {
+ mShowInputForced = true;
+ }
+ return true;
}
public void showWindow(boolean showInput) {
@@ -935,46 +1189,77 @@ public class InputMethodService extends AbstractInputMethodService {
}
if (DEBUG) Log.v(TAG, "showWindow: updating UI");
+ initialize();
updateFullscreenMode();
updateInputViewShown();
if (!mWindowAdded || !mWindowCreated) {
mWindowAdded = true;
mWindowCreated = true;
+ initialize();
+ if (DEBUG) Log.v(TAG, "CALL: onCreateCandidatesView");
View v = onCreateCandidatesView();
if (DEBUG) Log.v(TAG, "showWindow: candidates=" + v);
if (v != null) {
setCandidatesView(v);
}
}
- if (doShowInput) {
- if (mInputStarted) {
- if (DEBUG) Log.v(TAG, "showWindow: starting input view");
+ if (mShowInputRequested) {
+ if (!mInputViewStarted) {
+ if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
+ mInputViewStarted = true;
onStartInputView(mInputEditorInfo, false);
}
- startExtractingText();
+ } else if (!mCandidatesViewStarted) {
+ if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
+ mCandidatesViewStarted = true;
+ onStartCandidatesView(mInputEditorInfo, false);
+ }
+
+ if (doShowInput) {
+ startExtractingText(false);
}
if (!wasVisible) {
if (DEBUG) Log.v(TAG, "showWindow: showing!");
+ onWindowShown();
mWindow.show();
- if (mInputConnection != null) {
- mInputConnection.showStatusIcon(getPackageName(), mStatusIcon);
- }
}
}
public void hideWindow() {
+ if (mInputViewStarted) {
+ if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
+ onFinishInputView(false);
+ } else if (mCandidatesViewStarted) {
+ if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
+ onFinishCandidatesView(false);
+ }
+ mInputViewStarted = false;
+ mCandidatesViewStarted = false;
if (mWindowVisible) {
mWindow.hide();
mWindowVisible = false;
- if (mInputConnection != null) {
- mInputConnection.hideStatusIcon();
- }
+ onWindowHidden();
}
}
/**
+ * Called when the input method window has been shown to the user, after
+ * previously not being visible. This is done after all of the UI setup
+ * for the window has occurred (creating its views etc).
+ */
+ public void onWindowShown() {
+ }
+
+ /**
+ * Called when the input method window has been hidden from the user,
+ * after previously being visible.
+ */
+ public void onWindowHidden() {
+ }
+
+ /**
* Called when a new client has bound to the input method. This
* may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
* and {@link #onFinishInput()} calls as the user navigates through its
@@ -1008,18 +1293,46 @@ public class InputMethodService extends AbstractInputMethodService {
public void onStartInput(EditorInfo attribute, boolean restarting) {
}
- void doStartInput(EditorInfo attribute, boolean restarting) {
- if (mInputStarted && !restarting) {
+ void doFinishInput() {
+ if (mInputViewStarted) {
+ if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
+ onFinishInputView(true);
+ } else if (mCandidatesViewStarted) {
+ if (DEBUG) Log.v(TAG, "CALL: onFinishCandidatesView");
+ onFinishCandidatesView(true);
+ }
+ mInputViewStarted = false;
+ mCandidatesViewStarted = false;
+ if (mInputStarted) {
+ if (DEBUG) Log.v(TAG, "CALL: onFinishInput");
onFinishInput();
}
+ mInputStarted = false;
+ mStartedInputConnection = null;
+ mCurCompletions = null;
+ }
+
+ void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
+ if (!restarting) {
+ doFinishInput();
+ }
mInputStarted = true;
+ mStartedInputConnection = ic;
mInputEditorInfo = attribute;
+ initialize();
+ if (DEBUG) Log.v(TAG, "CALL: onStartInput");
onStartInput(attribute, restarting);
if (mWindowVisible) {
if (mShowInputRequested) {
+ if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
+ mInputViewStarted = true;
onStartInputView(mInputEditorInfo, restarting);
+ startExtractingText(true);
+ } else if (mCandidatesVisibility == View.VISIBLE) {
+ if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
+ mCandidatesViewStarted = true;
+ onStartCandidatesView(mInputEditorInfo, restarting);
}
- startExtractingText();
}
}
@@ -1029,8 +1342,17 @@ public class InputMethodService extends AbstractInputMethodService {
* {@link #onStartInput(EditorInfo, boolean)} to perform input in a
* new editor, or the input method may be left idle. This method is
* <em>not</em> called when input restarts in the same editor.
+ *
+ * <p>The default
+ * implementation uses the InputConnection to clear any active composing
+ * text; you can override this (not calling the base class implementation)
+ * to perform whatever behavior you would like.
*/
public void onFinishInput() {
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) {
+ ic.finishComposingText();
+ }
}
/**
@@ -1055,9 +1377,11 @@ public class InputMethodService extends AbstractInputMethodService {
if (mExtractedToken != token) {
return;
}
- if (mExtractEditText != null && text != null) {
- mExtractedText = text;
- mExtractEditText.setExtractedText(text);
+ if (text != null) {
+ if (mExtractEditText != null) {
+ mExtractedText = text;
+ mExtractEditText.setExtractedText(text);
+ }
}
}
@@ -1073,9 +1397,19 @@ public class InputMethodService extends AbstractInputMethodService {
public void onUpdateSelection(int oldSelStart, int oldSelEnd,
int newSelStart, int newSelEnd,
int candidatesStart, int candidatesEnd) {
- if (mExtractEditText != null && mExtractedText != null) {
+ final ExtractEditText eet = mExtractEditText;
+ if (eet != null && isFullscreenMode() && mExtractedText != null) {
final int off = mExtractedText.startOffset;
- mExtractEditText.setSelection(newSelStart-off, newSelEnd-off);
+ eet.startInternalChanges();
+ newSelStart -= off;
+ newSelEnd -= off;
+ final int len = eet.getText().length();
+ if (newSelStart < 0) newSelStart = 0;
+ else if (newSelStart > len) newSelStart = len;
+ if (newSelEnd < 0) newSelEnd = 0;
+ else if (newSelEnd > len) newSelEnd = len;
+ eet.setSelection(newSelStart, newSelEnd);
+ eet.finishInternalChanges();
}
}
@@ -1095,38 +1429,91 @@ public class InputMethodService extends AbstractInputMethodService {
* 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY
* InputMethodManager.HIDE_IMPLICIT_ONLY} bit set.
*/
- public void dismissSoftInput(int flags) {
- ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE))
- .hideSoftInputFromInputMethod(mToken, flags);
+ public void requestHideSelf(int flags) {
+ mImm.hideSoftInputFromInputMethod(mToken, flags);
+ }
+
+ /**
+ * Show the input method. This is a call back to the
+ * IMF to handle showing the input method.
+ * Close this input method's soft input area, removing it from the display.
+ * The input method will continue running, but the user can no longer use
+ * it to generate input by touching the screen.
+ * @param flags Provides additional operating flags. Currently may be
+ * 0 or have the {@link InputMethodManager#SHOW_FORCED
+ * InputMethodManager.} bit set.
+ */
+ private void requestShowSelf(int flags) {
+ mImm.showSoftInputFromInputMethod(mToken, flags);
}
+ /**
+ * Override this to intercept key down events before they are processed by the
+ * application. If you return true, the application will not itself
+ * process the event. If you return true, the normal application processing
+ * will occur as if the IME had not seen the event at all.
+ *
+ * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
+ * KeyEvent.KEYCODE_BACK} to hide the current IME UI if it is shown. In
+ * additional, in fullscreen mode only, it will consume DPAD movement
+ * events to move the cursor in the extracted text view, not allowing
+ * them to perform navigation in the underlying application.
+ */
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0) {
if (mShowInputRequested) {
// If the soft input area is shown, back closes it and we
// consume the back key.
- dismissSoftInput(0);
+ requestHideSelf(0);
return true;
- }
- if (mShowCandidatesRequested) {
- // If the candidates are shown, we just want to make sure
- // they are now hidden but otherwise let the app execute
- // the back.
- // XXX this needs better interaction with the soft input
- // implementation.
- //setCandidatesViewShown(false);
+ } else if (mWindowVisible) {
+ if (mCandidatesVisibility == View.VISIBLE) {
+ // If we are showing candidates even if no input area, then
+ // hide them.
+ setCandidatesViewShown(false);
+ return true;
+ } else {
+ // If we have the window visible for some other reason --
+ // most likely to show candidates -- then just get rid
+ // of it. This really shouldn't happen, but just in case...
+ hideWindow();
+ return true;
+ }
}
}
- return false;
+ return doMovementKey(keyCode, event, MOVEMENT_DOWN);
}
+ /**
+ * Override this to intercept special key multiple events before they are
+ * processed by the
+ * application. If you return true, the application will not itself
+ * process the event. If you return true, the normal application processing
+ * will occur as if the IME had not seen the event at all.
+ *
+ * <p>The default implementation always returns false, except when
+ * in fullscreen mode, where it will consume DPAD movement
+ * events to move the cursor in the extracted text view, not allowing
+ * them to perform navigation in the underlying application.
+ */
public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
- return false;
+ return doMovementKey(keyCode, event, count);
}
+ /**
+ * Override this to intercept key up events before they are processed by the
+ * application. If you return true, the application will not itself
+ * process the event. If you return true, the normal application processing
+ * will occur as if the IME had not seen the event at all.
+ *
+ * <p>The default implementation always returns false, except when
+ * in fullscreen mode, where it will consume DPAD movement
+ * events to move the cursor in the extracted text view, not allowing
+ * them to perform navigation in the underlying application.
+ */
public boolean onKeyUp(int keyCode, KeyEvent event) {
- return false;
+ return doMovementKey(keyCode, event, MOVEMENT_UP);
}
public boolean onTrackballEvent(MotionEvent event) {
@@ -1136,21 +1523,415 @@ public class InputMethodService extends AbstractInputMethodService {
public void onAppPrivateCommand(String action, Bundle data) {
}
- void startExtractingText() {
- if (mExtractEditText != null && getCurrentInputStarted()
+ /**
+ * Handle a request by the system to toggle the soft input area.
+ */
+ private void onToggleSoftInput(int showFlags, int hideFlags) {
+ if (DEBUG) Log.v(TAG, "toggleSoftInput()");
+ if (isInputViewShown()) {
+ requestHideSelf(hideFlags);
+ } else {
+ requestShowSelf(showFlags);
+ }
+ }
+
+ static final int MOVEMENT_DOWN = -1;
+ static final int MOVEMENT_UP = -2;
+
+ void reportExtractedMovement(int keyCode, int count) {
+ int dx = 0, dy = 0;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ dx = -count;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ dx = count;
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ dy = -count;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ dy = count;
+ break;
+ }
+ onExtractedCursorMovement(dx, dy);
+ }
+
+ boolean doMovementKey(int keyCode, KeyEvent event, int count) {
+ final ExtractEditText eet = mExtractEditText;
+ if (isFullscreenMode() && 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.
+ MovementMethod movement = eet.getMovementMethod();
+ Layout layout = eet.getLayout();
+ if (movement != null && layout != null) {
+ // We want our own movement method to handle the key, so the
+ // cursor will properly move in our own word wrapping.
+ if (count == MOVEMENT_DOWN) {
+ if (movement.onKeyDown(eet,
+ (Spannable)eet.getText(), keyCode, event)) {
+ reportExtractedMovement(keyCode, 1);
+ return true;
+ }
+ } else if (count == MOVEMENT_UP) {
+ if (movement.onKeyUp(eet,
+ (Spannable)eet.getText(), keyCode, event)) {
+ return true;
+ }
+ } else {
+ if (movement.onKeyOther(eet, (Spannable)eet.getText(), event)) {
+ reportExtractedMovement(keyCode, count);
+ } else {
+ KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
+ if (movement.onKeyDown(eet,
+ (Spannable)eet.getText(), keyCode, down)) {
+ KeyEvent up = new KeyEvent(event, KeyEvent.ACTION_UP);
+ movement.onKeyUp(eet,
+ (Spannable)eet.getText(), keyCode, up);
+ while (--count > 0) {
+ movement.onKeyDown(eet,
+ (Spannable)eet.getText(), keyCode, down);
+ movement.onKeyUp(eet,
+ (Spannable)eet.getText(), keyCode, up);
+ }
+ reportExtractedMovement(keyCode, count);
+ }
+ }
+ }
+ }
+ // Regardless of whether the movement method handled the key,
+ // we never allow DPAD navigation to the application.
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Send the given key event code (as defined by {@link KeyEvent}) to the
+ * current input connection is a key down + key up event pair. The sent
+ * events have {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD}
+ * set, so that the recipient can identify them as coming from a software
+ * input method, and
+ * {@link KeyEvent#FLAG_KEEP_TOUCH_MODE KeyEvent.FLAG_KEEP_TOUCH_MODE}, so
+ * that they don't impact the current touch mode of the UI.
+ *
+ * @param keyEventCode The raw key code to send, as defined by
+ * {@link KeyEvent}.
+ */
+ public void sendDownUpKeyEvents(int keyEventCode) {
+ InputConnection ic = getCurrentInputConnection();
+ if (ic == null) return;
+ long eventTime = SystemClock.uptimeMillis();
+ ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
+ KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, 0, 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
+ ic.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
+ KeyEvent.ACTION_UP, keyEventCode, 0, 0, 0, 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
+ }
+
+ /**
+ * Ask the input target to execute its default action via
+ * {@link InputConnection#performEditorAction
+ * InputConnection.performEditorAction()}.
+ *
+ * @param fromEnterKey If true, this will be executed as if the user had
+ * pressed an enter key on the keyboard, that is it will <em>not</em>
+ * be done if the editor has set {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION
+ * EditorInfo.IME_FLAG_NO_ENTER_ACTION}. If false, the action will be
+ * sent regardless of how the editor has set that flag.
+ *
+ * @return Returns a boolean indicating whether an action has been sent.
+ * If false, either the editor did not specify a default action or it
+ * does not want an action from the enter key. If true, the action was
+ * sent (or there was no input connection at all).
+ */
+ public boolean sendDefaultEditorAction(boolean fromEnterKey) {
+ EditorInfo ei = getCurrentInputEditorInfo();
+ if (ei != null &&
+ (!fromEnterKey || (ei.imeOptions &
+ EditorInfo.IME_FLAG_NO_ENTER_ACTION) == 0) &&
+ (ei.imeOptions & EditorInfo.IME_MASK_ACTION) !=
+ EditorInfo.IME_ACTION_NONE) {
+ // If the enter key was pressed, and the editor has a default
+ // action associated with pressing enter, then send it that
+ // explicit action instead of the key event.
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) {
+ ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Send the given UTF-16 character to the current input connection. Most
+ * characters will be delivered simply by calling
+ * {@link InputConnection#commitText InputConnection.commitText()} with
+ * the character; some, however, may be handled different. In particular,
+ * the enter character ('\n') will either be delivered as an action code
+ * or a raw key event, as appropriate.
+ *
+ * @param charCode The UTF-16 character code to send.
+ */
+ public void sendKeyChar(char charCode) {
+ switch (charCode) {
+ case '\n': // Apps may be listening to an enter key to perform an action
+ if (!sendDefaultEditorAction(true)) {
+ sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
+ }
+ break;
+ default:
+ // Make sure that digits go through any text watcher on the client side.
+ if (charCode >= '0' && charCode <= '9') {
+ sendDownUpKeyEvents(charCode - '0' + KeyEvent.KEYCODE_0);
+ } else {
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) {
+ ic.commitText(String.valueOf((char) charCode), 1);
+ }
+ }
+ break;
+ }
+ }
+
+ /**
+ * This is called when the user has moved the cursor in the extracted
+ * text view, when running in fullsreen mode. The default implementation
+ * performs the corresponding selection change on the underlying text
+ * editor.
+ */
+ public void onExtractedSelectionChanged(int start, int end) {
+ InputConnection conn = getCurrentInputConnection();
+ if (conn != null) {
+ conn.setSelection(start, end);
+ }
+ }
+
+ /**
+ * This is called when the user has clicked on the extracted text view,
+ * when running in fullscreen mode. The default implementation hides
+ * the candidates view when this happens, but only if the extracted text
+ * editor has a vertical scroll bar because its text doesn't fit.
+ * Re-implement this to provide whatever behavior you want.
+ */
+ public void onExtractedTextClicked() {
+ if (mExtractEditText == null) {
+ return;
+ }
+ if (mExtractEditText.hasVerticalScrollBar()) {
+ setCandidatesViewShown(false);
+ }
+ }
+
+ /**
+ * This is called when the user has performed a cursor movement in the
+ * extracted text view, when it is running in fullscreen mode. The default
+ * implementation hides the candidates view when a vertical movement
+ * happens, but only if the extracted text editor has a vertical scroll bar
+ * because its text doesn't fit.
+ * Re-implement this to provide whatever behavior you want.
+ * @param dx The amount of cursor movement in the x dimension.
+ * @param dy The amount of cursor movement in the y dimension.
+ */
+ public void onExtractedCursorMovement(int dx, int dy) {
+ if (mExtractEditText == null || dy == 0) {
+ return;
+ }
+ if (mExtractEditText.hasVerticalScrollBar()) {
+ setCandidatesViewShown(false);
+ }
+ }
+
+ /**
+ * This is called when the user has selected a context menu item from the
+ * extracted text view, when running in fullscreen mode. The default
+ * implementation sends this action to the current InputConnection's
+ * {@link InputConnection#performContextMenuAction(int)}, for it
+ * to be processed in underlying "real" editor. Re-implement this to
+ * provide whatever behavior you want.
+ */
+ public boolean onExtractTextContextMenuItem(int id) {
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) {
+ ic.performContextMenuAction(id);
+ }
+ return true;
+ }
+
+ /**
+ * Return text that can be used as a button label for the given
+ * {@link EditorInfo#imeOptions EditorInfo.imeOptions}. Returns null
+ * if there is no action requested. Note that there is no guarantee that
+ * the returned text will be relatively short, so you probably do not
+ * want to use it as text on a soft keyboard key label.
+ *
+ * @param imeOptions The value from @link EditorInfo#imeOptions EditorInfo.imeOptions}.
+ *
+ * @return Returns a label to use, or null if there is no action.
+ */
+ public CharSequence getTextForImeAction(int imeOptions) {
+ switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
+ case EditorInfo.IME_ACTION_NONE:
+ return null;
+ case EditorInfo.IME_ACTION_GO:
+ return getText(com.android.internal.R.string.ime_action_go);
+ case EditorInfo.IME_ACTION_SEARCH:
+ return getText(com.android.internal.R.string.ime_action_search);
+ case EditorInfo.IME_ACTION_SEND:
+ return getText(com.android.internal.R.string.ime_action_send);
+ case EditorInfo.IME_ACTION_NEXT:
+ return getText(com.android.internal.R.string.ime_action_next);
+ case EditorInfo.IME_ACTION_DONE:
+ return getText(com.android.internal.R.string.ime_action_done);
+ default:
+ return getText(com.android.internal.R.string.ime_action_default);
+ }
+ }
+
+ /**
+ * 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.
+ */
+ public void onUpdateExtractingAccessories(EditorInfo ei) {
+ 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);
+ if (hasAction) {
+ mExtractAccessories.setVisibility(View.VISIBLE);
+ if (ei.actionLabel != null) {
+ mExtractAction.setText(ei.actionLabel);
+ } else {
+ mExtractAction.setText(getTextForImeAction(ei.imeOptions));
+ }
+ mExtractAction.setOnClickListener(mActionClickListener);
+ } else {
+ mExtractAccessories.setVisibility(View.GONE);
+ mExtractAction.setOnClickListener(null);
+ }
+ }
+
+ /**
+ * This is called when, while currently displayed in extract mode, the
+ * current input target changes. The default implementation will
+ * auto-hide the IME if the new target is not a full editor, since this
+ * can be an confusing experience for the user.
+ */
+ public void onExtractingInputChanged(EditorInfo ei) {
+ if (ei.inputType == InputType.TYPE_NULL) {
+ requestHideSelf(InputMethodManager.HIDE_NOT_ALWAYS);
+ }
+ }
+
+ void startExtractingText(boolean inputChanged) {
+ final ExtractEditText eet = mExtractEditText;
+ if (eet != null && getCurrentInputStarted()
&& isFullscreenMode()) {
mExtractedToken++;
ExtractedTextRequest req = new ExtractedTextRequest();
req.token = mExtractedToken;
+ req.flags = InputConnection.GET_TEXT_WITH_STYLES;
req.hintMaxLines = 10;
req.hintMaxChars = 10000;
- mExtractedText = mInputConnection.getExtractedText(req,
- InputConnection.EXTRACTED_TEXT_MONITOR);
- if (mExtractedText != null) {
- mExtractEditText.setExtractedText(mExtractedText);
+ mExtractedText = getCurrentInputConnection().getExtractedText(req,
+ InputConnection.GET_EXTRACTED_TEXT_MONITOR);
+
+ final EditorInfo ei = getCurrentInputEditorInfo();
+
+ try {
+ eet.startInternalChanges();
+ onUpdateExtractingAccessories(ei);
+ int inputType = ei.inputType;
+ if ((inputType&EditorInfo.TYPE_MASK_CLASS)
+ == EditorInfo.TYPE_CLASS_TEXT) {
+ if ((inputType&EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE) != 0) {
+ inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
+ }
+ }
+ eet.setInputType(inputType);
+ eet.setHint(ei.hintText);
+ if (mExtractedText != null) {
+ eet.setEnabled(true);
+ eet.setExtractedText(mExtractedText);
+ } else {
+ eet.setEnabled(false);
+ eet.setText("");
+ }
+ } finally {
+ eet.finishInternalChanges();
+ }
+
+ if (inputChanged) {
+ onExtractingInputChanged(ei);
}
- mExtractEditText.setInputType(getCurrentInputEditorInfo().inputType);
- mExtractEditText.setHint(mInputEditorInfo.hintText);
}
}
+
+ /**
+ * Performs a dump of the InputMethodService's internal state. Override
+ * to add your own information to the dump.
+ */
+ @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ final Printer p = new PrintWriterPrinter(fout);
+ p.println("Input method service state for " + this + ":");
+ p.println(" mWindowCreated=" + mWindowCreated
+ + " mWindowAdded=" + mWindowAdded
+ + " mWindowVisible=" + mWindowVisible);
+ p.println(" Configuration=" + getResources().getConfiguration());
+ p.println(" mToken=" + mToken);
+ p.println(" mInputBinding=" + mInputBinding);
+ p.println(" mInputConnection=" + mInputConnection);
+ p.println(" mStartedInputConnection=" + mStartedInputConnection);
+ p.println(" mInputStarted=" + mInputStarted
+ + " mInputViewStarted=" + mInputViewStarted
+ + " mCandidatesViewStarted=" + mCandidatesViewStarted);
+
+ if (mInputEditorInfo != null) {
+ p.println(" mInputEditorInfo:");
+ mInputEditorInfo.dump(p, " ");
+ } else {
+ p.println(" mInputEditorInfo: null");
+ }
+
+ p.println(" mShowInputRequested=" + mShowInputRequested
+ + " mLastShowInputRequested=" + mLastShowInputRequested
+ + " mShowInputForced=" + mShowInputForced
+ + " mShowInputFlags=0x" + Integer.toHexString(mShowInputFlags));
+ p.println(" mCandidatesVisibility=" + mCandidatesVisibility
+ + " mFullscreenApplied=" + mFullscreenApplied
+ + " mIsFullscreen=" + mIsFullscreen);
+
+ if (mExtractedText != null) {
+ p.println(" mExtractedText:");
+ p.println(" text=" + mExtractedText.text.length() + " chars"
+ + " startOffset=" + mExtractedText.startOffset);
+ p.println(" selectionStart=" + mExtractedText.selectionStart
+ + " selectionEnd=" + mExtractedText.selectionEnd
+ + " flags=0x" + Integer.toHexString(mExtractedText.flags));
+ } else {
+ p.println(" mExtractedText: null");
+ }
+ p.println(" mExtractedToken=" + mExtractedToken);
+ p.println(" mIsInputViewShown=" + mIsInputViewShown
+ + " mStatusIcon=" + mStatusIcon);
+ p.println("Last computed insets:");
+ p.println(" contentTopInsets=" + mTmpInsets.contentTopInsets
+ + " visibleTopInsets=" + mTmpInsets.visibleTopInsets
+ + " touchableInsets=" + mTmpInsets.touchableInsets);
+ }
}
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
index cfd3188..6a560ce 100755
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -132,7 +132,19 @@ public class Keyboard {
/** Keyboard mode, or zero, if none. */
private int mKeyboardMode;
+
+ // Variables for pre-computing nearest keys.
+ private static final int GRID_WIDTH = 10;
+ private static final int GRID_HEIGHT = 5;
+ private static final int GRID_SIZE = GRID_WIDTH * GRID_HEIGHT;
+ private int mCellWidth;
+ private int mCellHeight;
+ private int[][] mGridNeighbors;
+ private int mProximityThreshold;
+ /** Number of key widths from current touch point to search for nearest keys. */
+ private static float SEARCH_DISTANCE = 1.4f;
+
/**
* Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
* Some of the key size defaults can be overridden per row from what the {@link Keyboard}
@@ -177,13 +189,13 @@ public class Keyboard {
parent.mDisplayWidth, parent.mDefaultWidth);
defaultHeight = getDimensionOrFraction(a,
com.android.internal.R.styleable.Keyboard_keyHeight,
- parent.mDisplayWidth, parent.mDefaultHeight);
- defaultHorizontalGap = getDimensionOrFraction(a,
+ parent.mDisplayHeight, parent.mDefaultHeight);
+ defaultHorizontalGap = getDimensionOrFraction(a,
com.android.internal.R.styleable.Keyboard_horizontalGap,
parent.mDisplayWidth, parent.mDefaultHorizontalGap);
verticalGap = getDimensionOrFraction(a,
com.android.internal.R.styleable.Keyboard_verticalGap,
- parent.mDisplayWidth, parent.mDefaultVerticalGap);
+ parent.mDisplayHeight, parent.mDefaultVerticalGap);
a.recycle();
a = res.obtainAttributes(Xml.asAttributeSet(parser),
com.android.internal.R.styleable.Keyboard_Row);
@@ -540,7 +552,6 @@ public class Keyboard {
row.defaultHorizontalGap = mDefaultHorizontalGap;
row.verticalGap = mDefaultVerticalGap;
row.rowEdgeFlags = EDGE_TOP | EDGE_BOTTOM;
-
final int maxColumns = columns == -1 ? Integer.MAX_VALUE : columns;
for (int i = 0; i < characters.length(); i++) {
char c = characters.charAt(i);
@@ -638,6 +649,52 @@ public class Keyboard {
public int getShiftKeyIndex() {
return mShiftKeyIndex;
}
+
+ private void computeNearestNeighbors() {
+ // Round-up so we don't have any pixels outside the grid
+ mCellWidth = (getMinWidth() + GRID_WIDTH - 1) / GRID_WIDTH;
+ mCellHeight = (getHeight() + GRID_HEIGHT - 1) / GRID_HEIGHT;
+ mGridNeighbors = new int[GRID_SIZE][];
+ int[] indices = new int[mKeys.size()];
+ final int gridWidth = GRID_WIDTH * mCellWidth;
+ final int gridHeight = GRID_HEIGHT * mCellHeight;
+ for (int x = 0; x < gridWidth; x += mCellWidth) {
+ for (int y = 0; y < gridHeight; y += mCellHeight) {
+ int count = 0;
+ for (int i = 0; i < mKeys.size(); i++) {
+ final Key key = mKeys.get(i);
+ if (key.squaredDistanceFrom(x, y) < mProximityThreshold ||
+ key.squaredDistanceFrom(x + mCellWidth - 1, y) < mProximityThreshold ||
+ key.squaredDistanceFrom(x + mCellWidth - 1, y + mCellHeight - 1)
+ < mProximityThreshold ||
+ key.squaredDistanceFrom(x, y + mCellHeight - 1) < mProximityThreshold) {
+ indices[count++] = i;
+ }
+ }
+ int [] cell = new int[count];
+ System.arraycopy(indices, 0, cell, 0, count);
+ mGridNeighbors[(y / mCellHeight) * GRID_WIDTH + (x / mCellWidth)] = cell;
+ }
+ }
+ }
+
+ /**
+ * Returns the indices of the keys that are closest to the given point.
+ * @param x the x-coordinate of the point
+ * @param y the y-coordinate of the point
+ * @return the array of integer indices for the nearest keys to the given point. If the given
+ * point is out of range, then an array of size zero is returned.
+ */
+ public int[] getNearestKeys(int x, int y) {
+ if (mGridNeighbors == null) computeNearestNeighbors();
+ if (x >= 0 && x < getMinWidth() && y >= 0 && y < getHeight()) {
+ int index = (y / mCellHeight) * GRID_WIDTH + (x / mCellWidth);
+ if (index < GRID_SIZE) {
+ return mGridNeighbors[index];
+ }
+ }
+ return new int[0];
+ }
protected Row createRowFromXml(Resources res, XmlResourceParser parser) {
return new Row(res, this, parser);
@@ -739,6 +796,8 @@ public class Keyboard {
mDefaultVerticalGap = getDimensionOrFraction(a,
com.android.internal.R.styleable.Keyboard_verticalGap,
mDisplayHeight, 0);
+ mProximityThreshold = (int) (mDefaultWidth * SEARCH_DISTANCE);
+ mProximityThreshold = mProximityThreshold * mProximityThreshold; // Square it for comparison
a.recycle();
}
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 2f3b54b..7a63c0c 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -16,34 +16,33 @@
package android.inputmethodservice;
-import com.android.internal.R;
-
import android.content.Context;
-import android.content.SharedPreferences;
import android.content.res.TypedArray;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.Paint.Align;
+import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.Keyboard.Key;
import android.os.Handler;
import android.os.Message;
-import android.os.Vibrator;
-import android.preference.PreferenceManager;
+import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup.LayoutParams;
-import android.widget.Button;
import android.widget.PopupWindow;
import android.widget.TextView;
+import com.android.internal.R;
+
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -74,7 +73,6 @@ public class KeyboardView extends View implements View.OnClickListener {
* For keys that repeat, this is only called once.
* @param primaryCode the unicode of the key being pressed. If the touch is not on a valid
* key, the value will be zero.
- * @hide Pending API Council approval
*/
void onPress(int primaryCode);
@@ -82,7 +80,6 @@ public class KeyboardView extends View implements View.OnClickListener {
* Called when the user releases a key. This is sent after the {@link #onKey} is called.
* For keys that repeat, this is only called once.
* @param primaryCode the code of the key that was released
- * @hide Pending API Council approval
*/
void onRelease(int primaryCode);
@@ -99,6 +96,12 @@ public class KeyboardView extends View implements View.OnClickListener {
void onKey(int primaryCode, int[] keyCodes);
/**
+ * Sends a sequence of characters to the listener.
+ * @param text the sequence of characters to be displayed.
+ */
+ void onText(CharSequence text);
+
+ /**
* Called when the user quickly moves the finger from right to left.
*/
void swipeLeft();
@@ -149,6 +152,7 @@ public class KeyboardView extends View implements View.OnClickListener {
private int mMiniKeyboardOffsetY;
private Map<Key,View> mMiniKeyboardCache;
private int[] mWindowOffset;
+ private Key[] mKeys;
/** Listener for {@link OnKeyboardActionListener}. */
private OnKeyboardActionListener mKeyboardActionListener;
@@ -158,12 +162,15 @@ public class KeyboardView extends View implements View.OnClickListener {
private static final int MSG_REPEAT = 3;
private static final int MSG_LONGPRESS = 4;
+ private static final int DELAY_BEFORE_PREVIEW = 70;
+ private static final int DELAY_AFTER_PREVIEW = 60;
+
private int mVerticalCorrection;
private int mProximityThreshold;
private boolean mPreviewCentered = false;
private boolean mShowPreview = true;
- private boolean mShowTouchPoints = false;
+ private boolean mShowTouchPoints = true;
private int mPopupPreviewX;
private int mPopupPreviewY;
@@ -213,12 +220,21 @@ public class KeyboardView extends View implements View.OnClickListener {
private static final int MULTITAP_INTERVAL = 800; // milliseconds
private StringBuilder mPreviewLabel = new StringBuilder(1);
+ /** Whether the keyboard bitmap needs to be redrawn before it's blitted. **/
+ private boolean mDrawPending;
+ /** The dirty region in the keyboard bitmap */
+ private Rect mDirtyRect = new Rect();
+ /** The keyboard bitmap for faster updates */
+ private Bitmap mBuffer;
+ /** The canvas for the above mutable keyboard bitmap */
+ private Canvas mCanvas;
+
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SHOW_PREVIEW:
- mPreviewText.setVisibility(VISIBLE);
+ showKey(msg.arg1);
break;
case MSG_REMOVE_PREVIEW:
mPreviewText.setVisibility(INVISIBLE);
@@ -233,7 +249,6 @@ public class KeyboardView extends View implements View.OnClickListener {
openPopupIfRequired((MotionEvent) msg.obj);
break;
}
-
}
};
@@ -334,7 +349,7 @@ public class KeyboardView extends View implements View.OnClickListener {
}
private void initGestureDetector() {
- mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
+ mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent me1, MotionEvent me2,
float velocityX, float velocityY) {
@@ -386,9 +401,15 @@ public class KeyboardView extends View implements View.OnClickListener {
showPreview(NOT_A_KEY);
}
mKeyboard = keyboard;
+ List<Key> keys = mKeyboard.getKeys();
+ mKeys = keys.toArray(new Key[keys.size()]);
requestLayout();
- invalidate();
+ // Release buffer, just in case the new keyboard has a different size.
+ // It will be reallocated on the next draw.
+ mBuffer = null;
+ invalidateAll();
computeProximityThreshold(keyboard);
+ mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views
}
/**
@@ -410,7 +431,7 @@ public class KeyboardView extends View implements View.OnClickListener {
if (mKeyboard != null) {
if (mKeyboard.setShifted(shifted)) {
// The whole keyboard probably needs to be redrawn
- invalidate();
+ invalidateAll();
return true;
}
}
@@ -492,7 +513,7 @@ public class KeyboardView extends View implements View.OnClickListener {
}
private CharSequence adjustCase(CharSequence label) {
- if (mKeyboard.isShifted() && label != null && label.length() == 1
+ if (mKeyboard.isShifted() && label != null && label.length() < 3
&& Character.isLowerCase(label.charAt(0))) {
label = label.toString().toUpperCase();
}
@@ -521,22 +542,44 @@ public class KeyboardView extends View implements View.OnClickListener {
*/
private void computeProximityThreshold(Keyboard keyboard) {
if (keyboard == null) return;
- List<Key> keys = keyboard.getKeys();
+ final Key[] keys = mKeys;
if (keys == null) return;
- int length = keys.size();
+ int length = keys.length;
int dimensionSum = 0;
for (int i = 0; i < length; i++) {
- Key key = keys.get(i);
- dimensionSum += key.width + key.gap + key.height;
+ Key key = keys[i];
+ dimensionSum += Math.min(key.width, key.height) + key.gap;
}
if (dimensionSum < 0 || length == 0) return;
- mProximityThreshold = dimensionSum / (length * 2);
+ mProximityThreshold = (int) (dimensionSum * 1.4f / length);
mProximityThreshold *= mProximityThreshold; // Square it
}
-
+
+ @Override
+ public void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ // Release the buffer, if any and it will be reallocated on the next draw
+ mBuffer = null;
+ }
+
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
+ if (mDrawPending || mBuffer == null) {
+ onBufferDraw();
+ }
+ canvas.drawBitmap(mBuffer, 0, 0, null);
+ }
+
+ private void onBufferDraw() {
+ if (mBuffer == null) {
+ mBuffer = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+ mCanvas = new Canvas(mBuffer);
+ invalidateAll();
+ }
+ final Canvas canvas = mCanvas;
+ canvas.clipRect(mDirtyRect, Op.REPLACE);
+
if (mKeyboard == null) return;
final Paint paint = mPaint;
@@ -545,29 +588,25 @@ public class KeyboardView extends View implements View.OnClickListener {
final Rect padding = mPadding;
final int kbdPaddingLeft = mPaddingLeft;
final int kbdPaddingTop = mPaddingTop;
- final List<Key> keys = mKeyboard.getKeys();
+ final Key[] keys = mKeys;
final Key invalidKey = mInvalidatedKey;
- //canvas.translate(0, mKeyboardPaddingTop);
+
paint.setAlpha(255);
paint.setColor(mKeyTextColor);
boolean drawSingleKey = false;
if (invalidKey != null && canvas.getClipBounds(clipRegion)) {
-// System.out.println("Key bounds = " + (invalidKey.x + mPaddingLeft) + ","
-// + (invalidKey.y + mPaddingTop) + ","
-// + (invalidKey.x + invalidKey.width + mPaddingLeft) + ","
-// + (invalidKey.y + invalidKey.height + mPaddingTop));
-// System.out.println("Clip bounds =" + clipRegion.toShortString());
- // Is clipRegion completely contained within the invalidated key?
- if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left &&
- invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top &&
- invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right &&
- invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) {
- drawSingleKey = true;
- }
+ // Is clipRegion completely contained within the invalidated key?
+ if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left &&
+ invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top &&
+ invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right &&
+ invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) {
+ drawSingleKey = true;
+ }
}
- final int keyCount = keys.size();
+ canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
+ final int keyCount = keys.length;
for (int i = 0; i < keyCount; i++) {
- final Key key = keys.get(i);
+ final Key key = keys[i];
if (drawSingleKey && invalidKey != key) {
continue;
}
@@ -635,18 +674,22 @@ public class KeyboardView extends View implements View.OnClickListener {
paint.setColor(0xFF00FF00);
canvas.drawCircle((mStartX + mLastX) / 2, (mStartY + mLastY) / 2, 2, paint);
}
+
+ mDrawPending = false;
+ mDirtyRect.setEmpty();
}
private int getKeyIndices(int x, int y, int[] allKeys) {
- final List<Key> keys = mKeyboard.getKeys();
+ final Key[] keys = mKeys;
final boolean shifted = mKeyboard.isShifted();
int primaryIndex = NOT_A_KEY;
int closestKey = NOT_A_KEY;
int closestKeyDist = mProximityThreshold + 1;
java.util.Arrays.fill(mDistances, Integer.MAX_VALUE);
- final int keyCount = keys.size();
+ int [] nearestKeyIndices = mKeyboard.getNearestKeys(x, y);
+ final int keyCount = nearestKeyIndices.length;
for (int i = 0; i < keyCount; i++) {
- final Key key = keys.get(i);
+ final Key key = keys[nearestKeyIndices[i]];
int dist = 0;
boolean isInside = key.isInside(x,y);
if (((mProximityCorrectOn
@@ -657,7 +700,7 @@ public class KeyboardView extends View implements View.OnClickListener {
final int nCodes = key.codes.length;
if (dist < closestKeyDist) {
closestKeyDist = dist;
- closestKey = i;
+ closestKey = nearestKeyIndices[i];
}
if (allKeys == null) continue;
@@ -671,9 +714,6 @@ public class KeyboardView extends View implements View.OnClickListener {
allKeys.length - j - nCodes);
for (int c = 0; c < nCodes; c++) {
allKeys[j + c] = key.codes[c];
- if (shifted) {
- //allKeys[j + c] = Character.toUpperCase(key.codes[c]);
- }
mDistances[j + c] = dist;
}
break;
@@ -682,7 +722,7 @@ public class KeyboardView extends View implements View.OnClickListener {
}
if (isInside) {
- primaryIndex = i;
+ primaryIndex = nearestKeyIndices[i];
}
}
if (primaryIndex == NOT_A_KEY) {
@@ -693,12 +733,10 @@ public class KeyboardView extends View implements View.OnClickListener {
private void detectAndSendKey(int x, int y, long eventTime) {
int index = mCurrentKey;
- if (index != NOT_A_KEY) {
- final Key key = mKeyboard.getKeys().get(index);
+ if (index != NOT_A_KEY && index < mKeys.length) {
+ final Key key = mKeys[index];
if (key.text != null) {
- for (int i = 0; i < key.text.length(); i++) {
- mKeyboardActionListener.onKey(key.text.charAt(i), key.codes);
- }
+ mKeyboardActionListener.onText(key.text);
mKeyboardActionListener.onRelease(NOT_A_KEY);
} else {
int code = key.codes[0];
@@ -743,14 +781,14 @@ public class KeyboardView extends View implements View.OnClickListener {
mCurrentKeyIndex = keyIndex;
// Release the old key and press the new key
- final List<Key> keys = mKeyboard.getKeys();
+ final Key[] keys = mKeys;
if (oldKeyIndex != mCurrentKeyIndex) {
- if (oldKeyIndex != NOT_A_KEY && keys.size() > oldKeyIndex) {
- keys.get(oldKeyIndex).onReleased(mCurrentKeyIndex == NOT_A_KEY);
+ if (oldKeyIndex != NOT_A_KEY && keys.length > oldKeyIndex) {
+ keys[oldKeyIndex].onReleased(mCurrentKeyIndex == NOT_A_KEY);
invalidateKey(oldKeyIndex);
}
- if (mCurrentKeyIndex != NOT_A_KEY && keys.size() > mCurrentKeyIndex) {
- keys.get(mCurrentKeyIndex).onPressed();
+ if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) {
+ keys[mCurrentKeyIndex].onPressed();
invalidateKey(mCurrentKeyIndex);
}
}
@@ -760,75 +798,99 @@ public class KeyboardView extends View implements View.OnClickListener {
if (previewPopup.isShowing()) {
if (keyIndex == NOT_A_KEY) {
mHandler.sendMessageDelayed(mHandler
- .obtainMessage(MSG_REMOVE_PREVIEW), 60);
+ .obtainMessage(MSG_REMOVE_PREVIEW),
+ DELAY_AFTER_PREVIEW);
}
}
if (keyIndex != NOT_A_KEY) {
- Key key = keys.get(keyIndex);
- if (key.icon != null) {
- mPreviewText.setCompoundDrawables(null, null, null,
- key.iconPreview != null ? key.iconPreview : key.icon);
- mPreviewText.setText(null);
- } else {
- mPreviewText.setCompoundDrawables(null, null, null, null);
- mPreviewText.setText(getPreviewText(key));
- if (key.label.length() > 1 && key.codes.length < 2) {
- mPreviewText.setTextSize(mLabelTextSize);
- } else {
- mPreviewText.setTextSize(mPreviewTextSizeLarge);
- }
- }
- mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width
- + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight());
- final int popupHeight = mPreviewHeight;
- LayoutParams lp = mPreviewText.getLayoutParams();
- if (lp != null) {
- lp.width = popupWidth;
- lp.height = popupHeight;
- }
- previewPopup.setWidth(popupWidth);
- previewPopup.setHeight(popupHeight);
- if (!mPreviewCentered) {
- mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + mPaddingLeft;
- mPopupPreviewY = key.y - popupHeight + mPreviewOffset;
- } else {
- // TODO: Fix this if centering is brought back
- mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2;
- mPopupPreviewY = - mPreviewText.getMeasuredHeight();
- }
- mHandler.removeMessages(MSG_REMOVE_PREVIEW);
- if (mOffsetInWindow == null) {
- mOffsetInWindow = new int[2];
- getLocationInWindow(mOffsetInWindow);
- mOffsetInWindow[0] += mMiniKeyboardOffsetX; // Offset may be zero
- mOffsetInWindow[1] += mMiniKeyboardOffsetY; // Offset may be zero
- }
- // Set the preview background state
- mPreviewText.getBackground().setState(
- key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET);
- if (previewPopup.isShowing()) {
- previewPopup.update(mPopupParent, mPopupPreviewX + mOffsetInWindow[0],
- mPopupPreviewY + mOffsetInWindow[1],
- popupWidth, popupHeight);
+ if (previewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) {
+ // Show right away, if it's already visible and finger is moving around
+ showKey(keyIndex);
} else {
- previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY,
- mPopupPreviewX + mOffsetInWindow[0],
- mPopupPreviewY + mOffsetInWindow[1]);
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0),
+ DELAY_BEFORE_PREVIEW);
}
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_PREVIEW, keyIndex, 0),
- ViewConfiguration.getTapTimeout());
}
}
}
+
+ private void showKey(final int keyIndex) {
+ final PopupWindow previewPopup = mPreviewPopup;
+ final Key[] keys = mKeys;
+ Key key = keys[keyIndex];
+ if (key.icon != null) {
+ mPreviewText.setCompoundDrawables(null, null, null,
+ key.iconPreview != null ? key.iconPreview : key.icon);
+ mPreviewText.setText(null);
+ } else {
+ mPreviewText.setCompoundDrawables(null, null, null, null);
+ mPreviewText.setText(getPreviewText(key));
+ if (key.label.length() > 1 && key.codes.length < 2) {
+ mPreviewText.setTextSize(mKeyTextSize);
+ mPreviewText.setTypeface(Typeface.DEFAULT_BOLD);
+ } else {
+ mPreviewText.setTextSize(mPreviewTextSizeLarge);
+ mPreviewText.setTypeface(Typeface.DEFAULT);
+ }
+ }
+ mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width
+ + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight());
+ final int popupHeight = mPreviewHeight;
+ LayoutParams lp = mPreviewText.getLayoutParams();
+ if (lp != null) {
+ lp.width = popupWidth;
+ lp.height = popupHeight;
+ }
+ if (!mPreviewCentered) {
+ mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + mPaddingLeft;
+ mPopupPreviewY = key.y - popupHeight + mPreviewOffset;
+ } else {
+ // TODO: Fix this if centering is brought back
+ mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2;
+ mPopupPreviewY = - mPreviewText.getMeasuredHeight();
+ }
+ mHandler.removeMessages(MSG_REMOVE_PREVIEW);
+ if (mOffsetInWindow == null) {
+ mOffsetInWindow = new int[2];
+ getLocationInWindow(mOffsetInWindow);
+ mOffsetInWindow[0] += mMiniKeyboardOffsetX; // Offset may be zero
+ mOffsetInWindow[1] += mMiniKeyboardOffsetY; // Offset may be zero
+ }
+ // Set the preview background state
+ mPreviewText.getBackground().setState(
+ key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET);
+ if (previewPopup.isShowing()) {
+ previewPopup.update(mPopupPreviewX + mOffsetInWindow[0],
+ mPopupPreviewY + mOffsetInWindow[1],
+ popupWidth, popupHeight);
+ } else {
+ previewPopup.setWidth(popupWidth);
+ previewPopup.setHeight(popupHeight);
+ previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY,
+ mPopupPreviewX + mOffsetInWindow[0],
+ mPopupPreviewY + mOffsetInWindow[1]);
+ }
+ mPreviewText.setVisibility(VISIBLE);
+ }
+ private void invalidateAll() {
+ mDirtyRect.union(0, 0, getWidth(), getHeight());
+ mDrawPending = true;
+ invalidate();
+ }
+
private void invalidateKey(int keyIndex) {
- if (keyIndex < 0 || keyIndex >= mKeyboard.getKeys().size()) {
+ if (keyIndex < 0 || keyIndex >= mKeys.length) {
return;
}
- final Key key = mKeyboard.getKeys().get(keyIndex);
+ final Key key = mKeys[keyIndex];
mInvalidatedKey = key;
+ mDirtyRect.union(key.x + mPaddingLeft, key.y + mPaddingTop,
+ key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop);
+ onBufferDraw();
invalidate(key.x + mPaddingLeft, key.y + mPaddingTop,
key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop);
}
@@ -838,11 +900,11 @@ public class KeyboardView extends View implements View.OnClickListener {
if (mPopupLayout == 0) {
return false;
}
- if (mCurrentKey < 0 || mCurrentKey >= mKeyboard.getKeys().size()) {
+ if (mCurrentKey < 0 || mCurrentKey >= mKeys.length) {
return false;
}
- Key popupKey = mKeyboard.getKeys().get(mCurrentKey);
+ Key popupKey = mKeys[mCurrentKey];
boolean result = onLongPress(popupKey);
if (result) {
mAbortKey = true;
@@ -878,6 +940,11 @@ public class KeyboardView extends View implements View.OnClickListener {
dismissPopupKeyboard();
}
+ public void onText(CharSequence text) {
+ mKeyboardActionListener.onText(text);
+ dismissPopupKeyboard();
+ }
+
public void swipeLeft() { }
public void swipeRight() { }
public void swipeUp() { }
@@ -926,7 +993,7 @@ public class KeyboardView extends View implements View.OnClickListener {
mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y);
mMiniKeyboardOnScreen = true;
//mMiniKeyboard.onTouchEvent(getTranslatedEvent(me));
- invalidate();
+ invalidateAll();
return true;
}
return false;
@@ -968,8 +1035,8 @@ public class KeyboardView extends View implements View.OnClickListener {
mLastMoveTime = mDownTime;
checkMultiTap(eventTime, keyIndex);
mKeyboardActionListener.onPress(keyIndex != NOT_A_KEY ?
- mKeyboard.getKeys().get(keyIndex).codes[0] : 0);
- if (mCurrentKey >= 0 && mKeyboard.getKeys().get(mCurrentKey).repeatable) {
+ mKeys[keyIndex].codes[0] : 0);
+ if (mCurrentKey >= 0 && mKeys[mCurrentKey].repeatable) {
mRepeatKeyIndex = mCurrentKey;
repeatKey();
Message msg = mHandler.obtainMessage(MSG_REPEAT);
@@ -1040,11 +1107,11 @@ public class KeyboardView extends View implements View.OnClickListener {
}
showPreview(NOT_A_KEY);
Arrays.fill(mKeyIndices, NOT_A_KEY);
- invalidateKey(keyIndex);
// If we're not on a repeating key (which sends on a DOWN event)
if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) {
detectAndSendKey(touchX, touchY, eventTime);
}
+ invalidateKey(keyIndex);
mRepeatKeyIndex = NOT_A_KEY;
break;
}
@@ -1054,7 +1121,7 @@ public class KeyboardView extends View implements View.OnClickListener {
}
private boolean repeatKey() {
- Key key = mKeyboard.getKeys().get(mRepeatKeyIndex);
+ Key key = mKeys[mRepeatKeyIndex];
detectAndSendKey(key.x, key.y, mLastTapTime);
return true;
}
@@ -1079,7 +1146,14 @@ public class KeyboardView extends View implements View.OnClickListener {
if (mPreviewPopup.isShowing()) {
mPreviewPopup.dismiss();
}
+ mHandler.removeMessages(MSG_REPEAT);
+ mHandler.removeMessages(MSG_LONGPRESS);
+ mHandler.removeMessages(MSG_SHOW_PREVIEW);
+
dismissPopupKeyboard();
+ mBuffer = null;
+ mCanvas = null;
+ mMiniKeyboardCache.clear();
}
@Override
@@ -1092,10 +1166,10 @@ public class KeyboardView extends View implements View.OnClickListener {
if (mPopupKeyboard.isShowing()) {
mPopupKeyboard.dismiss();
mMiniKeyboardOnScreen = false;
- invalidate();
+ invalidateAll();
}
}
-
+
public boolean handleBack() {
if (mPopupKeyboard.isShowing()) {
dismissPopupKeyboard();
@@ -1113,7 +1187,7 @@ public class KeyboardView extends View implements View.OnClickListener {
private void checkMultiTap(long eventTime, int keyIndex) {
if (keyIndex == NOT_A_KEY) return;
- Key key = mKeyboard.getKeys().get(keyIndex);
+ Key key = mKeys[keyIndex];
if (key.codes.length > 1) {
mInMultiTap = true;
if (eventTime < mLastTapTime + MULTITAP_INTERVAL
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index 9ff1665..c37845f 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -18,6 +18,7 @@ package android.inputmethodservice;
import android.app.Dialog;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.os.IBinder;
import android.view.Gravity;
import android.view.WindowManager;
@@ -139,6 +140,9 @@ class SoftInputWindow extends Dialog {
lp.gravity = Gravity.BOTTOM;
lp.width = -1;
+ // Let the input method window's orientation follow sensor based rotation
+ // Turn this off for now, it is very problematic.
+ //lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
getWindow().setAttributes(lp);
getWindow().setFlags(
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 213813a..1429bc1 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -16,6 +16,8 @@
package android.net;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.os.RemoteException;
/**
@@ -100,6 +102,18 @@ public class ConnectivityManager
*/
public static final String EXTRA_EXTRA_INFO = "extraInfo";
+ /**
+ * Broadcast Action: The setting for background data usage has changed
+ * values. Use {@link #getBackgroundDataSetting()} to get the current value.
+ * <p>
+ * If an application uses the network in the background, it should listen
+ * for this broadcast and stop using the background data if the value is
+ * false.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
+ "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+
public static final int TYPE_MOBILE = 0;
public static final int TYPE_WIFI = 1;
@@ -224,6 +238,43 @@ public class ConnectivityManager
}
/**
+ * Returns the value of the setting for background data usage. If false,
+ * applications should not use the network if the application is not in the
+ * foreground. Developers should respect this setting, and check the value
+ * of this before performing any background data operations.
+ * <p>
+ * All applications that have background services that use the network
+ * should listen to {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}.
+ *
+ * @return Whether background data usage is allowed.
+ */
+ public boolean getBackgroundDataSetting() {
+ try {
+ return mService.getBackgroundDataSetting();
+ } catch (RemoteException e) {
+ // Err on the side of safety
+ return false;
+ }
+ }
+
+ /**
+ * Sets the value of the setting for background data usage.
+ *
+ * @param allowBackgroundData Whether an application should use data while
+ * it is in the background.
+ *
+ * @attr ref android.Manifest.permission#CHANGE_BACKGROUND_DATA_SETTING
+ * @see #getBackgroundDataSetting()
+ * @hide
+ */
+ public void setBackgroundDataSetting(boolean allowBackgroundData) {
+ try {
+ mService.setBackgroundDataSetting(allowBackgroundData);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Don't allow use of default constructor.
*/
@SuppressWarnings({"UnusedDeclaration"})
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index e1d921f..de68598 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -44,4 +44,8 @@ interface IConnectivityManager
int stopUsingNetworkFeature(int networkType, in String feature);
boolean requestRouteToHost(int networkType, int hostAddress);
+
+ boolean getBackgroundDataSetting();
+
+ void setBackgroundDataSetting(boolean allowBackgroundData);
}
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index f816caa..deaa3c3 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -16,38 +16,45 @@
package android.net;
-import android.util.Log;
-import android.util.Config;
import android.net.http.DomainNameChecker;
import android.os.SystemProperties;
-
-import javax.net.SocketFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
+import android.util.Config;
+import android.util.Log;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
-import java.security.NoSuchAlgorithmException;
+import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
-import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
+
+/**
+ * SSLSocketFactory that provides optional (on debug devices, only) skipping of ssl certificfate
+ * chain validation and custom read timeouts used just when connecting to the server/negotiating
+ * an ssl session.
+ *
+ * You can skip the ssl certificate checking at runtime by setting socket.relaxsslcheck=yes on
+ * devices that do not have have ro.secure set.
+ */
public class SSLCertificateSocketFactory extends SSLSocketFactory {
- private static final boolean DBG = true;
private static final String LOG_TAG = "SSLCertificateSocketFactory";
-
- private static X509TrustManager sDefaultTrustManager;
- private final int socketReadTimeoutForSslHandshake;
+ private static X509TrustManager sDefaultTrustManager;
static {
try {
@@ -83,27 +90,56 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
};
- private SSLSocketFactory factory;
+ private final SSLSocketFactory mFactory;
+
+ private final int mSocketReadTimeoutForSslHandshake;
+ /**
+ * Do not use this constructor (will be deprecated). Use {@link #getDefault(int)} instead.
+ */
public SSLCertificateSocketFactory(int socketReadTimeoutForSslHandshake)
- throws NoSuchAlgorithmException, KeyManagementException {
- SSLContext context = SSLContext.getInstance("TLS");
- context.init(null, TRUST_MANAGER, new java.security.SecureRandom());
- factory = (SSLSocketFactory) context.getSocketFactory();
- this.socketReadTimeoutForSslHandshake = socketReadTimeoutForSslHandshake;
+ throws NoSuchAlgorithmException, KeyManagementException {
+ this(socketReadTimeoutForSslHandshake, null /* cache */);
+ }
+
+ private SSLCertificateSocketFactory(int socketReadTimeoutForSslHandshake,
+ SSLClientSessionCache cache) throws NoSuchAlgorithmException, KeyManagementException {
+ SSLContextImpl sslContext = new SSLContextImpl();
+ sslContext.engineInit(null /* kms */,
+ TRUST_MANAGER, new java.security.SecureRandom(),
+ cache /* client cache */, null /* server cache */);
+ this.mFactory = sslContext.engineGetSocketFactory();
+ this.mSocketReadTimeoutForSslHandshake = socketReadTimeoutForSslHandshake;
}
/**
- * Returns a default instantiation of a new socket factory which
- * only allows SSL connections with valid certificates.
+ * Returns a new instance of a socket factory using the specified socket read
+ * timeout while connecting with the server/negotiating an ssl session.
*
* @param socketReadTimeoutForSslHandshake the socket read timeout used for performing
* ssl handshake. The socket read timeout is set back to 0 after the handshake.
* @return a new SocketFactory, or null on error
*/
public static SocketFactory getDefault(int socketReadTimeoutForSslHandshake) {
+ return getDefault(socketReadTimeoutForSslHandshake, null /* cache */);
+ }
+
+ /**
+ * Returns a new instance of a socket factory using the specified socket read
+ * timeout while connecting with the server/negotiating an ssl session.
+ * Persists ssl sessions using the provided {@link SSLClientSessionCache}.
+ *
+ * @param socketReadTimeoutForSslHandshake the socket read timeout used for performing
+ * ssl handshake. The socket read timeout is set back to 0 after the handshake.
+ * @param cache The {@link SSLClientSessionCache} to use, if any.
+ * @return a new SocketFactory, or null on error
+ *
+ * @hide
+ */
+ public static SocketFactory getDefault(int socketReadTimeoutForSslHandshake,
+ SSLClientSessionCache cache) {
try {
- return new SSLCertificateSocketFactory(socketReadTimeoutForSslHandshake);
+ return new SSLCertificateSocketFactory(socketReadTimeoutForSslHandshake, cache);
} catch (NoSuchAlgorithmException e) {
Log.e(LOG_TAG,
"SSLCertifcateSocketFactory.getDefault" +
@@ -217,10 +253,10 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
public Socket createSocket(String s, int i, InetAddress inaddr, int j) throws IOException {
- SSLSocket sslSock = (SSLSocket) factory.createSocket(s, i, inaddr, j);
+ SSLSocket sslSock = (SSLSocket) mFactory.createSocket(s, i, inaddr, j);
- if (socketReadTimeoutForSslHandshake >= 0) {
- sslSock.setSoTimeout(socketReadTimeoutForSslHandshake);
+ if (mSocketReadTimeoutForSslHandshake >= 0) {
+ sslSock.setSoTimeout(mSocketReadTimeoutForSslHandshake);
}
validateSocket(sslSock,s);
@@ -230,10 +266,10 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
public Socket createSocket(String s, int i) throws IOException {
- SSLSocket sslSock = (SSLSocket) factory.createSocket(s, i);
+ SSLSocket sslSock = (SSLSocket) mFactory.createSocket(s, i);
- if (socketReadTimeoutForSslHandshake >= 0) {
- sslSock.setSoTimeout(socketReadTimeoutForSslHandshake);
+ if (mSocketReadTimeoutForSslHandshake >= 0) {
+ sslSock.setSoTimeout(mSocketReadTimeoutForSslHandshake);
}
validateSocket(sslSock,s);
@@ -243,11 +279,11 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
public String[] getDefaultCipherSuites() {
- return factory.getSupportedCipherSuites();
+ return mFactory.getSupportedCipherSuites();
}
public String[] getSupportedCipherSuites() {
- return factory.getSupportedCipherSuites();
+ return mFactory.getSupportedCipherSuites();
}
}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 32a26e4..c23df21 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -2235,12 +2235,13 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
/**
- * Creates a new Uri by encoding and appending a path segment to a base Uri.
+ * Creates a new Uri by appending an already-encoded path segment to a
+ * base Uri.
*
* @param baseUri Uri to append path segment to
- * @param pathSegment to encode and append
- * @return a new Uri based on baseUri with the given segment encoded and
- * appended to the path
+ * @param pathSegment encoded path segment to append
+ * @return a new Uri based on baseUri with the given segment appended to
+ * the path
* @throws NullPointerException if baseUri is null
*/
public static Uri withAppendedPath(Uri baseUri, String pathSegment) {
diff --git a/core/java/android/net/UrlQuerySanitizer.java b/core/java/android/net/UrlQuerySanitizer.java
index 70e50b7..a6efcdd 100644
--- a/core/java/android/net/UrlQuerySanitizer.java
+++ b/core/java/android/net/UrlQuerySanitizer.java
@@ -23,7 +23,7 @@ import java.util.Set;
import java.util.StringTokenizer;
/**
- *
+ *
* Sanitizes the Query portion of a URL. Simple example:
* <code>
* UrlQuerySanitizer sanitizer = new UrlQuerySanitizer();
@@ -32,7 +32,7 @@ import java.util.StringTokenizer;
* String name = sanitizer.getValue("name"));
* // name now contains "Joe_User"
* </code>
- *
+ *
* Register ValueSanitizers to customize the way individual
* parameters are sanitized:
* <code>
@@ -46,7 +46,7 @@ import java.util.StringTokenizer;
* unregistered parameter sanitizer does not allow any special characters,
* and ' ' is a special character.)
* </code>
- *
+ *
* There are several ways to create ValueSanitizers. In order of increasing
* sophistication:
* <ol>
@@ -56,7 +56,7 @@ import java.util.StringTokenizer;
* <li>Subclass UrlQuerySanitizer.ValueSanitizer to define your own value
* sanitizer.
* </ol>
- *
+ *
*/
public class UrlQuerySanitizer {
@@ -84,7 +84,7 @@ public class UrlQuerySanitizer {
*/
public String mValue;
}
-
+
final private HashMap<String, ValueSanitizer> mSanitizers =
new HashMap<String, ValueSanitizer>();
final private HashMap<String, String> mEntries =
@@ -95,9 +95,9 @@ public class UrlQuerySanitizer {
private boolean mPreferFirstRepeatedParameter;
private ValueSanitizer mUnregisteredParameterValueSanitizer =
getAllIllegal();
-
+
/**
- * A functor used to sanitize a single query value.
+ * A functor used to sanitize a single query value.
*
*/
public static interface ValueSanitizer {
@@ -108,7 +108,7 @@ public class UrlQuerySanitizer {
*/
public String sanitize(String value);
}
-
+
/**
* Sanitize values based on which characters they contain. Illegal
* characters are replaced with either space or '_', depending upon
@@ -117,7 +117,7 @@ public class UrlQuerySanitizer {
public static class IllegalCharacterValueSanitizer implements
ValueSanitizer {
private int mFlags;
-
+
/**
* Allow space (' ') characters.
*/
@@ -165,21 +165,21 @@ public class UrlQuerySanitizer {
* such as "javascript:" or "vbscript:"
*/
public final static int SCRIPT_URL_OK = 1 << 10;
-
+
/**
* Mask with all fields set to OK
*/
public final static int ALL_OK = 0x7ff;
-
+
/**
* Mask with both regular space and other whitespace OK
*/
public final static int ALL_WHITESPACE_OK =
SPACE_OK | OTHER_WHITESPACE_OK;
-
+
// Common flag combinations:
-
+
/**
* <ul>
* <li>Deny all special characters.
@@ -262,18 +262,18 @@ public class UrlQuerySanitizer {
*/
public final static int ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL =
ALL_OK & ~(NUL_OK | LT_OK | GT_OK);
-
+
/**
* Script URL definitions
*/
-
+
private final static String JAVASCRIPT_PREFIX = "javascript:";
-
+
private final static String VBSCRIPT_PREFIX = "vbscript:";
-
+
private final static int MIN_SCRIPT_PREFIX_LENGTH = Math.min(
JAVASCRIPT_PREFIX.length(), VBSCRIPT_PREFIX.length());
-
+
/**
* Construct a sanitizer. The parameters set the behavior of the
* sanitizer.
@@ -312,7 +312,7 @@ public class UrlQuerySanitizer {
}
}
}
-
+
// If whitespace isn't OK, get rid of whitespace at beginning
// and end of value.
if ( (mFlags & ALL_WHITESPACE_OK) == 0) {
@@ -337,7 +337,7 @@ public class UrlQuerySanitizer {
}
return stringBuilder.toString();
}
-
+
/**
* Trim whitespace from the beginning and end of a string.
* <p>
@@ -361,7 +361,7 @@ public class UrlQuerySanitizer {
}
return value.substring(start, end + 1);
}
-
+
/**
* Check if c is whitespace.
* @param c character to test
@@ -380,7 +380,7 @@ public class UrlQuerySanitizer {
return false;
}
}
-
+
/**
* Check whether an individual character is legal. Uses the
* flag bit-set passed into the constructor.
@@ -400,11 +400,11 @@ public class UrlQuerySanitizer {
case '%' : return (mFlags & PCT_OK) != 0;
case '\0': return (mFlags & NUL_OK) != 0;
default : return (c >= 32 && c < 127) ||
- (c >= 128 && c <= 255 && ((mFlags & NON_7_BIT_ASCII_OK) != 0));
- }
+ ((c >= 128) && ((mFlags & NON_7_BIT_ASCII_OK) != 0));
+ }
}
}
-
+
/**
* Get the current value sanitizer used when processing
* unregistered parameter values.
@@ -412,14 +412,14 @@ public class UrlQuerySanitizer {
* <b>Note:</b> The default unregistered parameter value sanitizer is
* one that doesn't allow any special characters, similar to what
* is returned by calling createAllIllegal.
- *
+ *
* @return the current ValueSanitizer used to sanitize unregistered
* parameter values.
*/
public ValueSanitizer getUnregisteredParameterValueSanitizer() {
return mUnregisteredParameterValueSanitizer;
}
-
+
/**
* Set the value sanitizer used when processing unregistered
* parameter values.
@@ -430,46 +430,46 @@ public class UrlQuerySanitizer {
ValueSanitizer sanitizer) {
mUnregisteredParameterValueSanitizer = sanitizer;
}
-
-
+
+
// Private fields for singleton sanitizers:
-
+
private static final ValueSanitizer sAllIllegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_ILLEGAL);
-
+
private static final ValueSanitizer sAllButNulLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_BUT_NUL_LEGAL);
-
+
private static final ValueSanitizer sAllButWhitespaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_BUT_WHITESPACE_LEGAL);
-
+
private static final ValueSanitizer sURLLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.URL_LEGAL);
-
+
private static final ValueSanitizer sUrlAndSpaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.URL_AND_SPACE_LEGAL);
-
+
private static final ValueSanitizer sAmpLegal =
new IllegalCharacterValueSanitizer(
- IllegalCharacterValueSanitizer.AMP_LEGAL);
-
+ IllegalCharacterValueSanitizer.AMP_LEGAL);
+
private static final ValueSanitizer sAmpAndSpaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.AMP_AND_SPACE_LEGAL);
-
+
private static final ValueSanitizer sSpaceLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.SPACE_LEGAL);
-
+
private static final ValueSanitizer sAllButNulAndAngleBracketsLegal =
new IllegalCharacterValueSanitizer(
IllegalCharacterValueSanitizer.ALL_BUT_NUL_AND_ANGLE_BRACKETS_LEGAL);
-
+
/**
* Return a value sanitizer that does not allow any special characters,
* and also does not allow script URLs.
@@ -478,7 +478,7 @@ public class UrlQuerySanitizer {
public static final ValueSanitizer getAllIllegal() {
return sAllIllegal;
}
-
+
/**
* Return a value sanitizer that allows everything except Nul ('\0')
* characters. Script URLs are allowed.
@@ -547,7 +547,7 @@ public class UrlQuerySanitizer {
public static final ValueSanitizer getAllButNulAndAngleBracketsLegal() {
return sAllButNulAndAngleBracketsLegal;
}
-
+
/**
* Constructs a UrlQuerySanitizer.
* <p>
@@ -560,7 +560,7 @@ public class UrlQuerySanitizer {
*/
public UrlQuerySanitizer() {
}
-
+
/**
* Constructs a UrlQuerySanitizer and parse a URL.
* This constructor is provided for convenience when the
@@ -585,7 +585,7 @@ public class UrlQuerySanitizer {
setAllowUnregisteredParamaters(true);
parseUrl(url);
}
-
+
/**
* Parse the query parameters out of an encoded URL.
* Works by extracting the query portion from the URL and then
@@ -604,7 +604,7 @@ public class UrlQuerySanitizer {
}
parseQuery(query);
}
-
+
/**
* Parse a query. A query string is any number of parameter-value clauses
* separated by any non-zero number of ampersands. A parameter-value clause
@@ -631,7 +631,7 @@ public class UrlQuerySanitizer {
}
}
}
-
+
/**
* Get a set of all of the parameters found in the sanitized query.
* <p>
@@ -641,7 +641,7 @@ public class UrlQuerySanitizer {
public Set<String> getParameterSet() {
return mEntries.keySet();
}
-
+
/**
* An array list of all of the parameter value pairs in the sanitized
* query, in the order they appeared in the query. May contain duplicate
@@ -691,7 +691,7 @@ public class UrlQuerySanitizer {
}
mSanitizers.put(parameter, valueSanitizer);
}
-
+
/**
* Register a value sanitizer for an array of parameters.
* @param parameters An array of unencoded parameter names.
@@ -705,7 +705,7 @@ public class UrlQuerySanitizer {
mSanitizers.put(parameters[i], valueSanitizer);
}
}
-
+
/**
* Set whether or not unregistered parameters are allowed. If they
* are not allowed, then they will be dropped when a query is sanitized.
@@ -718,7 +718,7 @@ public class UrlQuerySanitizer {
boolean allowUnregisteredParamaters) {
mAllowUnregisteredParamaters = allowUnregisteredParamaters;
}
-
+
/**
* Get whether or not unregistered parameters are allowed. If not
* allowed, they will be dropped when a query is parsed.
@@ -728,10 +728,10 @@ public class UrlQuerySanitizer {
public boolean getAllowUnregisteredParamaters() {
return mAllowUnregisteredParamaters;
}
-
+
/**
* Set whether or not the first occurrence of a repeated parameter is
- * preferred. True means the first repeated parameter is preferred.
+ * preferred. True means the first repeated parameter is preferred.
* False means that the last repeated parameter is preferred.
* <p>
* The preferred parameter is the one that is returned when getParameter
@@ -746,7 +746,7 @@ public class UrlQuerySanitizer {
boolean preferFirstRepeatedParameter) {
mPreferFirstRepeatedParameter = preferFirstRepeatedParameter;
}
-
+
/**
* Get whether or not the first occurrence of a repeated parameter is
* preferred.
@@ -757,10 +757,10 @@ public class UrlQuerySanitizer {
public boolean getPreferFirstRepeatedParameter() {
return mPreferFirstRepeatedParameter;
}
-
+
/**
* Parse an escaped parameter-value pair. The default implementation
- * unescapes both the parameter and the value, then looks up the
+ * unescapes both the parameter and the value, then looks up the
* effective value sanitizer for the parameter and uses it to sanitize
* the value. If all goes well then addSanitizedValue is called with
* the unescaped parameter and the sanitized unescaped value.
@@ -779,7 +779,7 @@ public class UrlQuerySanitizer {
String sanitizedValue = valueSanitizer.sanitize(unescapedValue);
addSanitizedEntry(unescapedParameter, sanitizedValue);
}
-
+
/**
* Record a sanitized parameter-value pair. Override if you want to
* do additional filtering or validation.
@@ -796,7 +796,7 @@ public class UrlQuerySanitizer {
}
mEntries.put(parameter, value);
}
-
+
/**
* Get the value sanitizer for a parameter. Returns null if there
* is no value sanitizer registered for the parameter.
@@ -807,7 +807,7 @@ public class UrlQuerySanitizer {
public ValueSanitizer getValueSanitizer(String parameter) {
return mSanitizers.get(parameter);
}
-
+
/**
* Get the effective value sanitizer for a parameter. Like getValueSanitizer,
* except if there is no value sanitizer registered for a parameter, and
@@ -823,7 +823,7 @@ public class UrlQuerySanitizer {
}
return sanitizer;
}
-
+
/**
* Unescape an escaped string.
* <ul>
@@ -867,7 +867,7 @@ public class UrlQuerySanitizer {
}
return stringBuilder.toString();
}
-
+
/**
* Test if a character is a hexidecimal digit. Both upper case and lower
* case hex digits are allowed.
@@ -877,7 +877,7 @@ public class UrlQuerySanitizer {
protected boolean isHexDigit(char c) {
return decodeHexDigit(c) >= 0;
}
-
+
/**
* Convert a character that represents a hexidecimal digit into an integer.
* If the character is not a hexidecimal digit, then -1 is returned.
@@ -885,7 +885,7 @@ public class UrlQuerySanitizer {
* @param c the hexidecimal digit.
* @return the integer value of the hexidecimal digit.
*/
-
+
protected int decodeHexDigit(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
@@ -900,7 +900,7 @@ public class UrlQuerySanitizer {
return -1;
}
}
-
+
/**
* Clear the existing entries. Called to get ready to parse a new
* query string.
diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java
index 01442ae..c2013d5 100644
--- a/core/java/android/net/http/AndroidHttpClient.java
+++ b/core/java/android/net/http/AndroidHttpClient.java
@@ -26,7 +26,6 @@ import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.ClientProtocolException;
@@ -48,6 +47,8 @@ import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.BasicHttpContext;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
import java.io.IOException;
import java.io.InputStream;
@@ -56,12 +57,13 @@ import java.io.OutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.net.URI;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.security.KeyManagementException;
import android.util.Log;
import android.content.ContentResolver;
import android.provider.Settings;
import android.text.TextUtils;
+import android.os.SystemProperties;
/**
* Subclass of the Apache {@link DefaultHttpClient} that is configured with
@@ -100,10 +102,13 @@ public final class AndroidHttpClient implements HttpClient {
/**
* Create a new HttpClient with reasonable defaults (which you can update).
+ *
* @param userAgent to report in your HTTP requests.
+ * @param sessionCache persistent session cache
* @return AndroidHttpClient for you to use for all your requests.
*/
- public static AndroidHttpClient newInstance(String userAgent) {
+ public static AndroidHttpClient newInstance(String userAgent,
+ SSLClientSessionCache sessionCache) {
HttpParams params = new BasicHttpParams();
// Turn off stale checking. Our connections break all the time anyway,
@@ -125,7 +130,8 @@ public final class AndroidHttpClient implements HttpClient {
schemeRegistry.register(new Scheme("http",
PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https",
- SSLSocketFactory.getSocketFactory(), 443));
+ socketFactoryWithCache(sessionCache), 443));
+
ClientConnectionManager manager =
new ThreadSafeClientConnManager(params, schemeRegistry);
@@ -134,6 +140,41 @@ public final class AndroidHttpClient implements HttpClient {
return new AndroidHttpClient(manager, params);
}
+ /**
+ * Returns a socket factory backed by the given persistent session cache.
+ *
+ * @param sessionCache to retrieve sessions from, null for no cache
+ */
+ private static SSLSocketFactory socketFactoryWithCache(
+ SSLClientSessionCache sessionCache) {
+ if (sessionCache == null) {
+ // Use the default factory which doesn't support persistent
+ // caching.
+ return SSLSocketFactory.getSocketFactory();
+ }
+
+ // Create a new SSL context backed by the cache.
+ // TODO: Keep a weak *identity* hash map of caches to engines. In the
+ // mean time, if we have two engines for the same cache, they'll still
+ // share sessions but will have to do so through the persistent cache.
+ SSLContextImpl sslContext = new SSLContextImpl();
+ try {
+ sslContext.engineInit(null, null, null, sessionCache, null);
+ } catch (KeyManagementException e) {
+ throw new AssertionError(e);
+ }
+ return new SSLSocketFactory(sslContext.engineGetSocketFactory());
+ }
+
+ /**
+ * Create a new HttpClient with reasonable defaults (which you can update).
+ * @param userAgent to report in your HTTP requests.
+ * @return AndroidHttpClient for you to use for all your requests.
+ */
+ public static AndroidHttpClient newInstance(String userAgent) {
+ return newInstance(userAgent, null /* session cache */);
+ }
+
private final HttpClient delegate;
private RuntimeException mLeakedException = new IllegalStateException(
@@ -347,6 +388,15 @@ public final class AndroidHttpClient implements HttpClient {
}
/**
+ * Returns true if auth logging is turned on for this configuration. Can only be set on
+ * insecure devices.
+ */
+ private boolean isAuthLoggable() {
+ String secure = SystemProperties.get("ro.secure");
+ return "0".equals(secure) && Log.isLoggable(tag + "-auth", level);
+ }
+
+ /**
* Prints a message using this configuration.
*/
private void println(String message) {
@@ -392,7 +442,8 @@ public final class AndroidHttpClient implements HttpClient {
if (configuration != null
&& configuration.isLoggable()
&& request instanceof HttpUriRequest) {
- configuration.println(toCurl((HttpUriRequest) request));
+ configuration.println(toCurl((HttpUriRequest) request,
+ configuration.isAuthLoggable()));
}
}
}
@@ -400,12 +451,17 @@ public final class AndroidHttpClient implements HttpClient {
/**
* Generates a cURL command equivalent to the given request.
*/
- private static String toCurl(HttpUriRequest request) throws IOException {
+ private static String toCurl(HttpUriRequest request, boolean logAuthToken) throws IOException {
StringBuilder builder = new StringBuilder();
builder.append("curl ");
for (Header header: request.getAllHeaders()) {
+ if (!logAuthToken
+ && (header.getName().equals("Authorization") ||
+ header.getName().equals("Cookie"))) {
+ continue;
+ }
builder.append("--header \"");
builder.append(header.toString().trim());
builder.append("\" ");
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index b7f7368..0edbe5b 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -16,8 +16,6 @@
package android.net.http;
-import android.os.SystemClock;
-
import java.io.IOException;
import java.security.cert.Certificate;
@@ -28,23 +26,13 @@ import java.security.cert.X509Certificate;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.Enumeration;
-
-import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
-import org.apache.http.HttpHost;
-
-import org.bouncycastle.asn1.x509.X509Name;
-
/**
* Class responsible for all server certificate validation functionality
*
@@ -52,9 +40,6 @@ import org.bouncycastle.asn1.x509.X509Name;
*/
class CertificateChainValidator {
- private static long sTotal = 0;
- private static long sTotalReused = 0;
-
/**
* The singleton instance of the certificate chain validator
*/
@@ -110,91 +95,42 @@ class CertificateChainValidator {
* @return An SSL error object if there is an error and null otherwise
*/
public SslError doHandshakeAndValidateServerCertificates(
- HttpsConnection connection, SSLSocket sslSocket, String domain)
- throws SSLHandshakeException, IOException {
-
- ++sTotal;
-
- SSLContext sslContext = HttpsConnection.getContext();
- if (sslContext == null) {
- closeSocketThrowException(sslSocket, "SSL context is null");
- }
-
+ HttpsConnection connection, SSLSocket sslSocket, String domain)
+ throws IOException {
X509Certificate[] serverCertificates = null;
- long sessionBeforeHandshakeLastAccessedTime = 0;
- byte[] sessionBeforeHandshakeId = null;
-
- SSLSession sessionAfterHandshake = null;
-
- synchronized(sslContext) {
- // get SSL session before the handshake
- SSLSession sessionBeforeHandshake =
- getSSLSession(sslContext, connection.getHost());
- if (sessionBeforeHandshake != null) {
- sessionBeforeHandshakeLastAccessedTime =
- sessionBeforeHandshake.getLastAccessedTime();
+ // start handshake, close the socket if we fail
+ try {
+ sslSocket.setUseClientMode(true);
+ sslSocket.startHandshake();
+ } catch (IOException e) {
+ closeSocketThrowException(
+ sslSocket, e.getMessage(),
+ "failed to perform SSL handshake");
+ }
- sessionBeforeHandshakeId =
- sessionBeforeHandshake.getId();
- }
+ // retrieve the chain of the server peer certificates
+ Certificate[] peerCertificates =
+ sslSocket.getSession().getPeerCertificates();
- // start handshake, close the socket if we fail
- try {
- sslSocket.setUseClientMode(true);
- sslSocket.startHandshake();
- } catch (IOException e) {
- closeSocketThrowException(
- sslSocket, e.getMessage(),
- "failed to perform SSL handshake");
+ if (peerCertificates == null || peerCertificates.length <= 0) {
+ closeSocketThrowException(
+ sslSocket, "failed to retrieve peer certificates");
+ } else {
+ serverCertificates =
+ new X509Certificate[peerCertificates.length];
+ for (int i = 0; i < peerCertificates.length; ++i) {
+ serverCertificates[i] =
+ (X509Certificate)(peerCertificates[i]);
}
- // retrieve the chain of the server peer certificates
- Certificate[] peerCertificates =
- sslSocket.getSession().getPeerCertificates();
-
- if (peerCertificates == null || peerCertificates.length <= 0) {
- closeSocketThrowException(
- sslSocket, "failed to retrieve peer certificates");
- } else {
- serverCertificates =
- new X509Certificate[peerCertificates.length];
- for (int i = 0; i < peerCertificates.length; ++i) {
- serverCertificates[i] =
- (X509Certificate)(peerCertificates[i]);
- }
-
- // update the SSL certificate associated with the connection
- if (connection != null) {
- if (serverCertificates[0] != null) {
- connection.setCertificate(
- new SslCertificate(serverCertificates[0]));
- }
+ // update the SSL certificate associated with the connection
+ if (connection != null) {
+ if (serverCertificates[0] != null) {
+ connection.setCertificate(
+ new SslCertificate(serverCertificates[0]));
}
}
-
- // get SSL session after the handshake
- sessionAfterHandshake =
- getSSLSession(sslContext, connection.getHost());
- }
-
- if (sessionBeforeHandshakeLastAccessedTime != 0 &&
- sessionAfterHandshake != null &&
- Arrays.equals(
- sessionBeforeHandshakeId, sessionAfterHandshake.getId()) &&
- sessionBeforeHandshakeLastAccessedTime <
- sessionAfterHandshake.getLastAccessedTime()) {
-
- if (HttpLog.LOGV) {
- HttpLog.v("SSL session was reused: total reused: "
- + sTotalReused
- + " out of total of: " + sTotal);
-
- ++sTotalReused;
- }
-
- // no errors!!!
- return null;
}
// check if the first certificate in the chain is for this site
@@ -216,7 +152,6 @@ class CertificateChainValidator {
}
}
- //
// first, we validate the chain using the standard validation
// solution; if we do not find any errors, we are done; if we
// fail the standard validation, we re-validate again below,
@@ -393,14 +328,14 @@ class CertificateChainValidator {
}
private void closeSocketThrowException(
- SSLSocket socket, String errorMessage, String defaultErrorMessage)
- throws SSLHandshakeException, IOException {
+ SSLSocket socket, String errorMessage, String defaultErrorMessage)
+ throws IOException {
closeSocketThrowException(
socket, errorMessage != null ? errorMessage : defaultErrorMessage);
}
- private void closeSocketThrowException(SSLSocket socket, String errorMessage)
- throws SSLHandshakeException, IOException {
+ private void closeSocketThrowException(SSLSocket socket,
+ String errorMessage) throws IOException {
if (HttpLog.LOGV) {
HttpLog.v("validation error: " + errorMessage);
}
@@ -416,29 +351,4 @@ class CertificateChainValidator {
throw new SSLHandshakeException(errorMessage);
}
-
- /**
- * @param sslContext The SSL context shared accross all the SSL sessions
- * @param host The host associated with the session
- * @return A suitable SSL session from the SSL context
- */
- private SSLSession getSSLSession(SSLContext sslContext, HttpHost host) {
- if (sslContext != null && host != null) {
- Enumeration en = sslContext.getClientSessionContext().getIds();
- while (en.hasMoreElements()) {
- byte[] id = (byte[]) en.nextElement();
- if (id != null) {
- SSLSession session =
- sslContext.getClientSessionContext().getSession(id);
- if (session.isValid() &&
- host.getHostName().equals(session.getPeerHost()) &&
- host.getPort() == session.getPeerPort()) {
- return session;
- }
- }
- }
- }
-
- return null;
- }
}
diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java
index 65e6117..c4ee5b0 100644
--- a/core/java/android/net/http/RequestHandle.java
+++ b/core/java/android/net/http/RequestHandle.java
@@ -55,7 +55,7 @@ public class RequestHandle {
private final static String AUTHORIZATION_HEADER = "Authorization";
private final static String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization";
- private final static int MAX_REDIRECT_COUNT = 16;
+ public final static int MAX_REDIRECT_COUNT = 16;
/**
* Creates a new request session.
@@ -106,6 +106,14 @@ public class RequestHandle {
return mRedirectCount >= MAX_REDIRECT_COUNT;
}
+ public int getRedirectCount() {
+ return mRedirectCount;
+ }
+
+ public void setRedirectCount(int count) {
+ mRedirectCount = count;
+ }
+
/**
* Create and queue a redirect request.
*
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index ed7c366..7590bfe 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1,33 +1,44 @@
package android.os;
-import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Formatter;
import java.util.Map;
+import android.util.Log;
+import android.util.Printer;
import android.util.SparseArray;
/**
* A class providing access to battery usage statistics, including information on
* wakelocks, processes, packages, and services. All times are represented in microseconds
* except where indicated otherwise.
+ * @hide
*/
-public abstract class BatteryStats {
+public abstract class BatteryStats implements Parcelable {
+ private static final boolean LOCAL_LOGV = false;
+
/**
- * A constant indicating a partial wake lock.
+ * A constant indicating a partial wake lock timer.
*/
public static final int WAKE_TYPE_PARTIAL = 0;
/**
- * A constant indicating a full wake lock.
+ * A constant indicating a full wake lock timer.
*/
public static final int WAKE_TYPE_FULL = 1;
/**
- * A constant indicating a window wake lock.
+ * A constant indicating a window wake lock timer.
*/
public static final int WAKE_TYPE_WINDOW = 2;
+
+ /**
+ * A constant indicating a sensor timer.
+ *
+ * {@hide}
+ */
+ public static final int SENSOR = 3;
/**
* Include all of the data in the stats, including previously saved data.
@@ -48,6 +59,22 @@ public abstract class BatteryStats {
* Include only the run since the last time the device was unplugged in the stats.
*/
public static final int STATS_UNPLUGGED = 3;
+
+ /**
+ * Bump the version on this if the checkin format changes.
+ */
+ private static final int BATTERY_STATS_CHECKIN_VERSION = 1;
+
+ // TODO: Update this list if you add/change any stats above.
+ private static final String[] STAT_NAMES = { "total", "last", "current", "unplugged" };
+
+ private static final String APK_DATA = "apk";
+ private static final String PROCESS_DATA = "process";
+ private static final String SENSOR_DATA = "sensor";
+ 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 MISC_DATA = "misc";
private final StringBuilder mFormatBuilder = new StringBuilder(8);
private final Formatter mFormatter = new Formatter(mFormatBuilder);
@@ -69,11 +96,16 @@ public abstract class BatteryStats {
* Returns the total time in microseconds associated with this Timer for the
* selected type of statistics.
*
- * @param now system uptime time in microseconds
+ * @param batteryRealtime system realtime on battery in microseconds
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
* @return a time in microseconds
*/
- public abstract long getTotalTime(long now, int which);
+ public abstract long getTotalTime(long batteryRealtime, int which);
+
+ /**
+ * Temporary for debugging.
+ */
+ public abstract void logState();
}
/**
@@ -115,8 +147,28 @@ public abstract class BatteryStats {
* @return a Map from Strings to Uid.Pkg objects.
*/
public abstract Map<String, ? extends Pkg> getPackageStats();
+
+ /**
+ * {@hide}
+ */
+ public abstract int getUid();
+
+ /**
+ * {@hide}
+ */
+ public abstract long getTcpBytesReceived(int which);
+
+ /**
+ * {@hide}
+ */
+ public abstract long getTcpBytesSent(int which);
public static abstract class Sensor {
+ // Magic sensor number for the GPS.
+ public static final int GPS = -10000;
+
+ public abstract int getHandle();
+
public abstract Timer getSensorTime();
}
@@ -173,11 +225,11 @@ public abstract class BatteryStats {
/**
* Returns the amount of time spent started.
*
- * @param now elapsed realtime in microseconds.
+ * @param batteryUptime elapsed uptime on battery in microseconds.
* @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
* @return
*/
- public abstract long getStartTime(long now, int which);
+ public abstract long getStartTime(long batteryUptime, int which);
/**
* Returns the total number of times startService() has been called.
@@ -200,7 +252,28 @@ public abstract class BatteryStats {
* Returns the number of times the device has been started.
*/
public abstract int getStartCount();
-
+
+ /**
+ * Returns the time in milliseconds that the screen has been on while the device was
+ * running on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getScreenOnTime(long batteryRealtime, int which);
+
+ /**
+ * Returns the time in milliseconds that the phone has been on while the device was
+ * running on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getPhoneOnTime(long batteryRealtime, int which);
+
+ /**
+ * Return whether we are currently running on battery.
+ */
+ public abstract boolean getIsOnBattery();
+
/**
* Returns a SparseArray containing the statistics for each uid.
*/
@@ -312,17 +385,20 @@ public abstract class BatteryStats {
*
* @param sb a StringBuilder object.
* @param timer a Timer object contining the wakelock times.
- * @param now the current time in microseconds.
+ * @param batteryRealtime the current on-battery time in microseconds.
* @param name the name of the wakelock.
* @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
* @param linePrefix a String to be prepended to each line of output.
* @return the line prefix
*/
- private final String printWakeLock(StringBuilder sb, Timer timer, long now,
- String name, int which, String linePrefix) {
+ private static final String printWakeLock(StringBuilder sb, Timer timer,
+ long batteryRealtime, String name, int which, String linePrefix) {
+
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTimeMillis = (timer.getTotalTime(now, which) + 500) / 1000;
+ long totalTimeMicros = timer.getTotalTime(batteryRealtime, which);
+ long totalTimeMillis = (totalTimeMicros + 500) / 1000;
+
int count = timer.getCount(which);
if (totalTimeMillis != 0) {
sb.append(linePrefix);
@@ -337,40 +413,225 @@ public abstract class BatteryStats {
}
return linePrefix;
}
+
+ /**
+ * Checkin version of wakelock printer. Prints simple comma-separated list.
+ *
+ * @param sb a StringBuilder object.
+ * @param timer a Timer object contining the wakelock times.
+ * @param now the current time in microseconds.
+ * @param name the name of the wakelock.
+ * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param linePrefix a String to be prepended to each line of output.
+ * @return the line prefix
+ */
+ private static final String printWakeLockCheckin(StringBuilder sb, Timer timer, long now,
+ String name, int which, String linePrefix) {
+ long totalTimeMicros = 0;
+ int count = 0;
+ if (timer != null) {
+ totalTimeMicros = timer.getTotalTime(now, which);
+ count = timer.getCount(which);
+ }
+ sb.append(linePrefix);
+ sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
+ sb.append(',');
+ sb.append(name);
+ sb.append(',');
+ sb.append(count);
+ return ",";
+ }
+
+ /**
+ * Dump a comma-separated line of values for terse checkin mode.
+ *
+ * @param pw the PageWriter to dump log to
+ * @param category category of data (e.g. "total", "last", "unplugged", "current" )
+ * @param type type of data (e.g. "wakelock", "sensor", "process", "apk" , "process", "network")
+ * @param args type-dependent data arguments
+ */
+ private static final void dumpLine(PrintWriter pw, int uid, String category, String type,
+ Object... args ) {
+ pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+ pw.print(uid); pw.print(',');
+ pw.print(category); pw.print(',');
+ pw.print(type);
+
+ for (Object arg : args) {
+ pw.print(',');
+ pw.print(arg);
+ }
+ pw.print('\n');
+ }
+
+ /**
+ * Checkin server version of dump to produce more compact, computer-readable log.
+ *
+ * NOTE: all times are expressed in 'ms'.
+ * @param fd
+ * @param pw
+ * @param which
+ */
+ private final void dumpCheckinLocked(PrintWriter pw, int which) {
+ final long rawUptime = SystemClock.uptimeMillis() * 1000;
+ final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
+ final long batteryUptime = getBatteryUptime(rawUptime);
+ final long batteryRealtime = getBatteryRealtime(rawRealtime);
+ final long whichBatteryUptime = computeBatteryUptime(rawUptime, which);
+ final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which);
+ final long totalRealtime = computeRealtime(rawRealtime, which);
+ final long totalUptime = computeUptime(rawUptime, which);
+ final long screenOnTime = getScreenOnTime(batteryRealtime, which);
+ final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
+
+ StringBuilder sb = new StringBuilder(128);
+
+ String category = STAT_NAMES[which];
+
+ // Dump "battery" stat
+ dumpLine(pw, 0 /* uid */, category, BATTERY_DATA,
+ which == STATS_TOTAL ? getStartCount() : "N/A",
+ whichBatteryUptime / 1000, whichBatteryRealtime / 1000,
+ totalUptime / 1000, totalRealtime / 1000);
+
+ // Dump misc stats
+ dumpLine(pw, 0 /* uid */, category, MISC_DATA,
+ screenOnTime / 1000, phoneOnTime / 1000);
+
+ SparseArray<? extends Uid> uidStats = getUidStats();
+ final int NU = uidStats.size();
+ for (int iu = 0; iu < NU; iu++) {
+ final int uid = uidStats.keyAt(iu);
+ Uid u = uidStats.valueAt(iu);
+ // Dump Network stats per uid, if any
+ long rx = u.getTcpBytesReceived(which);
+ long tx = u.getTcpBytesSent(which);
+ if (rx > 0 || tx > 0) dumpLine(pw, uid, category, NETWORK_DATA, rx, tx);
- @SuppressWarnings("unused")
- private final void dumpLocked(FileDescriptor fd, PrintWriter pw, String prefix, int which) {
- long uSecTime = SystemClock.elapsedRealtime() * 1000;
- final long uSecNow = getBatteryUptime(uSecTime);
+ Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
+ if (wakelocks.size() > 0) {
+ for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent
+ : wakelocks.entrySet()) {
+ Uid.Wakelock wl = ent.getValue();
+ String linePrefix = "";
+ sb.setLength(0);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime,
+ "full", which, linePrefix);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime,
+ "partial", which, linePrefix);
+ linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime,
+ "window", which, linePrefix);
+
+ // Only log if we had at lease one wakelock...
+ if (sb.length() > 0) {
+ dumpLine(pw, uid, category, WAKELOCK_DATA, ent.getKey(), sb.toString());
+ }
+ }
+ }
+
+ Map<Integer, ? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+ if (sensors.size() > 0) {
+ for (Map.Entry<Integer, ? extends BatteryStats.Uid.Sensor> ent
+ : sensors.entrySet()) {
+ Uid.Sensor se = ent.getValue();
+ int sensorNumber = ent.getKey();
+ Timer timer = se.getSensorTime();
+ if (timer != null) {
+ // Convert from microseconds to milliseconds with rounding
+ long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000;
+ int count = timer.getCount(which);
+ if (totalTime != 0) {
+ dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count);
+ }
+ }
+ }
+ }
- StringBuilder sb = new StringBuilder(128);
- if (which == STATS_TOTAL) {
- pw.println(prefix + "Current and Historic Battery Usage Statistics:");
- pw.println(prefix + " System starts: " + getStartCount());
- } else if (which == STATS_LAST) {
- pw.println(prefix + "Last Battery Usage Statistics:");
- } else {
- pw.println(prefix + "Current Battery Usage Statistics:");
+ Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
+ if (processStats.size() > 0) {
+ for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
+ : processStats.entrySet()) {
+ Uid.Proc ps = ent.getValue();
+
+ long userTime = ps.getUserTime(which);
+ long systemTime = ps.getSystemTime(which);
+ int starts = ps.getStarts(which);
+
+ if (userTime != 0 || systemTime != 0 || starts != 0) {
+ dumpLine(pw, uid, category, PROCESS_DATA,
+ ent.getKey(), // proc
+ userTime * 10, // cpu time in ms
+ systemTime * 10, // user time in ms
+ starts); // process starts
+ }
+ }
+ }
+
+ Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
+ if (packageStats.size() > 0) {
+ for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
+ : packageStats.entrySet()) {
+
+ Uid.Pkg ps = ent.getValue();
+ int wakeups = ps.getWakeups(which);
+ Map<String, ? extends Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
+ for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
+ : serviceStats.entrySet()) {
+ BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
+ long startTime = ss.getStartTime(batteryUptime, which);
+ int starts = ss.getStarts(which);
+ int launches = ss.getLaunches(which);
+ if (startTime != 0 || starts != 0 || launches != 0) {
+ dumpLine(pw, uid, category, APK_DATA,
+ wakeups, // wakeup alarms
+ ent.getKey(), // Apk
+ sent.getKey(), // service
+ startTime / 1000, // time spent started, in ms
+ starts,
+ launches);
+ }
+ }
+ }
+ }
}
- long batteryUptime = computeBatteryUptime(uSecNow, which);
- long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which);
- long elapsedRealtime = computeRealtime(uSecTime, which);
- long uptime = computeUptime(SystemClock.uptimeMillis() * 1000, which);
+ }
+
+ @SuppressWarnings("unused")
+ private final void dumpLocked(Printer pw, String prefix, int which) {
+ final long rawUptime = SystemClock.uptimeMillis() * 1000;
+ final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
+ final long batteryUptime = getBatteryUptime(rawUptime);
+ final long batteryRealtime = getBatteryUptime(rawRealtime);
+
+ final long whichBatteryUptime = computeBatteryUptime(rawUptime, which);
+ final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which);
+ final long totalRealtime = computeRealtime(rawRealtime, which);
+ final long totalUptime = computeUptime(rawUptime, which);
+
+ StringBuilder sb = new StringBuilder(128);
pw.println(prefix
- + " On battery: " + formatTimeMs(batteryUptime / 1000) + "("
- + formatRatioLocked(batteryUptime, batteryRealtime)
+ + " Time on battery: " + formatTimeMs(whichBatteryUptime / 1000)
+ + "(" + formatRatioLocked(whichBatteryUptime, totalRealtime)
+ ") uptime, "
- + formatTimeMs(batteryRealtime / 1000) + "("
- + formatRatioLocked(batteryRealtime, elapsedRealtime)
+ + formatTimeMs(whichBatteryRealtime / 1000) + "("
+ + formatRatioLocked(whichBatteryRealtime, totalRealtime)
+ ") realtime");
pw.println(prefix
+ " Total: "
- + formatTimeMs(uptime / 1000)
+ + formatTimeMs(totalUptime / 1000)
+ "uptime, "
- + formatTimeMs(elapsedRealtime / 1000)
+ + formatTimeMs(totalRealtime / 1000)
+ "realtime");
-
+
+ long screenOnTime = getScreenOnTime(batteryRealtime, which);
+ long phoneOnTime = getPhoneOnTime(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) + ")");
+
pw.println(" ");
SparseArray<? extends Uid> uidStats = getUidStats();
@@ -380,6 +641,13 @@ public abstract class BatteryStats {
Uid u = uidStats.valueAt(iu);
pw.println(prefix + " #" + uid + ":");
boolean uidActivity = false;
+
+ long tcpReceived = u.getTcpBytesReceived(which);
+ long tcpSent = u.getTcpBytesSent(which);
+ if (tcpReceived != 0 || tcpSent != 0) {
+ pw.println(prefix + " Network: " + tcpReceived + " bytes received, "
+ + tcpSent + " bytes sent");
+ }
Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
if (wakelocks.size() > 0) {
@@ -391,13 +659,15 @@ public abstract class BatteryStats {
sb.append(prefix);
sb.append(" Wake lock ");
sb.append(ent.getKey());
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow,
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime,
"full", which, linePrefix);
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow,
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime,
"partial", which, linePrefix);
- linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow,
+ linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime,
"window", which, linePrefix);
- if (linePrefix.equals(": ")) {
+ if (!linePrefix.equals(": ")) {
+ sb.append(" realtime");
+ } else {
sb.append(": (nothing executed)");
}
pw.println(sb.toString());
@@ -414,23 +684,30 @@ public abstract class BatteryStats {
sb.setLength(0);
sb.append(prefix);
sb.append(" Sensor ");
- sb.append(sensorNumber);
+ int handle = se.getHandle();
+ if (handle == Uid.Sensor.GPS) {
+ sb.append("GPS");
+ } else {
+ sb.append(handle);
+ }
+ sb.append(": ");
Timer timer = se.getSensorTime();
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000;
+ long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000;
int count = timer.getCount(which);
+ //timer.logState();
if (totalTime != 0) {
- sb.append(": ");
sb.append(formatTimeMs(totalTime));
- sb.append(' ');
- sb.append('(');
+ sb.append("realtime (");
sb.append(count);
sb.append(" times)");
+ } else {
+ sb.append("(not used)");
}
} else {
- sb.append(": (none used)");
+ sb.append("(not used)");
}
pw.println(sb.toString());
@@ -478,13 +755,14 @@ public abstract class BatteryStats {
for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
: serviceStats.entrySet()) {
BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
- long startTime = ss.getStartTime(uSecNow, which);
+ long startTime = ss.getStartTime(batteryUptime, which);
int starts = ss.getStarts(which);
int launches = ss.getLaunches(which);
if (startTime != 0 || starts != 0 || launches != 0) {
pw.println(prefix + " Service " + sent.getKey() + ":");
- pw.println(prefix + " Time spent started: "
- + formatTimeMs(startTime / 1000));
+ pw.println(prefix + " Created for: "
+ + formatTimeMs(startTime / 1000)
+ + " uptime");
pw.println(prefix + " Starts: " + starts
+ ", launches: " + launches);
apkActivity = true;
@@ -506,18 +784,45 @@ public abstract class BatteryStats {
/**
* Dumps a human-readable summary of the battery statistics to the given PrintWriter.
*
- * @param fd a FileDescriptor, currently unused.
- * @param pw a PrintWriter to receive the dump output.
- * @param args an array of Strings, currently unused.
+ * @param pw a Printer to receive the dump output.
*/
@SuppressWarnings("unused")
- public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
- synchronized (this) {
- dumpLocked(fd, pw, "", STATS_TOTAL);
- pw.println("");
- dumpLocked(fd, pw, "", STATS_LAST);
- pw.println("");
- dumpLocked(fd, pw, "", STATS_CURRENT);
+ public void dumpLocked(Printer pw) {
+ pw.println("Total Statistics (Current and Historic):");
+ pw.println(" System starts: " + getStartCount()
+ + ", currently on battery: " + getIsOnBattery());
+ dumpLocked(pw, "", STATS_TOTAL);
+ pw.println("");
+ pw.println("Last Run Statistics (Previous run of system):");
+ dumpLocked(pw, "", STATS_LAST);
+ pw.println("");
+ pw.println("Current Battery Statistics (Currently running system):");
+ dumpLocked(pw, "", STATS_CURRENT);
+ pw.println("");
+ pw.println("Unplugged Statistics (Since last unplugged from power):");
+ dumpLocked(pw, "", STATS_UNPLUGGED);
+ }
+
+ @SuppressWarnings("unused")
+ public void dumpCheckinLocked(PrintWriter pw, String[] args) {
+ boolean isUnpluggedOnly = false;
+
+ for (String arg : args) {
+ if ("-u".equals(arg)) {
+ if (LOCAL_LOGV) Log.v("BatteryStats", "Dumping unplugged data");
+ isUnpluggedOnly = true;
+ }
+ }
+
+ if (isUnpluggedOnly) {
+ dumpCheckinLocked(pw, STATS_UNPLUGGED);
+ }
+ else {
+ dumpCheckinLocked(pw, STATS_TOTAL);
+ dumpCheckinLocked(pw, STATS_LAST);
+ dumpCheckinLocked(pw, STATS_UNPLUGGED);
+ dumpCheckinLocked(pw, STATS_CURRENT);
}
}
+
}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 528e6bd..df10c6a 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -33,7 +33,7 @@ import java.lang.reflect.Modifier;
* the standard support creating a local implementation of such an object.
*
* <p>Most developers will not implement this class directly, instead using the
- * <a href="{@docRoot}reference/aidl.html">aidl</a> tool to describe the desired
+ * <a href="{@docRoot}guide/developing/tools/aidl.html">aidl</a> tool to describe the desired
* interface, having it generate the appropriate Binder subclass. You can,
* however, derive directly from Binder to implement your own custom RPC
* protocol or simply instantiate a raw Binder object directly to use as a
@@ -194,18 +194,15 @@ public class Binder implements IBinder {
return true;
} else if (code == DUMP_TRANSACTION) {
ParcelFileDescriptor fd = data.readFileDescriptor();
- FileOutputStream fout = fd != null
- ? new FileOutputStream(fd.getFileDescriptor()) : null;
- PrintWriter pw = fout != null ? new PrintWriter(fout) : null;
- if (pw != null) {
- String[] args = data.readStringArray();
- dump(fd.getFileDescriptor(), pw, args);
- pw.flush();
- }
+ String[] args = data.readStringArray();
if (fd != null) {
try {
- fd.close();
- } catch (IOException e) {
+ dump(fd.getFileDescriptor(), args);
+ } finally {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
}
}
return true;
@@ -214,6 +211,20 @@ public class Binder implements IBinder {
}
/**
+ * Implemented to call the more convenient version
+ * {@link #dump(FileDescriptor, PrintWriter, String[])}.
+ */
+ public void dump(FileDescriptor fd, String[] args) {
+ FileOutputStream fout = new FileOutputStream(fd);
+ PrintWriter pw = new PrintWriter(fout);
+ try {
+ dump(fd, pw, args);
+ } finally {
+ pw.flush();
+ }
+ }
+
+ /**
* Print the object's state into the given stream.
*
* @param fd The raw file descriptor that the dump is being sent to.
@@ -302,6 +313,17 @@ final class BinderProxy implements IBinder {
throws RemoteException;
public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
+ public void dump(FileDescriptor fd, String[] args) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeFileDescriptor(fd);
+ data.writeStringArray(args);
+ try {
+ transact(DUMP_TRANSACTION, data, null, 0);
+ } finally {
+ data.recycle();
+ }
+ }
+
BinderProxy() {
mSelf = new WeakReference(this);
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index cdf907b..467c17f 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -26,6 +26,9 @@ public class Build {
/** Either a changelist number, or a label like "M4-rc20". */
public static final String ID = getString("ro.build.id");
+ /** A build ID string meant for displaying to the user */
+ public static final String DISPLAY = getString("ro.build.display.id");
+
/** The name of the overall product. */
public static final String PRODUCT = getString("ro.product.name");
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 5f7f91f..950bb09 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -17,6 +17,7 @@
package android.os;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
@@ -28,12 +29,13 @@ import dalvik.bytecode.Opcodes;
import dalvik.system.VMDebug;
-/** Provides various debugging functions for Android applications, including
+/**
+ * Provides various debugging functions for Android applications, including
* tracing and allocation counts.
* <p><strong>Logging Trace Files</strong></p>
* <p>Debug can create log files that give details about an application, such as
* a call stack and start/stop times for any running methods. See <a
-href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for
+href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
* information about reading trace files. To start logging trace files, call one
* of the startMethodTracing() methods. To stop tracing, call
* {@link #stopMethodTracing()}.
@@ -285,7 +287,7 @@ public final class Debug
/**
* Start method tracing with default log name and buffer size. See <a
-href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for
+href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
* information about reading these files. Call stopMethodTracing() to stop
* tracing.
*/
@@ -297,7 +299,7 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra
* Start method tracing, specifying the trace log file name. The trace
* file will be put under "/sdcard" unless an absolute path is given.
* See <a
- href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for
+ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
* information about reading trace files.
*
* @param traceName Name for the trace log file to create.
@@ -313,7 +315,7 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra
* Start method tracing, specifying the trace log file name and the
* buffer size. The trace files will be put under "/sdcard" unless an
* absolute path is given. See <a
- href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for
+ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
* information about reading trace files.
* @param traceName Name for the trace log file to create.
* If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
@@ -330,7 +332,7 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra
* Start method tracing, specifying the trace log file name and the
* buffer size. The trace files will be put under "/sdcard" unless an
* absolute path is given. See <a
- href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for
+ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
* information about reading trace files.
*
* <p>
@@ -581,6 +583,18 @@ href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Progra
}
/**
+ * Dump "hprof" data to the specified file. This will cause a GC.
+ *
+ * @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof").
+ * @throws UnsupportedOperationException if the VM was built without
+ * HPROF support.
+ * @throws IOException if an error occurs while opening or writing files.
+ */
+ public static void dumpHprofData(String fileName) throws IOException {
+ VMDebug.dumpHprofData(fileName);
+ }
+
+ /**
* Returns the number of sent transactions from this process.
* @return The number of sent transactions or -1 if it could not read t.
*/
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index e37b551..f761e8e 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -75,6 +75,18 @@ public class Environment {
public static final String MEDIA_UNMOUNTED = "unmounted";
/**
+ * getExternalStorageState() returns MEDIA_CHECKING if the media is present
+ * and being disk-checked
+ */
+ public static final String MEDIA_CHECKING = "checking";
+
+ /**
+ * getExternalStorageState() returns MEDIA_NOFS if the media is present
+ * but is blank or is using an unsupported filesystem
+ */
+ public static final String MEDIA_NOFS = "nofs";
+
+ /**
* getExternalStorageState() returns MEDIA_MOUNTED if the media is present
* and mounted at its mount point with read/write access.
*/
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 3ec0e9b..5c40c9a0 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -16,6 +16,9 @@
package android.os;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* Base interface for a remotable object, the core part of a lightweight
* remote procedure call mechanism designed for high performance when
@@ -145,6 +148,14 @@ public interface IBinder {
public IInterface queryLocalInterface(String descriptor);
/**
+ * Print the object's state into the given stream.
+ *
+ * @param fd The raw file descriptor that the dump is being sent to.
+ * @param args additional arguments to the dump request.
+ */
+ public void dump(FileDescriptor fd, String[] args) throws RemoteException;
+
+ /**
* Perform a generic operation with the object.
*
* @param code The action to perform. This should
diff --git a/core/java/android/os/ICheckinService.aidl b/core/java/android/os/ICheckinService.aidl
index 70ad28e..e56b55d 100644
--- a/core/java/android/os/ICheckinService.aidl
+++ b/core/java/android/os/ICheckinService.aidl
@@ -26,6 +26,15 @@ import android.os.IParentalControlCallback;
* {@hide}
*/
interface ICheckinService {
+ /** Synchronously attempt a checkin with the server, return true
+ * on success.
+ * @throws IllegalStateException whenever an error occurs. The
+ * cause of the exception will be the real exception:
+ * IOException for network errors, JSONException for invalid
+ * server responses, etc.
+ */
+ boolean checkin();
+
/** Direct submission of crash data; returns after writing the crash. */
void reportCrashSync(in byte[] crashData);
diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl
index 0397446..96d44b6 100644
--- a/core/java/android/os/IMountService.aidl
+++ b/core/java/android/os/IMountService.aidl
@@ -48,4 +48,31 @@ interface IMountService
* Safely unmount external storage at given mount point.
*/
void unmountMedia(String mountPoint);
+
+ /**
+ * Format external storage given a mount point.
+ */
+ void formatMedia(String mountPoint);
+
+ /**
+ * Returns true if media notification sounds are enabled.
+ */
+ boolean getPlayNotificationSounds();
+
+ /**
+ * Sets whether or not media notification sounds are played.
+ */
+ void setPlayNotificationSounds(boolean value);
+
+ /**
+ * Returns true if USB Mass Storage is automatically started
+ * when a UMS host is detected.
+ */
+ boolean getAutoStartUms();
+
+ /**
+ * Sets whether or not USB Mass Storage is automatically started
+ * when a UMS host is detected.
+ */
+ void setAutoStartUms(boolean value);
}
diff --git a/core/java/android/os/INetStatService.aidl b/core/java/android/os/INetStatService.aidl
index fb840d8..a8f3de0 100644
--- a/core/java/android/os/INetStatService.aidl
+++ b/core/java/android/os/INetStatService.aidl
@@ -17,14 +17,19 @@
package android.os;
/**
- * Retrieves packet and byte counts for the phone data interface.
+ * Retrieves packet and byte counts for the phone data interface,
+ * and for all interfaces.
* Used for the data activity icon and the phone status in Settings.
*
* {@hide}
*/
interface INetStatService {
- int getTxPackets();
- int getRxPackets();
- int getTxBytes();
- int getRxBytes();
+ long getMobileTxPackets();
+ long getMobileRxPackets();
+ long getMobileTxBytes();
+ long getMobileRxBytes();
+ long getTotalTxPackets();
+ long getTotalRxPackets();
+ long getTotalTxBytes();
+ long getTotalRxBytes();
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index e48f152..5486920 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -29,4 +29,5 @@ interface IPowerManager
void setStayOnSetting(int val);
long getScreenOnTime();
void preventScreenOn(boolean prevent);
+ void setScreenBrightnessOverride(int brightness);
}
diff --git a/core/java/android/os/NetStat.java b/core/java/android/os/NetStat.java
index 7312236..e294cdf 100644
--- a/core/java/android/os/NetStat.java
+++ b/core/java/android/os/NetStat.java
@@ -16,36 +16,232 @@
package android.os;
+import android.util.Log;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.io.IOException;
+
/** @hide */
-public class NetStat{
+public class NetStat {
+
+ // Logging tag.
+ private final static String TAG = "netstat";
+
+ // We pre-create all the File objects so we don't spend a lot of
+ // CPU at runtime converting from Java Strings to byte[] for the
+ // kernel calls.
+ private final static File[] MOBILE_TX_PACKETS = mobileFiles("tx_packets");
+ private final static File[] MOBILE_RX_PACKETS = mobileFiles("rx_packets");
+ private final static File[] MOBILE_TX_BYTES = mobileFiles("tx_bytes");
+ private final static File[] MOBILE_RX_BYTES = mobileFiles("rx_bytes");
+ private final static File SYS_CLASS_NET_DIR = new File("/sys/class/net");
/**
- * Get total number of tx packets sent through ppp0
+ * Get total number of tx packets sent through rmnet0 or ppp0
*
- * @return number of Tx packets through ppp0
+ * @return number of Tx packets through rmnet0 or ppp0
*/
+ public static long getMobileTxPkts() {
+ return getMobileStat(MOBILE_TX_PACKETS);
+ }
- public native static int netStatGetTxPkts();
+ /**
+ * Get total number of rx packets received through rmnet0 or ppp0
+ *
+ * @return number of Rx packets through rmnet0 or ppp0
+ */
+ public static long getMobileRxPkts() {
+ return getMobileStat(MOBILE_RX_PACKETS);
+ }
/**
- * Get total number of rx packets received through ppp0
+ * Get total number of tx bytes received through rmnet0 or ppp0
*
- * @return number of Rx packets through ppp0
+ * @return number of Tx bytes through rmnet0 or ppp0
*/
- public native static int netStatGetRxPkts();
+ public static long getMobileTxBytes() {
+ return getMobileStat(MOBILE_TX_BYTES);
+ }
- /**
- * Get total number of tx bytes received through ppp0
+ /**
+ * Get total number of rx bytes received through rmnet0 or ppp0
*
- * @return number of Tx bytes through ppp0
+ * @return number of Rx bytes through rmnet0 or ppp0
*/
- public native static int netStatGetTxBytes();
+ public static long getMobileRxBytes() {
+ return getMobileStat(MOBILE_RX_BYTES);
+ }
/**
- * Get total number of rx bytes received through ppp0
+ * Get the total number of packets sent through all network interfaces.
*
- * @return number of Rx bytes through ppp0
+ * @return the number of packets sent through all network interfaces
*/
- public native static int netStatGetRxBytes();
+ public static long getTotalTxPkts() {
+ return getTotalStat("tx_packets");
+ }
+
+ /**
+ * Get the total number of packets received through all network interfaces.
+ *
+ * @return the number of packets received through all network interfaces
+ */
+ public static long getTotalRxPkts() {
+ return getTotalStat("rx_packets");
+ }
+
+ /**
+ * Get the total number of bytes sent through all network interfaces.
+ *
+ * @return the number of bytes sent through all network interfaces
+ */
+ public static long getTotalTxBytes() {
+ return getTotalStat("tx_bytes");
+ }
+
+ /**
+ * Get the total number of bytes received through all network interfaces.
+ *
+ * @return the number of bytes received through all network interfaces
+ */
+ public static long getTotalRxBytes() {
+ return getTotalStat("rx_bytes");
+ }
+
+ /**
+ * Gets network bytes sent for this UID.
+ * The statistics are across all interfaces.
+ * The statistics come from /proc/uid_stat.
+ *
+ * {@see android.os.Process#myUid()}.
+ *
+ * @param uid
+ * @return byte count
+ */
+ public static long getUidTxBytes(int uid) {
+ return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_snd");
+ }
+
+ /**
+ * Gets network bytes received for this UID.
+ * The statistics are across all interfaces.
+ * The statistics come from /proc/uid_stat.
+ *
+ * {@see android.os.Process#myUid()}.
+ *
+ * @param uid
+ * @return byte count
+ */
+ public static long getUidRxBytes(int uid) {
+ return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_rcv");
+ }
+
+ /**
+ * Returns the array of two possible File locations for a given
+ * statistic.
+ */
+ private static File[] mobileFiles(String whatStat) {
+ // Note that we stat them at runtime to see which is
+ // available, rather than here, to guard against the files
+ // coming & going later as modules shut down (e.g. airplane
+ // mode) and whatnot. The runtime stat() isn't expensive compared
+ // to the previous charset conversion that happened before we
+ // were reusing File instances.
+ File[] files = new File[2];
+ files[0] = new File("/sys/class/net/rmnet0/statistics/" + whatStat);
+ files[1] = new File("/sys/class/net/ppp0/statistics/" + whatStat);
+ return files;
+ }
+
+ private static long getTotalStat(String whatStat) {
+ File netdir = new File("/sys/class/net");
+
+ File[] nets = SYS_CLASS_NET_DIR.listFiles();
+ if (nets == null) {
+ return 0;
+ }
+ long total = 0;
+ StringBuffer strbuf = new StringBuffer();
+ for (File net : nets) {
+ strbuf.append(net.getPath()).append(File.separator).append("statistics")
+ .append(File.separator).append(whatStat);
+ total += getNumberFromFilePath(strbuf.toString());
+ strbuf.setLength(0);
+ }
+ return total;
+ }
+
+ private static long getMobileStat(File[] files) {
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+ if (!file.exists()) {
+ continue;
+ }
+ try {
+ RandomAccessFile raf = new RandomAccessFile(file, "r");
+ return getNumberFromFile(raf, file.getAbsolutePath());
+ } catch (IOException e) {
+ Log.w(TAG,
+ "Exception opening TCP statistics file " + file.getAbsolutePath(),
+ e);
+ }
+ }
+ return 0L;
+ }
+
+ // File will have format <number><newline>
+ private static long getNumberFromFilePath(String filename) {
+ RandomAccessFile raf = getFile(filename);
+ if (raf == null) {
+ return 0L;
+ }
+ return getNumberFromFile(raf, filename);
+ }
+
+ // Private buffer for getNumberFromFile. Safe for re-use because
+ // getNumberFromFile is synchronized.
+ private final static byte[] buf = new byte[16];
+
+ private static synchronized long getNumberFromFile(RandomAccessFile raf, String filename) {
+ try {
+ raf.read(buf);
+ raf.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Exception getting TCP bytes from " + filename, e);
+ return 0L;
+ } finally {
+ if (raf != null) {
+ try {
+ raf.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Exception closing " + filename, e);
+ }
+ }
+ }
+
+ long num = 0L;
+ for (int i = 0; i < buf.length; i++) {
+ if (buf[i] < '0' || buf[i] > '9') {
+ break;
+ }
+ num *= 10;
+ num += buf[i] - '0';
+ }
+ return num;
+ }
+
+ private static RandomAccessFile getFile(String filename) {
+ File f = new File(filename);
+ if (!f.canRead()) {
+ return null;
+ }
+ try {
+ return new RandomAccessFile(f, "r");
+ } catch (IOException e) {
+ Log.w(TAG, "Exception opening TCP statistics file " + filename, e);
+ return null;
+ }
+ }
}
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index ed138cb..3fcb18e 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -76,6 +76,11 @@ public class ParcelFileDescriptor implements Parcelable {
public static final int MODE_TRUNCATE = 0x04000000;
/**
+ * For use with {@link #open}: append to end of file while writing.
+ */
+ public static final int MODE_APPEND = 0x02000000;
+
+ /**
* Create a new ParcelFileDescriptor accessing a given file.
*
* @param file The file to be opened.
@@ -138,6 +143,19 @@ public class ParcelFileDescriptor implements Parcelable {
}
/**
+ * Return the total size of the file representing this fd, as determined
+ * by stat(). Returns -1 if the fd is not a file.
+ */
+ public native long getStatSize();
+
+ /**
+ * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
+ * and I really don't think we want it to be public.
+ * @hide
+ */
+ public native long seekTo(long pos);
+
+ /**
* Close the ParcelFileDescriptor. This implementation closes the underlying
* OS resources allocated to represent this stream.
*
diff --git a/core/res/res/drawable/checkbox_background.xml b/core/java/android/os/ResultReceiver.aidl
index 68bb178..28ce6d5 100644
--- a/core/res/res/drawable/checkbox_background.xml
+++ b/core/java/android/os/ResultReceiver.aidl
@@ -1,6 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/checkbox_background.xml
+/* //device/java/android/android/os/ParcelFileDescriptor.aidl
**
** Copyright 2007, The Android Open Source Project
**
@@ -16,8 +14,7 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/checkbox_label_background" />
-</selector>
+package android.os;
+
+parcelable ResultReceiver;
diff --git a/core/java/android/os/ResultReceiver.java b/core/java/android/os/ResultReceiver.java
new file mode 100644
index 0000000..711d4d9
--- /dev/null
+++ b/core/java/android/os/ResultReceiver.java
@@ -0,0 +1,130 @@
+/*
+ * 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 android.os;
+
+import com.android.internal.os.IResultReceiver;
+
+/**
+ * Generic interface for receiving a callback result from someone. Use this
+ * by creating a subclass and implement {@link #onReceiveResult}, which you can
+ * then pass to others and send through IPC, and receive results they
+ * supply with {@link #send}.
+ */
+public class ResultReceiver implements Parcelable {
+ final boolean mLocal;
+ final Handler mHandler;
+
+ IResultReceiver mReceiver;
+
+ class MyRunnable implements Runnable {
+ final int mResultCode;
+ final Bundle mResultData;
+
+ MyRunnable(int resultCode, Bundle resultData) {
+ mResultCode = resultCode;
+ mResultData = resultData;
+ }
+
+ public void run() {
+ onReceiveResult(mResultCode, mResultData);
+ }
+ }
+
+ class MyResultReceiver extends IResultReceiver.Stub {
+ public void send(int resultCode, Bundle resultData) {
+ if (mHandler != null) {
+ mHandler.post(new MyRunnable(resultCode, resultData));
+ } else {
+ onReceiveResult(resultCode, resultData);
+ }
+ }
+ }
+
+ /**
+ * Create a new ResultReceive to receive results. Your
+ * {@link #onReceiveResult} method will be called from the thread running
+ * <var>handler</var> if given, or from an arbitrary thread if null.
+ */
+ public ResultReceiver(Handler handler) {
+ mLocal = true;
+ mHandler = handler;
+ }
+
+ /**
+ * Deliver a result to this receiver. Will call {@link #onReceiveResult},
+ * always asynchronously if the receiver has supplied a Handler in which
+ * to dispatch the result.
+ * @param resultCode Arbitrary result code to deliver, as defined by you.
+ * @param resultData Any additional data provided by you.
+ */
+ public void send(int resultCode, Bundle resultData) {
+ if (mLocal) {
+ if (mHandler != null) {
+ mHandler.post(new MyRunnable(resultCode, resultData));
+ } else {
+ onReceiveResult(resultCode, resultData);
+ }
+ return;
+ }
+
+ if (mReceiver != null) {
+ try {
+ mReceiver.send(resultCode, resultData);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ /**
+ * Override to receive results delivered to this object.
+ *
+ * @param resultCode Arbitrary result code delivered by the sender, as
+ * defined by the sender.
+ * @param resultData Any additional data provided by the sender.
+ */
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ synchronized (this) {
+ if (mReceiver == null) {
+ mReceiver = new MyResultReceiver();
+ }
+ out.writeStrongBinder(mReceiver.asBinder());
+ }
+ }
+
+ ResultReceiver(Parcel in) {
+ mLocal = false;
+ mHandler = null;
+ mReceiver = IResultReceiver.Stub.asInterface(in.readStrongBinder());
+ }
+
+ public static final Parcelable.Creator<ResultReceiver> CREATOR
+ = new Parcelable.Creator<ResultReceiver>() {
+ public ResultReceiver createFromParcel(Parcel in) {
+ return new ResultReceiver(in);
+ }
+ public ResultReceiver[] newArray(int size) {
+ return new ResultReceiver[size];
+ }
+ };
+}
diff --git a/core/java/android/package.html b/core/java/android/package.html
index b6d2999..1f1be2d 100644
--- a/core/java/android/package.html
+++ b/core/java/android/package.html
@@ -5,6 +5,6 @@ Contains the resource classes used by standard Android applications.
This package contains the resource classes that Android defines to be used in
Android applications. Third party developers can use many of them also for their applications.
To learn more about how to use these classes, and what a
-resource is, see <a href="{@docRoot}devel/resources-i18n.html">Resources</a>.
+resource is, see <a href="{@docRoot}guide/topics/resources/index.html">Resources and Assets</a>.
</BODY>
</HTML>
diff --git a/core/java/android/pim/ICalendar.java b/core/java/android/pim/ICalendar.java
index 4a5d7e4..cc0f45e 100644
--- a/core/java/android/pim/ICalendar.java
+++ b/core/java/android/pim/ICalendar.java
@@ -405,13 +405,15 @@ public class ICalendar {
// TODO: get rid of this -- handle all of the parsing in one pass through
// the text.
private static String normalizeText(String text) {
- // first we deal with line folding, by replacing all "\r\n " strings
- // with nothing
- text = text.replaceAll("\r\n ", "");
-
// it's supposed to be \r\n, but not everyone does that
text = text.replaceAll("\r\n", "\n");
text = text.replaceAll("\r", "\n");
+
+ // we deal with line folding, by replacing all "\n " strings
+ // with nothing. The RFC specifies "\r\n " to be folded, but
+ // we handle "\n " and "\r " too because we can get those.
+ text = text.replaceAll("\n ", "");
+
return text;
}
@@ -440,7 +442,7 @@ public class ICalendar {
current = parseLine(line, state, current);
// if the provided component was null, we will return the root
// NOTE: in this case, if the first line is not a BEGIN, a
- // FormatException will get thrown.
+ // FormatException will get thrown.
if (component == null) {
component = current;
}
@@ -524,8 +526,7 @@ public class ICalendar {
private static String extractValue(ParserState state)
throws FormatException {
String line = state.line;
- char c = line.charAt(state.index);
- if (c != ':') {
+ if (state.index >= line.length() || line.charAt(state.index) != ':') {
throw new FormatException("Expected ':' before end of line in "
+ line);
}
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
index c6615da..1a287c8 100644
--- a/core/java/android/pim/RecurrenceSet.java
+++ b/core/java/android/pim/RecurrenceSet.java
@@ -140,7 +140,6 @@ public class RecurrenceSet {
recurrence = recurrence.substring(tzidx + 1);
}
Time time = new Time(tz);
- boolean rdateNotInUtc = !tz.equals(Time.TIMEZONE_UTC);
String[] rawDates = recurrence.split(",");
int n = rawDates.length;
long[] dates = new long[n];
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 3820f28..a255438 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -667,7 +667,6 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis
* {@link SharedPreferences}. This should be unique for the package.
*
* @param key The key for the preference.
- * @see #getId()
*/
public void setKey(String key) {
mKey = key;
@@ -1460,7 +1459,6 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis
* @param container The Bundle in which to save the instance of this Preference.
*
* @see #restoreHierarchyState
- * @see #dispatchSaveInstanceState
* @see #onSaveInstanceState
*/
public void saveHierarchyState(Bundle container) {
@@ -1474,7 +1472,6 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis
*
* @param container The Bundle in which to save the instance of this Preference.
*
- * @see #dispatchRestoreInstanceState
* @see #saveHierarchyState
* @see #onSaveInstanceState
*/
@@ -1503,7 +1500,6 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis
* The default implementation returns null.
* @see #onRestoreInstanceState
* @see #saveHierarchyState
- * @see #dispatchSaveInstanceState
*/
protected Parcelable onSaveInstanceState() {
mBaseMethodCalled = true;
@@ -1516,7 +1512,6 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis
* @param container The Bundle that holds the previously saved state.
*
* @see #saveHierarchyState
- * @see #dispatchRestoreInstanceState
* @see #onRestoreInstanceState
*/
public void restoreHierarchyState(Bundle container) {
@@ -1530,7 +1525,6 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis
* not want to save state for their children.
*
* @param container The Bundle that holds the previously saved state.
- * @see #dispatchSaveInstanceState
* @see #restoreHierarchyState
* @see #onRestoreInstanceState
*/
@@ -1557,7 +1551,6 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis
* {@link #onSaveInstanceState}.
* @see #onSaveInstanceState
* @see #restoreHierarchyState
- * @see #dispatchRestoreInstanceState
*/
protected void onRestoreInstanceState(Parcelable state) {
mBaseMethodCalled = true;
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 95970ea..837ce91 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -103,8 +103,6 @@ public abstract class PreferenceActivity extends ListActivity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
-
setContentView(com.android.internal.R.layout.preference_list_content);
mPreferenceManager = onCreatePreferenceManager();
@@ -214,6 +212,11 @@ public abstract class PreferenceActivity extends ListActivity implements
public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
postBindPreferences();
+ CharSequence title = getPreferenceScreen().getTitle();
+ // Set the title of the activity
+ if (title != null) {
+ setTitle(title);
+ }
}
}
diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java
index 4258b41..d008fd6 100644
--- a/core/java/android/preference/PreferenceGroup.java
+++ b/core/java/android/preference/PreferenceGroup.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.AttributeSet;
/**
@@ -223,6 +224,9 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
* @return The {@link Preference} with the key, or null.
*/
public Preference findPreference(CharSequence key) {
+ if (TextUtils.equals(getKey(), key)) {
+ return this;
+ }
final int preferenceCount = getPreferenceCount();
for (int i = 0; i < preferenceCount; i++) {
final Preference preference = getPreference(i);
diff --git a/core/java/android/preference/PreferenceGroupAdapter.java b/core/java/android/preference/PreferenceGroupAdapter.java
index 05c2952..14c0054 100644
--- a/core/java/android/preference/PreferenceGroupAdapter.java
+++ b/core/java/android/preference/PreferenceGroupAdapter.java
@@ -88,6 +88,9 @@ class PreferenceGroupAdapter extends BaseAdapter implements OnPreferenceChangeIn
public PreferenceGroupAdapter(PreferenceGroup preferenceGroup) {
mPreferenceGroup = preferenceGroup;
+ // If this group gets or loses any children, let us know
+ mPreferenceGroup.setOnPreferenceChangeInternalListener(this);
+
mPreferenceList = new ArrayList<Preference>();
mPreferenceClassNames = new ArrayList<String>();
@@ -239,7 +242,7 @@ class PreferenceGroupAdapter extends BaseAdapter implements OnPreferenceChangeIn
mHasReturnedViewTypeCount = true;
}
- return mPreferenceClassNames.size();
+ return Math.max(1, mPreferenceClassNames.size());
}
}
diff --git a/core/java/android/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java
index 9929b96..5353b53 100644
--- a/core/java/android/preference/PreferenceScreen.java
+++ b/core/java/android/preference/PreferenceScreen.java
@@ -100,7 +100,6 @@ public final class PreferenceScreen extends PreferenceGroup implements AdapterVi
*
* @return An adapter that provides the {@link Preference} contained in this
* {@link PreferenceScreen}.
- * @see PreferenceGroupAdapter
*/
public ListAdapter getRootAdapter() {
if (mRootAdapter == null) {
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 6e215dc..20702a1 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -194,13 +194,6 @@ public class VolumePreference extends SeekBarPreference implements
}
private void sample() {
-
- // Only play a preview sample when controlling the ringer stream
- if (mStreamType != AudioManager.STREAM_RING
- && mStreamType != AudioManager.STREAM_NOTIFICATION) {
- return;
- }
-
onSampleStarting(this);
mRingtone.play();
}
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 76aa51d..c597b3c 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -43,6 +43,18 @@ public class Browser {
*/
public static final String INITIAL_ZOOM_LEVEL = "browser.initialZoomLevel";
+ /**
+ * The name of the extra data when starting the Browser from another
+ * application.
+ * <p>
+ * The value is a unique identification string that will be used to
+ * indentify the calling application. The Browser will attempt to reuse the
+ * same window each time the application launches the Browser with the same
+ * identifier.
+ */
+ public static final String EXTRA_APPLICATION_ID =
+ "com.android.browser.application_id";
+
/* if you change column order you must also change indices
below */
public static final String[] HISTORY_PROJECTION = new String[] {
diff --git a/core/java/android/provider/Checkin.java b/core/java/android/provider/Checkin.java
index ef5eded..d11a9c5 100644
--- a/core/java/android/provider/Checkin.java
+++ b/core/java/android/provider/Checkin.java
@@ -30,10 +30,13 @@ import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
/**
- * Contract class for {@link android.server.checkin.CheckinProvider}.
+ * Contract class for the checkin provider, used to store events and
+ * statistics that will be uploaded to a checkin server eventually.
* Describes the exposed database schema, and offers methods to add
* events and statistics to be uploaded.
*
+ * TODO: Move this to vendor/google when we have a home for it.
+ *
* @hide
*/
public final class Checkin {
@@ -56,6 +59,15 @@ public final class Checkin {
/** Valid tag values. Extend as necessary for your needs. */
public enum Tag {
+ AUTOTEST_FAILURE,
+ AUTOTEST_SEQUENCE_BEGIN,
+ AUTOTEST_SUITE_BEGIN,
+ AUTOTEST_TCPDUMP_BEGIN,
+ AUTOTEST_TCPDUMP_DATA,
+ AUTOTEST_TCPDUMP_END,
+ AUTOTEST_TEST_BEGIN,
+ AUTOTEST_TEST_FAILURE,
+ AUTOTEST_TEST_SUCCESS,
BROWSER_BUG_REPORT,
CARRIER_BUG_REPORT,
CHECKIN_FAILURE,
@@ -88,14 +100,15 @@ public final class Checkin {
SETUP_RETRIES_EXHAUSTED,
SETUP_SERVER_ERROR,
SETUP_SERVER_TIMEOUT,
- SYSTEM_APP_NOT_RESPONDING,
+ SETUP_NO_DATA_NETWORK,
SYSTEM_BOOT,
SYSTEM_LAST_KMSG,
SYSTEM_RECOVERY_LOG,
SYSTEM_RESTART,
SYSTEM_SERVICE_LOOPING,
SYSTEM_TOMBSTONE,
- TEST,
+ TEST,
+ BATTERY_DISCHARGE_INFO,
}
}
@@ -116,6 +129,9 @@ public final class Checkin {
/** Valid tag values. Extend as necessary for your needs. */
public enum Tag {
+ BROWSER_SNAP_CENTER,
+ BROWSER_TEXT_SIZE_CHANGE,
+ BROWSER_ZOOM_OVERVIEW,
CRASHES_REPORTED,
CRASHES_TRUNCATED,
ELAPSED_REALTIME_SEC,
@@ -175,6 +191,9 @@ public final class Checkin {
// The category is used for GTalk service messages
public static final String CATEGORY = "android.server.checkin.CHECKIN";
+
+ // If true indicates that the checkin should only transfer market related data
+ public static final String EXTRA_MARKET_ONLY = "market_only";
}
private static final String TAG = "Checkin";
@@ -195,8 +214,11 @@ public final class Checkin {
values.put(Events.TAG, tag.toString());
if (value != null) values.put(Events.VALUE, value);
return resolver.insert(Events.CONTENT_URI, values);
+ } catch (IllegalArgumentException e) { // thrown when provider is unavailable.
+ Log.w(TAG, "Can't log event " + tag + ": " + e);
+ return null;
} catch (SQLException e) {
- Log.e(TAG, "Can't log event: " + tag, e); // Database errors are not fatal.
+ Log.e(TAG, "Can't log event " + tag, e); // Database errors are not fatal.
return null;
}
}
@@ -218,8 +240,11 @@ public final class Checkin {
if (count != 0) values.put(Stats.COUNT, count);
if (sum != 0.0) values.put(Stats.SUM, sum);
return resolver.insert(Stats.CONTENT_URI, values);
+ } catch (IllegalArgumentException e) { // thrown when provider is unavailable.
+ Log.w(TAG, "Can't update stat " + tag + ": " + e);
+ return null;
} catch (SQLException e) {
- Log.e(TAG, "Can't update stat: " + tag, e); // Database errors are not fatal.
+ Log.e(TAG, "Can't update stat " + tag, e); // Database errors are not fatal.
return null;
}
}
@@ -285,4 +310,3 @@ public final class Checkin {
}
}
}
-
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index e006d8c..e132bee 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -182,7 +182,7 @@ public class Contacts {
* <p>Type: TEXT</P>
*/
public static final String PHONETIC_NAME = "phonetic_name";
-
+
/**
* The display name. If name is not null name, else if number is not null number,
* else if email is not null email.
@@ -191,6 +191,14 @@ public class Contacts {
public static final String DISPLAY_NAME = "display_name";
/**
+ * The field for sorting list phonetically. The content of this field
+ * may not be human readable but phonetically sortable.
+ * <P>Type: TEXT</p>
+ * @hide Used only in Contacts application for now.
+ */
+ public static final String SORT_STRING = "sort_string";
+
+ /**
* Notes about the person.
* <P>Type: TEXT</P>
*/
@@ -231,7 +239,7 @@ public class Contacts {
* The server version of the photo
* <P>Type: TEXT (the version number portion of the photo URI)</P>
*/
- public static final String PHOTO_VERSION = "photo_version";
+ public static final String PHOTO_VERSION = "photo_version";
}
/**
@@ -932,27 +940,33 @@ public class Contacts {
}
/**
- * This looks up the provider category defined in
- * {@link android.provider.Im.ProviderCategories} from the predefined IM protocol id.
+ * This looks up the provider name defined in
+ * {@link android.provider.Im.ProviderNames} from the predefined IM protocol id.
* This is used for interacting with the IM application.
- *
+ *
* @param protocol the protocol ID
- * @return the provider category the IM app uses for the given protocol, or null if no
+ * @return the provider name the IM app uses for the given protocol, or null if no
* provider is defined for the given protocol
* @hide
*/
- public static String lookupProviderCategoryFromId(int protocol) {
+ public static String lookupProviderNameFromId(int protocol) {
switch (protocol) {
case PROTOCOL_GOOGLE_TALK:
- return Im.ProviderCategories.GTALK;
+ return Im.ProviderNames.GTALK;
case PROTOCOL_AIM:
- return Im.ProviderCategories.AIM;
+ return Im.ProviderNames.AIM;
case PROTOCOL_MSN:
- return Im.ProviderCategories.MSN;
+ return Im.ProviderNames.MSN;
case PROTOCOL_YAHOO:
- return Im.ProviderCategories.YAHOO;
+ return Im.ProviderNames.YAHOO;
case PROTOCOL_ICQ:
- return Im.ProviderCategories.ICQ;
+ return Im.ProviderNames.ICQ;
+ case PROTOCOL_JABBER:
+ return Im.ProviderNames.JABBER;
+ case PROTOCOL_SKYPE:
+ return Im.ProviderNames.SKYPE;
+ case PROTOCOL_QQ:
+ return Im.ProviderNames.QQ;
}
return null;
}
@@ -1417,7 +1431,42 @@ public class Contacts {
*/
public static final String ATTACH_IMAGE =
"com.android.contacts.action.ATTACH_IMAGE";
-
+
+ /**
+ * Takes as input a data URI with a mailto: or tel: scheme. If a single
+ * contact exists with the given data it will be shown. If no contact
+ * exists, a dialog will ask the user if they want to create a new
+ * contact with the provided details filled in. If multiple contacts
+ * share the data the user will be prompted to pick which contact they
+ * want to view.
+ * <p>
+ * For <code>mailto:</code> URIs, the scheme specific portion must be a
+ * raw email address, such as one built using
+ * {@link Uri#fromParts(String, String, String)}.
+ * <p>
+ * For <code>tel:</code> URIs, the scheme specific portion is compared
+ * to existing numbers using the standard caller ID lookup algorithm.
+ * The number must be properly encoded, for example using
+ * {@link Uri#fromParts(String, String, String)}.
+ * <p>
+ * Any extras from the {@link Insert} class will be passed along to the
+ * create activity if there are no contacts to show.
+ * <p>
+ * Passing true for the {@link #EXTRA_FORCE_CREATE} extra will skip
+ * prompting the user when the contact doesn't exist.
+ */
+ public static final String SHOW_OR_CREATE_CONTACT =
+ "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.
+ *
+ * <P>Type: BOOLEAN</P>
+ */
+ public static final String EXTRA_FORCE_CREATE =
+ "com.android.contacts.action.FORCE_CREATE";
+
/**
* Intents related to the Contacts app UI.
*/
diff --git a/core/java/android/provider/Gmail.java b/core/java/android/provider/Gmail.java
index 325f19d..cc03968 100644
--- a/core/java/android/provider/Gmail.java
+++ b/core/java/android/provider/Gmail.java
@@ -370,6 +370,25 @@ public final class Gmail {
"maxAttachmentSize";
}
+ /**
+ * These flags can be included as Selection Arguments when
+ * querying the provider.
+ */
+ public static class SelectionArguments {
+ private SelectionArguments() {
+ // forbid instantiation
+ }
+
+ /**
+ * Specifies that you do NOT wish the returned cursor to
+ * become the Active Network Cursor. If you do not include
+ * this flag as a selectionArg, the new cursor will become the
+ * Active Network Cursor by default.
+ */
+ public static final String DO_NOT_BECOME_ACTIVE_NETWORK_CURSOR =
+ "SELECTION_ARGUMENT_DO_NOT_BECOME_ACTIVE_NETWORK_CURSOR";
+ }
+
// These are the projections that we need when getting cursors from the
// content provider.
private static String[] CONVERSATION_PROJECTION = {
@@ -436,6 +455,28 @@ public final class Gmail {
}
/**
+ * Behavior for a new cursor: should it become the Active Network
+ * Cursor? This could potentially lead to bad behavior if someone
+ * else is using the Active Network Cursor, since theirs will stop
+ * being the Active Network Cursor.
+ */
+ public static enum BecomeActiveNetworkCursor {
+ /**
+ * The new cursor should become the one and only Active
+ * Network Cursor. Any other cursor that might already be the
+ * Active Network Cursor will cease to be so.
+ */
+ YES,
+
+ /**
+ * The new cursor should not become the Active Network
+ * Cursor. Any other cursor that might already be the Active
+ * Network Cursor will continue to be so.
+ */
+ NO
+ }
+
+ /**
* Wraps a Cursor in a ConversationCursor
*
* @param account the account the cursor is associated with
@@ -450,6 +491,20 @@ public final class Gmail {
}
/**
+ * Creates an array of SelectionArguments suitable for passing to the provider's query.
+ * Currently this only handles one flag, but it could be expanded in the future.
+ */
+ private static String[] getSelectionArguments(
+ BecomeActiveNetworkCursor becomeActiveNetworkCursor) {
+ if (BecomeActiveNetworkCursor.NO == becomeActiveNetworkCursor) {
+ return new String[] {SelectionArguments.DO_NOT_BECOME_ACTIVE_NETWORK_CURSOR};
+ } else {
+ // Default behavior; no args required.
+ return null;
+ }
+ }
+
+ /**
* Asynchronously gets a cursor over all conversations matching a query. The
* query is in Gmail's query syntax. When the operation is complete the handler's
* onQueryComplete() method is called with the resulting Cursor.
@@ -458,14 +513,17 @@ public final class Gmail {
* @param handler An AsyncQueryHanlder that will be used to run the query
* @param token The token to pass to startQuery, which will be passed back to onQueryComplete
* @param query a query in Gmail's query syntax
+ * @param becomeActiveNetworkCursor whether or not the returned
+ * cursor should become the Active Network Cursor
*/
public void runQueryForConversations(String account, AsyncQueryHandler handler, int token,
- String query) {
+ String query, BecomeActiveNetworkCursor becomeActiveNetworkCursor) {
if (TextUtils.isEmpty(account)) {
throw new IllegalArgumentException("account is empty");
}
+ String[] selectionArgs = getSelectionArguments(becomeActiveNetworkCursor);
handler.startQuery(token, null, Uri.withAppendedPath(CONVERSATIONS_URI, account),
- CONVERSATION_PROJECTION, query, null, null);
+ CONVERSATION_PROJECTION, query, selectionArgs, null);
}
/**
@@ -474,11 +532,15 @@ public final class Gmail {
*
* @param account run the query on this account
* @param query a query in Gmail's query syntax
+ * @param becomeActiveNetworkCursor whether or not the returned
+ * cursor should become the Active Network Cursor
*/
- public ConversationCursor getConversationCursorForQuery(String account, String query) {
+ public ConversationCursor getConversationCursorForQuery(
+ String account, String query, BecomeActiveNetworkCursor becomeActiveNetworkCursor) {
+ String[] selectionArgs = getSelectionArguments(becomeActiveNetworkCursor);
Cursor cursor = mContentResolver.query(
Uri.withAppendedPath(CONVERSATIONS_URI, account), CONVERSATION_PROJECTION,
- query, null, null);
+ query, selectionArgs, null);
return new ConversationCursor(this, account, cursor);
}
@@ -559,12 +621,10 @@ public final class Gmail {
* server message id.
* @param label the label to add or remove
* @param add true to add the label, false to remove it
- * @throws NonexistentLabelException thrown if the label does not exist
*/
public void addOrRemoveLabelOnConversation(
String account, long conversationId, long maxServerMessageId, String label,
- boolean add)
- throws NonexistentLabelException {
+ boolean add) {
if (TextUtils.isEmpty(account)) {
throw new IllegalArgumentException("account is empty");
}
@@ -599,7 +659,6 @@ public final class Gmail {
* @param messageId the id of the message to whose labels should be changed
* @param label the label to add or remove
* @param add true to add the label, false to remove it
- * @throws NonexistentLabelException thrown if the label does not exist
*/
public static void addOrRemoveLabelOnMessage(ContentResolver contentResolver, String account,
long conversationId, long messageId, String label, boolean add) {
@@ -1175,19 +1234,6 @@ public final class Gmail {
}
/**
- * Thrown when an operation is requested with a label that does not exist.
- *
- * TODO: this is here because I wanted a checked exception. However, I don't
- * think that that is appropriate. In fact, I don't think that we should
- * throw an exception at all because the label might have been valid when
- * the caller presented it to the user but removed as a result of a sync.
- * Maybe we should kill this and eat the errors.
- */
- public static class NonexistentLabelException extends Exception {
- // TODO: Add label name?
- }
-
- /**
* A cursor over labels.
*/
public final class LabelCursor extends MailCursor {
@@ -1431,10 +1477,20 @@ public final class Gmail {
LABEL_OUTBOX, LABEL_DRAFT, LABEL_ALL,
LABEL_SPAM, LABEL_TRASH);
+
+ private static final Set<String> USER_MEANINGFUL_SYSTEM_LABELS_SET =
+ Sets.newHashSet(
+ SORTED_USER_MEANINGFUL_SYSTEM_LABELS.toArray(
+ new String[]{}));
+
public static List<String> getSortedUserMeaningfulSystemLabels() {
return SORTED_USER_MEANINGFUL_SYSTEM_LABELS;
}
+ public static Set<String> getUserMeaningfulSystemLabelsSet() {
+ return USER_MEANINGFUL_SYSTEM_LABELS_SET;
+ }
+
/**
* If you are ever tempted to remove outbox or draft from this set make sure you have a
* way to stop draft and outbox messages from getting purged before they are sent to the
@@ -1484,7 +1540,15 @@ public final class Gmail {
/** Returns the number of unread conversation with a given label. */
public int getNumUnreadConversations(long labelId) {
- return getLabelIdValues(labelId).getAsInteger(LabelColumns.NUM_UNREAD_CONVERSATIONS);
+ Integer unreadConversations =
+ getLabelIdValues(labelId).getAsInteger(LabelColumns.NUM_UNREAD_CONVERSATIONS);
+ // There seems to be a race condition here that can get the label maps into a bad
+ // state and lose state on a particular label.
+ if (unreadConversations == null) {
+ return 0;
+ } else {
+ return unreadConversations;
+ }
}
/**
@@ -2021,10 +2085,8 @@ public final class Gmail {
*
* @param label the label to add or remove
* @param add whether to add or remove the label
- * @throws NonexistentLabelException thrown if the named label does not
- * exist
*/
- public void addOrRemoveLabel(String label, boolean add) throws NonexistentLabelException {
+ public void addOrRemoveLabel(String label, boolean add) {
addOrRemoveLabelOnMessage(mContentResolver, mAccount, getConversationId(),
getMessageId(), label, add);
}
diff --git a/core/java/android/provider/Im.java b/core/java/android/provider/Im.java
index 68b2acd..19ad158 100644
--- a/core/java/android/provider/Im.java
+++ b/core/java/android/provider/Im.java
@@ -78,21 +78,10 @@ public class Im {
String MSN = "MSN";
String ICQ = "ICQ";
String AIM = "AIM";
- }
-
- /**
- * The ProviderCategories definitions are used for the Intent category for the Intent
- *
- * Intent intent = new Intent(Intent.ACTION_SENDTO,
- * Uri.fromParts("im", data, null)).
- * addCategory(category);
- */
- public interface ProviderCategories {
- String GTALK = "com.android.im.category.GTALK";
- String AIM = "com.android.im.category.AIM";
- String MSN = "com.android.im.category.MSN";
- String YAHOO = "com.android.im.category.YAHOO";
- String ICQ = "com.android.im.category.ICQ";
+ String XMPP = "XMPP";
+ String JABBER = "JABBER";
+ String SKYPE = "SKYPE";
+ String QQ = "QQ";
}
/**
@@ -140,54 +129,6 @@ public class Im {
return retVal;
}
- /**
- * This returns the provider name given a provider category.
- *
- * @param providerCategory the provider category defined in {@link ProviderCategories}.
- * @return the corresponding provider name defined in {@link ProviderNames}.
- */
- public static String getProviderNameForCategory(String providerCategory) {
- if (providerCategory != null) {
- if (providerCategory.equalsIgnoreCase(ProviderCategories.GTALK)) {
- return ProviderNames.GTALK;
- } else if (providerCategory.equalsIgnoreCase(ProviderCategories.AIM)) {
- return ProviderNames.AIM;
- } else if (providerCategory.equalsIgnoreCase(ProviderCategories.MSN)) {
- return ProviderNames.MSN;
- } else if (providerCategory.equalsIgnoreCase(ProviderCategories.YAHOO)) {
- return ProviderNames.YAHOO;
- } else if (providerCategory.equalsIgnoreCase(ProviderCategories.ICQ)) {
- return ProviderNames.ICQ;
- }
- }
-
- return null;
- }
-
- /**
- * This returns the provider category given a provider name.
- *
- * @param providername the provider name defined in {@link ProviderNames}.
- * @return the provider category defined in {@link ProviderCategories}.
- */
- public static String getProviderCategoryFromName(String providername) {
- if (providername != null) {
- if (providername.equalsIgnoreCase(Im.ProviderNames.GTALK)) {
- return Im.ProviderCategories.GTALK;
- } else if (providername.equalsIgnoreCase(Im.ProviderNames.AIM)) {
- return Im.ProviderCategories.AIM;
- } else if (providername.equalsIgnoreCase(Im.ProviderNames.MSN)) {
- return Im.ProviderCategories.MSN;
- } else if (providername.equalsIgnoreCase(Im.ProviderNames.YAHOO)) {
- return Im.ProviderCategories.YAHOO;
- } else if (providername.equalsIgnoreCase(Im.ProviderNames.ICQ)) {
- return Im.ProviderCategories.ICQ;
- }
- }
-
- return null;
- }
-
private static final String[] PROVIDER_PROJECTION = new String[] {
_ID,
NAME
@@ -797,6 +738,13 @@ public class Im {
String ETAG = "etag";
/**
+ * The OTR etag, computed by the server, stored on the client. There is one OTR etag
+ * per account roster.
+ * <P>Type: TEXT</P>
+ */
+ String OTR_ETAG = "otr_etag";
+
+ /**
* The account id for the etag.
* <P> Type: INTEGER </P>
*/
@@ -837,12 +785,38 @@ public class Im {
return retVal;
}
+ public static final String getOtrEtag(ContentResolver resolver, long accountId) {
+ String retVal = null;
+
+ Cursor c = resolver.query(CONTENT_URI,
+ CONTACT_OTR_ETAG_PROJECTION,
+ ACCOUNT + "=" + accountId,
+ null /* selection args */,
+ null /* sort order */);
+
+ try {
+ if (c.moveToFirst()) {
+ retVal = c.getString(COLUMN_OTR_ETAG);
+ }
+ } finally {
+ c.close();
+ }
+
+ return retVal;
+ }
+
private static final String[] CONTACT_ETAG_PROJECTION = new String[] {
Im.ContactsEtag.ETAG // 0
};
private static int COLUMN_ETAG = 0;
+ private static final String[] CONTACT_OTR_ETAG_PROJECTION = new String[] {
+ Im.ContactsEtag.OTR_ETAG // 0
+ };
+
+ private static int COLUMN_OTR_ETAG = 0;
+
/**
* The content:// style URL for this table
*/
@@ -1271,9 +1245,9 @@ public class Im {
}
/**
- * Columns shared between the IM and contacts presence tables
+ * Common presence columns shared between the IM and contacts presence tables
*/
- interface CommonPresenceColumns {
+ public interface CommonPresenceColumns {
/**
* The priority, an integer, used by XMPP presence
* <P>Type: INTEGER</P>
@@ -2070,4 +2044,37 @@ public class Im {
*/
public static final Uri CONTENT_URI = Uri.parse("content://im/lastRmqId");
}
+
+ /**
+ * Columns for IM branding resource map cache table. This table caches the result of
+ * loading the branding resources to speed up IM landing page start.
+ */
+ public interface BrandingResourceMapCacheColumns {
+ /**
+ * The provider ID
+ * <P>Type: INTEGER</P>
+ */
+ String PROVIDER_ID = "provider_id";
+ /**
+ * The application resource ID
+ * <P>Type: INTEGER</P>
+ */
+ String APP_RES_ID = "app_res_id";
+ /**
+ * The plugin resource ID
+ * <P>Type: INTEGER</P>
+ */
+ String PLUGIN_RES_ID = "plugin_res_id";
+ }
+
+ /**
+ * The table for caching the result of loading IM branding resources.
+ */
+ public static final class BrandingResourceMapCache
+ implements BaseColumns, BrandingResourceMapCacheColumns {
+ /**
+ * The content:// style URL for this table.
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://im/brandingResMapCache");
+ }
}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 87a02e6..b91bc9d 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -91,14 +91,14 @@ public final class MediaStore
public static final String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation";
/**
- * The name of the Intent-extra used to control the orientation of a ViewImage.
+ * The name of an Intent-extra used to control the UI of a ViewImage.
* This is a boolean property that overrides the activity's default fullscreen state.
* @hide
*/
public static final String EXTRA_FULL_SCREEN = "android.intent.extra.fullScreen";
/**
- * The name of the Intent-extra used to control the orientation of a ViewImage.
+ * The name of an Intent-extra used to control the UI of a ViewImage.
* This is a boolean property that specifies whether or not to show action icons.
* @hide
*/
@@ -117,25 +117,36 @@ public final class MediaStore
*/
public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
-
/**
* The name of the Intent action used to launch a camera in video mode.
*/
public static final String INTENT_ACTION_VIDEO_CAMERA = "android.media.action.VIDEO_CAMERA";
/**
- * Standard Intent action that can be sent to have the media application
- * capture an image and return it. The image is returned as a Bitmap
- * object in the extra field.
- * @hide
+ * Standard Intent action that can be sent to have the camera application
+ * capture an image and return it.
+ * <p>
+ * The caller may pass an extra EXTRA_OUTPUT to control where this image will be written.
+ * If the EXTRA_OUTPUT is not present, then a small sized image is returned as a Bitmap
+ * object in the extra field. This is useful for applications that only need a small image.
+ * If the EXTRA_OUTPUT is present, then the full-sized image will be written to the Uri
+ * value of EXTRA_OUTPUT.
+ * @see #EXTRA_OUTPUT
+ * @see #EXTRA_VIDEO_QUALITY
*/
public final static String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
/**
- * Standard Intent action that can be sent to have the media application
- * capture an video and return it. The caller may pass in an extra EXTRA_VIDEO_QUALITY
- * control the video quality.
- * @hide
+ * Standard Intent action that can be sent to have the camera application
+ * capture an video and return it.
+ * <p>
+ * The caller may pass in an extra EXTRA_VIDEO_QUALITY to control the video quality.
+ * <p>
+ * The caller may pass in an extra EXTRA_OUTPUT to control
+ * where the video is written. If EXTRA_OUTPUT is not present the video will be
+ * written to the standard location for videos, and the Uri of that location will be
+ * returned in the data field of the Uri.
+ * @see #EXTRA_OUTPUT
*/
public final static String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
@@ -143,15 +154,19 @@ public final class MediaStore
* The name of the Intent-extra used to control the quality of a recorded video. This is an
* integer property. Currently value 0 means low quality, suitable for MMS messages, and
* value 1 means high quality. In the future other quality levels may be added.
- * @hide
*/
public final static String EXTRA_VIDEO_QUALITY = "android.intent.extra.videoQuality";
/**
- * The name of the Intent-extra used to indicate a Uri to be used to
- * store the requested image or video.
+ * Specify the maximum allowed size.
* @hide
*/
+ public final static String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit";
+
+ /**
+ * The name of the Intent-extra used to indicate a content resolver Uri to be used to
+ * store the requested image or video.
+ */
public final static String EXTRA_OUTPUT = "output";
/**
@@ -471,7 +486,7 @@ public final class MediaStore
/**
* The default sort order for this table
*/
- public static final String DEFAULT_SORT_ORDER = "name ASC";
+ public static final String DEFAULT_SORT_ORDER = ImageColumns.BUCKET_DISPLAY_NAME;
}
public static class Thumbnails implements BaseColumns
@@ -582,6 +597,14 @@ public final class MediaStore
public static final String DURATION = "duration";
/**
+ * The position, in ms, playback was at when playback for this file
+ * was last stopped.
+ * <P>Type: INTEGER (long)</P>
+ * @hide
+ */
+ public static final String BOOKMARK = "bookmark";
+
+ /**
* The id of the artist who created the audio file, if any
* <P>Type: INTEGER (long)</P>
*/
@@ -654,6 +677,13 @@ public final class MediaStore
public static final String IS_MUSIC = "is_music";
/**
+ * Non-zero if the audio file is a podcast
+ * <P>Type: INTEGER (boolean)</P>
+ * @hide
+ */
+ public static final String IS_PODCAST = "is_podcast";
+
+ /**
* Non-zero id the audio file may be a ringtone
* <P>Type: INTEGER (boolean)</P>
*/
@@ -1198,22 +1228,15 @@ public final class MediaStore
}
public static final class Video {
- /**
- * deprecated Replaced by DEFAULT_SORT_ORDER2
- * This variable is a mistake that is retained for backwards compatibility.
- * (There is no "name" column in the Video table.)
- */
- public static final String DEFAULT_SORT_ORDER = "name ASC";
/**
- * The default sort order for this table
- * @hide
+ * The default sort order for this table.
*/
- public static final String DEFAULT_SORT_ORDER2 = MediaColumns.DISPLAY_NAME;
+ public static final String DEFAULT_SORT_ORDER = MediaColumns.DISPLAY_NAME;
public static final Cursor query(ContentResolver cr, Uri uri, String[] projection)
{
- return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER2);
+ return cr.query(uri, projection, null, null, DEFAULT_SORT_ORDER);
}
public interface VideoColumns extends MediaColumns {
@@ -1316,7 +1339,6 @@ public final class MediaStore
* video should start playing at the next time it is opened. If the value is null or
* out of the range 0..DURATION-1 then the video should start playing from the
* beginning.
- * @hide
* <P>Type: INTEGER</P>
*/
public static final String BOOKMARK = "bookmark";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index abbfd5b..b0ee479 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -235,6 +235,35 @@ public final class Settings {
"android.settings.LOCALE_SETTINGS";
/**
+ * Activity Action: Show settings to configure input methods, in particular
+ * allowing the user to enable input methods.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_INPUT_METHOD_SETTINGS =
+ "android.settings.INPUT_METHOD_SETTINGS";
+
+ /**
+ * Activity Action: Show settings to manage the user input dictionary.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_USER_DICTIONARY_SETTINGS =
+ "android.settings.USER_DICTIONARY_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow configuration of application-related settings.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -850,15 +879,6 @@ public final class Settings {
public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
/**
- * The interval in milliseconds after which Wi-Fi is considered idle.
- * When idle, it is possible for the device to be switched from Wi-Fi to
- * the mobile data network.
- *
- * @hide pending API Council approval
- */
- public static final String WIFI_IDLE_MS = "wifi_idle_ms";
-
- /**
* The policy for deciding when Wi-Fi should go to sleep (which will in
* turn switch to using the mobile data as an Internet connection).
* <p>
@@ -1233,6 +1253,13 @@ public final class Settings {
public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
/**
+ * Scaling factor for normal window animations. Setting to 0 will disable window
+ * animations.
+ * @hide
+ */
+ public static final String FANCY_IME_ANIMATIONS = "fancy_ime_animations";
+
+ /**
* Control whether the accelerometer will be used to change screen
* orientation. If 0, it will not be used unless explicitly requested
* by the application; if 1, it will be used by default unless explicitly
@@ -1252,6 +1279,12 @@ public final class Settings {
*/
public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
+ /**
+ * Whether the haptic feedback (long presses, ...) are enabled. The value is
+ * boolean (1 or 0).
+ */
+ public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
+
// Settings moved to Settings.Secure
/**
@@ -2008,6 +2041,14 @@ public final class Settings {
*/
public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
"wifi_mobile_data_transition_wakelock_timeout_ms";
+
+ /**
+ * Whether background data usage is allowed by the user. See
+ * ConnectivityManager for more info.
+ *
+ * @hide pending API council
+ */
+ public static final String BACKGROUND_DATA = "background_data";
}
/**
@@ -2130,6 +2171,11 @@ public final class Settings {
* Event tags from the kernel event log to upload during checkin.
*/
public static final String CHECKIN_EVENTS = "checkin_events";
+
+ /**
+ * Event tags for list of services to upload during checkin.
+ */
+ public static final String CHECKIN_DUMPSYS_LIST = "checkin_dumpsys_list";
/**
* The interval (in seconds) between periodic checkin attempts.
@@ -2137,6 +2183,12 @@ public final class Settings {
public static final String CHECKIN_INTERVAL = "checkin_interval";
/**
+ * Boolean indicating if the market app should force market only checkins on
+ * install/uninstall. Any non-0 value is considered true.
+ */
+ public static final String MARKET_FORCE_CHECKIN = "market_force_checkin";
+
+ /**
* How frequently (in seconds) to check the memory status of the
* device.
*/
@@ -2275,6 +2327,13 @@ public final class Settings {
public static final String GMAIL_SEND_IMMEDIATELY = "gmail_send_immediately";
/**
+ * Controls whether gmail buffers server responses. Possible values are "memory", for a
+ * memory-based buffer, or "file", for a temp-file-based buffer. All other values
+ * (including not set) disable buffering.
+ */
+ public static final String GMAIL_BUFFER_SERVER_RESPONSE = "gmail_buffer_server_response";
+
+ /**
* Hostname of the GTalk server.
*/
public static final String GTALK_SERVICE_HOSTNAME = "gtalk_hostname";
@@ -2402,6 +2461,14 @@ public final class Settings {
"gtalk_ssl_handshake_timeout_ms";
/**
+ * Enable use of ssl session caching.
+ * 'db' - save each session in a (per process) database
+ * 'file' - save each session in a (per process) file
+ * not set or any other value - normal java in-memory caching
+ */
+ public static final String SSL_SESSION_CACHE = "ssl_session_cache";
+
+ /**
* How many bytes long a message has to be, in order to be gzipped.
*/
public static final String SYNC_MIN_GZIP_BYTES =
@@ -2496,28 +2563,28 @@ public final class Settings {
*/
public static final String SETTINGS_CONTRIBUTORS_PRETTY_URL =
"settings_contributors_pretty_url";
-
+
/**
* URL that points to the Terms Of Service for the device.
* <p>
- * This should be a pretty http URL.
+ * This should be a pretty http URL.
*/
public static final String SETUP_GOOGLE_TOS_URL = "setup_google_tos_url";
-
+
/**
* URL that points to the Android privacy policy for the device.
* <p>
* This should be a pretty http URL.
*/
public static final String SETUP_ANDROID_PRIVACY_URL = "setup_android_privacy_url";
-
+
/**
* URL that points to the Google privacy policy for the device.
* <p>
- * This should be a pretty http URL.
+ * This should be a pretty http URL.
*/
public static final String SETUP_GOOGLE_PRIVACY_URL = "setup_google_privacy_url";
-
+
/**
* Request an MSISDN token for various Google services.
*/
@@ -2683,6 +2750,13 @@ public final class Settings {
"gprs_register_check_period_ms";
/**
+ * The interval in milliseconds after which Wi-Fi is considered idle.
+ * When idle, it is possible for the device to be switched from Wi-Fi to
+ * the mobile data network.
+ */
+ public static final String WIFI_IDLE_MS = "wifi_idle_ms";
+
+ /**
* Screen timeout in milliseconds corresponding to the
* PowerManager's POKE_LOCK_SHORT_TIMEOUT flag (i.e. the fastest
* possible screen timeout behavior.)
@@ -2704,8 +2778,59 @@ public final class Settings {
* Speech encoding used with voice search on WIFI networks. To be factored out of this class.
*/
public static final String VOICE_SEARCH_ENCODING_WIFI = "voice_search_encoding_wifi";
+
+ /**
+ * Whether to use automatic gain control in voice search (0 = disable, 1 = enable).
+ * To be factored out of this class.
+ */
+ public static final String VOICE_SEARCH_ENABLE_AGC = "voice_search_enable_agc";
+
+ /**
+ * Whether to use noise suppression in voice search (0 = disable, 1 = enable).
+ * To be factored out of this class.
+ */
+ public static final String VOICE_SEARCH_ENABLE_NS = "voice_search_enable_ns";
+
+ /**
+ * Whether to use the IIR filter in voice search (0 = disable, 1 = enable).
+ * To be factored out of this class.
+ */
+ public static final String VOICE_SEARCH_ENABLE_IIR = "voice_search_enable_iir";
+
+ /**
+ * List of test suites (local disk filename) for the automatic instrumentation test runner.
+ * The file format is similar to automated_suites.xml, see AutoTesterService.
+ * If this setting is missing or empty, the automatic test runner will not start.
+ */
+ public static final String AUTOTEST_SUITES_FILE = "autotest_suites_file";
+
+ /**
+ * Interval between synchronous checkins forced by the automatic test runner.
+ * If you set this to a value smaller than CHECKIN_INTERVAL, then the test runner's
+ * frequent checkins will prevent asynchronous background checkins from interfering
+ * with any performance measurements.
+ */
+ public static final String AUTOTEST_CHECKIN_SECONDS = "autotest_checkin_seconds";
+
+ /**
+ * Interval between reboots forced by the automatic test runner.
+ */
+ public static final String AUTOTEST_REBOOT_SECONDS = "autotest_reboot_seconds";
+
+
+ /**
+ * Threshold values for the duration and level of a discharge cycle, under
+ * which we log discharge cycle info.
+ */
+ public static final String BATTERY_DISCHARGE_DURATION_THRESHOLD =
+ "battery_discharge_duration_threshold";
+ public static final String BATTERY_DISCHARGE_THRESHOLD = "battery_discharge_threshold";
-
+ /**
+ * An email address that anr bugreports should be sent to.
+ */
+ public static final String ANR_BUGREPORT_RECIPIENT = "anr_bugreport_recipient";
+
/**
* @deprecated
* @hide
@@ -2772,7 +2897,7 @@ public final class Settings {
* Arbitrary string (displayed to the user) that allows bookmarks to be
* organized into categories. There are some special names for
* standard folders, which all start with '@'. The label displayed for
- * the folder changes with the locale (via {@link #labelForFolder}) but
+ * the folder changes with the locale (via {@link #getLabelForFolder}) but
* the folder name does not change so you can consistently query for
* the folder regardless of the current locale.
*
@@ -2912,9 +3037,10 @@ public final class Settings {
*
* @param context A context.
* @param cursor A cursor pointing to the row whose title should be
- * returned. The cursor must contain at least the
- * {@link #TITLE} and {@link #INTENT} columns.
- * @return A title that is localized and can be displayed to the user.
+ * returned. The cursor must contain at least the {@link #TITLE}
+ * and {@link #INTENT} columns.
+ * @return A title that is localized and can be displayed to the user,
+ * or the empty string if one could not be found.
*/
public static CharSequence getTitle(Context context, Cursor cursor) {
int titleColumn = cursor.getColumnIndex(TITLE);
@@ -2943,7 +3069,7 @@ public final class Settings {
PackageManager packageManager = context.getPackageManager();
ResolveInfo info = packageManager.resolveActivity(intent, 0);
- return info.loadLabel(packageManager);
+ return info != null ? info.loadLabel(packageManager) : "";
}
}
diff --git a/core/java/android/provider/Sync.java b/core/java/android/provider/Sync.java
index 94bf807..628852f 100644
--- a/core/java/android/provider/Sync.java
+++ b/core/java/android/provider/Sync.java
@@ -273,6 +273,7 @@ public final class Sync {
public static final int ERROR_CONFLICT = 5;
public static final int ERROR_TOO_MANY_DELETIONS = 6;
public static final int ERROR_TOO_MANY_RETRIES = 7;
+ public static final int ERROR_INTERNAL = 8;
// The MESG column will contain one of these or one of the Error types.
public static final String MESG_SUCCESS = "success";
@@ -292,6 +293,7 @@ public final class Sync {
case ERROR_CONFLICT: return "conflict detected";
case ERROR_TOO_MANY_DELETIONS: return "too many deletions";
case ERROR_TOO_MANY_RETRIES: return "too many retries";
+ case ERROR_INTERNAL: return "internal error";
default: return "unknown error";
}
}
@@ -491,11 +493,6 @@ public final class Sync {
/** controls whether or not the device listens for sync tickles */
public static final String SETTING_LISTEN_FOR_TICKLES = "listen_for_tickles";
- /** controls whether or not the device connect to Google in background for various
- * stuff, including GTalk, checkin, Market and data sync ...
- */
- public static final String SETTING_BACKGROUND_DATA = "background_data";
-
/** controls whether or not the individual provider is synced when tickles are received */
public static final String SETTING_SYNC_PROVIDER_PREFIX = "sync_provider_";
@@ -572,18 +569,6 @@ public final class Sync {
putBoolean(contentResolver, SETTING_LISTEN_FOR_TICKLES, flag);
}
- /**
- * A convenience method to set whether or not the device should connect to Google
- * in background.
- *
- * @param contentResolver the ContentResolver to use to access the settings table
- * @param flag true if it should connect.
- */
- static public void setBackgroundData(ContentResolver contentResolver,
- boolean flag) {
- putBoolean(contentResolver, SETTING_BACKGROUND_DATA, flag);
- }
-
public static class QueryMap extends ContentQueryMap {
private ContentResolver mContentResolver;
@@ -632,24 +617,6 @@ public final class Sync {
}
/**
- * Set whether or not the device should connect to Google in background
- *
- * @param flag true if it should
- */
- public void setBackgroundData(boolean flag) {
- Settings.setBackgroundData(mContentResolver, flag);
- }
-
- /**
- * Check if the device should connect to Google in background.
-
- * @return true if it should
- */
- public boolean getBackgroundData() {
- return getBoolean(SETTING_BACKGROUND_DATA, true);
- }
-
- /**
* Convenience function for retrieving a single settings value
* as a boolean.
*
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 18c64ed..d802c14 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1023,6 +1023,11 @@ public final class Telephony {
* <P>Type: INTEGER</P>
*/
public static final String ERROR = "error";
+ /**
+ * Indicates whether this thread contains any attachments.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String HAS_ATTACHMENT = "has_attachment";
}
/**
diff --git a/core/java/android/provider/UserDictionary.java b/core/java/android/provider/UserDictionary.java
index 58e5731..5a7ef85 100644
--- a/core/java/android/provider/UserDictionary.java
+++ b/core/java/android/provider/UserDictionary.java
@@ -25,10 +25,13 @@ import android.net.Uri;
import android.text.TextUtils;
/**
- *
- * @hide Pending API council approval
+ * A provider of user defined words for input methods to use for predictive text input.
+ * Applications and input methods may add words into the dictionary. Words can have associated
+ * frequency information and locale information.
*/
public class UserDictionary {
+
+ /** Authority string for this provider. */
public static final String AUTHORITY = "user_dictionary";
/**
@@ -39,7 +42,6 @@ public class UserDictionary {
/**
* Contains the user defined words.
- * @hide Pending API council approval
*/
public static class Words implements BaseColumns {
/**
@@ -67,14 +69,14 @@ public class UserDictionary {
public static final String WORD = "word";
/**
- * The frequency column. A value between 1 and 255.
+ * The frequency column. A value between 1 and 255. Higher values imply higher frequency.
* <p>TYPE: INTEGER</p>
*/
public static final String FREQUENCY = "frequency";
/**
* The locale that this word belongs to. Null if it pertains to all
- * locales. Locale is a 5 letter string such as <pre>en_US</pre>.
+ * locales. Locale is as defined by the string returned by Locale.toString().
* <p>TYPE: TEXT</p>
*/
public static final String LOCALE = "locale";
@@ -85,8 +87,10 @@ public class UserDictionary {
*/
public static final String APP_ID = "appid";
+ /** The locale type to specify that the word is common to all locales. */
public static final int LOCALE_TYPE_ALL = 0;
+ /** The locale type to specify that the word is for the current locale. */
public static final int LOCALE_TYPE_CURRENT = 1;
/**
@@ -94,7 +98,14 @@ public class UserDictionary {
*/
public static final String DEFAULT_SORT_ORDER = FREQUENCY + " DESC";
-
+ /** Adds a word to the dictionary, with the given frequency and the specified
+ * specified locale type.
+ * @param context the current application context
+ * @param word the word to add to the dictionary. This should not be null or
+ * empty.
+ * @param localeType the locale type for this word. It should be one of
+ * {@link #LOCALE_TYPE_ALL} or {@link #LOCALE_TYPE_CURRENT}.
+ */
public static void addWord(Context context, String word,
int frequency, int localeType) {
final ContentResolver resolver = context.getContentResolver();
diff --git a/core/java/android/provider/package.html b/core/java/android/provider/package.html
index a553592..055b037 100644
--- a/core/java/android/provider/package.html
+++ b/core/java/android/provider/package.html
@@ -6,6 +6,6 @@ Android.
as contact informations, calendar information, and media files. These classes
provide simplified methods of adding or retrieving data from these content
providers. For information about how to use a content provider, see <a
-href="{@docRoot}devel/data.html">Reading and Writing Persistent Data</a>.
+href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.
</BODY>
</HTML>
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 8486e4b..3aa4078 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -15,8 +15,7 @@
*/
/**
- * TODO: Move this to
- * java/services/com/android/server/BluetoothA2dpService.java
+ * TODO: Move this to services.jar
* and make the contructor package private again.
* @hide
*/
@@ -35,15 +34,16 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
import android.provider.Settings;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.List;
import java.util.HashMap;
-import java.util.Iterator;
+import java.util.List;
public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private static final String TAG = "BluetoothA2dpService";
@@ -55,6 +55,9 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
private static final String A2DP_SINK_ADDRESS = "a2dp_sink_address";
+ private static final String BLUETOOTH_ENABLED = "bluetooth_enabled";
+
+ private static final int MESSAGE_CONNECT_TO = 1;
private final Context mContext;
private final IntentFilter mIntentFilter;
@@ -85,6 +88,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
mIntentFilter = new IntentFilter(BluetoothIntent.ENABLED_ACTION);
mIntentFilter.addAction(BluetoothIntent.DISABLED_ACTION);
mIntentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
+ mIntentFilter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
mContext.registerReceiver(mReceiver, mIntentFilter);
if (device.isEnabled()) {
@@ -122,6 +126,37 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
setSinkPriority(address, BluetoothA2dp.PRIORITY_OFF);
break;
}
+ } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION)) {
+ if (getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF) {
+ // This device is a preferred sink. Make an A2DP connection
+ // after a delay. We delay to avoid connection collisions,
+ // and to give other profiles such as HFP a chance to
+ // connect first.
+ Message msg = Message.obtain(mHandler, MESSAGE_CONNECT_TO, address);
+ mHandler.sendMessageDelayed(msg, 6000);
+ }
+ }
+ }
+ };
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ 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 &&
+ lookupSinksMatchingStates(new int[] {
+ BluetoothA2dp.STATE_CONNECTING,
+ BluetoothA2dp.STATE_CONNECTED,
+ BluetoothA2dp.STATE_PLAYING,
+ BluetoothA2dp.STATE_DISCONNECTING}).size() == 0) {
+ log("Auto-connecting A2DP to sink " + address);
+ connectSink(address);
+ }
+ break;
}
}
};
@@ -136,10 +171,31 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
BluetoothA2dp.STATE_DISCONNECTED));
}
}
+ mAudioManager.setParameter(BLUETOOTH_ENABLED, "true");
}
private synchronized void onBluetoothDisable() {
- mAudioDevices = null;
+ if (mAudioDevices != null) {
+ // copy to allow modification during iteration
+ String[] paths = new String[mAudioDevices.size()];
+ paths = mAudioDevices.keySet().toArray(paths);
+ for (String path : paths) {
+ switch (mAudioDevices.get(path).state) {
+ case BluetoothA2dp.STATE_CONNECTING:
+ case BluetoothA2dp.STATE_CONNECTED:
+ case BluetoothA2dp.STATE_PLAYING:
+ disconnectSinkNative(path);
+ updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+ break;
+ case BluetoothA2dp.STATE_DISCONNECTING:
+ updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+ break;
+ }
+ }
+ mAudioDevices = null;
+ }
+ mAudioManager.setBluetoothA2dpOn(false);
+ mAudioManager.setParameter(BLUETOOTH_ENABLED, "false");
}
public synchronized int connectSink(String address) {
@@ -152,6 +208,15 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
if (mAudioDevices == null) {
return BluetoothError.ERROR;
}
+ // ignore if there are any active sinks
+ if (lookupSinksMatchingStates(new int[] {
+ BluetoothA2dp.STATE_CONNECTING,
+ BluetoothA2dp.STATE_CONNECTED,
+ BluetoothA2dp.STATE_PLAYING,
+ BluetoothA2dp.STATE_DISCONNECTING}).size() != 0) {
+ return BluetoothError.ERROR;
+ }
+
String path = lookupPath(address);
if (path == null) {
path = createHeadsetNative(address);
@@ -215,17 +280,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
public synchronized List<String> listConnectedSinks() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- List<String> connectedSinks = new ArrayList<String>();
- if (mAudioDevices == null) {
- return connectedSinks;
- }
- for (SinkState sink : mAudioDevices.values()) {
- if (sink.state == BluetoothA2dp.STATE_CONNECTED ||
- sink.state == BluetoothA2dp.STATE_PLAYING) {
- connectedSinks.add(sink.address);
- }
- }
- return connectedSinks;
+ return lookupSinksMatchingStates(new int[] {BluetoothA2dp.STATE_CONNECTED,
+ BluetoothA2dp.STATE_PLAYING});
}
public synchronized int getSinkState(String address) {
@@ -279,7 +335,11 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
// bluez 3.36 quietly disconnects the previous sink when a new sink
// is connected, so we need to mark all previously connected sinks as
// disconnected
- for (String oldPath : mAudioDevices.keySet()) {
+
+ // copy to allow modification during iteration
+ String[] paths = new String[mAudioDevices.size()];
+ paths = mAudioDevices.keySet().toArray(paths);
+ for (String oldPath : paths) {
if (path.equals(oldPath)) {
continue;
}
@@ -289,6 +349,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
}
}
+ updateState(path, BluetoothA2dp.STATE_CONNECTING);
mAudioManager.setParameter(A2DP_SINK_ADDRESS, lookupAddress(path));
mAudioManager.setBluetoothA2dpOn(true);
updateState(path, BluetoothA2dp.STATE_CONNECTED);
@@ -309,6 +370,11 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private synchronized final String lookupAddress(String path) {
if (mAudioDevices == null) return null;
+ SinkState sink = mAudioDevices.get(path);
+ if (sink == null) {
+ Log.w(TAG, "lookupAddress() called for unknown device " + path);
+ updateState(path, BluetoothA2dp.STATE_DISCONNECTED);
+ }
String address = mAudioDevices.get(path).address;
if (address == null) Log.e(TAG, "Can't find address for " + path);
return address;
@@ -325,6 +391,22 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return null;
}
+ private synchronized List<String> lookupSinksMatchingStates(int[] states) {
+ List<String> sinks = new ArrayList<String>();
+ if (mAudioDevices == null) {
+ return sinks;
+ }
+ for (SinkState sink : mAudioDevices.values()) {
+ for (int state : states) {
+ if (sink.state == state) {
+ sinks.add(sink.address);
+ break;
+ }
+ }
+ }
+ return sinks;
+ }
+
private synchronized void updateState(String path, int state) {
if (mAudioDevices == null) return;
@@ -349,6 +431,15 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
intent.putExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothA2dp.SINK_STATE, state);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+
+ if ((prevState == BluetoothA2dp.STATE_CONNECTED ||
+ prevState == BluetoothA2dp.STATE_PLAYING) &&
+ (state != BluetoothA2dp.STATE_CONNECTED &&
+ state != BluetoothA2dp.STATE_PLAYING)) {
+ // disconnected
+ intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
+ }
}
}
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
index 3ce34c3..9e9ba62 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothDeviceService.java
@@ -25,8 +25,8 @@
package android.server;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset; // just for dump()
import android.bluetooth.BluetoothError;
+import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothIntent;
import android.bluetooth.IBluetoothDevice;
import android.bluetooth.IBluetoothDeviceCallback;
@@ -35,22 +35,19 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Log;
import android.os.Binder;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteException;
import android.os.SystemService;
+import android.provider.Settings;
+import android.util.Log;
-import java.io.IOException;
import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -84,15 +81,16 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
*/
public synchronized void init() {
initializeNativeDataNative();
- mIsEnabled = (isEnabledNative() == 1);
- if (mIsEnabled) {
- mBondState.loadBondState();
+
+ if (isEnabledNative() == 1) {
+ Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
+ disableNative();
}
+
+ mIsEnabled = false;
mIsDiscovering = false;
mEventLoop = new BluetoothEventLoop(mContext, this);
registerForAirplaneMode();
-
- disableEsco(); // TODO: enable eSCO support once its fully supported
}
private native void initializeNativeDataNative();
@@ -116,12 +114,22 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
private native int isEnabledNative();
/**
- * Disable bluetooth. Returns true on success.
+ * Bring down bluetooth and disable BT in settings. Returns true on success.
*/
- public synchronized boolean disable() {
+ public boolean disable() {
+ return disable(true);
+ }
+
+ /**
+ * 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");
-
+
if (mEnableThread != null && mEnableThread.isAlive()) {
return false;
}
@@ -130,22 +138,63 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
}
mEventLoop.stop();
disableNative();
+
+ // mark in progress bondings as cancelled
+ for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
+ mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
+ BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
+ }
+
+ // Remove remoteServiceChannelCallbacks
+ HashMap<String, IBluetoothDeviceCallback> callbacksMap =
+ mEventLoop.getRemoteServiceChannelCallbacks();
+ IBluetoothDeviceCallback callback;
+
+ for (String address : callbacksMap.keySet()) {
+ callback = callbacksMap.get(address);
+ try {
+ callback.onGetRemoteServiceChannelResult(address, BluetoothError.ERROR_DISABLED);
+ } catch (RemoteException e) {}
+ callbacksMap.remove(address);
+ }
+
+ // update mode
+ Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothDevice.SCAN_MODE_NONE);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+
mIsEnabled = false;
- Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON, 0);
+ if (saveSetting) {
+ persistBluetoothOnSetting(false);
+ }
mIsDiscovering = false;
- Intent intent = new Intent(BluetoothIntent.DISABLED_ACTION);
+ intent = new Intent(BluetoothIntent.DISABLED_ACTION);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
return true;
}
/**
+ * 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);
+ }
+
+ /**
* Enable this Bluetooth device, asynchronously.
* This turns on/off the underlying hardware.
*
- * @return True on success (so far), guarenteeing the callback with be
+ * @param saveSetting If true, enable BT in settings
+ *
+ * @return True on success (so far), guaranteeing the callback with be
* notified when complete.
*/
- public synchronized boolean enable(IBluetoothDeviceCallback callback) {
+ public synchronized boolean enable(IBluetoothDeviceCallback callback,
+ boolean saveSetting) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
@@ -159,7 +208,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
if (mEnableThread != null && mEnableThread.isAlive()) {
return false;
}
- mEnableThread = new EnableThread(callback);
+ mEnableThread = new EnableThread(callback, saveSetting);
mEnableThread.start();
return true;
}
@@ -183,13 +232,36 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
private class EnableThread extends Thread {
private final IBluetoothDeviceCallback mEnableCallback;
- public EnableThread(IBluetoothDeviceCallback callback) {
+ private final boolean mSaveSetting;
+ public EnableThread(IBluetoothDeviceCallback callback, boolean saveSetting) {
mEnableCallback = callback;
+ mSaveSetting = saveSetting;
}
public void run() {
boolean res = (enableNative() == 0);
if (res) {
- mEventLoop.start();
+ int retryCount = 2;
+ boolean running = false;
+ while ((retryCount-- > 0) && !running) {
+ mEventLoop.start();
+ // 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) {
+ if (mEventLoop.isEventLoopRunning()) {
+ running = true;
+ break;
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {}
+ }
+ }
+ if (!running) {
+ log("bt EnableThread giving up");
+ res = false;
+ disableNative();
+ }
}
if (mEnableCallback != null) {
@@ -202,17 +274,35 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
if (res) {
mIsEnabled = true;
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.BLUETOOTH_ON, 1);
+ if (mSaveSetting) {
+ persistBluetoothOnSetting(true);
+ }
mIsDiscovering = false;
- Intent intent = new Intent(BluetoothIntent.ENABLED_ACTION);
mBondState.loadBondState();
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mHandler.sendMessageDelayed(mHandler.obtainMessage(REGISTER_SDP_RECORDS), 3000);
+
+ // 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;
}
- };
+ }
+
+ private void persistBluetoothOnSetting(boolean bluetoothOn) {
+ long origCallerIdentityToken = Binder.clearCallingIdentity();
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
+ bluetoothOn ? 1 : 0);
+ Binder.restoreCallingIdentity(origCallerIdentityToken);
+ }
private native int enableNative();
private native int disableNative();
@@ -229,6 +319,16 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
public class BondState {
private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
+ private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>();
+ // List of all the vendor_id prefix of Bluetooth addresses for which
+ // auto pairing is not attempted
+ private final ArrayList<String> mAutoPairingBlacklisted =
+ new ArrayList<String>(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
+ ));
public synchronized void loadBondState() {
if (!mIsEnabled) {
@@ -263,8 +363,8 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
intent.putExtra(BluetoothIntent.BOND_PREVIOUS_STATE, oldState);
if (state == BluetoothDevice.BOND_NOT_BONDED) {
if (reason <= 0) {
- Log.w(TAG, "setBondState() called to unbond device with invalid reason code " +
- "Setting reason = BOND_RESULT_REMOVED");
+ Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
+ "invalid. Overriding reason code with BOND_RESULT_REMOVED");
reason = BluetoothDevice.UNBOND_REASON_REMOVED;
}
intent.putExtra(BluetoothIntent.REASON, reason);
@@ -272,14 +372,17 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
} else {
mState.put(address, state);
}
- if (state == BluetoothDevice.BOND_BONDING) {
- mPinAttempt.put(address, Integer.valueOf(0));
- } else {
- mPinAttempt.remove(address);
- }
+
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
+ public boolean isAutoPairingBlacklisted(String address) {
+ for (String blacklistAddress : mAutoPairingBlacklisted) {
+ if (address.startsWith(blacklistAddress)) return true;
+ }
+ return false;
+ }
+
public synchronized int getBondState(String address) {
Integer state = mState.get(address);
if (state == null) {
@@ -288,16 +391,34 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
return state.intValue();
}
- public synchronized String[] listBonds() {
+ private synchronized String[] listInState(int state) {
ArrayList<String> result = new ArrayList<String>(mState.size());
for (Map.Entry<String, Integer> e : mState.entrySet()) {
- if (e.getValue().intValue() == BluetoothDevice.BOND_BONDED) {
+ if (e.getValue().intValue() == state) {
result.add(e.getKey());
}
}
return result.toArray(new String[result.size()]);
}
+ public synchronized void addAutoPairingFailure(String address) {
+ if (!mAutoPairingFailures.contains(address)) {
+ mAutoPairingFailures.add(address);
+ }
+ }
+
+ public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
+ return getAttempt(address) != 0;
+ }
+
+ public synchronized void clearPinAttempts(String address) {
+ mPinAttempt.remove(address);
+ }
+
+ public synchronized boolean hasAutoPairingFailed(String address) {
+ return mAutoPairingFailures.contains(address);
+ }
+
public synchronized int getAttempt(String address) {
Integer attempt = mPinAttempt.get(address);
if (attempt == null) {
@@ -308,10 +429,13 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
public synchronized void attempt(String address) {
Integer attempt = mPinAttempt.get(address);
+ int newAttempt;
if (attempt == null) {
- return;
+ newAttempt = 1;
+ } else {
+ newAttempt = attempt.intValue() + 1;
}
- mPinAttempt.put(address, new Integer(attempt.intValue() + 1));
+ mPinAttempt.put(address, new Integer(newAttempt));
}
}
@@ -353,18 +477,6 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
}
private native boolean setNameNative(String name);
- public synchronized String getMajorClass() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getMajorClassNative();
- }
- private native String getMajorClassNative();
-
- public synchronized String getMinorClass() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return getMinorClassNative();
- }
- private native String getMinorClassNative();
-
/**
* Returns the user-friendly name of a remote device. This value is
* retrned from our local cache, which is updated during device discovery.
@@ -386,24 +498,6 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
/* pacakge */ native String getAdapterPathNative();
- /**
- * Initiate a remote-device-discovery procedure. This procedure may be
- * canceled by calling {@link #stopDiscovery}. Remote-device discoveries
- * are returned as intents
- * <p>
- * Typically, when a remote device is found, your
- * android.bluetooth.DiscoveryEventNotifier#notifyRemoteDeviceFound
- * method will be invoked, and subsequently, your
- * android.bluetooth.RemoteDeviceEventNotifier#notifyRemoteNameUpdated
- * will tell you the user-friendly name of the remote device. However,
- * it is possible that the name update may fail for various reasons, so you
- * should display the device's Bluetooth address as soon as you get a
- * notifyRemoteDeviceFound event, and update the name when you get the
- * remote name.
- *
- * @return true if discovery has started,
- * false otherwise.
- */
public synchronized boolean startDiscovery(boolean resolveNames) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
@@ -411,12 +505,6 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
}
private native boolean startDiscoveryNative(boolean resolveNames);
- /**
- * Cancel a remote-device discovery.
- *
- * Note: you may safely call this method even when discovery has not been
- * started.
- */
public synchronized boolean cancelDiscovery() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
@@ -492,171 +580,23 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
}
private native boolean isConnectedNative(String address);
- /**
- * Detetermines whether this device is connectable (that is, whether remote
- * devices can connect to it.)
- * <p>
- * Note: A Bluetooth adapter has separate connectable and discoverable
- * states, and you could have any combination of those. Although
- * any combination is possible (such as discoverable but not
- * connectable), we restrict the possible combinations to one of
- * three possibilities: discoverable and connectable, connectable
- * but not discoverable, and neither connectable nor discoverable.
- *
- * @return true if this adapter is connectable
- * false otherwise
- *
- * @see #isDiscoverable
- * @see #getMode
- * @see #setMode
- */
- public synchronized boolean isConnectable() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return isConnectableNative();
- }
- private native boolean isConnectableNative();
-
- /**
- * Detetermines whether this device is discoverable.
- *
- * Note: a Bluetooth adapter has separate connectable and discoverable
- * states, and you could have any combination of those. Although
- * any combination is possible (such as discoverable but not
- * connectable), we restrict the possible combinations to one of
- * three possibilities: discoverable and connectable, connectable
- * but not discoverable, and neither connectable nor discoverable.
- *
- * @return true if this adapter is discoverable
- * false otherwise
- *
- * @see #isConnectable
- * @see #getMode
- * @see #setMode
- */
- public synchronized boolean isDiscoverable() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return isDiscoverableNative();
- }
- private native boolean isDiscoverableNative();
-
- /**
- * Determines which one of three modes this adapter is in: discoverable and
- * connectable, not discoverable but connectable, or neither.
- *
- * @return Mode enumeration containing the current mode.
- *
- * @see #setMode
- */
- public synchronized int getMode() {
+ public synchronized int getScanMode() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- String mode = getModeNative();
- if (mode == null) {
- return BluetoothDevice.MODE_UNKNOWN;
- }
- if (mode.equalsIgnoreCase("off")) {
- return BluetoothDevice.MODE_OFF;
- }
- else if (mode.equalsIgnoreCase("connectable")) {
- return BluetoothDevice.MODE_CONNECTABLE;
- }
- else if (mode.equalsIgnoreCase("discoverable")) {
- return BluetoothDevice.MODE_DISCOVERABLE;
- }
- else {
- return BluetoothDevice.MODE_UNKNOWN;
- }
+ return bluezStringToScanMode(getModeNative());
}
private native String getModeNative();
- /**
- * Set the discoverability and connectability mode of this adapter. The
- * possibilities are discoverable and connectable (MODE_DISCOVERABLE),
- * connectable but not discoverable (MODE_CONNECTABLE), and neither
- * (MODE_OFF).
- *
- * Note: MODE_OFF does not mean that the adapter is physically off. It
- * may be neither discoverable nor connectable, but it could still
- * initiate outgoing connections, or could participate in a
- * connection initiated by a remote device before its mode was set
- * to MODE_OFF.
- *
- * @param mode the new mode
- * @see #getMode
- */
- public synchronized boolean setMode(int mode) {
+ public synchronized boolean setScanMode(int mode) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- switch (mode) {
- case BluetoothDevice.MODE_OFF:
- return setModeNative("off");
- case BluetoothDevice.MODE_CONNECTABLE:
- return setModeNative("connectable");
- case BluetoothDevice.MODE_DISCOVERABLE:
- return setModeNative("discoverable");
+ String bluezMode = scanModeToBluezString(mode);
+ if (bluezMode != null) {
+ return setModeNative(bluezMode);
}
return false;
}
private native boolean setModeNative(String mode);
- /**
- * Retrieves the alias of a remote device. The alias is a local feature,
- * and allows us to associate a name with a remote device that is different
- * from that remote device's user-friendly name. The remote device knows
- * nothing about this. The alias can be changed with
- * {@link #setRemoteAlias}, and it may be removed with
- * {@link #clearRemoteAlias}
- *
- * @param address Bluetooth address of remote device.
- *
- * @return The alias of the remote device.
- */
- public synchronized String getRemoteAlias(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteAliasNative(address);
- }
- private native String getRemoteAliasNative(String address);
-
- /**
- * Changes the alias of a remote device. The alias is a local feature,
- * from that remote device's user-friendly name. The remote device knows
- * nothing about this. The alias can be retrieved with
- * {@link #getRemoteAlias}, and it may be removed with
- * {@link #clearRemoteAlias}.
- *
- * @param address Bluetooth address of remote device
- * @param alias Alias for the remote device
- */
- public synchronized boolean setRemoteAlias(String address, String alias) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (alias == null || !BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- return setRemoteAliasNative(address, alias);
- }
- private native boolean setRemoteAliasNative(String address, String alias);
-
- /**
- * Removes the alias of a remote device. The alias is a local feature,
- * from that remote device's user-friendly name. The remote device knows
- * nothing about this. The alias can be retrieved with
- * {@link #getRemoteAlias}.
- *
- * @param address Bluetooth address of remote device
- */
- public synchronized boolean clearRemoteAlias(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH_ADMIN permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return false;
- }
- return clearRemoteAliasNative(address);
- }
- private native boolean clearRemoteAliasNative(String address);
-
public synchronized boolean disconnectRemoteDeviceAcl(String address) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
@@ -674,7 +614,19 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
return false;
}
address = address.toUpperCase();
- if (mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) {
+
+ String[] bonding = mBondState.listInState(BluetoothDevice.BOND_BONDING);
+ if (bonding.length > 0 && !bonding[0].equals(address)) {
+ log("Ignoring createBond(): another device is bonding");
+ // a different device is currently bonding, fail
+ return false;
+ }
+
+ // Check for bond state only if we are not performing auto
+ // pairing exponential back-off attempts.
+ if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
+ mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) {
+ log("Ignoring createBond(): this device is already bonding or bonded");
return false;
}
@@ -699,7 +651,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
}
mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
- BluetoothDevice.UNBOND_REASON_CANCELLED);
+ BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
cancelBondingProcessNative(address);
return true;
}
@@ -717,7 +669,7 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
public synchronized String[] listBonds() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBondState.listBonds();
+ return mBondState.listInState(BluetoothDevice.BOND_BONDED);
}
public synchronized int getBondState(String address) {
@@ -919,69 +871,6 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
private native String lastUsedNative(String address);
/**
- * Gets the major device class of the specified device.
- * Example: "computer"
- *
- * Note: This is simply a string desciption of the major class of the
- * device-class information, which is returned as a 32-bit value
- * during device discovery.
- *
- * @param address The Bluetooth address of the remote device.
- *
- * @return remote-device major class
- *
- * @see #getRemoteClass
- */
- public synchronized String getRemoteMajorClass(String address) {
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return null;
- }
- return getRemoteMajorClassNative(address);
- }
- private native String getRemoteMajorClassNative(String address);
-
- /**
- * Gets the minor device class of the specified device.
- * Example: "laptop"
- *
- * Note: This is simply a string desciption of the minor class of the
- * device-class information, which is returned as a 32-bit value
- * during device discovery.
- *
- * @param address The Bluetooth address of the remote device.
- *
- * @return remote-device minor class
- *
- * @see #getRemoteClass
- */
- public synchronized String getRemoteMinorClass(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteMinorClassNative(address);
- }
- private native String getRemoteMinorClassNative(String address);
-
- /**
- * Gets the service classes of the specified device.
- * Example: ["networking", "object transfer"]
- *
- * @return a String array with the descriptions of the service classes.
- *
- * @see #getRemoteClass
- */
- public synchronized String[] getRemoteServiceClasses(String address) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!BluetoothDevice.checkBluetoothAddress(address)) {
- return null;
- }
- return getRemoteServiceClassesNative(address);
- }
- private native String[] getRemoteServiceClassesNative(String address);
-
- /**
* Gets the remote major, minor, and service classes encoded as a 32-bit
* integer.
*
@@ -1162,9 +1051,9 @@ 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);
+ enable(null, false);
} else {
- disable();
+ disable(false);
}
}
}
@@ -1188,16 +1077,6 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
Settings.System.AIRPLANE_MODE_ON, 0) == 1;
}
- private static final String DISABLE_ESCO_PATH = "/sys/module/sco/parameters/disable_esco";
- private static void disableEsco() {
- try {
- FileWriter file = new FileWriter(DISABLE_ESCO_PATH);
- file.write("Y");
- file.close();
- } catch (FileNotFoundException e) {
- } catch (IOException e) {}
- }
-
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mIsEnabled) {
@@ -1248,6 +1127,34 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub {
pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive);
}
+ /* package */ static int bluezStringToScanMode(String mode) {
+ if (mode == null) {
+ return BluetoothError.ERROR;
+ }
+ mode = mode.toLowerCase();
+ if (mode.equals("off")) {
+ return BluetoothDevice.SCAN_MODE_NONE;
+ } else if (mode.equals("connectable")) {
+ return BluetoothDevice.SCAN_MODE_CONNECTABLE;
+ } else if (mode.equals("discoverable")) {
+ return BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
+ } else {
+ return BluetoothError.ERROR;
+ }
+ }
+
+ /* package */ static String scanModeToBluezString(int mode) {
+ switch (mode) {
+ case BluetoothDevice.SCAN_MODE_NONE:
+ return "off";
+ case BluetoothDevice.SCAN_MODE_CONNECTABLE:
+ return "connectable";
+ case BluetoothDevice.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ return "discoverable";
+ }
+ return null;
+ }
+
private static void log(String msg) {
Log.d(TAG, msg);
}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 4f63f98..8e77eed 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -16,6 +16,7 @@
package android.server;
+import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothError;
@@ -23,6 +24,8 @@ import android.bluetooth.BluetoothIntent;
import android.bluetooth.IBluetoothDeviceCallback;
import android.content.Context;
import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
@@ -41,15 +44,45 @@ class BluetoothEventLoop {
private int mNativeData;
private Thread mThread;
+ private boolean mStarted;
private boolean mInterrupted;
private HashMap<String, Integer> mPasskeyAgentRequestData;
private HashMap<String, IBluetoothDeviceCallback> mGetRemoteServiceChannelCallbacks;
private BluetoothDeviceService mBluetoothService;
private Context mContext;
+ private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
+ private static final int EVENT_RESTART_BLUETOOTH = 2;
+
+ // The time (in millisecs) to delay the pairing attempt after the first
+ // auto pairing attempt fails. We use an exponential delay with
+ // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
+ // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
+ private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
+ private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
+
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
+ String address = (String)msg.obj;
+ if (address != null) {
+ mBluetoothService.createBond(address);
+ return;
+ }
+ break;
+ case EVENT_RESTART_BLUETOOTH:
+ mBluetoothService.disable();
+ mBluetoothService.enable(null);
+ break;
+ }
+ }
+ };
+
static { classInitNative(); }
private static native void classInitNative();
@@ -95,14 +128,18 @@ class BluetoothEventLoop {
public void run() {
try {
if (setUpEventLoopNative()) {
+ mStarted = true;
while (!mInterrupted) {
waitForAndDispatchEvent(0);
sleep(500);
}
- tearDownEventLoopNative();
}
+ // tear down even in the error case to clean
+ // up anything we started to setup
+ tearDownEventLoopNative();
} catch (InterruptedException e) { }
if (DBG) log("Event Loop thread finished");
+ mThread = null;
}
};
if (DBG) log("Starting Event Loop thread");
@@ -114,9 +151,7 @@ class BluetoothEventLoop {
public synchronized void stop() {
if (mThread != null) {
-
mInterrupted = true;
-
try {
mThread.join();
mThread = null;
@@ -127,135 +162,150 @@ class BluetoothEventLoop {
}
public synchronized boolean isEventLoopRunning() {
- return mThread != null;
+ return mThread != null && mStarted;
}
- public void onModeChanged(String mode) {
- Intent intent = new Intent(BluetoothIntent.MODE_CHANGED_ACTION);
- int intMode = BluetoothDevice.MODE_UNKNOWN;
- if (mode.equalsIgnoreCase("off")) {
- intMode = BluetoothDevice.MODE_OFF;
+ /*package*/ void onModeChanged(String bluezMode) {
+ int mode = BluetoothDeviceService.bluezStringToScanMode(bluezMode);
+ if (mode >= 0) {
+ Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
+ intent.putExtra(BluetoothIntent.SCAN_MODE, mode);
+ mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- else if (mode.equalsIgnoreCase("connectable")) {
- intMode = BluetoothDevice.MODE_CONNECTABLE;
- }
- else if (mode.equalsIgnoreCase("discoverable")) {
- intMode = BluetoothDevice.MODE_DISCOVERABLE;
- }
- intent.putExtra(BluetoothIntent.MODE, intMode);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onDiscoveryStarted() {
+ private void onDiscoveryStarted() {
mBluetoothService.setIsDiscovering(true);
Intent intent = new Intent(BluetoothIntent.DISCOVERY_STARTED_ACTION);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onDiscoveryCompleted() {
+ private void onDiscoveryCompleted() {
mBluetoothService.setIsDiscovering(false);
Intent intent = new Intent(BluetoothIntent.DISCOVERY_COMPLETED_ACTION);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onPairingRequest() {
- Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
- mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
- }
-
- public void onPairingCancel() {
- Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
- mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
- }
-
- public void onRemoteDeviceFound(String address, int deviceClass, short rssi) {
+ private void onRemoteDeviceFound(String address, int deviceClass, short rssi) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
intent.putExtra(BluetoothIntent.CLASS, deviceClass);
intent.putExtra(BluetoothIntent.RSSI, rssi);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onRemoteDeviceDisappeared(String address) {
+ private void onRemoteDeviceDisappeared(String address) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onRemoteClassUpdated(String address, int deviceClass) {
+ private void onRemoteClassUpdated(String address, int deviceClass) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
intent.putExtra(BluetoothIntent.CLASS, deviceClass);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onRemoteDeviceConnected(String address) {
+ private void onRemoteDeviceConnected(String address) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onRemoteDeviceDisconnectRequested(String address) {
+ private void onRemoteDeviceDisconnectRequested(String address) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECT_REQUESTED_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onRemoteDeviceDisconnected(String address) {
+ private void onRemoteDeviceDisconnected(String address) {
Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onRemoteNameUpdated(String address, String name) {
+ private void onRemoteNameUpdated(String address, String name) {
Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
intent.putExtra(BluetoothIntent.NAME, name);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onRemoteNameFailed(String address) {
+ private void onRemoteNameFailed(String address) {
Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_FAILED_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onRemoteNameChanged(String address, String name) {
+ private void onRemoteNameChanged(String address, String name) {
Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
intent.putExtra(BluetoothIntent.NAME, name);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onRemoteAliasChanged(String address, String alias) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_ALIAS_CHANGED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- intent.putExtra(BluetoothIntent.ALIAS, alias);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
- public void onRemoteAliasCleared(String address) {
- Intent intent = new Intent(BluetoothIntent.REMOTE_ALIAS_CLEARED_ACTION);
- intent.putExtra(BluetoothIntent.ADDRESS, address);
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- }
private void onCreateBondingResult(String address, int result) {
address = address.toUpperCase();
if (result == BluetoothError.SUCCESS) {
mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
+ if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
+ mBluetoothService.getBondState().clearPinAttempts(address);
+ }
+ } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
+ mBluetoothService.getBondState().getAttempt(address) == 1) {
+ mBluetoothService.getBondState().addAutoPairingFailure(address);
+ pairingAttempt(address, result);
+ } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
+ mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
+ pairingAttempt(address, result);
} else {
mBluetoothService.getBondState().setBondState(address,
BluetoothDevice.BOND_NOT_BONDED, result);
+ if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
+ mBluetoothService.getBondState().clearPinAttempts(address);
+ }
+ }
+ }
+
+ private void pairingAttempt(String address, int result) {
+ // This happens when our initial guess of "0000" as the pass key
+ // fails. Try to create the bond again and display the pin dialog
+ // to the user. Use back-off while posting the delayed
+ // message. The initial value is
+ // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
+ // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
+ // reached, display an error to the user.
+ int attempt = mBluetoothService.getBondState().getAttempt(address);
+ if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
+ MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
+ mBluetoothService.getBondState().clearPinAttempts(address);
+ mBluetoothService.getBondState().setBondState(address,
+ BluetoothDevice.BOND_NOT_BONDED, result);
+ return;
+ }
+
+ Message message = mHandler.obtainMessage(EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+ message.obj = address;
+ boolean postResult = mHandler.sendMessageDelayed(message,
+ attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
+ if (!postResult) {
+ mBluetoothService.getBondState().clearPinAttempts(address);
+ mBluetoothService.getBondState().setBondState(address,
+ BluetoothDevice.BOND_NOT_BONDED, result);
+ return;
}
+ mBluetoothService.getBondState().attempt(address);
}
- public void onBondingCreated(String address) {
+ private void onBondingCreated(String address) {
mBluetoothService.getBondState().setBondState(address.toUpperCase(),
BluetoothDevice.BOND_BONDED);
}
- public void onBondingRemoved(String address) {
+ private void onBondingRemoved(String address) {
mBluetoothService.getBondState().setBondState(address.toUpperCase(),
BluetoothDevice.BOND_NOT_BONDED, BluetoothDevice.UNBOND_REASON_REMOVED);
}
- public void onNameChanged(String name) {
+ private void onNameChanged(String name) {
Intent intent = new Intent(BluetoothIntent.NAME_CHANGED_ACTION);
intent.putExtra(BluetoothIntent.NAME, name);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- public void onPasskeyAgentRequest(String address, int nativeData) {
+ private void onPasskeyAgentRequest(String address, int nativeData) {
address = address.toUpperCase();
mPasskeyAgentRequestData.put(address, new Integer(nativeData));
@@ -272,35 +322,65 @@ class BluetoothEventLoop {
case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
- if (mBluetoothService.getBondState().getAttempt(address) < 1) {
+ if (!mBluetoothService.getBondState().hasAutoPairingFailed(address) &&
+ !mBluetoothService.getBondState().isAutoPairingBlacklisted(address)) {
mBluetoothService.getBondState().attempt(address);
mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
return;
}
- }
+ }
}
Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
}
- public void onPasskeyAgentCancel(String address) {
+ private void onPasskeyAgentCancel(String address) {
address = address.toUpperCase();
mPasskeyAgentRequestData.remove(address);
Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
intent.putExtra(BluetoothIntent.ADDRESS, address);
mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
- BluetoothDevice.UNBOND_REASON_CANCELLED);
+ BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
+ }
+
+ private boolean onAuthAgentAuthorize(String address, String service, String uuid) {
+ boolean authorized = false;
+ if (service.endsWith("service_audio")) {
+ BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
+ authorized = a2dp.getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF;
+ if (authorized) {
+ Log.i(TAG, "Allowing incoming A2DP connection from " + address);
+ } else {
+ Log.i(TAG, "Rejecting incoming A2DP connection from " + address);
+ }
+ } else {
+ Log.i(TAG, "Rejecting incoming " + service + " connection from " + address);
+ }
+ return authorized;
+ }
+
+ private void onAuthAgentCancel(String address, String service, String uuid) {
+ // We immediately response to DBUS Authorize() so this should not
+ // usually happen
+ log("onAuthAgentCancel(" + address + ", " + service + ", " + uuid + ")");
}
private void onGetRemoteServiceChannelResult(String address, int channel) {
IBluetoothDeviceCallback callback = mGetRemoteServiceChannelCallbacks.get(address);
if (callback != null) {
+ mGetRemoteServiceChannelCallbacks.remove(address);
try {
callback.onGetRemoteServiceChannelResult(address, channel);
} catch (RemoteException e) {}
- mGetRemoteServiceChannelCallbacks.remove(address);
+ }
+ }
+
+ private void onRestartRequired() {
+ if (mBluetoothService.isEnabled()) {
+ Log.e(TAG, "*** A serious error occured (did hcid crash?) - restarting Bluetooth ***");
+ mHandler.sendEmptyMessage(EVENT_RESTART_BLUETOOTH);
}
}
diff --git a/core/java/android/server/checkin/CheckinProvider.java b/core/java/android/server/checkin/CheckinProvider.java
deleted file mode 100644
index 86ece4a..0000000
--- a/core/java/android/server/checkin/CheckinProvider.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2006 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 android.server.checkin;
-
-import android.content.ContentProvider;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteQueryBuilder;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.BaseColumns;
-import android.provider.Checkin;
-import android.util.Log;
-
-import java.io.File;
-
-/**
- * Content provider for the database used to store events and statistics
- * while they wait to be uploaded by the checkin service.
- */
-public class CheckinProvider extends ContentProvider {
- /** Class identifier for logging. */
- private static final String TAG = "CheckinProvider";
-
- /** Filename of database (in /data directory). */
- private static final String DATABASE_FILENAME = "checkin.db";
-
- /** Version of database schema. */
- private static final int DATABASE_VERSION = 1;
-
- /** Maximum number of events recorded. */
- private static final int EVENT_LIMIT = 1000;
-
- /** Maximum size of individual event data. */
- private static final int EVENT_SIZE = 8192;
-
- /** Maximum number of crashes recorded. */
- private static final int CRASH_LIMIT = 25;
-
- /** Maximum size of individual crashes recorded. */
- private static final int CRASH_SIZE = 16384;
-
- /** Permission required for access to the 'properties' database. */
- private static final String PROPERTIES_PERMISSION =
- "android.permission.ACCESS_CHECKIN_PROPERTIES";
-
- /** Lock for stats read-modify-write update cycle (see {@link #insert}). */
- private final Object mStatsLock = new Object();
-
- /** The underlying SQLite database. */
- private SQLiteOpenHelper mOpenHelper;
-
- private static class OpenHelper extends SQLiteOpenHelper {
- public OpenHelper(Context context) {
- super(context, DATABASE_FILENAME, null, DATABASE_VERSION);
-
- // The database used to live in /data/checkin.db.
- File oldLocation = Environment.getDataDirectory();
- File old = new File(oldLocation, DATABASE_FILENAME);
- File file = context.getDatabasePath(DATABASE_FILENAME);
-
- // Try to move the file to the new location.
- // TODO: Remove this code before shipping.
- if (old.exists() && !file.exists() && !old.renameTo(file)) {
- Log.e(TAG, "Can't rename " + old + " to " + file);
- }
- if (old.exists() && !old.delete()) {
- // Clean up the old data file in any case.
- Log.e(TAG, "Can't remove " + old);
- }
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + Checkin.Events.TABLE_NAME + " (" +
- BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- Checkin.Events.TAG + " TEXT NOT NULL," +
- Checkin.Events.VALUE + " TEXT DEFAULT \"\"," +
- Checkin.Events.DATE + " INTEGER NOT NULL)");
-
- db.execSQL("CREATE INDEX events_index ON " +
- Checkin.Events.TABLE_NAME + " (" +
- Checkin.Events.TAG + ")");
-
- db.execSQL("CREATE TABLE " + Checkin.Stats.TABLE_NAME + " (" +
- BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- Checkin.Stats.TAG + " TEXT UNIQUE," +
- Checkin.Stats.COUNT + " INTEGER DEFAULT 0," +
- Checkin.Stats.SUM + " REAL DEFAULT 0.0)");
-
- db.execSQL("CREATE TABLE " + Checkin.Crashes.TABLE_NAME + " (" +
- BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- Checkin.Crashes.DATA + " TEXT NOT NULL," +
- Checkin.Crashes.LOGS + " TEXT)");
-
- db.execSQL("CREATE TABLE " + Checkin.Properties.TABLE_NAME + " (" +
- BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- Checkin.Properties.TAG + " TEXT UNIQUE ON CONFLICT REPLACE,"
- + Checkin.Properties.VALUE + " TEXT DEFAULT \"\")");
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int old, int version) {
- db.execSQL("DROP TABLE IF EXISTS " + Checkin.Events.TABLE_NAME);
- db.execSQL("DROP TABLE IF EXISTS " + Checkin.Stats.TABLE_NAME);
- db.execSQL("DROP TABLE IF EXISTS " + Checkin.Crashes.TABLE_NAME);
- db.execSQL("DROP TABLE IF EXISTS " + Checkin.Properties.TABLE_NAME);
- onCreate(db);
- }
- }
-
- @Override public boolean onCreate() {
- mOpenHelper = new OpenHelper(getContext());
- return true;
- }
-
- @Override
- public Cursor query(Uri uri, String[] select,
- String where, String[] args, String sort) {
- checkPermissions(uri);
- SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
- qb.setTables(uri.getPathSegments().get(0));
- if (uri.getPathSegments().size() == 2) {
- qb.appendWhere("_id=" + ContentUris.parseId(uri));
- } else if (uri.getPathSegments().size() != 1) {
- throw new IllegalArgumentException("Invalid query URI: " + uri);
- }
-
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- Cursor cursor = qb.query(db, select, where, args, null, null, sort);
- cursor.setNotificationUri(getContext().getContentResolver(), uri);
- return cursor;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- checkPermissions(uri);
- if (uri.getPathSegments().size() != 1) {
- throw new IllegalArgumentException("Invalid insert URI: " + uri);
- }
-
- long id;
- String table = uri.getPathSegments().get(0);
- if (Checkin.Events.TABLE_NAME.equals(table)) {
- id = insertEvent(values);
- } else if (Checkin.Stats.TABLE_NAME.equals(table)) {
- id = insertStats(values);
- } else if (Checkin.Crashes.TABLE_NAME.equals(table)) {
- id = insertCrash(values);
- } else {
- id = mOpenHelper.getWritableDatabase().insert(table, null, values);
- }
-
- if (id < 0) {
- return null;
- } else {
- uri = ContentUris.withAppendedId(uri, id);
- getContext().getContentResolver().notifyChange(uri, null);
- return uri;
- }
- }
-
- /**
- * Insert an entry into the events table.
- * Trims old events from the table to keep the size bounded.
- * @param values to insert
- * @return the row ID of the new entry
- */
- private long insertEvent(ContentValues values) {
- String value = values.getAsString(Checkin.Events.VALUE);
- if (value != null && value.length() > EVENT_SIZE) {
- // Event values are readable text, so they can be truncated.
- value = value.substring(0, EVENT_SIZE - 3) + "...";
- values.put(Checkin.Events.VALUE, value);
- }
-
- if (!values.containsKey(Checkin.Events.DATE)) {
- values.put(Checkin.Events.DATE, System.currentTimeMillis());
- }
-
- // TODO: Make this more efficient; don't do it on every insert.
- // Also, consider keeping the most recent instance of every tag,
- // and possibly update a counter when events are deleted.
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.execSQL("DELETE FROM " +
- Checkin.Events.TABLE_NAME + " WHERE " +
- Checkin.Events._ID + " IN (SELECT " +
- Checkin.Events._ID + " FROM " +
- Checkin.Events.TABLE_NAME + " ORDER BY " +
- Checkin.Events.DATE + " DESC LIMIT -1 OFFSET " +
- (EVENT_LIMIT - 1) + ")");
- return db.insert(Checkin.Events.TABLE_NAME, null, values);
- }
-
- /**
- * Add an entry into the stats table.
- * For statistics, instead of just inserting a row into the database,
- * we add the count and sum values to the existing values (if any)
- * for the specified tag. This must be done with a lock held,
- * to avoid a race condition during the read-modify-write update.
- * @param values to insert
- * @return the row ID of the modified entry
- */
- private long insertStats(ContentValues values) {
- synchronized (mStatsLock) {
- String tag = values.getAsString(Checkin.Stats.TAG);
- if (tag == null) {
- throw new IllegalArgumentException("Tag required:" + values);
- }
-
- // Look for existing values with this tag.
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- Cursor cursor = db.query(false,
- Checkin.Stats.TABLE_NAME,
- new String[] {
- Checkin.Stats._ID,
- Checkin.Stats.COUNT,
- Checkin.Stats.SUM
- },
- Checkin.Stats.TAG + "=?",
- new String[] { tag },
- null, null, null, null /* limit */);
-
- try {
- if (cursor == null || !cursor.moveToNext()) {
- // This is a new statistic, insert it directly.
- return db.insert(Checkin.Stats.TABLE_NAME, null, values);
- } else {
- // Depend on SELECT column order to avoid getColumnIndex()
- long id = cursor.getLong(0);
- int count = cursor.getInt(1);
- double sum = cursor.getDouble(2);
-
- Integer countAdd = values.getAsInteger(Checkin.Stats.COUNT);
- if (countAdd != null) count += countAdd.intValue();
-
- Double sumAdd = values.getAsDouble(Checkin.Stats.SUM);
- if (sumAdd != null) sum += sumAdd.doubleValue();
-
- if (count <= 0 && sum == 0.0) {
- // Updated to nothing: delete the row!
- cursor.deleteRow();
- getContext().getContentResolver().notifyChange(
- ContentUris.withAppendedId(Checkin.Stats.CONTENT_URI, id), null);
- return -1;
- } else {
- if (countAdd != null) cursor.updateInt(1, count);
- if (sumAdd != null) cursor.updateDouble(2, sum);
- cursor.commitUpdates();
- return id;
- }
- }
- } finally {
- // Always clean up the cursor.
- if (cursor != null) cursor.close();
- }
- }
- }
-
- /**
- * Add an entry into the crashes table.
- * @param values to insert
- * @return the row ID of the modified entry
- */
- private long insertCrash(ContentValues values) {
- try {
- int crashSize = values.getAsString(Checkin.Crashes.DATA).length();
- if (crashSize > CRASH_SIZE) {
- // The crash is too big. Don't report it, but do log a stat.
- Checkin.updateStats(getContext().getContentResolver(),
- Checkin.Stats.Tag.CRASHES_TRUNCATED, 1, 0.0);
- throw new IllegalArgumentException("Too big: " + crashSize);
- }
-
- // Count the number of crashes reported, even if they roll over.
- Checkin.updateStats(getContext().getContentResolver(),
- Checkin.Stats.Tag.CRASHES_REPORTED, 1, 0.0);
-
- // Trim the crashes database, if needed.
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.execSQL("DELETE FROM " +
- Checkin.Crashes.TABLE_NAME + " WHERE " +
- Checkin.Crashes._ID + " IN (SELECT " +
- Checkin.Crashes._ID + " FROM " +
- Checkin.Crashes.TABLE_NAME + " ORDER BY " +
- Checkin.Crashes._ID + " DESC LIMIT -1 OFFSET " +
- (CRASH_LIMIT - 1) + ")");
-
- return db.insert(Checkin.Crashes.TABLE_NAME, null, values);
- } catch (Throwable t) {
- // To avoid an infinite crash-reporting loop, swallow the error.
- Log.e("CheckinProvider", "Error inserting crash: " + t);
- return -1;
- }
- }
-
- // TODO: optimize bulkInsert, especially for stats?
-
- @Override
- public int update(Uri uri, ContentValues values,
- String where, String[] args) {
- checkPermissions(uri);
- if (uri.getPathSegments().size() == 2) {
- if (where != null && where.length() > 0) {
- throw new UnsupportedOperationException(
- "WHERE clause not supported for update: " + uri);
- }
- where = "_id=" + ContentUris.parseId(uri);
- args = null;
- } else if (uri.getPathSegments().size() != 1) {
- throw new IllegalArgumentException("Invalid update URI: " + uri);
- }
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- int count = db.update(uri.getPathSegments().get(0), values, where, args);
- getContext().getContentResolver().notifyChange(uri, null);
- return count;
- }
-
- @Override
- public int delete(Uri uri, String where, String[] args) {
- checkPermissions(uri);
- if (uri.getPathSegments().size() == 2) {
- if (where != null && where.length() > 0) {
- throw new UnsupportedOperationException(
- "WHERE clause not supported for delete: " + uri);
- }
- where = "_id=" + ContentUris.parseId(uri);
- args = null;
- } else if (uri.getPathSegments().size() != 1) {
- throw new IllegalArgumentException("Invalid delete URI: " + uri);
- }
-
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- int count = db.delete(uri.getPathSegments().get(0), where, args);
- getContext().getContentResolver().notifyChange(uri, null);
- return count;
- }
-
- @Override
- public String getType(Uri uri) {
- if (uri.getPathSegments().size() == 1) {
- return "vnd.android.cursor.dir/" + uri.getPathSegments().get(0);
- } else if (uri.getPathSegments().size() == 2) {
- return "vnd.android.cursor.item/" + uri.getPathSegments().get(0);
- } else {
- throw new IllegalArgumentException("Invalid URI: " + uri);
- }
- }
-
- /**
- * Make sure the caller has permission to the database.
- * @param uri the caller is requesting access to
- * @throws SecurityException if the caller is forbidden.
- */
- private void checkPermissions(Uri uri) {
- if (uri.getPathSegments().size() < 1) {
- throw new IllegalArgumentException("Invalid query URI: " + uri);
- }
-
- String table = uri.getPathSegments().get(0);
- if (table.equals(Checkin.Properties.TABLE_NAME) &&
- getContext().checkCallingOrSelfPermission(PROPERTIES_PERMISSION) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Cannot access checkin properties");
- }
- }
-}
diff --git a/core/java/android/server/checkin/FallbackCheckinService.java b/core/java/android/server/checkin/FallbackCheckinService.java
deleted file mode 100644
index 65921af..0000000
--- a/core/java/android/server/checkin/FallbackCheckinService.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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 android.server.checkin;
-
-import android.os.ICheckinService;
-import android.os.RemoteException;
-import android.os.IParentalControlCallback;
-import com.google.android.net.ParentalControlState;
-
-/**
- * @hide
- */
-public final class FallbackCheckinService extends ICheckinService.Stub {
- public FallbackCheckinService() {
- }
-
- public void reportCrashSync(byte[] crashData) throws RemoteException {
- }
-
- public void reportCrashAsync(byte[] crashData) throws RemoteException {
- }
-
- public void masterClear() throws RemoteException {
- }
-
- public void getParentalControlState(IParentalControlCallback p) throws RemoteException {
- ParentalControlState state = new ParentalControlState();
- state.isEnabled = false;
- p.onResult(state);
- }
-
- public void getParentalControlState(IParentalControlCallback p, String requestingApp)
- throws android.os.RemoteException {
- }
-}
diff --git a/core/java/android/server/checkin/package.html b/core/java/android/server/checkin/package.html
deleted file mode 100644
index 1c9bf9d..0000000
--- a/core/java/android/server/checkin/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<html>
-<body>
- {@hide}
-</body>
-</html>
diff --git a/core/java/android/server/search/SearchableInfo.java b/core/java/android/server/search/SearchableInfo.java
index c8f395e..0c04839 100644
--- a/core/java/android/server/search/SearchableInfo.java
+++ b/core/java/android/server/search/SearchableInfo.java
@@ -35,6 +35,7 @@ import android.text.InputType;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
+import android.view.inputmethod.EditorInfo;
import java.io.IOException;
import java.util.ArrayList;
@@ -77,6 +78,7 @@ public final class SearchableInfo implements Parcelable {
private int mIconId = 0;
private int mSearchButtonText = 0;
private int mSearchInputType = 0;
+ private int mSearchImeOptions = 0;
private String mSuggestAuthority = null;
private String mSuggestPath = null;
private String mSuggestSelection = null;
@@ -86,6 +88,16 @@ public final class SearchableInfo implements Parcelable {
private String mSuggestProviderPackage = null;
private Context mCacheActivityContext = null; // use during setup only - don't hold memory!
+ // Flag values for Searchable_voiceSearchMode
+ private static int VOICE_SEARCH_SHOW_BUTTON = 1;
+ private static int VOICE_SEARCH_LAUNCH_WEB_SEARCH = 2;
+ private static int VOICE_SEARCH_LAUNCH_RECOGNIZER = 4;
+ private int mVoiceSearchMode = 0;
+ private int mVoiceLanguageModeId; // voiceLanguageModel
+ private int mVoicePromptTextId; // voicePromptText
+ private int mVoiceLanguageId; // voiceLanguage
+ private int mVoiceMaxResults; // voiceMaxResults
+
/**
* Set the default searchable activity (when none is specified).
*/
@@ -419,8 +431,9 @@ public final class SearchableInfo implements Parcelable {
com.android.internal.R.styleable.Searchable_searchButtonText, 0);
mSearchInputType = a.getInt(com.android.internal.R.styleable.Searchable_inputType,
InputType.TYPE_CLASS_TEXT |
- InputType.TYPE_TEXT_FLAG_SEARCH |
- InputType.TYPE_TEXT_VARIATION_SEARCH_STRING);
+ InputType.TYPE_TEXT_VARIATION_NORMAL);
+ mSearchImeOptions = a.getInt(com.android.internal.R.styleable.Searchable_imeOptions,
+ EditorInfo.IME_ACTION_SEARCH);
setSearchModeFlags();
if (DBG_INHIBIT_SUGGESTIONS == 0) {
@@ -435,6 +448,18 @@ public final class SearchableInfo implements Parcelable {
mSuggestIntentData = a.getString(
com.android.internal.R.styleable.Searchable_searchSuggestIntentData);
}
+ mVoiceSearchMode =
+ a.getInt(com.android.internal.R.styleable.Searchable_voiceSearchMode, 0);
+ // TODO this didn't work - came back zero from YouTube
+ mVoiceLanguageModeId =
+ a.getResourceId(com.android.internal.R.styleable.Searchable_voiceLanguageModel, 0);
+ mVoicePromptTextId =
+ a.getResourceId(com.android.internal.R.styleable.Searchable_voicePromptText, 0);
+ mVoiceLanguageId =
+ a.getResourceId(com.android.internal.R.styleable.Searchable_voiceLanguage, 0);
+ mVoiceMaxResults =
+ a.getInt(com.android.internal.R.styleable.Searchable_voiceMaxResults, 0);
+
a.recycle();
// get package info for suggestions provider (if any)
@@ -462,11 +487,6 @@ public final class SearchableInfo implements Parcelable {
* Convert searchmode to flags.
*/
private void setSearchModeFlags() {
- // decompose searchMode attribute
- // TODO How do I reconcile these hardcoded values with the flag bits defined in
- // in attrs.xml? e.g. android.R.id.filterMode = 0x010200a4 instead of just "1"
- /* mFilterMode = (0 != (mSearchMode & 1)); */
- /* mQuickStart = (0 != (mSearchMode & 2)); */
mBadgeLabel = (0 != (mSearchMode & 4));
mBadgeIcon = (0 != (mSearchMode & 8)) && (mIconId != 0);
mQueryRewriteFromData = (0 != (mSearchMode & 0x10));
@@ -654,6 +674,59 @@ public final class SearchableInfo implements Parcelable {
}
/**
+ * @return true if android:voiceSearchMode="showVoiceSearchButton"
+ */
+ public boolean getVoiceSearchEnabled() {
+ return 0 != (mVoiceSearchMode & VOICE_SEARCH_SHOW_BUTTON);
+ }
+
+ /**
+ * @return true if android:voiceSearchMode="launchWebSearch"
+ */
+ public boolean getVoiceSearchLaunchWebSearch() {
+ return 0 != (mVoiceSearchMode & VOICE_SEARCH_LAUNCH_WEB_SEARCH);
+ }
+
+ /**
+ * @return true if android:voiceSearchMode="launchRecognizer"
+ */
+ public boolean getVoiceSearchLaunchRecognizer() {
+ return 0 != (mVoiceSearchMode & VOICE_SEARCH_LAUNCH_RECOGNIZER);
+ }
+
+ /**
+ * @return the resource Id of the language model string, if specified in the searchable
+ * activity's metadata, or 0 if not specified.
+ */
+ public int getVoiceLanguageModeId() {
+ return mVoiceLanguageModeId;
+ }
+
+ /**
+ * @return the resource Id of the voice prompt text string, if specified in the searchable
+ * activity's metadata, or 0 if not specified.
+ */
+ public int getVoicePromptTextId() {
+ return mVoicePromptTextId;
+ }
+
+ /**
+ * @return the resource Id of the spoken langauge, if specified in the searchable
+ * activity's metadata, or 0 if not specified.
+ */
+ public int getVoiceLanguageId() {
+ return mVoiceLanguageId;
+ }
+
+ /**
+ * @return the max results count, if specified in the searchable
+ * activity's metadata, or 0 if not specified.
+ */
+ public int getVoiceMaxResults() {
+ return mVoiceMaxResults;
+ }
+
+ /**
* Return the resource Id of replacement text for the "Search" button.
*
* @return Returns the resource Id, or 0 if not specified by this package.
@@ -673,6 +746,17 @@ public final class SearchableInfo implements Parcelable {
}
/**
+ * Return the input method options specified in the searchable attributes.
+ * This will default to EditorInfo.ACTION_SEARCH if not specified (which is
+ * appropriate for a search box).
+ *
+ * @return the input type
+ */
+ public int getImeOptions() {
+ return mSearchImeOptions;
+ }
+
+ /**
* Return the list of searchable activities, for use in the drop-down.
*/
public static ArrayList<SearchableInfo> getSearchablesList() {
@@ -712,6 +796,7 @@ public final class SearchableInfo implements Parcelable {
mIconId = in.readInt();
mSearchButtonText = in.readInt();
mSearchInputType = in.readInt();
+ mSearchImeOptions = in.readInt();
setSearchModeFlags();
mSuggestAuthority = in.readString();
@@ -727,6 +812,12 @@ public final class SearchableInfo implements Parcelable {
}
mSuggestProviderPackage = in.readString();
+
+ mVoiceSearchMode = in.readInt();
+ mVoiceLanguageModeId = in.readInt();
+ mVoicePromptTextId = in.readInt();
+ mVoiceLanguageId = in.readInt();
+ mVoiceMaxResults = in.readInt();
}
public int describeContents() {
@@ -742,6 +833,7 @@ public final class SearchableInfo implements Parcelable {
dest.writeInt(mIconId);
dest.writeInt(mSearchButtonText);
dest.writeInt(mSearchInputType);
+ dest.writeInt(mSearchImeOptions);
dest.writeString(mSuggestAuthority);
dest.writeString(mSuggestPath);
@@ -764,5 +856,11 @@ public final class SearchableInfo implements Parcelable {
}
dest.writeString(mSuggestProviderPackage);
+
+ dest.writeInt(mVoiceSearchMode);
+ dest.writeInt(mVoiceLanguageModeId);
+ dest.writeInt(mVoicePromptTextId);
+ dest.writeInt(mVoiceLanguageId);
+ dest.writeInt(mVoiceMaxResults);
}
}
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index abbf8a7..987e763 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -22,8 +22,6 @@ import android.content.Intent;
/**
* Constants for supporting speech recognition through starting an {@link Intent}
- *
- * @hide {pending API council review}
*/
public class RecognizerIntent {
private RecognizerIntent() {
@@ -32,7 +30,8 @@ public class RecognizerIntent {
/**
* Starts an activity that will prompt the user for speech and sends it through a
- * speech recognizer.
+ * speech recognizer. The results will be returned via activity results, or forwarded
+ * via a PendingIntent if one is provided.
*
* <p>Required extras:
* <ul>
@@ -41,9 +40,11 @@ public class RecognizerIntent {
*
* <p>Optional extras:
* <ul>
- * <li>{@link Intent#EXTRA_PROMPT}
+ * <li>{@link #EXTRA_PROMPT}
* <li>{@link #EXTRA_LANGUAGE}
* <li>{@link #EXTRA_MAX_RESULTS}
+ * <li>{@link #EXTRA_RESULTS_PENDINGINTENT}
+ * <li>{@link #EXTRA_RESULTS_PENDINGINTENT_BUNDLE}
* </ul>
*
* <p> Result extras:
@@ -57,6 +58,32 @@ public class RecognizerIntent {
public static final String ACTION_RECOGNIZE_SPEECH = "android.speech.action.RECOGNIZE_SPEECH";
/**
+ * Starts an activity that will prompt the user for speech, sends it through a
+ * speech recognizer, and invokes and displays a web search result.
+ *
+ * <p>Required extras:
+ * <ul>
+ * <li>{@link #EXTRA_LANGUAGE_MODEL}
+ * </ul>
+ *
+ * <p>Optional extras:
+ * <ul>
+ * <li>{@link #EXTRA_PROMPT}
+ * <li>{@link #EXTRA_LANGUAGE}
+ * <li>{@link #EXTRA_MAX_RESULTS}
+ * </ul>
+ *
+ * <p> Result extras:
+ * <ul>
+ * <li>{@link #EXTRA_RESULTS}
+ * </ul>
+ *
+ * <p>NOTE: There may not be any applications installed to handle this action, so you should
+ * make sure to catch {@link ActivityNotFoundException}.
+ */
+ public static final String ACTION_WEB_SEARCH = "android.speech.action.WEB_SEARCH";
+
+ /**
* Informs the recognizer which speech model to prefer when performing
* {@link #ACTION_RECOGNIZE_SPEECH}. The recognizer uses this
* information to fine tune the results. This extra is required. Activities implementing
@@ -65,27 +92,51 @@ public class RecognizerIntent {
* @see #LANGUAGE_MODEL_FREE_FORM
* @see #LANGUAGE_MODEL_WEB_SEARCH
*/
- public static final String EXTRA_LANGUAGE_MODEL = "language_model";
+ public static final String EXTRA_LANGUAGE_MODEL = "android.speech.extra.LANGUAGE_MODEL";
- /** Free form speech recognition */
+ /**
+ * Use a language model based on free-form speech recognition. This is a value to use for
+ * {@link #EXTRA_LANGUAGE_MODEL}.
+ * @see #EXTRA_LANGUAGE_MODEL
+ */
public static final String LANGUAGE_MODEL_FREE_FORM = "free_form";
- /** Use a language model based on web search terms */
+ /**
+ * Use a language model based on web search terms. This is a value to use for
+ * {@link #EXTRA_LANGUAGE_MODEL}.
+ * @see #EXTRA_LANGUAGE_MODEL
+ */
public static final String LANGUAGE_MODEL_WEB_SEARCH = "web_search";
/** Optional text prompt to show to the user when asking them to speak. */
- public static final String EXTRA_PROMPT = "prompt";
+ public static final String EXTRA_PROMPT = "android.speech.extra.PROMPT";
/**
* Optional language override to inform the recognizer that it should expect speech in
* a language different than the one set in the {@link java.util.Locale#getDefault()}.
*/
- public static final String EXTRA_LANGUAGE = "lang";
+ public static final String EXTRA_LANGUAGE = "android.speech.extra.LANGUAGE";
/**
* Optional limit on the maximum number of results to return. If omitted the recognizer
* will choose how many results to return. Must be an integer.
*/
- public static final String EXTRA_MAX_RESULTS = "max_results";
+ public static final String EXTRA_MAX_RESULTS = "android.speech.extra.MAX_RESULTS";
+
+ /**
+ * When the intent is {@link #ACTION_RECOGNIZE_SPEECH}, the speech input activity will
+ * return results to you via the activity results mechanism. Alternatively, if you use this
+ * extra to supply a PendingIntent, the results will be added to its bundle and the
+ * PendingIntent will be sent to its target.
+ */
+ public static final String EXTRA_RESULTS_PENDINGINTENT =
+ "android.speech.extra.RESULTS_PENDINGINTENT";
+ /**
+ * If you use {@link #EXTRA_RESULTS_PENDINGINTENT} to supply a forwarding intent, you can
+ * also use this extra to supply additional extras for the final intent. The search results
+ * will be added to this bundle, and the combined bundle will be sent to the target.
+ */
+ public static final String EXTRA_RESULTS_PENDINGINTENT_BUNDLE =
+ "android.speech.extra.RESULTS_PENDINGINTENT_BUNDLE";
/** Result code returned when no matches are found for the given speech */
public static final int RESULT_NO_MATCH = Activity.RESULT_FIRST_USER;
@@ -102,5 +153,5 @@ public class RecognizerIntent {
* An ArrayList<String> of the potential results when performing
* {@link #ACTION_RECOGNIZE_SPEECH}. Only present when {@link Activity#RESULT_OK} is returned.
*/
- public static final String EXTRA_RESULTS = "results";
+ public static final String EXTRA_RESULTS = "android.speech.extra.RESULTS";
}
diff --git a/core/java/android/speech/srec/MicrophoneInputStream.java b/core/java/android/speech/srec/MicrophoneInputStream.java
index 160a003..fab77a9 100644
--- a/core/java/android/speech/srec/MicrophoneInputStream.java
+++ b/core/java/android/speech/srec/MicrophoneInputStream.java
@@ -1,5 +1,5 @@
/*---------------------------------------------------------------------------*
- * MicrophoneInputStream.java *
+ * MicrophoneInputStream.java *
* *
* Copyright 2007 Nuance Communciations, Inc. *
* *
@@ -45,8 +45,12 @@ public final class MicrophoneInputStream extends InputStream {
*/
public MicrophoneInputStream(int sampleRate, int fifoDepth) throws IOException {
mAudioRecord = AudioRecordNew(sampleRate, fifoDepth);
- if (mAudioRecord == 0) throw new IllegalStateException("not open");
- AudioRecordStart(mAudioRecord);
+ if (mAudioRecord == 0) throw new IOException("AudioRecord constructor failed - busy?");
+ int status = AudioRecordStart(mAudioRecord);
+ if (status != 0) {
+ close();
+ throw new IOException("AudioRecord start failed: " + status);
+ }
}
@Override
@@ -99,7 +103,7 @@ public final class MicrophoneInputStream extends InputStream {
// AudioRecord JNI interface
//
private static native int AudioRecordNew(int sampleRate, int fifoDepth);
- private static native void AudioRecordStart(int audioRecord);
+ private static native int AudioRecordStart(int audioRecord);
private static native int AudioRecordRead(int audioRecord, byte[] b, int offset, int length) throws IOException;
private static native void AudioRecordStop(int audioRecord) throws IOException;
private static native void AudioRecordDelete(int audioRecord) throws IOException;
diff --git a/core/java/android/speech/srec/package.html b/core/java/android/speech/srec/package.html
index 723b30b..9a99df8 100644
--- a/core/java/android/speech/srec/package.html
+++ b/core/java/android/speech/srec/package.html
@@ -1,5 +1,6 @@
<HTML>
<BODY>
Simple, synchronous SREC speech recognition API.
+@hide
</BODY>
</HTML>
diff --git a/core/java/android/text/Annotation.java b/core/java/android/text/Annotation.java
index a3812a8..dbc290b 100644
--- a/core/java/android/text/Annotation.java
+++ b/core/java/android/text/Annotation.java
@@ -16,20 +16,40 @@
package android.text;
+import android.os.Parcel;
+
/**
* Annotations are simple key-value pairs that are preserved across
* TextView save/restore cycles and can be used to keep application-specific
* data that needs to be maintained for regions of text.
*/
-public class Annotation {
- private String mKey;
- private String mValue;
+public class Annotation implements ParcelableSpan {
+ private final String mKey;
+ private final String mValue;
public Annotation(String key, String value) {
mKey = key;
mValue = value;
}
+ public Annotation(Parcel src) {
+ mKey = src.readString();
+ mValue = src.readString();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.ANNOTATION;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mKey);
+ dest.writeString(mValue);
+ }
+
public String getKey() {
return mKey;
}
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 90f5e4c..8495714 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -700,7 +700,41 @@ class HtmlToSpannedConverter implements ContentHandler {
}
public void characters(char ch[], int start, int length) throws SAXException {
- mSpannableStringBuilder.append(CharBuffer.wrap(ch, start, length));
+ StringBuilder sb = new StringBuilder();
+
+ /*
+ * Ignore whitespace that immediately follows other whitespace;
+ * newlines count as spaces.
+ */
+
+ for (int i = 0; i < length; i++) {
+ char c = ch[i + start];
+
+ if (c == ' ' || c == '\n') {
+ char pred;
+ int len = sb.length();
+
+ if (len == 0) {
+ len = mSpannableStringBuilder.length();
+
+ if (len == 0) {
+ pred = '\n';
+ } else {
+ pred = mSpannableStringBuilder.charAt(len - 1);
+ }
+ } else {
+ pred = sb.charAt(len - 1);
+ }
+
+ if (pred != ' ' && pred != '\n') {
+ sb.append(' ');
+ }
+ } else {
+ sb.append(c);
+ }
+ }
+
+ mSpannableStringBuilder.append(sb);
}
public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index bd86834..d50684a 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -116,14 +116,17 @@ public interface InputType {
/**
* Flag for {@link #TYPE_CLASS_TEXT}: multiple lines of text can be
- * entered into the field.
+ * entered into the field. If this flag is not set, the text field
+ * will be constrained to a single line.
*/
public static final int TYPE_TEXT_FLAG_MULTI_LINE = 0x00020000;
/**
- * Flag for {@link #TYPE_CLASS_TEXT}: flags any text being used as a search string
+ * Flag for {@link #TYPE_CLASS_TEXT}: the regular text view associated
+ * with this should not be multi-line, but when a fullscreen input method
+ * is providing text it should use multiple lines if it can.
*/
- public static final int TYPE_TEXT_FLAG_SEARCH = 0x00040000;
+ public static final int TYPE_TEXT_FLAG_IME_MULTI_LINE = 0x00040000;
// ----------------------------------------------------------------------
@@ -149,35 +152,54 @@ public interface InputType {
public static final int TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 0x00000030;
/**
- * Variation of {@link #TYPE_CLASS_TEXT}: entering the content of
- * an e-mail.
+ * Variation of {@link #TYPE_CLASS_TEXT}: entering a short, possibly informal
+ * message such as an instant message or a text message.
*/
- public static final int TYPE_TEXT_VARIATION_EMAIL_CONTENT = 0x00000040;
+ public static final int TYPE_TEXT_VARIATION_SHORT_MESSAGE = 0x00000040;
/**
+ * Variation of {@link #TYPE_CLASS_TEXT}: entering the content of a long, possibly
+ * formal message such as the body of an e-mail.
+ */
+ public static final int TYPE_TEXT_VARIATION_LONG_MESSAGE = 0x00000050;
+
+ /**
* Variation of {@link #TYPE_CLASS_TEXT}: entering the name of a person.
*/
- public static final int TYPE_TEXT_VARIATION_PERSON_NAME = 0x00000050;
+ public static final int TYPE_TEXT_VARIATION_PERSON_NAME = 0x00000060;
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering a postal mailing address.
*/
- public static final int TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 0x00000060;
+ public static final int TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 0x00000070;
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering a password.
*/
- public static final int TYPE_TEXT_VARIATION_PASSWORD = 0x00000070;
+ public static final int TYPE_TEXT_VARIATION_PASSWORD = 0x00000080;
/**
- * Variation of {@link #TYPE_CLASS_TEXT}: entering a simple text search (e.g. web search)
+ * Variation of {@link #TYPE_CLASS_TEXT}: entering a password, which should
+ * be visible to the user.
*/
- public static final int TYPE_TEXT_VARIATION_SEARCH_STRING = 0x00000080;
+ public static final int TYPE_TEXT_VARIATION_VISIBLE_PASSWORD = 0x00000090;
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering text inside of a web form.
*/
- public static final int TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 0x00000090;
+ public static final int TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 0x000000a0;
+
+ /**
+ * Variation of {@link #TYPE_CLASS_TEXT}: entering text to filter contents
+ * of a list etc.
+ */
+ public static final int TYPE_TEXT_VARIATION_FILTER = 0x000000b0;
+
+ /**
+ * Variation of {@link #TYPE_CLASS_TEXT}: entering text for phonetic
+ * pronunciation, such as a phonetic name field in contacts.
+ */
+ public static final int TYPE_TEXT_VARIATION_PHONETIC = 0x000000c0;
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
diff --git a/core/java/android/text/NoCopySpan.java b/core/java/android/text/NoCopySpan.java
new file mode 100644
index 0000000..0855c0b
--- /dev/null
+++ b/core/java/android/text/NoCopySpan.java
@@ -0,0 +1,31 @@
+/*
+ * 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 android.text;
+
+/**
+ * This interface should be added to a span object that should not be copied
+ * into a new Spenned when performing a slice or copy operation on the original
+ * Spanned it was placed in.
+ */
+public interface NoCopySpan {
+ /**
+ * Convenience equivalent for when you would just want a new Object() for
+ * a span but want it to be no-copy. Use this instead.
+ */
+ public class Concrete implements NoCopySpan {
+ }
+}
diff --git a/location/java/com/android/internal/location/protocol/GAddress.java b/core/java/android/text/ParcelableSpan.java
index 86a3912..224511a 100644
--- a/location/java/com/android/internal/location/protocol/GAddress.java
+++ b/core/java/android/text/ParcelableSpan.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -14,10 +14,18 @@
* limitations under the License.
*/
-package com.android.internal.location.protocol;
+package android.text;
-public interface GAddress {
- static final int FORMATTED_ADDRESS_LINE = 1;
- static final int COMPONENT = 2;
-}
+import android.os.Parcelable;
+/**
+ * A special kind of Parcelable for objects that will serve as text spans.
+ * This can only be used by code in the framework; it is not intended for
+ * applications to implement their own Parcelable spans.
+ */
+public interface ParcelableSpan extends Parcelable {
+ /**
+ * Return a special type identifier for this span class.
+ */
+ public abstract int getSpanTypeId();
+}
diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java
index 44469ec..bb98bce 100644
--- a/core/java/android/text/Selection.java
+++ b/core/java/android/text/Selection.java
@@ -72,7 +72,7 @@ public class Selection {
if (ostart != start || oend != stop) {
text.setSpan(SELECTION_START, start, start,
- Spanned.SPAN_POINT_POINT);
+ Spanned.SPAN_POINT_POINT|Spanned.SPAN_INTERMEDIATE);
text.setSpan(SELECTION_END, stop, stop,
Spanned.SPAN_POINT_POINT);
}
@@ -417,8 +417,8 @@ public class Selection {
}
}
- private static final class START { };
- private static final class END { };
+ private static final class START implements NoCopySpan { };
+ private static final class END implements NoCopySpan { };
/*
* Public constants
diff --git a/core/java/android/text/SpanWatcher.java b/core/java/android/text/SpanWatcher.java
index f99882a..01e82c8 100644
--- a/core/java/android/text/SpanWatcher.java
+++ b/core/java/android/text/SpanWatcher.java
@@ -21,7 +21,7 @@ package android.text;
* will be called to notify it that other markup objects have been
* added, changed, or removed.
*/
-public interface SpanWatcher {
+public interface SpanWatcher extends NoCopySpan {
/**
* This method is called to notify you that the specified object
* has been attached to the specified range of the text.
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 223ce2f..caaafa1 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -70,6 +70,10 @@ implements CharSequence, GetChars, Spannable, Editable, Appendable,
Object[] spans = sp.getSpans(start, end, Object.class);
for (int i = 0; i < spans.length; i++) {
+ if (spans[i] instanceof NoCopySpan) {
+ continue;
+ }
+
int st = sp.getSpanStart(spans[i]) - start;
int en = sp.getSpanEnd(spans[i]) - start;
int fl = sp.getSpanFlags(spans[i]);
diff --git a/core/java/android/text/Spanned.java b/core/java/android/text/Spanned.java
index bd0a16b..154497d 100644
--- a/core/java/android/text/Spanned.java
+++ b/core/java/android/text/Spanned.java
@@ -106,6 +106,14 @@ extends CharSequence
public static final int SPAN_COMPOSING = 0x100;
/**
+ * This flag will be set for intermediate span changes, meaning there
+ * is guaranteed to be another change following it. Typically it is
+ * used for {@link Selection} which automatically uses this with the first
+ * offset it sets when updating the selection.
+ */
+ public static final int SPAN_INTERMEDIATE = 0x200;
+
+ /**
* The bits numbered SPAN_USER_SHIFT and above are available
* for callers to use to store scalar data associated with their
* span object.
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index ceb9f4f..0fef40b 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -576,7 +576,28 @@ extends Layout
if (fmbottom > fitbottom)
fitbottom = fmbottom;
- if (c == ' ' || c == '\t') {
+ /*
+ * From the Unicode Line Breaking Algorithm:
+ * (at least approximately)
+ *
+ * .,:; are class IS: breakpoints
+ * except when adjacent to digits
+ * / is class SY: a breakpoint
+ * except when followed by a digit.
+ * - is class HY: a breakpoint
+ * except when followed by a digit.
+ *
+ * Ideographs are class ID: breakpoints when adjacent.
+ */
+
+ if (c == ' ' || c == '\t' ||
+ ((c == '.' || c == ',' || c == ':' || c == ';') &&
+ (j - 1 < here || !Character.isDigit(chs[j - 1 - start])) &&
+ (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
+ ((c == '/' || c == '-') &&
+ (j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
+ (c >= FIRST_CJK && isIdeographic(c) &&
+ j + 1 < next && isIdeographic(chs[j + 1 - start]))) {
okwidth = w;
ok = j + 1;
@@ -592,6 +613,11 @@ extends Layout
} else if (breakOnlyAtSpaces) {
if (ok != here) {
// Log.e("text", "output ok " + here + " to " +ok);
+
+ while (ok < next && chs[ok - start] == ' ') {
+ ok++;
+ }
+
v = out(source,
here, ok,
okascent, okdescent, oktop, okbottom,
@@ -623,6 +649,11 @@ extends Layout
} else {
if (ok != here) {
// Log.e("text", "output ok " + here + " to " +ok);
+
+ while (ok < next && chs[ok - start] == ' ') {
+ ok++;
+ }
+
v = out(source,
here, ok,
okascent, okdescent, oktop, okbottom,
@@ -739,6 +770,51 @@ extends Layout
}
}
+ private static final char FIRST_CJK = '\u2E80';
+ /**
+ * Returns true if the specified character is one of those specified
+ * as being Ideographic (class ID) by the Unicode Line Breaking Algorithm
+ * (http://www.unicode.org/unicode/reports/tr14/), and is therefore OK
+ * to break between a pair of.
+ */
+ private static final boolean isIdeographic(char c) {
+ if (c >= '\u2E80' && c <= '\u2FFF') {
+ return true; // CJK, KANGXI RADICALS, DESCRIPTION SYMBOLS
+ }
+ if (c == '\u3000') {
+ return true; // IDEOGRAPHIC SPACE
+ }
+ if (c >= '\u3040' && c <= '\u309F') {
+ return true; // Hiragana (except small characters)
+ }
+ if (c >= '\u30A0' && c <= '\u30FF') {
+ return true; // Katakana (except small characters)
+ }
+ if (c >= '\u3400' && c <= '\u4DB5') {
+ return true; // CJK UNIFIED IDEOGRAPHS EXTENSION A
+ }
+ if (c >= '\u4E00' && c <= '\u9FBB') {
+ return true; // CJK UNIFIED IDEOGRAPHS
+ }
+ if (c >= '\uF900' && c <= '\uFAD9') {
+ return true; // CJK COMPATIBILITY IDEOGRAPHS
+ }
+ if (c >= '\uA000' && c <= '\uA48F') {
+ return true; // YI SYLLABLES
+ }
+ if (c >= '\uA490' && c <= '\uA4CF') {
+ return true; // YI RADICALS
+ }
+ if (c >= '\uFE62' && c <= '\uFE66') {
+ return true; // SMALL PLUS SIGN to SMALL EQUALS SIGN
+ }
+ if (c >= '\uFF10' && c <= '\uFF19') {
+ return true; // WIDE DIGITS
+ }
+
+ return false;
+ }
+
/*
private static void dump(byte[] data, int count, String label) {
if (false) {
diff --git a/core/java/android/text/Styled.java b/core/java/android/text/Styled.java
index 05c27ea..0aa2004 100644
--- a/core/java/android/text/Styled.java
+++ b/core/java/android/text/Styled.java
@@ -16,25 +16,26 @@
package android.text;
-import android.graphics.Paint;
import android.graphics.Canvas;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.graphics.Typeface;
-import android.graphics.MaskFilter;
-import android.graphics.Rasterizer;
-import android.graphics.LayerRasterizer;
-import android.text.style.*;
-
-/* package */ class Styled
+import android.graphics.Paint;
+import android.text.style.CharacterStyle;
+import android.text.style.MetricAffectingSpan;
+import android.text.style.ReplacementSpan;
+
+/**
+ * This class provides static methods for drawing and measuring styled texts, like
+ * {@link android.text.Spanned} object with {@link android.text.style.ReplacementSpan}.
+ * @hide
+ */
+public class Styled
{
private static float each(Canvas canvas,
Spanned text, int start, int end,
int dir, boolean reverse,
float x, int top, int y, int bottom,
- Paint.FontMetricsInt fm,
- TextPaint realPaint,
+ Paint.FontMetricsInt fmi,
TextPaint paint,
+ TextPaint workPaint,
boolean needwid) {
boolean havewid = false;
@@ -43,9 +44,9 @@ import android.text.style.*;
ReplacementSpan replacement = null;
- realPaint.bgColor = 0;
- realPaint.baselineShift = 0;
- paint.set(realPaint);
+ paint.bgColor = 0;
+ paint.baselineShift = 0;
+ workPaint.set(paint);
if (spans.length > 0) {
for (int i = 0; i < spans.length; i++) {
@@ -55,7 +56,7 @@ import android.text.style.*;
replacement = (ReplacementSpan)span;
}
else {
- span.updateDrawState(paint);
+ span.updateDrawState(workPaint);
}
}
}
@@ -74,66 +75,66 @@ import android.text.style.*;
tmpend = end;
}
- if (fm != null) {
- paint.getFontMetricsInt(fm);
+ if (fmi != null) {
+ workPaint.getFontMetricsInt(fmi);
}
if (canvas != null) {
- if (paint.bgColor != 0) {
- int c = paint.getColor();
- Paint.Style s = paint.getStyle();
- paint.setColor(paint.bgColor);
- paint.setStyle(Paint.Style.FILL);
+ if (workPaint.bgColor != 0) {
+ int c = workPaint.getColor();
+ Paint.Style s = workPaint.getStyle();
+ workPaint.setColor(workPaint.bgColor);
+ workPaint.setStyle(Paint.Style.FILL);
if (!havewid) {
- ret = paint.measureText(tmp, tmpstart, tmpend);
+ ret = workPaint.measureText(tmp, tmpstart, tmpend);
havewid = true;
}
if (dir == Layout.DIR_RIGHT_TO_LEFT)
- canvas.drawRect(x - ret, top, x, bottom, paint);
+ canvas.drawRect(x - ret, top, x, bottom, workPaint);
else
- canvas.drawRect(x, top, x + ret, bottom, paint);
+ canvas.drawRect(x, top, x + ret, bottom, workPaint);
- paint.setStyle(s);
- paint.setColor(c);
+ workPaint.setStyle(s);
+ workPaint.setColor(c);
}
if (dir == Layout.DIR_RIGHT_TO_LEFT) {
if (!havewid) {
- ret = paint.measureText(tmp, tmpstart, tmpend);
+ ret = workPaint.measureText(tmp, tmpstart, tmpend);
havewid = true;
}
canvas.drawText(tmp, tmpstart, tmpend,
- x - ret, y + paint.baselineShift, paint);
+ x - ret, y + workPaint.baselineShift, workPaint);
} else {
if (needwid) {
if (!havewid) {
- ret = paint.measureText(tmp, tmpstart, tmpend);
+ ret = workPaint.measureText(tmp, tmpstart, tmpend);
havewid = true;
}
}
canvas.drawText(tmp, tmpstart, tmpend,
- x, y + paint.baselineShift, paint);
+ x, y + workPaint.baselineShift, workPaint);
}
} else {
if (needwid && !havewid) {
- ret = paint.measureText(tmp, tmpstart, tmpend);
+ ret = workPaint.measureText(tmp, tmpstart, tmpend);
havewid = true;
}
}
} else {
- ret = replacement.getSize(paint, text, start, end, fm);
+ ret = replacement.getSize(workPaint, text, start, end, fmi);
if (canvas != null) {
if (dir == Layout.DIR_RIGHT_TO_LEFT)
replacement.draw(canvas, text, start, end,
- x - ret, top, y, bottom, paint);
+ x - ret, top, y, bottom, workPaint);
else
replacement.draw(canvas, text, start, end,
- x, top, y, bottom, paint);
+ x, top, y, bottom, workPaint);
}
}
@@ -143,15 +144,29 @@ import android.text.style.*;
return ret;
}
- public static int getTextWidths(TextPaint realPaint,
- TextPaint paint,
- Spanned text, int start, int end,
- float[] widths, Paint.FontMetricsInt fm) {
-
+ /**
+ * Return the advance widths for the characters in the string.
+ * See also {@link android.graphics.Paint#getTextWidths(CharSequence, int, int, float[])}.
+ *
+ * @param paint The main {@link TextPaint} object.
+ * @param workPaint The {@link TextPaint} object used for temporal workspace.
+ * @param text The text to measure
+ * @param start The index of the first char to to measure
+ * @param end The end of the text slice to measure
+ * @param widths Array to receive the advance widths of the characters.
+ * Must be at least a large as (end - start).
+ * @param fmi FontMetrics information. Can be null.
+ * @return The actual number of widths returned.
+ */
+ public static int getTextWidths(TextPaint paint,
+ TextPaint workPaint,
+ Spanned text, int start, int end,
+ float[] widths, Paint.FontMetricsInt fmi) {
+ // Keep workPaint as is so that developers reuse the workspace.
MetricAffectingSpan[] spans = text.getSpans(start, end, MetricAffectingSpan.class);
ReplacementSpan replacement = null;
- paint.set(realPaint);
+ workPaint.set(paint);
for (int i = 0; i < spans.length; i++) {
MetricAffectingSpan span = spans[i];
@@ -159,15 +174,15 @@ import android.text.style.*;
replacement = (ReplacementSpan)span;
}
else {
- span.updateMeasureState(paint);
+ span.updateMeasureState(workPaint);
}
}
if (replacement == null) {
- paint.getFontMetricsInt(fm);
- paint.getTextWidths(text, start, end, widths);
+ workPaint.getFontMetricsInt(fmi);
+ workPaint.getTextWidths(text, start, end, widths);
} else {
- int wid = replacement.getSize(paint, text, start, end, fm);
+ int wid = replacement.getSize(workPaint, text, start, end, fmi);
if (end > start) {
widths[0] = wid;
@@ -183,10 +198,10 @@ import android.text.style.*;
CharSequence text, int start, int end,
int dir, boolean reverse,
float x, int top, int y, int bottom,
- Paint.FontMetricsInt fm,
+ Paint.FontMetricsInt fmi,
TextPaint paint,
TextPaint workPaint,
- boolean needwid) {
+ boolean needWidth) {
if (! (text instanceof Spanned)) {
float ret = 0;
@@ -194,22 +209,22 @@ import android.text.style.*;
CharSequence tmp = TextUtils.getReverse(text, start, end);
int tmpend = end - start;
- if (canvas != null || needwid)
+ if (canvas != null || needWidth)
ret = paint.measureText(tmp, 0, tmpend);
if (canvas != null)
canvas.drawText(tmp, 0, tmpend,
x - ret, y, paint);
} else {
- if (needwid)
+ if (needWidth)
ret = paint.measureText(text, start, end);
if (canvas != null)
canvas.drawText(text, start, end, x, y, paint);
}
- if (fm != null) {
- paint.getFontMetricsInt(fm);
+ if (fmi != null) {
+ paint.getFontMetricsInt(fmi);
}
return ret * dir; //Layout.DIR_RIGHT_TO_LEFT == -1
@@ -232,67 +247,129 @@ import android.text.style.*;
next = sp.nextSpanTransition(i, end, division);
x += each(canvas, sp, i, next, dir, reverse,
- x, top, y, bottom, fm, paint, workPaint,
- needwid || next != end);
-
- if (fm != null) {
- if (fm.ascent < asc)
- asc = fm.ascent;
- if (fm.descent > desc)
- desc = fm.descent;
-
- if (fm.top < ftop)
- ftop = fm.top;
- if (fm.bottom > fbot)
- fbot = fm.bottom;
+ x, top, y, bottom, fmi, paint, workPaint,
+ needWidth || next != end);
+
+ if (fmi != null) {
+ if (fmi.ascent < asc)
+ asc = fmi.ascent;
+ if (fmi.descent > desc)
+ desc = fmi.descent;
+
+ if (fmi.top < ftop)
+ ftop = fmi.top;
+ if (fmi.bottom > fbot)
+ fbot = fmi.bottom;
}
}
- if (fm != null) {
+ if (fmi != null) {
if (start == end) {
- paint.getFontMetricsInt(fm);
+ paint.getFontMetricsInt(fmi);
} else {
- fm.ascent = asc;
- fm.descent = desc;
- fm.top = ftop;
- fm.bottom = fbot;
+ fmi.ascent = asc;
+ fmi.descent = desc;
+ fmi.top = ftop;
+ fmi.bottom = fbot;
}
}
return x - ox;
}
- public static float drawText(Canvas canvas,
- CharSequence text, int start, int end,
- int dir, boolean reverse,
- float x, int top, int y, int bottom,
- TextPaint paint,
- TextPaint workPaint,
- boolean needwid) {
- if ((dir == Layout.DIR_RIGHT_TO_LEFT && !reverse)||(reverse && dir == Layout.DIR_LEFT_TO_RIGHT)) {
+
+ /* package */ static float drawText(Canvas canvas,
+ CharSequence text, int start, int end,
+ int direction, boolean reverse,
+ float x, int top, int y, int bottom,
+ TextPaint paint,
+ TextPaint workPaint,
+ boolean needWidth) {
+ if ((direction == Layout.DIR_RIGHT_TO_LEFT && !reverse) ||
+ (reverse && direction == Layout.DIR_LEFT_TO_RIGHT)) {
float ch = foreach(null, text, start, end, Layout.DIR_LEFT_TO_RIGHT,
false, 0, 0, 0, 0, null, paint, workPaint,
true);
- ch *= dir; // DIR_RIGHT_TO_LEFT == -1
- foreach(canvas, text, start, end, -dir,
+ ch *= direction; // DIR_RIGHT_TO_LEFT == -1
+ foreach(canvas, text, start, end, -direction,
reverse, x + ch, top, y, bottom, null, paint,
workPaint, true);
return ch;
}
- return foreach(canvas, text, start, end, dir, reverse,
+ return foreach(canvas, text, start, end, direction, reverse,
x, top, y, bottom, null, paint, workPaint,
- needwid);
+ needWidth);
}
-
+
+ /**
+ * Draw the specified range of text, specified by start/end, with its origin at (x,y),
+ * in the specified Paint. The origin is interpreted based on the Align setting in the
+ * Paint.
+ *
+ * This method considers style information in the text
+ * (e.g. Even when text is an instance of {@link android.text.Spanned}, this method
+ * correctly draws the text).
+ * See also
+ * {@link android.graphics.Canvas#drawText(CharSequence, int, int, float, float, Paint)}
+ * and
+ * {@link android.graphics.Canvas#drawRect(float, float, float, float, Paint)}.
+ *
+ * @param canvas The target canvas.
+ * @param text The text to be drawn
+ * @param start The index of the first character in text to draw
+ * @param end (end - 1) is the index of the last character in text to draw
+ * @param direction The direction of the text. This must be
+ * {@link android.text.Layout#DIR_LEFT_TO_RIGHT} or
+ * {@link android.text.Layout#DIR_RIGHT_TO_LEFT}.
+ * @param x The x-coordinate of origin for where to draw the text
+ * @param top The top side of the rectangle to be drawn
+ * @param y The y-coordinate of origin for where to draw the text
+ * @param bottom The bottom side of the rectangle to be drawn
+ * @param paint The main {@link TextPaint} object.
+ * @param workPaint The {@link TextPaint} object used for temporal workspace.
+ * @param needWidth If true, this method returns the width of drawn text.
+ * @return Width of the drawn text if needWidth is true.
+ */
+ public static float drawText(Canvas canvas,
+ CharSequence text, int start, int end,
+ int direction,
+ float x, int top, int y, int bottom,
+ TextPaint paint,
+ TextPaint workPaint,
+ boolean needWidth) {
+ // For safety.
+ direction = direction >= 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT;
+ /*
+ * Hided "reverse" parameter since it is meaningless for external developers.
+ * Kept workPaint as is so that developers reuse the workspace.
+ */
+ return drawText(canvas, text, start, end, direction, false,
+ x, top, y, bottom, paint, workPaint, needWidth);
+ }
+
+ /**
+ * Return the width of the text, considering style information in the text
+ * (e.g. Even when text is an instance of {@link android.text.Spanned}, this method
+ * correctly mesures the width of the text).
+ *
+ * @param paint The main {@link TextPaint} object.
+ * @param workPaint The {@link TextPaint} object used for temporal workspace.
+ * @param text The text to measure
+ * @param start The index of the first character to start measuring
+ * @param end 1 beyond the index of the last character to measure
+ * @param fmi FontMetrics information. Can be null
+ * @return The width of the text
+ */
public static float measureText(TextPaint paint,
TextPaint workPaint,
CharSequence text, int start, int end,
- Paint.FontMetricsInt fm) {
+ Paint.FontMetricsInt fmi) {
+ // Keep workPaint as is so that developers reuse the workspace.
return foreach(null, text, start, end,
Layout.DIR_LEFT_TO_RIGHT, false,
- 0, 0, 0, 0, fm, paint, workPaint, true);
+ 0, 0, 0, 0, fmi, paint, workPaint, true);
}
}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 405d934..5b4c380 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -236,6 +236,13 @@ public class TextUtils {
return match;
}
+ /**
+ * Create a new String object containing the given range of characters
+ * from the source string. This is different than simply calling
+ * {@link CharSequence#subSequence(int, int) CharSequence.subSequence}
+ * in that it does not preserve any style runs in the source sequence,
+ * allowing a more efficient implementation.
+ */
public static String substring(CharSequence source, int start, int end) {
if (source instanceof String)
return ((String) source).substring(start, end);
@@ -447,13 +454,26 @@ public class TextUtils {
/**
* Returns true if a and b are equal, including if they are both null.
- *
+ * <p><i>Note: In platform versions 1.1 and earlier, this method only worked well if
+ * both the arguments were instances of String.</i></p>
* @param a first CharSequence to check
* @param b second CharSequence to check
* @return true if a and b are equal
*/
public static boolean equals(CharSequence a, CharSequence b) {
- return a == b || (a != null && a.equals(b));
+ if (a == b) return true;
+ int length;
+ if (a != null && b != null && (length = a.length()) == b.length()) {
+ if (a instanceof String && b instanceof String) {
+ return a.equals(b);
+ } else {
+ for (int i = 0; i < length; i++) {
+ if (a.charAt(i) != b.charAt(i)) return false;
+ }
+ return true;
+ }
+ }
+ return false;
}
// XXX currently this only reverses chars, not spans
@@ -510,24 +530,42 @@ public class TextUtils {
private int mEnd;
}
- private static final int ALIGNMENT_SPAN = 1;
- private static final int FOREGROUND_COLOR_SPAN = 2;
- private static final int RELATIVE_SIZE_SPAN = 3;
- private static final int SCALE_X_SPAN = 4;
- private static final int STRIKETHROUGH_SPAN = 5;
- private static final int UNDERLINE_SPAN = 6;
- private static final int STYLE_SPAN = 7;
- private static final int BULLET_SPAN = 8;
- private static final int QUOTE_SPAN = 9;
- private static final int LEADING_MARGIN_SPAN = 10;
- private static final int URL_SPAN = 11;
- private static final int BACKGROUND_COLOR_SPAN = 12;
- private static final int TYPEFACE_SPAN = 13;
- private static final int SUPERSCRIPT_SPAN = 14;
- private static final int SUBSCRIPT_SPAN = 15;
- private static final int ABSOLUTE_SIZE_SPAN = 16;
- private static final int TEXT_APPEARANCE_SPAN = 17;
- private static final int ANNOTATION = 18;
+ /** @hide */
+ public static final int ALIGNMENT_SPAN = 1;
+ /** @hide */
+ public static final int FOREGROUND_COLOR_SPAN = 2;
+ /** @hide */
+ public static final int RELATIVE_SIZE_SPAN = 3;
+ /** @hide */
+ public static final int SCALE_X_SPAN = 4;
+ /** @hide */
+ public static final int STRIKETHROUGH_SPAN = 5;
+ /** @hide */
+ public static final int UNDERLINE_SPAN = 6;
+ /** @hide */
+ public static final int STYLE_SPAN = 7;
+ /** @hide */
+ public static final int BULLET_SPAN = 8;
+ /** @hide */
+ public static final int QUOTE_SPAN = 9;
+ /** @hide */
+ public static final int LEADING_MARGIN_SPAN = 10;
+ /** @hide */
+ public static final int URL_SPAN = 11;
+ /** @hide */
+ public static final int BACKGROUND_COLOR_SPAN = 12;
+ /** @hide */
+ public static final int TYPEFACE_SPAN = 13;
+ /** @hide */
+ public static final int SUPERSCRIPT_SPAN = 14;
+ /** @hide */
+ public static final int SUBSCRIPT_SPAN = 15;
+ /** @hide */
+ public static final int ABSOLUTE_SIZE_SPAN = 16;
+ /** @hide */
+ public static final int TEXT_APPEARANCE_SPAN = 17;
+ /** @hide */
+ public static final int ANNOTATION = 18;
/**
* Flatten a CharSequence and whatever styles can be copied across processes
@@ -555,136 +593,10 @@ public class TextUtils {
prop = ((CharacterStyle) prop).getUnderlying();
}
- if (prop instanceof AlignmentSpan) {
- p.writeInt(ALIGNMENT_SPAN);
- p.writeString(((AlignmentSpan) prop).getAlignment().name());
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof ForegroundColorSpan) {
- p.writeInt(FOREGROUND_COLOR_SPAN);
- p.writeInt(((ForegroundColorSpan) prop).getForegroundColor());
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof RelativeSizeSpan) {
- p.writeInt(RELATIVE_SIZE_SPAN);
- p.writeFloat(((RelativeSizeSpan) prop).getSizeChange());
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof ScaleXSpan) {
- p.writeInt(SCALE_X_SPAN);
- p.writeFloat(((ScaleXSpan) prop).getScaleX());
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof StrikethroughSpan) {
- p.writeInt(STRIKETHROUGH_SPAN);
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof UnderlineSpan) {
- p.writeInt(UNDERLINE_SPAN);
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof StyleSpan) {
- p.writeInt(STYLE_SPAN);
- p.writeInt(((StyleSpan) prop).getStyle());
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof LeadingMarginSpan) {
- if (prop instanceof BulletSpan) {
- p.writeInt(BULLET_SPAN);
- writeWhere(p, sp, o);
- } else if (prop instanceof QuoteSpan) {
- p.writeInt(QUOTE_SPAN);
- p.writeInt(((QuoteSpan) prop).getColor());
- writeWhere(p, sp, o);
- } else {
- p.writeInt(LEADING_MARGIN_SPAN);
- p.writeInt(((LeadingMarginSpan) prop).
- getLeadingMargin(true));
- p.writeInt(((LeadingMarginSpan) prop).
- getLeadingMargin(false));
- writeWhere(p, sp, o);
- }
- }
-
- if (prop instanceof URLSpan) {
- p.writeInt(URL_SPAN);
- p.writeString(((URLSpan) prop).getURL());
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof BackgroundColorSpan) {
- p.writeInt(BACKGROUND_COLOR_SPAN);
- p.writeInt(((BackgroundColorSpan) prop).getBackgroundColor());
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof TypefaceSpan) {
- p.writeInt(TYPEFACE_SPAN);
- p.writeString(((TypefaceSpan) prop).getFamily());
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof SuperscriptSpan) {
- p.writeInt(SUPERSCRIPT_SPAN);
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof SubscriptSpan) {
- p.writeInt(SUBSCRIPT_SPAN);
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof AbsoluteSizeSpan) {
- p.writeInt(ABSOLUTE_SIZE_SPAN);
- p.writeInt(((AbsoluteSizeSpan) prop).getSize());
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof TextAppearanceSpan) {
- TextAppearanceSpan tas = (TextAppearanceSpan) prop;
- p.writeInt(TEXT_APPEARANCE_SPAN);
-
- String tf = tas.getFamily();
- if (tf != null) {
- p.writeInt(1);
- p.writeString(tf);
- } else {
- p.writeInt(0);
- }
-
- p.writeInt(tas.getTextStyle());
- p.writeInt(tas.getTextSize());
-
- ColorStateList csl = tas.getTextColor();
- if (csl == null) {
- p.writeInt(0);
- } else {
- p.writeInt(1);
- csl.writeToParcel(p, parcelableFlags);
- }
-
- csl = tas.getLinkTextColor();
- if (csl == null) {
- p.writeInt(0);
- } else {
- p.writeInt(1);
- csl.writeToParcel(p, parcelableFlags);
- }
-
- writeWhere(p, sp, o);
- }
-
- if (prop instanceof Annotation) {
- p.writeInt(ANNOTATION);
- p.writeString(((Annotation) prop).getKey());
- p.writeString(((Annotation) prop).getValue());
+ if (prop instanceof ParcelableSpan) {
+ ParcelableSpan ps = (ParcelableSpan)prop;
+ p.writeInt(ps.getSpanTypeId());
+ ps.writeToParcel(p, parcelableFlags);
writeWhere(p, sp, o);
}
}
@@ -707,8 +619,7 @@ public class TextUtils {
}
public static final Parcelable.Creator<CharSequence> CHAR_SEQUENCE_CREATOR
- = new Parcelable.Creator<CharSequence>()
- {
+ = new Parcelable.Creator<CharSequence>() {
/**
* Read and return a new CharSequence, possibly with styles,
* from the parcel.
@@ -729,89 +640,75 @@ public class TextUtils {
switch (kind) {
case ALIGNMENT_SPAN:
- readSpan(p, sp, new AlignmentSpan.Standard(
- Layout.Alignment.valueOf(p.readString())));
+ readSpan(p, sp, new AlignmentSpan.Standard(p));
break;
case FOREGROUND_COLOR_SPAN:
- readSpan(p, sp, new ForegroundColorSpan(p.readInt()));
+ readSpan(p, sp, new ForegroundColorSpan(p));
break;
case RELATIVE_SIZE_SPAN:
- readSpan(p, sp, new RelativeSizeSpan(p.readFloat()));
+ readSpan(p, sp, new RelativeSizeSpan(p));
break;
case SCALE_X_SPAN:
- readSpan(p, sp, new ScaleXSpan(p.readFloat()));
+ readSpan(p, sp, new ScaleXSpan(p));
break;
case STRIKETHROUGH_SPAN:
- readSpan(p, sp, new StrikethroughSpan());
+ readSpan(p, sp, new StrikethroughSpan(p));
break;
case UNDERLINE_SPAN:
- readSpan(p, sp, new UnderlineSpan());
+ readSpan(p, sp, new UnderlineSpan(p));
break;
case STYLE_SPAN:
- readSpan(p, sp, new StyleSpan(p.readInt()));
+ readSpan(p, sp, new StyleSpan(p));
break;
case BULLET_SPAN:
- readSpan(p, sp, new BulletSpan());
+ readSpan(p, sp, new BulletSpan(p));
break;
case QUOTE_SPAN:
- readSpan(p, sp, new QuoteSpan(p.readInt()));
+ readSpan(p, sp, new QuoteSpan(p));
break;
case LEADING_MARGIN_SPAN:
- readSpan(p, sp, new LeadingMarginSpan.Standard(p.readInt(),
- p.readInt()));
+ readSpan(p, sp, new LeadingMarginSpan.Standard(p));
break;
case URL_SPAN:
- readSpan(p, sp, new URLSpan(p.readString()));
+ readSpan(p, sp, new URLSpan(p));
break;
case BACKGROUND_COLOR_SPAN:
- readSpan(p, sp, new BackgroundColorSpan(p.readInt()));
+ readSpan(p, sp, new BackgroundColorSpan(p));
break;
case TYPEFACE_SPAN:
- readSpan(p, sp, new TypefaceSpan(p.readString()));
+ readSpan(p, sp, new TypefaceSpan(p));
break;
case SUPERSCRIPT_SPAN:
- readSpan(p, sp, new SuperscriptSpan());
+ readSpan(p, sp, new SuperscriptSpan(p));
break;
case SUBSCRIPT_SPAN:
- readSpan(p, sp, new SubscriptSpan());
+ readSpan(p, sp, new SubscriptSpan(p));
break;
case ABSOLUTE_SIZE_SPAN:
- readSpan(p, sp, new AbsoluteSizeSpan(p.readInt()));
+ readSpan(p, sp, new AbsoluteSizeSpan(p));
break;
case TEXT_APPEARANCE_SPAN:
- readSpan(p, sp, new TextAppearanceSpan(
- p.readInt() != 0
- ? p.readString()
- : null,
- p.readInt(), // style
- p.readInt(), // size
- p.readInt() != 0
- ? ColorStateList.CREATOR.createFromParcel(p)
- : null,
- p.readInt() != 0
- ? ColorStateList.CREATOR.createFromParcel(p)
- : null));
+ readSpan(p, sp, new TextAppearanceSpan(p));
break;
case ANNOTATION:
- readSpan(p, sp,
- new Annotation(p.readString(), p.readString()));
+ readSpan(p, sp, new Annotation(p));
break;
default:
diff --git a/core/java/android/text/TextWatcher.java b/core/java/android/text/TextWatcher.java
index 7456b28..bad09f2 100644
--- a/core/java/android/text/TextWatcher.java
+++ b/core/java/android/text/TextWatcher.java
@@ -20,7 +20,7 @@ package android.text;
* When an object of a type is attached to an Editable, its methods will
* be called when the text is changed.
*/
-public interface TextWatcher {
+public interface TextWatcher extends NoCopySpan {
/**
* This method is called to notify you that, within <code>s</code>,
* the <code>count</code> characters beginning at <code>start</code>
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 73adedf..0dc96c3 100644
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -27,6 +27,7 @@ import com.android.internal.R;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
+import java.util.Locale;
import java.util.TimeZone;
import java.text.SimpleDateFormat;
@@ -188,6 +189,12 @@ public class DateFormat {
*/
public static final char YEAR = 'y';
+
+ private static final Object sLocaleLock = new Object();
+ private static Locale sIs24HourLocale;
+ private static boolean sIs24Hour;
+
+
/**
* Returns true if user preference is set to 24-hour format.
* @param context the context to use for the content resolver
@@ -198,20 +205,34 @@ public class DateFormat {
Settings.System.TIME_12_24);
if (value == null) {
+ Locale locale = context.getResources().getConfiguration().locale;
+
+ synchronized (sLocaleLock) {
+ if (sIs24HourLocale != null && sIs24HourLocale.equals(locale)) {
+ return sIs24Hour;
+ }
+ }
+
java.text.DateFormat natural =
java.text.DateFormat.getTimeInstance(
- java.text.DateFormat.LONG,
- context.getResources().getConfiguration().locale);
+ java.text.DateFormat.LONG, locale);
if (natural instanceof SimpleDateFormat) {
SimpleDateFormat sdf = (SimpleDateFormat) natural;
String pattern = sdf.toPattern();
if (pattern.indexOf('H') >= 0) {
- return true;
+ value = "24";
} else {
- return false;
+ value = "12";
}
+ } else {
+ value = "12";
+ }
+
+ synchronized (sLocaleLock) {
+ sIs24HourLocale = locale;
+ sIs24Hour = !value.equals("12");
}
}
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index feae6cf..8a7cdd9 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -595,6 +595,17 @@ public class DateUtils
* @param elapsedSeconds the elapsed time in seconds.
*/
public static String formatElapsedTime(long elapsedSeconds) {
+ return formatElapsedTime(null, elapsedSeconds);
+ }
+
+ /**
+ * Formats an elapsed time in the form "MM:SS" or "H:MM:SS"
+ * for display on the call-in-progress screen.
+ *
+ * @param recycle {@link StringBuilder} to recycle, if possible
+ * @param elapsedSeconds the elapsed time in seconds.
+ */
+ public static String formatElapsedTime(StringBuilder recycle, long elapsedSeconds) {
initFormatStrings();
long hours = 0;
@@ -613,18 +624,24 @@ public class DateUtils
String result;
if (hours > 0) {
- return formatElapsedTime(sElapsedFormatHMMSS, hours, minutes, seconds);
+ return formatElapsedTime(recycle, sElapsedFormatHMMSS, hours, minutes, seconds);
} else {
- return formatElapsedTime(sElapsedFormatMMSS, minutes, seconds);
+ return formatElapsedTime(recycle, sElapsedFormatMMSS, minutes, seconds);
}
}
/**
* Fast formatting of h:mm:ss
*/
- private static String formatElapsedTime(String format, long hours, long minutes, long seconds) {
+ private static String formatElapsedTime(StringBuilder recycle, String format, long hours,
+ long minutes, long seconds) {
if (FAST_FORMAT_HMMSS.equals(format)) {
- StringBuffer sb = new StringBuffer(16);
+ StringBuilder sb = recycle;
+ if (sb == null) {
+ sb = new StringBuilder(8);
+ } else {
+ sb.setLength(0);
+ }
sb.append(hours);
sb.append(TIME_SEPARATOR);
if (minutes < 10) {
@@ -649,9 +666,15 @@ public class DateUtils
/**
* Fast formatting of m:ss
*/
- private static String formatElapsedTime(String format, long minutes, long seconds) {
+ private static String formatElapsedTime(StringBuilder recycle, String format, long minutes,
+ long seconds) {
if (FAST_FORMAT_MMSS.equals(format)) {
- StringBuffer sb = new StringBuffer(16);
+ StringBuilder sb = recycle;
+ if (sb == null) {
+ sb = new StringBuilder(8);
+ } else {
+ sb.setLength(0);
+ }
if (minutes < 10) {
sb.append(TIME_PADDING);
} else {
@@ -1028,8 +1051,9 @@ public class DateUtils
* If FORMAT_NO_YEAR is set, then the year is not shown.
* If neither FORMAT_SHOW_YEAR nor FORMAT_NO_YEAR are set, then the year
* is shown only if it is different from the current year, or if the start
- * and end dates fall on different years.
- *
+ * and end dates fall on different years. If both are set,
+ * FORMAT_SHOW_YEAR takes precedence.
+ *
* <p>
* Normally the date is shown unless the start and end day are the same.
* If FORMAT_SHOW_DATE is set, then the date is always shown, even for
@@ -1120,24 +1144,28 @@ public class DateUtils
boolean abbrevMonth = (flags & (FORMAT_ABBREV_MONTH | FORMAT_ABBREV_ALL)) != 0;
boolean noMonthDay = (flags & FORMAT_NO_MONTH_DAY) != 0;
boolean numericDate = (flags & FORMAT_NUMERIC_DATE) != 0;
-
- Time startDate;
+
+ // If we're getting called with a single instant in time (from
+ // e.g. formatDateTime(), below), then we can skip a lot of
+ // computation below that'd otherwise be thrown out.
+ boolean isInstant = (startMillis == endMillis);
+
+ Time startDate = useUTC ? new Time(Time.TIMEZONE_UTC) : new Time();
+ startDate.set(startMillis);
+
Time endDate;
-
- if (useUTC) {
- startDate = new Time(Time.TIMEZONE_UTC);
- endDate = new Time(Time.TIMEZONE_UTC);
+ int dayDistance;
+ if (isInstant) {
+ endDate = startDate;
+ dayDistance = 0;
} else {
- startDate = new Time();
- endDate = new Time();
+ endDate = useUTC ? new Time(Time.TIMEZONE_UTC) : new Time();
+ endDate.set(endMillis);
+ int startJulianDay = Time.getJulianDay(startMillis, startDate.gmtoff);
+ int endJulianDay = Time.getJulianDay(endMillis, endDate.gmtoff);
+ dayDistance = endJulianDay - startJulianDay;
}
-
- startDate.set(startMillis);
- endDate.set(endMillis);
- int startJulianDay = Time.getJulianDay(startMillis, startDate.gmtoff);
- int endJulianDay = Time.getJulianDay(endMillis, endDate.gmtoff);
- int dayDistance = endJulianDay - startJulianDay;
-
+
// If the end date ends at 12am at the beginning of a day,
// then modify it to make it look like it ends at midnight on
// the previous day. This will allow us to display "8pm - midnight",
@@ -1152,20 +1180,21 @@ public class DateUtils
// and an end date of Nov 12 at 00:00.
// If the start and end time are the same, then skip this and don't
// adjust the date.
- if ((endDate.hour | endDate.minute | endDate.second) == 0
- && (!showTime || dayDistance <= 1) && (startMillis != endMillis)) {
+ if (!isInstant
+ && (endDate.hour | endDate.minute | endDate.second) == 0
+ && (!showTime || dayDistance <= 1)) {
endDate.monthDay -= 1;
endDate.normalize(true /* ignore isDst */);
}
-
+
int startDay = startDate.monthDay;
int startMonthNum = startDate.month;
int startYear = startDate.year;
-
+
int endDay = endDate.monthDay;
int endMonthNum = endDate.month;
int endYear = endDate.year;
-
+
String startWeekDayString = "";
String endWeekDayString = "";
if (showWeekDay) {
@@ -1176,9 +1205,9 @@ public class DateUtils
weekDayFormat = WEEKDAY_FORMAT;
}
startWeekDayString = startDate.format(weekDayFormat);
- endWeekDayString = endDate.format(weekDayFormat);
+ endWeekDayString = isInstant ? startWeekDayString : endDate.format(weekDayFormat);
}
-
+
String startTimeString = "";
String endTimeString = "";
if (showTime) {
@@ -1204,7 +1233,7 @@ public class DateUtils
boolean capNoon = (flags & FORMAT_CAP_NOON) != 0;
boolean noMidnight = (flags & FORMAT_NO_MIDNIGHT) != 0;
boolean capMidnight = (flags & FORMAT_CAP_MIDNIGHT) != 0;
-
+
boolean startOnTheHour = startDate.minute == 0 && startDate.second == 0;
boolean endOnTheHour = endDate.minute == 0 && endDate.second == 0;
if (abbrevTime && startOnTheHour) {
@@ -1220,20 +1249,41 @@ public class DateUtils
startTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm);
}
}
- if (abbrevTime && endOnTheHour) {
- if (capAMPM) {
- endTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm);
+
+ // Don't waste time on setting endTimeFormat when
+ // we're dealing with an instant, where we'll never
+ // need the end point. (It's the same as the start
+ // point)
+ if (!isInstant) {
+ if (abbrevTime && endOnTheHour) {
+ if (capAMPM) {
+ endTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm);
+ } else {
+ endTimeFormat = res.getString(com.android.internal.R.string.hour_ampm);
+ }
} else {
- endTimeFormat = res.getString(com.android.internal.R.string.hour_ampm);
+ if (capAMPM) {
+ endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm);
+ } else {
+ endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm);
+ }
}
- } else {
- if (capAMPM) {
- endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm);
- } else {
- endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm);
+
+ if (endDate.hour == 12 && endOnTheHour && !noNoon) {
+ if (capNoon) {
+ endTimeFormat = res.getString(com.android.internal.R.string.Noon);
+ } else {
+ endTimeFormat = res.getString(com.android.internal.R.string.noon);
+ }
+ } else if (endDate.hour == 0 && endOnTheHour && !noMidnight) {
+ if (capMidnight) {
+ endTimeFormat = res.getString(com.android.internal.R.string.Midnight);
+ } else {
+ endTimeFormat = res.getString(com.android.internal.R.string.midnight);
+ }
}
}
-
+
if (startDate.hour == 12 && startOnTheHour && !noNoon) {
if (capNoon) {
startTimeFormat = res.getString(com.android.internal.R.string.Noon);
@@ -1243,37 +1293,32 @@ public class DateUtils
// Don't show the start time starting at midnight. Show
// 12am instead.
}
-
- if (endDate.hour == 12 && endOnTheHour && !noNoon) {
- if (capNoon) {
- endTimeFormat = res.getString(com.android.internal.R.string.Noon);
- } else {
- endTimeFormat = res.getString(com.android.internal.R.string.noon);
- }
- } else if (endDate.hour == 0 && endOnTheHour && !noMidnight) {
- if (capMidnight) {
- endTimeFormat = res.getString(com.android.internal.R.string.Midnight);
- } else {
- endTimeFormat = res.getString(com.android.internal.R.string.midnight);
- }
- }
}
+
startTimeString = startDate.format(startTimeFormat);
- endTimeString = endDate.format(endTimeFormat);
+ endTimeString = isInstant ? startTimeString : endDate.format(endTimeFormat);
}
-
- // Get the current year
- long millis = System.currentTimeMillis();
- Time time = new Time();
- time.set(millis);
- int currentYear = time.year;
-
+
// Show the year if the user specified FORMAT_SHOW_YEAR or if
// the starting and end years are different from each other
// or from the current year. But don't show the year if the
- // user specified FORMAT_NO_YEAR;
- showYear = showYear || (!noYear && (startYear != endYear || startYear != currentYear));
-
+ // user specified FORMAT_NO_YEAR.
+ if (showYear) {
+ // No code... just a comment for clarity. Keep showYear
+ // on, as they enabled it with FORMAT_SHOW_YEAR. This
+ // takes precedence over them setting FORMAT_NO_YEAR.
+ } else if (noYear) {
+ // They explicitly didn't want a year.
+ showYear = false;
+ } else if (startYear != endYear) {
+ showYear = true;
+ } else {
+ // Show the year if it's not equal to the current year.
+ Time currentTime = new Time();
+ currentTime.setToNow();
+ showYear = startYear != currentTime.year;
+ }
+
String defaultDateFormat, fullFormat, dateRange;
if (numericDate) {
defaultDateFormat = res.getString(com.android.internal.R.string.numeric_date);
@@ -1306,7 +1351,7 @@ public class DateUtils
}
}
}
-
+
if (showWeekDay) {
if (showTime) {
fullFormat = res.getString(com.android.internal.R.string.wday1_date1_time1_wday2_date2_time2);
@@ -1320,20 +1365,20 @@ public class DateUtils
fullFormat = res.getString(com.android.internal.R.string.date1_date2);
}
}
-
+
if (noMonthDay && startMonthNum == endMonthNum) {
// Example: "January, 2008"
String startDateString = startDate.format(defaultDateFormat);
return startDateString;
}
-
+
if (startYear != endYear || noMonthDay) {
// Different year or we are not showing the month day number.
// Example: "December 31, 2007 - January 1, 2008"
// Or: "January - February, 2008"
String startDateString = startDate.format(defaultDateFormat);
String endDateString = endDate.format(defaultDateFormat);
-
+
// The values that are used in a fullFormat string are specified
// by position.
dateRange = String.format(fullFormat,
@@ -1341,7 +1386,7 @@ public class DateUtils
endWeekDayString, endDateString, endTimeString);
return dateRange;
}
-
+
// Get the month, day, and year strings for the start and end dates
String monthFormat;
if (numericDate) {
@@ -1354,16 +1399,17 @@ public class DateUtils
String startMonthString = startDate.format(monthFormat);
String startMonthDayString = startDate.format(MONTH_DAY_FORMAT);
String startYearString = startDate.format(YEAR_FORMAT);
- String endMonthString = endDate.format(monthFormat);
- String endMonthDayString = endDate.format(MONTH_DAY_FORMAT);
- String endYearString = endDate.format(YEAR_FORMAT);
-
+
+ String endMonthString = isInstant ? null : endDate.format(monthFormat);
+ String endMonthDayString = isInstant ? null : endDate.format(MONTH_DAY_FORMAT);
+ String endYearString = isInstant ? null : endDate.format(YEAR_FORMAT);
+
if (startMonthNum != endMonthNum) {
// Same year, different month.
// Example: "October 28 - November 3"
// or: "Wed, Oct 31 - Sat, Nov 3, 2007"
// or: "Oct 31, 8am - Sat, Nov 3, 2007, 5pm"
-
+
int index = 0;
if (showWeekDay) index = 1;
if (showYear) index += 2;
@@ -1371,7 +1417,7 @@ public class DateUtils
if (numericDate) index += 8;
int resId = sameYearTable[index];
fullFormat = res.getString(resId);
-
+
// The values that are used in a fullFormat string are specified
// by position.
dateRange = String.format(fullFormat,
@@ -1381,7 +1427,7 @@ public class DateUtils
endYearString, endTimeString);
return dateRange;
}
-
+
if (startDay != endDay) {
// Same month, different day.
int index = 0;
@@ -1391,7 +1437,7 @@ public class DateUtils
if (numericDate) index += 8;
int resId = sameMonthTable[index];
fullFormat = res.getString(resId);
-
+
// The values that are used in a fullFormat string are specified
// by position.
dateRange = String.format(fullFormat,
@@ -1401,19 +1447,19 @@ public class DateUtils
endYearString, endTimeString);
return dateRange;
}
-
+
// Same start and end day
boolean showDate = (flags & FORMAT_SHOW_DATE) != 0;
-
+
// If nothing was specified, then show the date.
if (!showTime && !showDate && !showWeekDay) showDate = true;
-
+
// Compute the time string (example: "10:00 - 11:00 am")
String timeString = "";
if (showTime) {
// If the start and end time are the same, then just show the
// start time.
- if (startMillis == endMillis) {
+ if (isInstant) {
// Same start and end time.
// Example: "10:15 AM"
timeString = startTimeString;
@@ -1423,7 +1469,7 @@ public class DateUtils
timeString = String.format(timeFormat, startTimeString, endTimeString);
}
}
-
+
// Figure out which full format to use.
fullFormat = "";
String dateString = "";
@@ -1457,7 +1503,7 @@ public class DateUtils
} else if (showTime) {
return timeString;
}
-
+
// The values that are used in a fullFormat string are specified
// by position.
dateRange = String.format(fullFormat, timeString, startWeekDayString, dateString);
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index 5bf9b20..daa99c2 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -394,6 +394,7 @@ public class Time {
*
* @param s the string to parse
* @return true if the resulting time value is in UTC time
+ * @throws android.util.TimeFormatException if s cannot be parsed.
*/
public boolean parse(String s) {
if (nativeParse(s)) {
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 7457439..17c7a6c 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -16,6 +16,7 @@
package android.text.method;
+import android.util.Log;
import android.view.KeyEvent;
import android.text.*;
import android.widget.TextView;
@@ -131,6 +132,16 @@ implements MovementMethod
}
public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) {
+ if (executeDown(widget, buffer, keyCode)) {
+ MetaKeyKeyListener.adjustMetaAfterKeypress(buffer);
+ MetaKeyKeyListener.resetLockedMeta(buffer);
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean executeDown(TextView widget, Spannable buffer, int keyCode) {
boolean handled = false;
switch (keyCode) {
@@ -170,6 +181,20 @@ implements MovementMethod
return false;
}
+ public boolean onKeyOther(TextView view, Spannable text, KeyEvent event) {
+ int code = event.getKeyCode();
+ if (code != KeyEvent.KEYCODE_UNKNOWN
+ && event.getAction() == KeyEvent.ACTION_MULTIPLE) {
+ int repeat = event.getRepeatCount();
+ boolean handled = false;
+ while ((--repeat) > 0) {
+ handled |= executeDown(view, text, code);
+ }
+ return handled;
+ }
+ return false;
+ }
+
public boolean onTrackballEvent(TextView widget, Spannable text,
MotionEvent event) {
return false;
@@ -179,7 +204,7 @@ implements MovementMethod
MotionEvent event) {
boolean handled = Touch.onTouchEvent(widget, buffer, event);
- if (widget.isFocused()) {
+ if (widget.isFocused() && !widget.didTouchFocusSelect()) {
if (event.getAction() == MotionEvent.ACTION_UP) {
int x = (int) event.getX();
int y = (int) event.getY();
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index a875368..6df6a3a 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -18,7 +18,6 @@ package android.text.method;
import android.view.KeyEvent;
import android.view.View;
-import android.text.InputType;
import android.text.*;
import android.text.method.TextKeyListener.Capitalize;
import android.widget.TextView;
@@ -26,7 +25,7 @@ import android.widget.TextView;
public abstract class BaseKeyListener
extends MetaKeyKeyListener
implements KeyListener {
- /* package */ static final Object OLD_SEL_START = new Object();
+ /* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete();
/**
* Performs the action that happens when you press the DEL key in
@@ -127,5 +126,35 @@ implements KeyListener {
return super.onKeyDown(view, content, keyCode, event);
}
+
+ /**
+ * Base implementation handles ACTION_MULTIPLE KEYCODE_UNKNOWN by inserting
+ * the event's text into the content.
+ */
+ public boolean onKeyOther(View view, Editable content, KeyEvent event) {
+ if (event.getAction() != KeyEvent.ACTION_MULTIPLE
+ || event.getKeyCode() != KeyEvent.KEYCODE_UNKNOWN) {
+ // Not something we are interested in.
+ return false;
+ }
+
+ int selStart, selEnd;
+
+ {
+ int a = Selection.getSelectionStart(content);
+ int b = Selection.getSelectionEnd(content);
+
+ selStart = Math.min(a, b);
+ selEnd = Math.max(a, b);
+ }
+
+ CharSequence text = event.getCharacters();
+ if (text == null) {
+ return false;
+ }
+
+ content.replace(selStart, selEnd, text);
+ return true;
+ }
}
diff --git a/core/java/android/text/method/KeyListener.java b/core/java/android/text/method/KeyListener.java
index 4ae6191..8594852 100644
--- a/core/java/android/text/method/KeyListener.java
+++ b/core/java/android/text/method/KeyListener.java
@@ -66,6 +66,13 @@ public interface KeyListener {
int keyCode, KeyEvent event);
/**
+ * If the key listener wants to other kinds of key events, return true,
+ * otherwise return false and the caller (i.e. the widget host)
+ * will handle the key.
+ */
+ public boolean onKeyOther(View view, Editable text, KeyEvent event);
+
+ /**
* Remove the given shift states from the edited text.
*/
public void clearMetaKeyState(View view, Editable content, int states);
diff --git a/core/java/android/text/method/LinkMovementMethod.java b/core/java/android/text/method/LinkMovementMethod.java
index 92ac531..22e9cc6 100644
--- a/core/java/android/text/method/LinkMovementMethod.java
+++ b/core/java/android/text/method/LinkMovementMethod.java
@@ -252,5 +252,5 @@ extends ScrollingMovementMethod
}
private static LinkMovementMethod sInstance;
- private static Object FROM_BELOW = new Object();
+ private static Object FROM_BELOW = new NoCopySpan.Concrete();
}
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index d5a473b..61ec67f 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -71,10 +71,10 @@ public abstract class MetaKeyKeyListener {
| META_SYM_LOCKED | META_SYM_USED
| META_SYM_PRESSED | META_SYM_RELEASED;
- private static final Object CAP = new Object();
- private static final Object ALT = new Object();
- private static final Object SYM = new Object();
- private static final Object SELECTING = new Object();
+ private static final Object CAP = new NoCopySpan.Concrete();
+ private static final Object ALT = new NoCopySpan.Concrete();
+ private static final Object SYM = new NoCopySpan.Concrete();
+ private static final Object SELECTING = new NoCopySpan.Concrete();
/**
* Resets all meta state to inactive.
@@ -159,13 +159,21 @@ public abstract class MetaKeyKeyListener {
/**
* Returns true if this object is one that this class would use to
- * keep track of meta state in the specified text.
+ * keep track of any meta state in the specified text.
*/
public static boolean isMetaTracker(CharSequence text, Object what) {
return what == CAP || what == ALT || what == SYM ||
what == SELECTING;
}
+ /**
+ * Returns true if this object is one that this class would use to
+ * keep track of the selecting meta state in the specified text.
+ */
+ public static boolean isSelectingMetaTracker(CharSequence text, Object what) {
+ return what == SELECTING;
+ }
+
private static void adjust(Spannable content, Object what) {
int current = content.getSpanFlags(what);
@@ -283,10 +291,14 @@ public abstract class MetaKeyKeyListener {
}
public void clearMetaKeyState(View view, Editable content, int states) {
- if ((states&META_SHIFT_ON) != 0) resetLock(content, CAP);
- if ((states&META_ALT_ON) != 0) resetLock(content, ALT);
- if ((states&META_SYM_ON) != 0) resetLock(content, SYM);
- if ((states&META_SELECTING) != 0) resetLock(content, SELECTING);
+ clearMetaKeyState(content, states);
+ }
+
+ public static void clearMetaKeyState(Editable content, int states) {
+ if ((states&META_SHIFT_ON) != 0) content.removeSpan(CAP);
+ if ((states&META_ALT_ON) != 0) content.removeSpan(ALT);
+ if ((states&META_SYM_ON) != 0) content.removeSpan(SYM);
+ if ((states&META_SELECTING) != 0) content.removeSpan(SELECTING);
}
/**
diff --git a/core/java/android/text/method/MovementMethod.java b/core/java/android/text/method/MovementMethod.java
index 9e37e59..29f67a1 100644
--- a/core/java/android/text/method/MovementMethod.java
+++ b/core/java/android/text/method/MovementMethod.java
@@ -26,6 +26,14 @@ public interface MovementMethod
public void initialize(TextView widget, Spannable text);
public boolean onKeyDown(TextView widget, Spannable text, int keyCode, KeyEvent event);
public boolean onKeyUp(TextView widget, Spannable text, int keyCode, KeyEvent event);
+
+ /**
+ * If the key listener wants to other kinds of key events, return true,
+ * otherwise return false and the caller (i.e. the widget host)
+ * will handle the key.
+ */
+ public boolean onKeyOther(TextView view, Spannable text, KeyEvent event);
+
public void onTakeFocus(TextView widget, Spannable text, int direction);
public boolean onTrackballEvent(TextView widget, Spannable text,
MotionEvent event);
diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java
index 348b658..9270ca5 100644
--- a/core/java/android/text/method/NumberKeyListener.java
+++ b/core/java/android/text/method/NumberKeyListener.java
@@ -24,7 +24,6 @@ import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
-import android.util.SparseIntArray;
/**
* For numeric text entry
@@ -102,6 +101,11 @@ public abstract class NumberKeyListener extends BaseKeyListener
selEnd = Math.max(a, b);
}
+ if (selStart < 0 || selEnd < 0) {
+ selStart = selEnd = 0;
+ Selection.setSelection(content, 0);
+ }
+
int i = event != null ? lookup(event, content) : 0;
int repeatCount = event != null ? event.getRepeatCount() : 0;
if (repeatCount == 0) {
diff --git a/core/java/android/text/method/PasswordTransformationMethod.java b/core/java/android/text/method/PasswordTransformationMethod.java
index edaa836..fad4f64 100644
--- a/core/java/android/text/method/PasswordTransformationMethod.java
+++ b/core/java/android/text/method/PasswordTransformationMethod.java
@@ -22,6 +22,7 @@ import android.graphics.Rect;
import android.view.View;
import android.text.Editable;
import android.text.GetChars;
+import android.text.NoCopySpan;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.Selection;
@@ -104,8 +105,10 @@ implements TransformationMethod, TextWatcher
sp.removeSpan(old[i]);
}
- sp.setSpan(new Visible(sp, this), start, start + count,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ if (count == 1) {
+ sp.setSpan(new Visible(sp, this), start, start + count,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
}
}
}
@@ -249,7 +252,8 @@ implements TransformationMethod, TextWatcher
* Used to stash a reference back to the View in the Editable so we
* can use it to check the settings.
*/
- private static class ViewReference extends WeakReference<View> {
+ private static class ViewReference extends WeakReference<View>
+ implements NoCopySpan {
public ViewReference(View v) {
super(v);
}
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 863b2e2..21bc2a6 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -16,18 +16,12 @@
package android.text.method;
-import android.os.Message;
-import android.os.Handler;
import android.text.*;
import android.text.method.TextKeyListener.Capitalize;
import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.widget.TextView;
-
-import java.util.HashMap;
/**
* This is the standard key listener for alphabetic input on qwerty
@@ -302,21 +296,30 @@ public class QwertyKeyListener extends BaseKeyListener {
String old = new String(repl[0].mText);
content.removeSpan(repl[0]);
- content.setSpan(TextKeyListener.INHIBIT_REPLACEMENT,
- en, en, Spannable.SPAN_POINT_POINT);
- content.replace(st, en, old);
- en = content.getSpanStart(TextKeyListener.INHIBIT_REPLACEMENT);
- if (en - 1 >= 0) {
+ // only cancel the autocomplete if the cursor is at the end of
+ // the replaced span (or after it, because the user is
+ // backspacing over the space after the word, not the word
+ // itself).
+ if (selStart >= en) {
content.setSpan(TextKeyListener.INHIBIT_REPLACEMENT,
- en - 1, en,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ en, en, Spannable.SPAN_POINT_POINT);
+ content.replace(st, en, old);
+
+ en = content.getSpanStart(TextKeyListener.INHIBIT_REPLACEMENT);
+ if (en - 1 >= 0) {
+ content.setSpan(TextKeyListener.INHIBIT_REPLACEMENT,
+ en - 1, en,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ } else {
+ content.removeSpan(TextKeyListener.INHIBIT_REPLACEMENT);
+ }
+ adjustMetaAfterKeypress(content);
} else {
- content.removeSpan(TextKeyListener.INHIBIT_REPLACEMENT);
+ adjustMetaAfterKeypress(content);
+ return super.onKeyDown(view, content, keyCode, event);
}
- adjustMetaAfterKeypress(content);
-
return true;
}
}
@@ -442,7 +445,7 @@ public class QwertyKeyListener extends BaseKeyListener {
return Character.toUpperCase(src.charAt(0)) + src.substring(1);
}
- /* package */ static class Replaced
+ /* package */ static class Replaced implements NoCopySpan
{
public Replaced(char[] text) {
mText = text;
diff --git a/core/java/android/text/method/ScrollingMovementMethod.java b/core/java/android/text/method/ScrollingMovementMethod.java
index db470be..563ceed 100644
--- a/core/java/android/text/method/ScrollingMovementMethod.java
+++ b/core/java/android/text/method/ScrollingMovementMethod.java
@@ -144,6 +144,10 @@ implements MovementMethod
}
public boolean onKeyDown(TextView widget, Spannable buffer, int keyCode, KeyEvent event) {
+ return executeDown(widget, buffer, keyCode);
+ }
+
+ private boolean executeDown(TextView widget, Spannable buffer, int keyCode) {
boolean handled = false;
switch (keyCode) {
@@ -171,6 +175,26 @@ implements MovementMethod
return false;
}
+ public boolean onKeyOther(TextView view, Spannable text, KeyEvent event) {
+ int code = event.getKeyCode();
+ if (code != KeyEvent.KEYCODE_UNKNOWN
+ && event.getAction() == KeyEvent.ACTION_MULTIPLE) {
+ int repeat = event.getRepeatCount();
+ boolean first = true;
+ boolean handled = false;
+ while ((--repeat) > 0) {
+ if (first && executeDown(view, text, code)) {
+ handled = true;
+ MetaKeyKeyListener.adjustMetaAfterKeypress(text);
+ MetaKeyKeyListener.resetLockedMeta(text);
+ }
+ first = false;
+ }
+ return handled;
+ }
+ return false;
+ }
+
public boolean onTrackballEvent(TextView widget, Spannable text,
MotionEvent event) {
return false;
diff --git a/core/java/android/text/method/SingleLineTransformationMethod.java b/core/java/android/text/method/SingleLineTransformationMethod.java
index a4fcf15..6a05fe4 100644
--- a/core/java/android/text/method/SingleLineTransformationMethod.java
+++ b/core/java/android/text/method/SingleLineTransformationMethod.java
@@ -27,22 +27,24 @@ import android.view.View;
/**
* This transformation method causes any newline characters (\n) to be
- * displayed as spaces instead of causing line breaks.
+ * displayed as spaces instead of causing line breaks, and causes
+ * carriage return characters (\r) to have no appearance.
*/
public class SingleLineTransformationMethod
extends ReplacementTransformationMethod {
- private static char[] ORIGINAL = new char[] { '\n' };
- private static char[] REPLACEMENT = new char[] { ' ' };
+ private static char[] ORIGINAL = new char[] { '\n', '\r' };
+ private static char[] REPLACEMENT = new char[] { ' ', '\uFEFF' };
/**
- * The character to be replaced is \n.
+ * The characters to be replaced are \n and \r.
*/
protected char[] getOriginal() {
return ORIGINAL;
}
/**
- * The character \n is replaced with is space.
+ * The character \n is replaced with is space;
+ * the character \r is replaced with is FEFF (zero width space).
*/
protected char[] getReplacement() {
return REPLACEMENT;
diff --git a/core/java/android/text/method/TextKeyListener.java b/core/java/android/text/method/TextKeyListener.java
index b1c380a..5be2a48 100644
--- a/core/java/android/text/method/TextKeyListener.java
+++ b/core/java/android/text/method/TextKeyListener.java
@@ -38,10 +38,10 @@ public class TextKeyListener extends BaseKeyListener implements SpanWatcher {
private static TextKeyListener[] sInstance =
new TextKeyListener[Capitalize.values().length * 2];
- /* package */ static final Object ACTIVE = new Object();
- /* package */ static final Object CAPPED = new Object();
- /* package */ static final Object INHIBIT_REPLACEMENT = new Object();
- /* package */ static final Object LAST_TYPED = new Object();
+ /* package */ static final Object ACTIVE = new NoCopySpan.Concrete();
+ /* package */ static final Object CAPPED = new NoCopySpan.Concrete();
+ /* package */ static final Object INHIBIT_REPLACEMENT = new NoCopySpan.Concrete();
+ /* package */ static final Object LAST_TYPED = new NoCopySpan.Concrete();
private Capitalize mAutoCap;
private boolean mAutoText;
@@ -140,6 +140,13 @@ public class TextKeyListener extends BaseKeyListener implements SpanWatcher {
return im.onKeyUp(view, content, keyCode, event);
}
+ @Override
+ public boolean onKeyOther(View view, Editable content, KeyEvent event) {
+ KeyListener im = getKeyListener(event);
+
+ return im.onKeyOther(view, content, event);
+ }
+
/**
* Clear all the input state (autotext, autocap, multitap, undo)
* from the specified Editable, going beyond Editable.clear(), which
@@ -205,6 +212,10 @@ public class TextKeyListener extends BaseKeyListener implements SpanWatcher {
return false;
}
+ public boolean onKeyOther(View view, Editable content, KeyEvent event) {
+ return false;
+ }
+
public void clearMetaKeyState(View view, Editable content, int states) {
}
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index 8b097c5..65036ad 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -17,6 +17,7 @@
package android.text.method;
import android.text.Layout;
+import android.text.NoCopySpan;
import android.text.Layout.Alignment;
import android.text.Spannable;
import android.view.MotionEvent;
@@ -103,7 +104,7 @@ public class Touch {
if (ds.length > 0) {
if (ds[0].mFarEnough == false) {
- int slop = ViewConfiguration.getTouchSlop();
+ int slop = ViewConfiguration.get(widget.getContext()).getScaledTouchSlop();
if (Math.abs(event.getX() - ds[0].mX) >= slop ||
Math.abs(event.getY() - ds[0].mY) >= slop) {
@@ -141,7 +142,7 @@ public class Touch {
return false;
}
- private static class DragState {
+ private static class DragState implements NoCopySpan {
public float mX;
public float mY;
public boolean mFarEnough;
diff --git a/core/java/android/text/style/AbsoluteSizeSpan.java b/core/java/android/text/style/AbsoluteSizeSpan.java
index 8f6ed5a..484f8ce 100644
--- a/core/java/android/text/style/AbsoluteSizeSpan.java
+++ b/core/java/android/text/style/AbsoluteSizeSpan.java
@@ -16,17 +16,35 @@
package android.text.style;
-import android.graphics.Paint;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
-public class AbsoluteSizeSpan extends MetricAffectingSpan {
+public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableSpan {
- private int mSize;
+ private final int mSize;
public AbsoluteSizeSpan(int size) {
mSize = size;
}
+ public AbsoluteSizeSpan(Parcel src) {
+ mSize = src.readInt();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.ABSOLUTE_SIZE_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mSize);
+ }
+
public int getSize() {
return mSize;
}
diff --git a/core/java/android/text/style/AlignmentSpan.java b/core/java/android/text/style/AlignmentSpan.java
index d51edcc..b8a37da 100644
--- a/core/java/android/text/style/AlignmentSpan.java
+++ b/core/java/android/text/style/AlignmentSpan.java
@@ -16,24 +16,40 @@
package android.text.style;
+import android.os.Parcel;
import android.text.Layout;
+import android.text.ParcelableSpan;
+import android.text.TextUtils;
-public interface AlignmentSpan
-extends ParagraphStyle
-{
+public interface AlignmentSpan extends ParagraphStyle {
public Layout.Alignment getAlignment();
public static class Standard
- implements AlignmentSpan
- {
+ implements AlignmentSpan, ParcelableSpan {
public Standard(Layout.Alignment align) {
mAlignment = align;
}
+ public Standard(Parcel src) {
+ mAlignment = Layout.Alignment.valueOf(src.readString());
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.ALIGNMENT_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mAlignment.name());
+ }
+
public Layout.Alignment getAlignment() {
return mAlignment;
}
- private Layout.Alignment mAlignment;
+ private final Layout.Alignment mAlignment;
}
}
diff --git a/core/java/android/text/style/BackgroundColorSpan.java b/core/java/android/text/style/BackgroundColorSpan.java
index 27eda69..580a369 100644
--- a/core/java/android/text/style/BackgroundColorSpan.java
+++ b/core/java/android/text/style/BackgroundColorSpan.java
@@ -16,16 +16,36 @@
package android.text.style;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
-public class BackgroundColorSpan extends CharacterStyle implements UpdateAppearance {
+public class BackgroundColorSpan extends CharacterStyle
+ implements UpdateAppearance, ParcelableSpan {
- private int mColor;
+ private final int mColor;
public BackgroundColorSpan(int color) {
mColor = color;
}
+ public BackgroundColorSpan(Parcel src) {
+ mColor = src.readInt();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.BACKGROUND_COLOR_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mColor);
+ }
+
public int getBackgroundColor() {
return mColor;
}
diff --git a/core/java/android/text/style/BulletSpan.java b/core/java/android/text/style/BulletSpan.java
index 70c4d33..655bd81 100644
--- a/core/java/android/text/style/BulletSpan.java
+++ b/core/java/android/text/style/BulletSpan.java
@@ -18,17 +18,30 @@ package android.text.style;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.os.Parcel;
import android.text.Layout;
+import android.text.ParcelableSpan;
import android.text.Spanned;
+import android.text.TextUtils;
-public class BulletSpan implements LeadingMarginSpan {
+public class BulletSpan implements LeadingMarginSpan, ParcelableSpan {
+ private final int mGapWidth;
+ private final boolean mWantColor;
+ private final int mColor;
+
+ private static final int BULLET_RADIUS = 3;
+ public static final int STANDARD_GAP_WIDTH = 2;
public BulletSpan() {
mGapWidth = STANDARD_GAP_WIDTH;
+ mWantColor = false;
+ mColor = 0;
}
public BulletSpan(int gapWidth) {
mGapWidth = gapWidth;
+ mWantColor = false;
+ mColor = 0;
}
public BulletSpan(int gapWidth, int color) {
@@ -37,6 +50,26 @@ public class BulletSpan implements LeadingMarginSpan {
mColor = color;
}
+ public BulletSpan(Parcel src) {
+ mGapWidth = src.readInt();
+ mWantColor = src.readInt() != 0;
+ mColor = src.readInt();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.BULLET_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mGapWidth);
+ dest.writeInt(mWantColor ? 1 : 0);
+ dest.writeInt(mColor);
+ }
+
public int getLeadingMargin(boolean first) {
return 2 * BULLET_RADIUS + mGapWidth;
}
@@ -66,11 +99,4 @@ public class BulletSpan implements LeadingMarginSpan {
p.setStyle(style);
}
}
-
- private int mGapWidth;
- private boolean mWantColor;
- private int mColor;
-
- private static final int BULLET_RADIUS = 3;
- public static final int STANDARD_GAP_WIDTH = 2;
}
diff --git a/core/java/android/text/style/ForegroundColorSpan.java b/core/java/android/text/style/ForegroundColorSpan.java
index 99b3381..476124d 100644
--- a/core/java/android/text/style/ForegroundColorSpan.java
+++ b/core/java/android/text/style/ForegroundColorSpan.java
@@ -16,16 +16,36 @@
package android.text.style;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
-public class ForegroundColorSpan extends CharacterStyle implements UpdateAppearance {
+public class ForegroundColorSpan extends CharacterStyle
+ implements UpdateAppearance, ParcelableSpan {
- private int mColor;
+ private final int mColor;
public ForegroundColorSpan(int color) {
mColor = color;
}
+ public ForegroundColorSpan(Parcel src) {
+ mColor = src.readInt();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.FOREGROUND_COLOR_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mColor);
+ }
+
public int getForegroundColor() {
return mColor;
}
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index 2eebc0d..29c0c76 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -44,8 +44,9 @@ public class ImageSpan extends DynamicDrawableSpan {
public ImageSpan(Bitmap b, int verticalAlignment) {
super(verticalAlignment);
mDrawable = new BitmapDrawable(b);
- mDrawable.setBounds(0, 0, mDrawable.getIntrinsicWidth(),
- mDrawable.getIntrinsicHeight());
+ int width = mDrawable.getIntrinsicWidth();
+ int height = mDrawable.getIntrinsicHeight();
+ mDrawable.setBounds(0, 0, width > 0 ? width : 0, height > 0 ? height : 0);
}
public ImageSpan(Drawable d) {
@@ -87,6 +88,7 @@ public class ImageSpan extends DynamicDrawableSpan {
super(verticalAlignment);
mContext = context;
mContentUri = uri;
+ mSource = uri.toString();
}
public ImageSpan(Context context, int resourceId) {
@@ -116,6 +118,8 @@ public class ImageSpan extends DynamicDrawableSpan {
mContentUri);
bitmap = BitmapFactory.decodeStream(is);
drawable = new BitmapDrawable(bitmap);
+ drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight());
is.close();
} catch (Exception e) {
Log.e("sms", "Failed to loaded content " + mContentUri, e);
diff --git a/core/java/android/text/style/LeadingMarginSpan.java b/core/java/android/text/style/LeadingMarginSpan.java
index 85a27dc..8e212e3 100644
--- a/core/java/android/text/style/LeadingMarginSpan.java
+++ b/core/java/android/text/style/LeadingMarginSpan.java
@@ -18,7 +18,10 @@ package android.text.style;
import android.graphics.Paint;
import android.graphics.Canvas;
+import android.os.Parcel;
import android.text.Layout;
+import android.text.ParcelableSpan;
+import android.text.TextUtils;
public interface LeadingMarginSpan
extends ParagraphStyle
@@ -30,9 +33,9 @@ extends ParagraphStyle
CharSequence text, int start, int end,
boolean first, Layout layout);
- public static class Standard
- implements LeadingMarginSpan
- {
+ public static class Standard implements LeadingMarginSpan, ParcelableSpan {
+ private final int mFirst, mRest;
+
public Standard(int first, int rest) {
mFirst = first;
mRest = rest;
@@ -42,6 +45,24 @@ extends ParagraphStyle
this(every, every);
}
+ public Standard(Parcel src) {
+ mFirst = src.readInt();
+ mRest = src.readInt();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.LEADING_MARGIN_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mFirst);
+ dest.writeInt(mRest);
+ }
+
public int getLeadingMargin(boolean first) {
return first ? mFirst : mRest;
}
@@ -53,7 +74,5 @@ extends ParagraphStyle
boolean first, Layout layout) {
;
}
-
- private int mFirst, mRest;
}
}
diff --git a/core/java/android/text/style/QuoteSpan.java b/core/java/android/text/style/QuoteSpan.java
index 3f4a32f..29dd273 100644
--- a/core/java/android/text/style/QuoteSpan.java
+++ b/core/java/android/text/style/QuoteSpan.java
@@ -18,26 +18,43 @@ package android.text.style;
import android.graphics.Paint;
import android.graphics.Canvas;
-import android.graphics.RectF;
+import android.os.Parcel;
import android.text.Layout;
+import android.text.ParcelableSpan;
+import android.text.TextUtils;
-public class QuoteSpan
-implements LeadingMarginSpan
-{
+public class QuoteSpan implements LeadingMarginSpan, ParcelableSpan {
private static final int STRIPE_WIDTH = 2;
private static final int GAP_WIDTH = 2;
- private int mColor = 0xff0000ff;
+ private final int mColor;
public QuoteSpan() {
super();
+ mColor = 0xff0000ff;
}
public QuoteSpan(int color) {
- this();
+ super();
mColor = color;
}
+ public QuoteSpan(Parcel src) {
+ mColor = src.readInt();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.QUOTE_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mColor);
+ }
+
public int getColor() {
return mColor;
}
diff --git a/core/java/android/text/style/RelativeSizeSpan.java b/core/java/android/text/style/RelativeSizeSpan.java
index a8ad076..9717362 100644
--- a/core/java/android/text/style/RelativeSizeSpan.java
+++ b/core/java/android/text/style/RelativeSizeSpan.java
@@ -16,17 +16,35 @@
package android.text.style;
-import android.graphics.Paint;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
-public class RelativeSizeSpan extends MetricAffectingSpan {
+public class RelativeSizeSpan extends MetricAffectingSpan implements ParcelableSpan {
- private float mProportion;
+ private final float mProportion;
public RelativeSizeSpan(float proportion) {
mProportion = proportion;
}
+ public RelativeSizeSpan(Parcel src) {
+ mProportion = src.readFloat();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.RELATIVE_SIZE_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeFloat(mProportion);
+ }
+
public float getSizeChange() {
return mProportion;
}
diff --git a/core/java/android/text/style/ScaleXSpan.java b/core/java/android/text/style/ScaleXSpan.java
index ac9e35d..655064b 100644
--- a/core/java/android/text/style/ScaleXSpan.java
+++ b/core/java/android/text/style/ScaleXSpan.java
@@ -16,17 +16,35 @@
package android.text.style;
-import android.graphics.Paint;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
-public class ScaleXSpan extends MetricAffectingSpan {
+public class ScaleXSpan extends MetricAffectingSpan implements ParcelableSpan {
- private float mProportion;
+ private final float mProportion;
public ScaleXSpan(float proportion) {
mProportion = proportion;
}
+ public ScaleXSpan(Parcel src) {
+ mProportion = src.readFloat();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.SCALE_X_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeFloat(mProportion);
+ }
+
public float getScaleX() {
return mProportion;
}
diff --git a/core/java/android/text/style/StrikethroughSpan.java b/core/java/android/text/style/StrikethroughSpan.java
index dd430e5..b51363a 100644
--- a/core/java/android/text/style/StrikethroughSpan.java
+++ b/core/java/android/text/style/StrikethroughSpan.java
@@ -16,9 +16,29 @@
package android.text.style;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
-public class StrikethroughSpan extends CharacterStyle implements UpdateAppearance {
+public class StrikethroughSpan extends CharacterStyle
+ implements UpdateAppearance, ParcelableSpan {
+ public StrikethroughSpan() {
+ }
+
+ public StrikethroughSpan(Parcel src) {
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.STRIKETHROUGH_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ }
@Override
public void updateDrawState(TextPaint ds) {
diff --git a/core/java/android/text/style/StyleSpan.java b/core/java/android/text/style/StyleSpan.java
index cc8b06c..8e6147c 100644
--- a/core/java/android/text/style/StyleSpan.java
+++ b/core/java/android/text/style/StyleSpan.java
@@ -18,7 +18,10 @@ package android.text.style;
import android.graphics.Paint;
import android.graphics.Typeface;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
/**
*
@@ -28,9 +31,9 @@ import android.text.TextPaint;
* you get bold italic. You can't turn off a style from the base style.
*
*/
-public class StyleSpan extends MetricAffectingSpan {
+public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan {
- private int mStyle;
+ private final int mStyle;
/**
*
@@ -42,6 +45,22 @@ public class StyleSpan extends MetricAffectingSpan {
mStyle = style;
}
+ public StyleSpan(Parcel src) {
+ mStyle = src.readInt();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.STYLE_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mStyle);
+ }
+
/**
* Returns the style constant defined in {@link android.graphics.Typeface}.
*/
diff --git a/core/java/android/text/style/SubscriptSpan.java b/core/java/android/text/style/SubscriptSpan.java
index 78d6ba9..de1d8b2 100644
--- a/core/java/android/text/style/SubscriptSpan.java
+++ b/core/java/android/text/style/SubscriptSpan.java
@@ -16,9 +16,29 @@
package android.text.style;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
+
+public class SubscriptSpan extends MetricAffectingSpan implements ParcelableSpan {
+ public SubscriptSpan() {
+ }
+
+ public SubscriptSpan(Parcel src) {
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.SUBSCRIPT_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ }
-public class SubscriptSpan extends MetricAffectingSpan {
@Override
public void updateDrawState(TextPaint tp) {
tp.baselineShift -= (int) (tp.ascent() / 2);
diff --git a/core/java/android/text/style/SuperscriptSpan.java b/core/java/android/text/style/SuperscriptSpan.java
index 79be4de..285fe84 100644
--- a/core/java/android/text/style/SuperscriptSpan.java
+++ b/core/java/android/text/style/SuperscriptSpan.java
@@ -16,9 +16,29 @@
package android.text.style;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
+
+public class SuperscriptSpan extends MetricAffectingSpan implements ParcelableSpan {
+ public SuperscriptSpan() {
+ }
+
+ public SuperscriptSpan(Parcel src) {
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.SUPERSCRIPT_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ }
-public class SuperscriptSpan extends MetricAffectingSpan {
@Override
public void updateDrawState(TextPaint tp) {
tp.baselineShift += (int) (tp.ascent() / 2);
diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java
index c4ec976..de929e3 100644
--- a/core/java/android/text/style/TextAppearanceSpan.java
+++ b/core/java/android/text/style/TextAppearanceSpan.java
@@ -19,20 +19,22 @@ package android.text.style;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
-import android.graphics.Paint;
import android.graphics.Typeface;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
/**
* Sets the text color, size, style, and typeface to match a TextAppearance
* resource.
*/
-public class TextAppearanceSpan extends MetricAffectingSpan {
- private String mTypeface;
- private int mStyle;
- private int mTextSize;
- private ColorStateList mTextColor;
- private ColorStateList mTextColorLink;
+public class TextAppearanceSpan extends MetricAffectingSpan implements ParcelableSpan {
+ private final String mTypeface;
+ private final int mStyle;
+ private final int mTextSize;
+ private final ColorStateList mTextColor;
+ private final ColorStateList mTextColorLink;
/**
* Uses the specified TextAppearance resource to determine the
@@ -53,11 +55,13 @@ public class TextAppearanceSpan extends MetricAffectingSpan {
*/
public TextAppearanceSpan(Context context, int appearance,
int colorList) {
+ ColorStateList textColor;
+
TypedArray a =
context.obtainStyledAttributes(appearance,
com.android.internal.R.styleable.TextAppearance);
- mTextColor = a.getColorStateList(com.android.internal.R.styleable.
+ textColor = a.getColorStateList(com.android.internal.R.styleable.
TextAppearance_textColor);
mTextColorLink = a.getColorStateList(com.android.internal.R.styleable.
TextAppearance_textColorLink);
@@ -79,6 +83,10 @@ public class TextAppearanceSpan extends MetricAffectingSpan {
case 3:
mTypeface = "monospace";
break;
+
+ default:
+ mTypeface = null;
+ break;
}
a.recycle();
@@ -87,9 +95,11 @@ public class TextAppearanceSpan extends MetricAffectingSpan {
a = context.obtainStyledAttributes(com.android.internal.R.style.Theme,
com.android.internal.R.styleable.Theme);
- mTextColor = a.getColorStateList(colorList);
+ textColor = a.getColorStateList(colorList);
a.recycle();
}
+
+ mTextColor = textColor;
}
/**
@@ -105,6 +115,48 @@ public class TextAppearanceSpan extends MetricAffectingSpan {
mTextColorLink = linkColor;
}
+ public TextAppearanceSpan(Parcel src) {
+ mTypeface = src.readString();
+ mStyle = src.readInt();
+ mTextSize = src.readInt();
+ if (src.readInt() != 0) {
+ mTextColor = ColorStateList.CREATOR.createFromParcel(src);
+ } else {
+ mTextColor = null;
+ }
+ if (src.readInt() != 0) {
+ mTextColorLink = ColorStateList.CREATOR.createFromParcel(src);
+ } else {
+ mTextColorLink = null;
+ }
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.TEXT_APPEARANCE_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mTypeface);
+ dest.writeInt(mStyle);
+ dest.writeInt(mTextSize);
+ if (mTextColor != null) {
+ dest.writeInt(1);
+ mTextColor.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mTextColorLink != null) {
+ dest.writeInt(1);
+ mTextColorLink.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
/**
* Returns the typeface family specified by this span, or <code>null</code>
* if it does not specify one.
diff --git a/core/java/android/text/style/TypefaceSpan.java b/core/java/android/text/style/TypefaceSpan.java
index 7519ac2..f194060 100644
--- a/core/java/android/text/style/TypefaceSpan.java
+++ b/core/java/android/text/style/TypefaceSpan.java
@@ -18,13 +18,16 @@ package android.text.style;
import android.graphics.Paint;
import android.graphics.Typeface;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
/**
* Changes the typeface family of the text to which the span is attached.
*/
-public class TypefaceSpan extends MetricAffectingSpan {
- private String mFamily;
+public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan {
+ private final String mFamily;
/**
* @param family The font family for this typeface. Examples include
@@ -34,6 +37,22 @@ public class TypefaceSpan extends MetricAffectingSpan {
mFamily = family;
}
+ public TypefaceSpan(Parcel src) {
+ mFamily = src.readString();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.TYPEFACE_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mFamily);
+ }
+
/**
* Returns the font family name.
*/
diff --git a/core/java/android/text/style/URLSpan.java b/core/java/android/text/style/URLSpan.java
index 79809b5..d29bfb6 100644
--- a/core/java/android/text/style/URLSpan.java
+++ b/core/java/android/text/style/URLSpan.java
@@ -16,19 +16,39 @@
package android.text.style;
+import android.content.Context;
import android.content.Intent;
import android.net.Uri;
-import android.text.TextPaint;
+import android.os.Parcel;
+import android.provider.Browser;
+import android.text.ParcelableSpan;
+import android.text.TextUtils;
import android.view.View;
-public class URLSpan extends ClickableSpan {
+public class URLSpan extends ClickableSpan implements ParcelableSpan {
- private String mURL;
+ private final String mURL;
public URLSpan(String url) {
mURL = url;
}
+ public URLSpan(Parcel src) {
+ mURL = src.readString();
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.URL_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mURL);
+ }
+
public String getURL() {
return mURL;
}
@@ -36,8 +56,9 @@ public class URLSpan extends ClickableSpan {
@Override
public void onClick(View widget) {
Uri uri = Uri.parse(getURL());
+ Context context = widget.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- intent.addCategory(Intent.CATEGORY_BROWSABLE);
- widget.getContext().startActivity(intent);
+ intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
+ context.startActivity(intent);
}
}
diff --git a/core/java/android/text/style/UnderlineSpan.java b/core/java/android/text/style/UnderlineSpan.java
index ca6f10c..b0cb0e8 100644
--- a/core/java/android/text/style/UnderlineSpan.java
+++ b/core/java/android/text/style/UnderlineSpan.java
@@ -16,9 +16,29 @@
package android.text.style;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
import android.text.TextPaint;
+import android.text.TextUtils;
-public class UnderlineSpan extends CharacterStyle implements UpdateAppearance {
+public class UnderlineSpan extends CharacterStyle
+ implements UpdateAppearance, ParcelableSpan {
+ public UnderlineSpan() {
+ }
+
+ public UnderlineSpan(Parcel src) {
+ }
+
+ public int getSpanTypeId() {
+ return TextUtils.UNDERLINE_SPAN;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ }
@Override
public void updateDrawState(TextPaint ds) {
diff --git a/core/java/android/text/util/Regex.java b/core/java/android/text/util/Regex.java
index 4c128ad..a349b82 100644
--- a/core/java/android/text/util/Regex.java
+++ b/core/java/android/text/util/Regex.java
@@ -66,9 +66,9 @@ public class Regex {
public static final Pattern WEB_URL_PATTERN
= Pattern.compile(
"((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
- + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2}))+(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
- + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2}))+)?\\@)?)?"
- + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)+" // named host
+ + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+ + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+ + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+" // named host
+ "(?:" // plus top level domain
+ "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+ "|(?:biz|b[abdefghijmnorstvwyz])"
@@ -122,12 +122,12 @@ public class Regex {
public static final Pattern EMAIL_ADDRESS_PATTERN
= Pattern.compile(
- "[a-zA-Z0-9\\+\\.\\_\\%\\-]+" +
+ "[a-zA-Z0-9\\+\\.\\_\\%\\-]{1,256}" +
"\\@" +
- "[a-zA-Z0-9][a-zA-Z0-9\\-]*" +
+ "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
"(" +
"\\." +
- "[a-zA-Z0-9][a-zA-Z0-9\\-]*" +
+ "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
")+"
);
diff --git a/core/java/android/text/util/Rfc822Validator.java b/core/java/android/text/util/Rfc822Validator.java
index 9f03bb0..6a6bf69 100644
--- a/core/java/android/text/util/Rfc822Validator.java
+++ b/core/java/android/text/util/Rfc822Validator.java
@@ -16,6 +16,7 @@
package android.text.util;
+import android.text.TextUtils;
import android.widget.AutoCompleteTextView;
import java.util.regex.Pattern;
@@ -67,7 +68,7 @@ public class Rfc822Validator implements AutoCompleteTextView.Validator {
/**
* @return a string in which all the characters that are illegal for the username
- * part of the email address have been removed.
+ * or the domain name part of the email address have been removed.
*/
private String removeIllegalCharacters(String s) {
StringBuilder result = new StringBuilder();
@@ -101,6 +102,9 @@ public class Rfc822Validator implements AutoCompleteTextView.Validator {
* {@inheritDoc}
*/
public CharSequence fixText(CharSequence cs) {
+ // Return an empty string if the email address only contains spaces, \n or \t
+ if (TextUtils.getTrimmedLength(cs) == 0) return "";
+
Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(cs);
StringBuilder sb = new StringBuilder();
@@ -111,10 +115,10 @@ public class Rfc822Validator implements AutoCompleteTextView.Validator {
// If there is no @, just append the domain of the account
tokens[i].setAddress(removeIllegalCharacters(text) + "@" + mDomain);
} else {
- // Otherwise, remove everything right of the '@' and append the domain
- // ("a@b" becomes "a@gmail.com").
+ // Otherwise, remove the illegal characters on both sides of the '@'
String fix = removeIllegalCharacters(text.substring(0, index));
- tokens[i].setAddress(fix + "@" + mDomain);
+ String domain = removeIllegalCharacters(text.substring(index + 1));
+ tokens[i].setAddress(fix + "@" + (domain.length() != 0 ? domain : mDomain));
}
sb.append(tokens[i].toString());
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 8fc3602..9de4cbe 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -16,6 +16,8 @@
package android.util;
+import android.os.*;
+
/**
* A structure describing general information about a display, such as its
@@ -23,6 +25,16 @@ package android.util;
*/
public class DisplayMetrics {
/**
+ * The reference density used throughout the system.
+ *
+ * @hide Pending API council approval
+ */
+ public static final int DEFAULT_DENSITY = 160;
+
+ private static final int sLcdDensity = SystemProperties.getInt("ro.sf.lcd_density",
+ DEFAULT_DENSITY);
+
+ /**
* The absolute width of the display in pixels.
*/
public int widthPixels;
@@ -43,7 +55,9 @@ public class DisplayMetrics {
* example, a 240x320 screen will have a density of 1 even if its width is
* 1.8", 1.3", etc. However, if the screen resolution is increased to
* 320x480 but the screen size remained 1.5"x2" then the density would be
- * increased (probably to 1.5).
+ * increased (probably to 1.5).
+ *
+ * @see #DEFAULT_DENSITY
*/
public float density;
/**
@@ -60,7 +74,7 @@ public class DisplayMetrics {
* The exact physical pixels per inch of the screen in the Y dimension.
*/
public float ydpi;
-
+
public DisplayMetrics() {
}
@@ -76,10 +90,9 @@ public class DisplayMetrics {
public void setToDefaults() {
widthPixels = 0;
heightPixels = 0;
- density = 1;
- scaledDensity = 1;
- xdpi = 160;
- ydpi = 160;
+ density = sLcdDensity / (float) DEFAULT_DENSITY;
+ scaledDensity = density;
+ xdpi = sLcdDensity;
+ ydpi = sLcdDensity;
}
}
-
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index 610cfd4..9ab3b53 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -73,13 +73,20 @@ public class SparseIntArray {
int i = binarySearch(mKeys, 0, mSize, key);
if (i >= 0) {
- System.arraycopy(mKeys, i + 1, mKeys, i, mSize - (i + 1));
- System.arraycopy(mValues, i + 1, mValues, i, mSize - (i + 1));
- mSize--;
+ removeAt(i);
}
}
/**
+ * Removes the mapping at the given index.
+ */
+ public void removeAt(int index) {
+ System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
+ System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1));
+ mSize--;
+ }
+
+ /**
* Adds a mapping from the specified key to the specified value,
* replacing the previous mapping from the specified key if there
* was one.
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index a4ee35a..d4ba9e2 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -16,9 +16,6 @@
package android.util;
-import android.util.Config;
-import android.util.Log;
-
/**
* Container for a dynamically typed data value. Primarily used with
* {@link android.content.res.Resources} for holding resource values.
@@ -141,6 +138,16 @@ public class TypedValue {
/* ------------------------------------------------------------ */
+ /**
+ * If {@link #density} is equal to this value, then the density should be
+ * treated as the system's default density value: {@link DisplayMetrics#DEFAULT_DENSITY}.
+ *
+ * @hide Pending API council approval
+ */
+ public static final int DENSITY_DEFAULT = 0;
+
+ /* ------------------------------------------------------------ */
+
/** The type held by this value, as defined by the constants here.
* This tells you how to interpret the other fields in the object. */
public int type;
@@ -161,7 +168,14 @@ public class TypedValue {
/** If Value came from a resource, these are the configurations for which
* its contents can change. */
public int changingConfigurations = -1;
-
+
+ /**
+ * If the Value came from a resource, this holds the corresponding pixel density.
+ *
+ * @hide Pending API council approval
+ * */
+ public int density;
+
/* ------------------------------------------------------------ */
/** Return the data for this value as a float. Only use for values
@@ -454,6 +468,7 @@ public class TypedValue {
data = other.data;
assetCookie = other.assetCookie;
resourceId = other.resourceId;
+ density = other.density;
}
public String toString()
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 4048763..15fb839 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -397,7 +397,7 @@ public class FocusFinder {
int numTouchables = touchables.size();
- int edgeSlop = ViewConfiguration.getEdgeSlop();
+ int edgeSlop = ViewConfiguration.get(root.mContext).getScaledEdgeSlop();
Rect closestBounds = new Rect();
Rect touchableBounds = mOtherRect;
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index fc9af05..f7ac522 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -18,6 +18,7 @@ package android.view;
import android.os.Handler;
import android.os.Message;
+import android.content.Context;
/**
* Detects various gestures and events using the supplied {@link MotionEvent}s.
@@ -34,7 +35,6 @@ import android.os.Message;
* </ul>
*/
public class GestureDetector {
-
/**
* The listener that is used to notify when gestures occur.
* If you want to listen for all the different gestures then implement
@@ -113,12 +113,48 @@ public class GestureDetector {
}
/**
- * A convenience class to extend when you only want to listen for a
- * subset of all the gestures. This implements all methods in the
- * {@link OnGestureListener} but does nothing and return {@code false}
- * for all applicable methods.
+ * The listener that is used to notify when a double-tap or a confirmed
+ * single-tap occur.
*/
- public static class SimpleOnGestureListener implements OnGestureListener {
+ public interface OnDoubleTapListener {
+ /**
+ * Notified when a single-tap occurs.
+ * <p>
+ * Unlike {@link OnGestureListener#onSingleTapUp(MotionEvent)}, this
+ * will only be called after the detector is confident that the user's
+ * first tap is not followed by a second tap leading to a double-tap
+ * gesture.
+ *
+ * @param e The down motion event of the single-tap.
+ * @return true if the event is consumed, else false
+ */
+ boolean onSingleTapConfirmed(MotionEvent e);
+
+ /**
+ * Notified when a double-tap occurs.
+ *
+ * @param e The down motion event of the first tap of the double-tap.
+ * @return true if the event is consumed, else false
+ */
+ boolean onDoubleTap(MotionEvent e);
+
+ /**
+ * Notified when an event within a double-tap gesture occurs, including
+ * the down, move, and up events.
+ *
+ * @param e The motion event that occurred during the double-tap gesture.
+ * @return true if the event is consumed, else false
+ */
+ boolean onDoubleTapEvent(MotionEvent e);
+ }
+
+ /**
+ * A convenience class to extend when you only want to listen for a subset
+ * of all the gestures. This implements all methods in the
+ * {@link OnGestureListener} and {@link OnDoubleTapListener} but does
+ * nothing and return {@code false} for all applicable methods.
+ */
+ public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener {
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@@ -142,23 +178,55 @@ public class GestureDetector {
public boolean onDown(MotionEvent e) {
return false;
}
+
+ public boolean onDoubleTap(MotionEvent e) {
+ return false;
+ }
+
+ public boolean onDoubleTapEvent(MotionEvent e) {
+ return false;
+ }
+
+ public boolean onSingleTapConfirmed(MotionEvent e) {
+ return false;
+ }
}
- private static final int TOUCH_SLOP_SQUARE = ViewConfiguration.getTouchSlop()
- * ViewConfiguration.getTouchSlop();
+ // TODO: ViewConfiguration
+ private int mBiggerTouchSlopSquare = 20 * 20;
+
+ private int mTouchSlopSquare;
+ private int mDoubleTapSlopSquare;
+ private int mMinimumFlingVelocity;
+
+ 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
private static final int SHOW_PRESS = 1;
private static final int LONG_PRESS = 2;
+ private static final int TAP = 3;
private final Handler mHandler;
private final OnGestureListener mListener;
+ private OnDoubleTapListener mDoubleTapListener;
+ private boolean mStillDown;
private boolean mInLongPress;
private boolean mAlwaysInTapRegion;
+ private boolean mAlwaysInBiggerTapRegion;
private MotionEvent mCurrentDownEvent;
- private MotionEvent mCurrentUpEvent;
+ private MotionEvent mPreviousUpEvent;
+
+ /**
+ * True when the user is still touching for the second tap (down, move, and
+ * up events). Can only be true if there is a double tap listener attached.
+ */
+ private boolean mIsDoubleTapping;
private float mLastMotionY;
private float mLastMotionX;
@@ -189,9 +257,16 @@ public class GestureDetector {
case LONG_PRESS:
dispatchLongPress();
break;
+
+ case TAP:
+ // If the user's finger is still down, do not count it as a tap
+ if (mDoubleTapListener != null && !mStillDown) {
+ mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent);
+ }
+ break;
default:
- throw new RuntimeException("Unknown message " + msg); //never
+ throw new RuntimeException("Unknown message " + msg); //never
}
}
}
@@ -203,16 +278,17 @@ public class GestureDetector {
*
* @param listener the listener invoked for all the callbacks, this must
* not be null.
- * @param handler the handler to use, this must
- * not be null.
+ * @param handler the handler to use
*
* @throws NullPointerException if either {@code listener} or
* {@code handler} is null.
+ *
+ * @deprecated Use {@link #GestureDetector(android.content.Context,
+ * android.view.GestureDetector.OnGestureListener, android.os.Handler)} instead.
*/
+ @Deprecated
public GestureDetector(OnGestureListener listener, Handler handler) {
- mHandler = new GestureHandler(handler);
- mListener = listener;
- init();
+ this(null, listener, handler);
}
/**
@@ -222,19 +298,90 @@ public class GestureDetector {
*
* @param listener the listener invoked for all the callbacks, this must
* not be null.
+ *
* @throws NullPointerException if {@code listener} is null.
+ *
+ * @deprecated Use {@link #GestureDetector(android.content.Context,
+ * android.view.GestureDetector.OnGestureListener)} instead.
*/
+ @Deprecated
public GestureDetector(OnGestureListener listener) {
- mHandler = new GestureHandler();
+ this(null, listener, null);
+ }
+
+ /**
+ * Creates a GestureDetector with the supplied listener.
+ * You may only use this constructor from a UI thread (this is the usual situation).
+ * @see android.os.Handler#Handler()
+ *
+ * @param context the application's context
+ * @param listener the listener invoked for all the callbacks, this must
+ * not be null.
+ *
+ * @throws NullPointerException if {@code listener} is null.
+ */
+ public GestureDetector(Context context, OnGestureListener listener) {
+ this(context, listener, null);
+ }
+
+ /**
+ * Creates a GestureDetector with the supplied listener.
+ * You may only use this constructor from a UI thread (this is the usual situation).
+ * @see android.os.Handler#Handler()
+ *
+ * @param context the application's context
+ * @param listener the listener invoked for all the callbacks, this must
+ * not be null.
+ * @param handler the handler to use
+ *
+ * @throws NullPointerException if {@code listener} is null.
+ */
+ public GestureDetector(Context context, OnGestureListener listener, Handler handler) {
+ if (handler != null) {
+ mHandler = new GestureHandler(handler);
+ } else {
+ mHandler = new GestureHandler();
+ }
mListener = listener;
- init();
+ if (listener instanceof OnDoubleTapListener) {
+ setOnDoubleTapListener((OnDoubleTapListener) listener);
+ }
+ init(context);
}
- private void init() {
+ private void init(Context context) {
if (mListener == null) {
throw new NullPointerException("OnGestureListener must not be null");
}
mIsLongpressEnabled = true;
+
+ // Fallback to support pre-donuts releases
+ int touchSlop, doubleTapSlop;
+ if (context == null) {
+ //noinspection deprecation
+ touchSlop = ViewConfiguration.getTouchSlop();
+ doubleTapSlop = ViewConfiguration.getDoubleTapSlop();
+ //noinspection deprecation
+ mMinimumFlingVelocity = ViewConfiguration.getMinimumFlingVelocity();
+ } else {
+ final ViewConfiguration configuration = ViewConfiguration.get(context);
+ touchSlop = configuration.getScaledTouchSlop();
+ doubleTapSlop = configuration.getScaledDoubleTapSlop();
+ mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();
+ }
+ mTouchSlopSquare = touchSlop * touchSlop;
+ mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop;
+ }
+
+ /**
+ * Sets the listener which will be called for double-tap and related
+ * gestures.
+ *
+ * @param onDoubleTapListener the listener invoked for all the callbacks, or
+ * null to stop listening for double-tap gestures.
+ */
+ public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) {
+ mDoubleTapListener = onDoubleTapListener;
}
/**
@@ -266,9 +413,6 @@ public class GestureDetector {
* else false.
*/
public boolean onTouchEvent(MotionEvent ev) {
- final long tapTime = ViewConfiguration.getTapTimeout();
- final long longpressTime = ViewConfiguration.getLongPressTimeout();
- final int touchSlop = ViewConfiguration.getTouchSlop();
final int action = ev.getAction();
final float y = ev.getY();
final float x = ev.getX();
@@ -282,19 +426,38 @@ public class GestureDetector {
switch (action) {
case MotionEvent.ACTION_DOWN:
+ if (mDoubleTapListener != null) {
+ boolean hadTapMessage = mHandler.hasMessages(TAP);
+ if (hadTapMessage) mHandler.removeMessages(TAP);
+ if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage &&
+ isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {
+ // This is a second tap
+ mIsDoubleTapping = true;
+ // Give a callback with the first tap of the double-tap
+ handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);
+ // Give a callback with down event of the double-tap
+ handled |= mDoubleTapListener.onDoubleTapEvent(ev);
+ } else {
+ // This is a first tap
+ mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);
+ }
+ }
+
mLastMotionX = x;
mLastMotionY = y;
mCurrentDownEvent = MotionEvent.obtain(ev);
mAlwaysInTapRegion = true;
+ mAlwaysInBiggerTapRegion = true;
+ mStillDown = true;
mInLongPress = false;
-
+
if (mIsLongpressEnabled) {
mHandler.removeMessages(LONG_PRESS);
mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
- + tapTime + longpressTime);
+ + TAP_TIMEOUT + LONGPRESS_TIMEOUT);
}
- mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + tapTime);
- handled = mListener.onDown(ev);
+ mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
+ handled |= mListener.onDown(ev);
break;
case MotionEvent.ACTION_MOVE:
@@ -303,18 +466,25 @@ public class GestureDetector {
}
final float scrollX = mLastMotionX - x;
final float scrollY = mLastMotionY - y;
- if (mAlwaysInTapRegion) {
+ if (mIsDoubleTapping) {
+ // Give the move events of the double-tap
+ handled |= mDoubleTapListener.onDoubleTapEvent(ev);
+ } else if (mAlwaysInTapRegion) {
final int deltaX = (int) (x - mCurrentDownEvent.getX());
final int deltaY = (int) (y - mCurrentDownEvent.getY());
int distance = (deltaX * deltaX) + (deltaY * deltaY);
- if (distance > TOUCH_SLOP_SQUARE) {
+ if (distance > mTouchSlopSquare) {
handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
mLastMotionX = x;
mLastMotionY = y;
mAlwaysInTapRegion = false;
+ mHandler.removeMessages(TAP);
mHandler.removeMessages(SHOW_PRESS);
mHandler.removeMessages(LONG_PRESS);
}
+ if (distance > mBiggerTouchSlopSquare) {
+ mAlwaysInBiggerTapRegion = false;
+ }
} else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
mLastMotionX = x;
@@ -323,12 +493,15 @@ public class GestureDetector {
break;
case MotionEvent.ACTION_UP:
- mCurrentUpEvent = MotionEvent.obtain(ev);
- if (mInLongPress) {
+ mStillDown = false;
+ MotionEvent currentUpEvent = MotionEvent.obtain(ev);
+ if (mIsDoubleTapping) {
+ // Finally, give the up event of the double-tap
+ handled |= mDoubleTapListener.onDoubleTapEvent(ev);
+ } else if (mInLongPress) {
+ mHandler.removeMessages(TAP);
mInLongPress = false;
- break;
- }
- if (mAlwaysInTapRegion) {
+ } else if (mAlwaysInTapRegion) {
handled = mListener.onSingleTapUp(ev);
} else {
@@ -338,21 +511,26 @@ public class GestureDetector {
final float velocityY = velocityTracker.getYVelocity();
final float velocityX = velocityTracker.getXVelocity();
- if ((Math.abs(velocityY) > ViewConfiguration.getMinimumFlingVelocity())
- || (Math.abs(velocityX) > ViewConfiguration.getMinimumFlingVelocity())){
- handled = mListener.onFling(mCurrentDownEvent, mCurrentUpEvent, velocityX, velocityY);
+ if ((Math.abs(velocityY) > mMinimumFlingVelocity)
+ || (Math.abs(velocityX) > mMinimumFlingVelocity)){
+ handled = mListener.onFling(mCurrentDownEvent, currentUpEvent, velocityX, velocityY);
}
}
+ mPreviousUpEvent = MotionEvent.obtain(ev);
mVelocityTracker.recycle();
mVelocityTracker = null;
+ mIsDoubleTapping = false;
mHandler.removeMessages(SHOW_PRESS);
mHandler.removeMessages(LONG_PRESS);
break;
case MotionEvent.ACTION_CANCEL:
mHandler.removeMessages(SHOW_PRESS);
mHandler.removeMessages(LONG_PRESS);
+ mHandler.removeMessages(TAP);
mVelocityTracker.recycle();
mVelocityTracker = null;
+ mIsDoubleTapping = false;
+ mStillDown = false;
if (mInLongPress) {
mInLongPress = false;
break;
@@ -361,7 +539,23 @@ public class GestureDetector {
return handled;
}
+ private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp,
+ MotionEvent secondDown) {
+ if (!mAlwaysInBiggerTapRegion) {
+ return false;
+ }
+
+ if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) {
+ return false;
+ }
+
+ int deltaX = (int) firstDown.getX() - (int) secondDown.getX();
+ int deltaY = (int) firstDown.getY() - (int) secondDown.getY();
+ return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare);
+ }
+
private void dispatchLongPress() {
+ mHandler.removeMessages(TAP);
mInLongPress = true;
mListener.onLongPress(mCurrentDownEvent);
}
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
new file mode 100644
index 0000000..841066c
--- /dev/null
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -0,0 +1,42 @@
+/*
+ * 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 android.view;
+
+/**
+ * Constants to be used to perform haptic feedback effects via
+ * {@link View#performHapticFeedback(int)}
+ */
+public class HapticFeedbackConstants {
+
+ private HapticFeedbackConstants() {}
+
+ public static final int LONG_PRESS = 0;
+
+ /**
+ * Flag for {@link View#performHapticFeedback(int, int)
+ * View.performHapticFeedback(int, int)}: Ignore the setting in the
+ * view for whether to perform haptic feedback, do it always.
+ */
+ public static final int FLAG_IGNORE_VIEW_SETTING = 0x0001;
+
+ /**
+ * Flag for {@link View#performHapticFeedback(int, int)
+ * View.performHapticFeedback(int, int)}: Ignore the global setting
+ * for whether to perform haptic feedback, do it always.
+ */
+ public static final int FLAG_IGNORE_GLOBAL_SETTING = 0x0002;
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 40251db..a856b24 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -104,6 +104,9 @@ interface IWindowManager
int getKeycodeState(int sw);
int getKeycodeStateForDevice(int devid, int sw);
+ // Report whether the hardware supports the given keys; returns true if successful
+ boolean hasKeys(in int[] keycodes, inout boolean[] keyExists);
+
// For testing
void setInTouchMode(boolean showFocus);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 7276f17..1156856 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -106,5 +106,6 @@ interface IWindowSession {
void setInTouchMode(boolean showFocus);
boolean getInTouchMode();
+
+ boolean performHapticFeedback(IWindow window, int effectId, boolean always);
}
-
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 0347d50..25958aa 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -18,6 +18,8 @@ package android.view;
import android.text.method.MetaKeyKeyListener;
import android.util.SparseIntArray;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.SparseArray;
@@ -350,6 +352,28 @@ public class KeyCharacterMap
return getKeyboardType_native(mPointer);
}
+ /**
+ * Queries the framework about whether any physical keys exist on the
+ * device that are capable of producing the given key codes.
+ */
+ public static boolean deviceHasKey(int keyCode) {
+ int[] codeArray = new int[1];
+ codeArray[0] = keyCode;
+ boolean[] ret = deviceHasKeys(codeArray);
+ return ret[0];
+ }
+
+ public static boolean[] deviceHasKeys(int[] keyCodes) {
+ boolean[] ret = new boolean[keyCodes.length];
+ IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+ try {
+ wm.hasKeys(keyCodes, ret);
+ } catch (RemoteException e) {
+ // no fallback; just return the empty array
+ }
+ return ret;
+ }
+
private int mPointer;
private int mKeyboardDevice;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 1575aad..430cc71 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -92,7 +92,7 @@ public class KeyEvent implements Parcelable {
public static final int KEYCODE_SYM = 63;
public static final int KEYCODE_EXPLORER = 64;
public static final int KEYCODE_ENVELOPE = 65;
- public static final int KEYCODE_ENTER = 66;
+ public static final int KEYCODE_ENTER = 66;
public static final int KEYCODE_DEL = 67;
public static final int KEYCODE_GRAVE = 68;
public static final int KEYCODE_MINUS = 69;
@@ -117,7 +117,8 @@ public class KeyEvent implements Parcelable {
public static final int KEYCODE_PREVIOUSSONG = 88;
public static final int KEYCODE_REWIND = 89;
public static final int KEYCODE_FORWARD = 90;
- private static final int LAST_KEYCODE = KEYCODE_FORWARD;
+ public static final int KEYCODE_MUTE = 91;
+ private static final int LAST_KEYCODE = KEYCODE_MUTE;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
@@ -144,8 +145,12 @@ public class KeyEvent implements Parcelable {
public static final int ACTION_UP = 1;
/**
* {@link #getAction} value: multiple duplicate key events have
- * occurred in a row. The {#link {@link #getRepeatCount()} method returns
- * the number of duplicates.
+ * occurred in a row, or a complex string is being delivered. If the
+ * key code is not {#link {@link #KEYCODE_UNKNOWN} then the
+ * {#link {@link #getRepeatCount()} method returns the number of times
+ * the given key code should be executed.
+ * Otherwise, if the key code {@link #KEYCODE_UNKNOWN}, then
+ * this is a sequence of characters as returned by {@link #getCharacters}.
*/
public static final int ACTION_MULTIPLE = 2;
@@ -224,6 +229,12 @@ public class KeyEvent implements Parcelable {
public static final int FLAG_SOFT_KEYBOARD = 0x2;
/**
+ * This mask is set if we don't want the key event to cause us to leave
+ * touch mode.
+ */
+ public static final int FLAG_KEEP_TOUCH_MODE = 0x4;
+
+ /**
* Returns the maximum keycode.
*/
public static int getMaxKeyCode() {
@@ -248,6 +259,7 @@ public class KeyEvent implements Parcelable {
private int mFlags;
private long mDownTime;
private long mEventTime;
+ private String mCharacters;
public interface Callback {
/**
@@ -406,6 +418,28 @@ public class KeyEvent implements Parcelable {
}
/**
+ * Create a new key event for a string of characters. The key code,
+ * action, and repeat could will automatically be set to
+ * {@link #KEYCODE_UNKNOWN}, {@link #ACTION_MULTIPLE}, and 0 for you.
+ *
+ * @param time The time (in {@link android.os.SystemClock#uptimeMillis})
+ * at which this event occured.
+ * @param characters The string of characters.
+ * @param device The device ID that generated the key event.
+ * @param flags The flags for this key event
+ */
+ public KeyEvent(long time, String characters, int device, int flags) {
+ mDownTime = time;
+ mEventTime = time;
+ mCharacters = characters;
+ mAction = ACTION_MULTIPLE;
+ mKeyCode = KEYCODE_UNKNOWN;
+ mRepeatCount = 0;
+ mDeviceId = device;
+ mFlags = flags;
+ }
+
+ /**
* Copy an existing key event, modifying its time and repeat count.
*
* @param origEvent The existing event to be copied.
@@ -423,6 +457,7 @@ public class KeyEvent implements Parcelable {
mDeviceId = origEvent.mDeviceId;
mScancode = origEvent.mScancode;
mFlags = origEvent.mFlags;
+ mCharacters = origEvent.mCharacters;
}
/**
@@ -441,6 +476,8 @@ public class KeyEvent implements Parcelable {
mDeviceId = origEvent.mDeviceId;
mScancode = origEvent.mScancode;
mFlags = origEvent.mFlags;
+ // Don't copy mCharacters, since one way or the other we'll lose it
+ // when changing the action.
}
/**
@@ -472,6 +509,7 @@ public class KeyEvent implements Parcelable {
case KEYCODE_ENDCALL:
case KEYCODE_VOLUME_UP:
case KEYCODE_VOLUME_DOWN:
+ case KEYCODE_MUTE:
case KEYCODE_POWER:
case KEYCODE_HEADSETHOOK:
case KEYCODE_PLAYPAUSE:
@@ -580,7 +618,7 @@ public class KeyEvent implements Parcelable {
/**
* Retrieve the key code of the key event. This is the physical key that
- * was pressed -- not the Unicode character.
+ * was pressed, <em>not</em> the Unicode character.
*
* @return The key code of the event.
*/
@@ -589,6 +627,18 @@ public class KeyEvent implements Parcelable {
}
/**
+ * For the special case of a {@link #ACTION_MULTIPLE} event with key
+ * code of {@link #KEYCODE_UNKNOWN}, this is a raw string of characters
+ * associated with the event. In all other cases it is null.
+ *
+ * @return Returns a String of 1 or more characters associated with
+ * the event.
+ */
+ public final String getCharacters() {
+ return mCharacters;
+ }
+
+ /**
* Retrieve the hardware key id of this key event. These values are not
* reliable and vary from device to device.
*
@@ -772,16 +822,18 @@ public class KeyEvent implements Parcelable {
if (receiver.onKeyMultiple(code, count, this)) {
return true;
}
- mAction = ACTION_DOWN;
- mRepeatCount = 0;
- boolean handled = receiver.onKeyDown(code, this);
- if (handled) {
- mAction = ACTION_UP;
- receiver.onKeyUp(code, this);
+ if (code != KeyEvent.KEYCODE_UNKNOWN) {
+ mAction = ACTION_DOWN;
+ mRepeatCount = 0;
+ boolean handled = receiver.onKeyDown(code, this);
+ if (handled) {
+ mAction = ACTION_UP;
+ receiver.onKeyUp(code, this);
+ }
+ mAction = ACTION_MULTIPLE;
+ mRepeatCount = count;
+ return handled;
}
- mAction = ACTION_MULTIPLE;
- mRepeatCount = count;
- return handled;
}
return false;
}
diff --git a/core/java/android/view/OrientationEventListener.java b/core/java/android/view/OrientationEventListener.java
new file mode 100755
index 0000000..391ba1e
--- /dev/null
+++ b/core/java/android/view/OrientationEventListener.java
@@ -0,0 +1,174 @@
+/*
+ * 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 android.view;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.util.Config;
+import android.util.Log;
+
+/**
+ * Helper class for receiving notifications from the SensorManager when
+ * the orientation of the device has changed.
+ */
+public abstract class OrientationEventListener {
+ private static final String TAG = "OrientationEventListener";
+ private static final boolean DEBUG = false;
+ private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
+ private int mOrientation = ORIENTATION_UNKNOWN;
+ private SensorManager mSensorManager;
+ private boolean mEnabled = false;
+ private int mRate;
+ private Sensor mSensor;
+ private SensorEventListener mSensorEventListener;
+ private OrientationListener mOldListener;
+
+ /**
+ * Returned from onOrientationChanged when the device orientation cannot be determined
+ * (typically when the device is in a close to flat position).
+ *
+ * @see #onOrientationChanged
+ */
+ public static final int ORIENTATION_UNKNOWN = -1;
+
+ /**
+ * Creates a new OrientationEventListener.
+ *
+ * @param context for the OrientationEventListener.
+ */
+ public OrientationEventListener(Context context) {
+ this(context, SensorManager.SENSOR_DELAY_NORMAL);
+ }
+
+ /**
+ * Creates a new OrientationEventListener.
+ *
+ * @param context for the OrientationEventListener.
+ * @param rate at which sensor events are processed (see also
+ * {@link android.hardware.SensorManager SensorManager}). Use the default
+ * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL
+ * SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
+ */
+ public OrientationEventListener(Context context, int rate) {
+ mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+ mRate = rate;
+ mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ if (mSensor != null) {
+ // Create listener only if sensors do exist
+ mSensorEventListener = new SensorEventListenerImpl();
+ }
+ }
+
+ void registerListener(OrientationListener lis) {
+ mOldListener = lis;
+ }
+
+ /**
+ * Enables the OrientationEventListener so it will monitor the sensor and call
+ * {@link #onOrientationChanged} when the device orientation changes.
+ */
+ public void enable() {
+ if (mSensor == null) {
+ Log.w(TAG, "Cannot detect sensors. Not enabled");
+ return;
+ }
+ if (mEnabled == false) {
+ if (localLOGV) Log.d(TAG, "OrientationEventListener enabled");
+ mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
+ mEnabled = true;
+ }
+ }
+
+ /**
+ * Disables the OrientationEventListener.
+ */
+ public void disable() {
+ if (mSensor == null) {
+ Log.w(TAG, "Cannot detect sensors. Invalid disable");
+ return;
+ }
+ if (mEnabled == true) {
+ if (localLOGV) Log.d(TAG, "OrientationEventListener disabled");
+ mSensorManager.unregisterListener(mSensorEventListener);
+ mEnabled = false;
+ }
+ }
+
+ class SensorEventListenerImpl implements SensorEventListener {
+ private static final int _DATA_X = 0;
+ private static final int _DATA_Y = 1;
+ private static final int _DATA_Z = 2;
+
+ public void onSensorChanged(SensorEvent event) {
+ float[] values = event.values;
+ int orientation = ORIENTATION_UNKNOWN;
+ float X = -values[_DATA_X];
+ float Y = -values[_DATA_Y];
+ float Z = -values[_DATA_Z];
+ float magnitude = X*X + Y*Y;
+ // Don't trust the angle if the magnitude is small compared to the y value
+ if (magnitude * 4 >= Z*Z) {
+ float OneEightyOverPi = 57.29577957855f;
+ float angle = (float)Math.atan2(-Y, X) * OneEightyOverPi;
+ orientation = 90 - (int)Math.round(angle);
+ // normalize to 0 - 359 range
+ while (orientation >= 360) {
+ orientation -= 360;
+ }
+ while (orientation < 0) {
+ orientation += 360;
+ }
+ }
+ if (mOldListener != null) {
+ mOldListener.onSensorChanged(Sensor.TYPE_ACCELEROMETER, event.values);
+ }
+ if (orientation != mOrientation) {
+ mOrientation = orientation;
+ onOrientationChanged(orientation);
+ }
+ }
+
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+
+ }
+ }
+
+ /*
+ * Returns true if sensor is enabled and false otherwise
+ */
+ public boolean canDetectOrientation() {
+ return mSensor != null;
+ }
+
+ /**
+ * Called when the orientation of the device has changed.
+ * orientation parameter is in degrees, ranging from 0 to 359.
+ * orientation is 0 degrees when the device is oriented in its natural position,
+ * 90 degrees when its left side is at the top, 180 degrees when it is upside down,
+ * and 270 degrees when its right side is to the top.
+ * {@link #ORIENTATION_UNKNOWN} is returned when the device is close to flat
+ * and the orientation cannot be determined.
+ *
+ * @param orientation The new orientation of the device.
+ *
+ * @see #ORIENTATION_UNKNOWN
+ */
+ abstract public void onOrientationChanged(int orientation);
+}
diff --git a/core/java/android/view/OrientationListener.java b/core/java/android/view/OrientationListener.java
index 974c2e8..ce8074e 100644
--- a/core/java/android/view/OrientationListener.java
+++ b/core/java/android/view/OrientationListener.java
@@ -18,23 +18,16 @@ package android.view;
import android.content.Context;
import android.hardware.SensorListener;
-import android.hardware.SensorManager;
-import android.util.Config;
-import android.util.Log;
/**
* Helper class for receiving notifications from the SensorManager when
* the orientation of the device has changed.
+ * @deprecated use {@link android.view.OrientationEventListener} instead.
+ * This class internally uses the OrientationEventListener.
*/
+@Deprecated
public abstract class OrientationListener implements SensorListener {
-
- private static final String TAG = "OrientationListener";
- private static final boolean DEBUG = false;
- private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
- private SensorManager mSensorManager;
- private int mOrientation = ORIENTATION_UNKNOWN;
- private boolean mEnabled = false;
- private int mRate;
+ private OrientationEventListener mOrientationEventLis;
/**
* Returned from onOrientationChanged when the device orientation cannot be determined
@@ -42,7 +35,7 @@ public abstract class OrientationListener implements SensorListener {
*
* @see #onOrientationChanged
*/
- public static final int ORIENTATION_UNKNOWN = -1;
+ public static final int ORIENTATION_UNKNOWN = OrientationEventListener.ORIENTATION_UNKNOWN;
/**
* Creates a new OrientationListener.
@@ -50,8 +43,7 @@ public abstract class OrientationListener implements SensorListener {
* @param context for the OrientationListener.
*/
public OrientationListener(Context context) {
- mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
- mRate = SensorManager.SENSOR_DELAY_NORMAL;
+ mOrientationEventLis = new OrientationEventListenerInternal(context);
}
/**
@@ -64,78 +56,55 @@ public abstract class OrientationListener implements SensorListener {
* SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
*/
public OrientationListener(Context context, int rate) {
- mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
- mRate = rate;
+ mOrientationEventLis = new OrientationEventListenerInternal(context, rate);
}
-
+
+ class OrientationEventListenerInternal extends OrientationEventListener {
+ OrientationEventListenerInternal(Context context) {
+ super(context);
+ }
+
+ OrientationEventListenerInternal(Context context, int rate) {
+ super(context, rate);
+ // register so that onSensorChanged gets invoked
+ registerListener(OrientationListener.this);
+ }
+
+ public void onOrientationChanged(int orientation) {
+ OrientationListener.this.onOrientationChanged(orientation);
+ }
+ }
+
/**
* Enables the OrientationListener so it will monitor the sensor and call
* {@link #onOrientationChanged} when the device orientation changes.
*/
public void enable() {
- if (mEnabled == false) {
- if (localLOGV) Log.d(TAG, "OrientationListener enabled");
- mSensorManager.registerListener(this, SensorManager.SENSOR_ACCELEROMETER, mRate);
- mEnabled = true;
- }
+ mOrientationEventLis.enable();
}
/**
* Disables the OrientationListener.
*/
public void disable() {
- if (mEnabled == true) {
- if (localLOGV) Log.d(TAG, "OrientationListener disabled");
- mSensorManager.unregisterListener(this);
- mEnabled = false;
- }
+ mOrientationEventLis.disable();
}
-
- /**
- *
- */
+
+ public void onAccuracyChanged(int sensor, int accuracy) {
+ }
+
public void onSensorChanged(int sensor, float[] values) {
- int orientation = ORIENTATION_UNKNOWN;
- float X = values[SensorManager.RAW_DATA_X];
- float Y = values[SensorManager.RAW_DATA_Y];
- float Z = values[SensorManager.RAW_DATA_Z];
- float magnitude = X*X + Y*Y;
- // Don't trust the angle if the magnitude is small compared to the y value
- if (magnitude * 4 >= Z*Z) {
- float OneEightyOverPi = 57.29577957855f;
- float angle = (float)Math.atan2(-Y, X) * OneEightyOverPi;
- orientation = 90 - (int)Math.round(angle);
- // normalize to 0 - 359 range
- while (orientation >= 360) {
- orientation -= 360;
- }
- while (orientation < 0) {
- orientation += 360;
- }
- }
-
- if (orientation != mOrientation) {
- mOrientation = orientation;
- onOrientationChanged(orientation);
- }
+ // just ignore the call here onOrientationChanged is invoked anyway
}
- public void onAccuracyChanged(int sensor, int accuracy) {
- // TODO Auto-generated method stub
- }
/**
- * Called when the orientation of the device has changed.
- * orientation parameter is in degrees, ranging from 0 to 359.
- * orientation is 0 degrees when the device is oriented in its natural position,
- * 90 degrees when its left side is at the top, 180 degrees when it is upside down,
- * and 270 degrees when its right side is to the top.
- * {@link #ORIENTATION_UNKNOWN} is returned when the device is close to flat
- * and the orientation cannot be determined.
- *
+ * Look at {@link android.view.OrientationEventListener#onOrientationChanged}
+ * for method description and usage
* @param orientation The new orientation of the device.
*
* @see #ORIENTATION_UNKNOWN
*/
abstract public void onOrientationChanged(int orientation);
+
}
diff --git a/location/java/com/android/internal/location/protocol/GrectangleMessageTypes.java b/core/java/android/view/RemotableViewMethod.java
index aeb0047..4318290 100644
--- a/location/java/com/android/internal/location/protocol/GrectangleMessageTypes.java
+++ b/core/java/android/view/RemotableViewMethod.java
@@ -14,19 +14,22 @@
* limitations under the License.
*/
-package com.android.internal.location.protocol;
+package android.view;
-import com.google.common.io.protocol.ProtoBufType;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @hide
+ * This annotation indicates that a method on a subclass of View
+ * is alllowed to be used with the {@link android.widget.RemoteViews} mechanism.
+ */
+@Target({ ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RemotableViewMethod {
+}
-public class GrectangleMessageTypes {
- public static final ProtoBufType GRECTANGLE = new ProtoBufType();
- static {
- GRECTANGLE
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_MESSAGE,
- GRectangle.LOWER_LEFT, GlatlngMessageTypes.GLAT_LNG)
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_MESSAGE,
- GRectangle.UPPER_RIGHT, GlatlngMessageTypes.GLAT_LNG);
- }
-}
diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java
index 21a72e7..3d0dda3 100644
--- a/core/java/android/view/SurfaceHolder.java
+++ b/core/java/android/view/SurfaceHolder.java
@@ -240,7 +240,7 @@ public interface SurfaceHolder {
* in particular there is no guarantee that the content of the Surface
* will remain unchanged when lockCanvas() is called again.
*
- * @see android.view.SurfaceHolder.lockCanvas
+ * @see #lockCanvas()
*
* @param canvas The Canvas previously returned by lockCanvas().
*/
diff --git a/core/java/android/view/TouchDelegate.java b/core/java/android/view/TouchDelegate.java
index 057df92..27b49db 100644
--- a/core/java/android/view/TouchDelegate.java
+++ b/core/java/android/view/TouchDelegate.java
@@ -77,7 +77,9 @@ public class TouchDelegate {
* actual extent.
*/
public static final int TO_RIGHT = 8;
-
+
+ private int mSlop;
+
/**
* Constructor
*
@@ -87,10 +89,10 @@ public class TouchDelegate {
*/
public TouchDelegate(Rect bounds, View delegateView) {
mBounds = bounds;
-
- int slop = ViewConfiguration.getTouchSlop();
+
+ mSlop = ViewConfiguration.get(delegateView.getContext()).getScaledTouchSlop();
mSlopBounds = new Rect(bounds);
- mSlopBounds.inset(-slop, -slop);
+ mSlopBounds.inset(-mSlop, -mSlop);
mDelegateView = delegateView;
}
@@ -141,7 +143,7 @@ public class TouchDelegate {
} else {
// Offset event coordinates to be outside the target view (in case it does
// something like tracking pressed state)
- int slop = ViewConfiguration.getTouchSlop();
+ int slop = mSlop;
event.setLocation(-(slop * 2), -(slop * 2));
}
handled = delegateView.dispatchTouchEvent(event);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 85f482c..c3e00c4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -57,15 +57,35 @@ import com.android.internal.view.menu.MenuBuilder;
import java.util.ArrayList;
import java.util.Arrays;
+import java.lang.ref.SoftReference;
/**
* <p>
- * The <code>View</code> class represents the basic UI building block. A view
+ * This class represents the basic building block for user interface components. A View
* occupies a rectangular area on the screen and is responsible for drawing and
- * event handling. <code>View</code> is the base class for <em>widgets</em>,
- * used to create interactive graphical user interfaces.
+ * event handling. View is the base class for <em>widgets</em>, which are
+ * used to create interactive UI components (buttons, text fields, etc.). The
+ * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which
+ * are invisible containers that hold other Views (or other ViewGroups) and define
+ * their layout properties.
* </p>
*
+ * <div class="special">
+ * <p>For an introduction to using this class to develop your
+ * application's user interface, read the Developer Guide documentation on
+ * <strong><a href="{@docRoot}guide/topics/ui/index.html">User Interface</a></strong>. Special topics
+ * include:
+ * <br/><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a>
+ * <br/><a href="{@docRoot}guide/topics/ui/menus.html">Creating Menus</a>
+ * <br/><a href="{@docRoot}guide/topics/ui/layout-objects.html">Common Layout Objects</a>
+ * <br/><a href="{@docRoot}guide/topics/ui/binding.html">Binding to Data with AdapterView</a>
+ * <br/><a href="{@docRoot}guide/topics/ui/ui-events.html">Handling UI Events</a>
+ * <br/><a href="{@docRoot}guide/topics/ui/themes.html">Applying Styles and Themes</a>
+ * <br/><a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a>
+ * <br/><a href="{@docRoot}guide/topics/ui/how-android-draws.html">How Android Draws Views</a>.
+ * </p>
+ * </div>
+ *
* <a name="Using"></a>
* <h3>Using Views</h3>
* <p>
@@ -817,6 +837,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
public static final int SOUND_EFFECTS_ENABLED = 0x08000000;
/**
+ * View flag indicating whether this view should have haptic feedback
+ * enabled for events such as long presses.
+ */
+ public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000;
+
+ /**
* Use with {@link #focusSearch}. Move focus to the previous selectable
* item.
*/
@@ -1308,6 +1334,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
static final int HAS_BOUNDS = 0x00000010;
/** {@hide} */
static final int DRAWN = 0x00000020;
+ /**
+ * When this flag is set, this view is running an animation on behalf of its
+ * children and should therefore not cancel invalidate requests, even if they
+ * lie outside of this view's bounds.
+ *
+ * {@hide}
+ */
+ static final int DRAW_ANIMATION = 0x00000040;
/** {@hide} */
static final int SKIP_DRAW = 0x00000080;
/** {@hide} */
@@ -1353,8 +1387,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
*/
static final int SCROLL_CONTAINER_ADDED = 0x00100000;
- // Note: flag 0x00000040 is available
-
/**
* The parent this view is attached to.
* {@hide}
@@ -1479,8 +1511,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
@ViewDebug.ExportedProperty
int mUserPaddingBottom;
- private int mOldWidthMeasureSpec = Integer.MIN_VALUE;
- private int mOldHeightMeasureSpec = Integer.MIN_VALUE;
+ /**
+ * @hide
+ */
+ int mOldWidthMeasureSpec = Integer.MIN_VALUE;
+ /**
+ * @hide
+ */
+ int mOldHeightMeasureSpec = Integer.MIN_VALUE;
private Resources mResources = null;
@@ -1532,7 +1570,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
private int[] mDrawableState = null;
- private Bitmap mDrawingCache;
+ private SoftReference<Bitmap> mDrawingCache;
/**
* When this view has focus and the next focus is {@link #FOCUS_LEFT},
@@ -1559,6 +1597,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
private int mNextFocusDownId = View.NO_ID;
private CheckForLongPress mPendingCheckForLongPress;
+ private UnsetPressedState mUnsetPressedState;
/**
* Whether the long press's action has been invoked. The tap's action is invoked on the
@@ -1611,6 +1650,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
public View(Context context) {
mContext = context;
mResources = context != null ? context.getResources() : null;
+ mViewFlags = SOUND_EFFECTS_ENABLED|HAPTIC_FEEDBACK_ENABLED;
++sInstanceCount;
}
@@ -1677,9 +1717,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY;
- viewFlagValues |= SOUND_EFFECTS_ENABLED;
- viewFlagMasks |= SOUND_EFFECTS_ENABLED;
-
final int N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
@@ -1775,6 +1812,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
viewFlagValues &= ~SOUND_EFFECTS_ENABLED;
viewFlagMasks |= SOUND_EFFECTS_ENABLED;
}
+ case com.android.internal.R.styleable.View_hapticFeedbackEnabled:
+ if (!a.getBoolean(attr, true)) {
+ viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED;
+ viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED;
+ }
case R.styleable.View_scrollbars:
final int scrollbars = a.getInt(attr, SCROLLBARS_NONE);
if (scrollbars != SCROLLBARS_NONE) {
@@ -1898,7 +1940,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
initScrollCache();
mScrollCache.fadingEdgeLength = a.getDimensionPixelSize(
- R.styleable.View_fadingEdgeLength, ViewConfiguration.getFadingEdgeLength());
+ R.styleable.View_fadingEdgeLength,
+ ViewConfiguration.get(mContext).getScaledFadingEdgeLength());
}
/**
@@ -2013,36 +2056,38 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
mScrollCache.scrollBar = new ScrollBarDrawable();
}
- mScrollCache.scrollBarSize = a.getDimensionPixelSize(
+ final ScrollabilityCache scrollabilityCache = mScrollCache;
+
+ scrollabilityCache.scrollBarSize = a.getDimensionPixelSize(
com.android.internal.R.styleable.View_scrollbarSize,
- ViewConfiguration.getScrollBarSize());
+ ViewConfiguration.get(mContext).getScaledScrollBarSize());
Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal);
- mScrollCache.scrollBar.setHorizontalTrackDrawable(track);
+ scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track);
Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal);
if (thumb != null) {
- mScrollCache.scrollBar.setHorizontalThumbDrawable(thumb);
+ scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb);
}
boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack,
false);
if (alwaysDraw) {
- mScrollCache.scrollBar.setAlwaysDrawHorizontalTrack(true);
+ scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true);
}
track = a.getDrawable(R.styleable.View_scrollbarTrackVertical);
- mScrollCache.scrollBar.setVerticalTrackDrawable(track);
+ scrollabilityCache.scrollBar.setVerticalTrackDrawable(track);
thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical);
if (thumb != null) {
- mScrollCache.scrollBar.setVerticalThumbDrawable(thumb);
+ scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb);
}
alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack,
false);
if (alwaysDraw) {
- mScrollCache.scrollBar.setAlwaysDrawVerticalTrack(true);
+ scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true);
}
// Re-apply user/background padding so that scrollbar(s) get added
@@ -2056,7 +2101,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
*/
private void initScrollCache() {
if (mScrollCache == null) {
- mScrollCache = new ScrollabilityCache();
+ mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext));
}
}
@@ -2153,6 +2198,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
if (!handled) {
handled = showContextMenu();
}
+ if (handled) {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
return handled;
}
@@ -2619,9 +2667,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* @attr ref android.R.styleable#View_visibility
*/
@ViewDebug.ExportedProperty(mapping = {
- @ViewDebug.IntToString(from = 0, to = "VISIBLE"),
- @ViewDebug.IntToString(from = 4, to = "INVISIBLE"),
- @ViewDebug.IntToString(from = 8, to = "GONE")
+ @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"),
+ @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"),
+ @ViewDebug.IntToString(from = GONE, to = "GONE")
})
public int getVisibility() {
return mViewFlags & VISIBILITY_MASK;
@@ -2633,8 +2681,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
* @attr ref android.R.styleable#View_visibility
*/
+ @RemotableViewMethod
public void setVisibility(int visibility) {
setFlags(visibility, VISIBILITY_MASK);
+ if (mBGDrawable != null) mBGDrawable.setVisible(visibility == VISIBLE, false);
}
/**
@@ -2712,7 +2762,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* Set whether this view should have sound effects enabled for events such as
* clicking and touching.
*
- * You may wish to disable sound effects for a view if you already play sounds,
+ * <p>You may wish to disable sound effects for a view if you already play sounds,
* for instance, a dial key that plays dtmf tones.
*
* @param soundEffectsEnabled whether sound effects are enabled for this view.
@@ -2738,6 +2788,35 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
/**
+ * Set whether this view should have haptic feedback for events such as
+ * long presses.
+ *
+ * <p>You may wish to disable haptic feedback if your view already controls
+ * its own haptic feedback.
+ *
+ * @param hapticFeedbackEnabled whether haptic feedback enabled for this view.
+ * @see #isHapticFeedbackEnabled()
+ * @see #performHapticFeedback(int)
+ * @attr ref android.R.styleable#View_hapticFeedbackEnabled
+ */
+ public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) {
+ setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED);
+ }
+
+ /**
+ * @return whether this view should have haptic feedback enabled for events
+ * long presses.
+ *
+ * @see #setHapticFeedbackEnabled(boolean)
+ * @see #performHapticFeedback(int)
+ * @attr ref android.R.styleable#View_hapticFeedbackEnabled
+ */
+ @ViewDebug.ExportedProperty
+ public boolean isHapticFeedbackEnabled() {
+ return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED);
+ }
+
+ /**
* If this view doesn't do any drawing on its own, set this flag to
* allow further optimizations. By default, this flag is not set on
* View, but could be set on some View subclasses such as ViewGroup.
@@ -3195,13 +3274,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
/**
+ * This is called when a container is going to temporarily detach a child
+ * that currently has focus, with
+ * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}.
+ * It will either be followed by {@link #onFinishTemporaryDetach()} or
+ * {@link #onDetachedFromWindow()} when the container is done. Generally
+ * this is currently only done ListView for a view with focus.
+ */
+ public void onStartTemporaryDetach() {
+ }
+
+ /**
+ * Called after {@link #onStartTemporaryDetach} when the container is done
+ * changing the view.
+ */
+ public void onFinishTemporaryDetach() {
+ }
+
+ /**
* capture information of this view for later analysis: developement only
* check dynamic switch to make sure we only dump view
* when ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW) is set
*/
private static void captureViewInfo(String subTag, View v) {
- if (v == null ||
- SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW, 0) == 0) {
+ if (v == null || SystemProperties.getInt(ViewDebug.SYSTEM_PROPERTY_CAPTURE_VIEW, 0) == 0) {
return;
}
ViewDebug.dumpCapturedView(subTag, v);
@@ -3410,6 +3506,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
void performCollectViewAttributes(int visibility) {
+ //noinspection PointlessBitwiseExpression
if (((visibility | mViewFlags) & (VISIBILITY_MASK | KEEP_SCREEN_ON))
== (VISIBLE | KEEP_SCREEN_ON)) {
mAttachInfo.mKeepScreenOn = true;
@@ -3571,8 +3668,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* would make sense to automatically display a soft input window for
* it. Subclasses should override this if they implement
* {@link #onCreateInputConnection(EditorInfo)} to return true if
- * a call on that method would return a non-null InputConnection. The
- * default implementation always returns false.
+ * a call on that method would return a non-null InputConnection, and
+ * they are really a first-class editor that the user would normally
+ * start typing on when the go into a window containing your view.
+ *
+ * <p>The default implementation always returns false. This does
+ * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)}
+ * will not be called or the user can not otherwise perform edits on your
+ * view; it is just a hint to the system that this is not the primary
+ * purpose of this view.
*
* @return Returns true if this view is a text editor, else false.
*/
@@ -3597,6 +3701,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
/**
+ * Called by the {@link android.view.inputmethod.InputMethodManager}
+ * when a view who is not the current
+ * input connection target is trying to make a call on the manager. The
+ * default implementation returns false; you can override this to return
+ * true for certain views if you are performing InputConnection proxying
+ * to them.
+ * @param view The View that is making the InputMethodManager call.
+ * @return Return true to allow the call, false to reject.
+ */
+ public boolean checkInputConnectionProxy(View view) {
+ return false;
+ }
+
+ /**
* Show the context menu for this view. It is not safe to hold on to the
* menu after returning from this method.
*
@@ -3708,10 +3826,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
}
- final UnsetPressedState unsetPressedState = new UnsetPressedState();
- if (!post(unsetPressedState)) {
+ if (mUnsetPressedState == null) {
+ mUnsetPressedState = new UnsetPressedState();
+ }
+
+ if (!post(mUnsetPressedState)) {
// If the post failed, unpress right now
- unsetPressedState.run();
+ mUnsetPressedState.run();
}
}
break;
@@ -3734,7 +3855,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
final int y = (int) event.getY();
// Be lenient about moving outside of buttons
- int slop = ViewConfiguration.getTouchSlop();
+ int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
if ((x < 0 - slop) || (x >= getWidth() + slop) ||
(y < 0 - slop) || (y >= getHeight() + slop)) {
// Outside button
@@ -3874,25 +3995,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
if ((changed & WILL_NOT_CACHE_DRAWING) != 0) {
- if (mDrawingCache != null) {
- mDrawingCache.recycle();
- }
- mDrawingCache = null;
+ destroyDrawingCache();
}
if ((changed & DRAWING_CACHE_ENABLED) != 0) {
- if (mDrawingCache != null) {
- mDrawingCache.recycle();
- }
- mDrawingCache = null;
+ destroyDrawingCache();
mPrivateFlags &= ~DRAWING_CACHE_VALID;
}
if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) {
- if (mDrawingCache != null) {
- mDrawingCache.recycle();
- }
- mDrawingCache = null;
+ destroyDrawingCache();
mPrivateFlags &= ~DRAWING_CACHE_VALID;
}
@@ -3941,6 +4053,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
*/
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
mBackgroundSizeChanged = true;
+
+ final AttachInfo ai = mAttachInfo;
+ if (ai != null) {
+ ai.mViewScrollChanged = true;
+ }
}
/**
@@ -4413,14 +4530,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* @see #invalidate()
*/
public void postInvalidate() {
- // We try only with the AttachInfo because there's no point in invalidating
- // if we are not attached to our window
- if (mAttachInfo != null) {
- Message msg = Message.obtain();
- msg.what = AttachInfo.INVALIDATE_MSG;
- msg.obj = this;
- mAttachInfo.mHandler.sendMessage(msg);
- }
+ postInvalidateDelayed(0);
}
/**
@@ -4436,16 +4546,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* @see #invalidate(Rect)
*/
public void postInvalidate(int left, int top, int right, int bottom) {
- // We try only with the AttachInfo because there's no point in invalidating
- // if we are not attached to our window
- if (mAttachInfo != null) {
- Message msg = Message.obtain();
- msg.what = AttachInfo.INVALIDATE_RECT_MSG;
- msg.obj = this;
- msg.arg1 = (left << 16) | (top & 0xFFFF);
- msg.arg2 = (right << 16) | (bottom & 0xFFFF);
- mAttachInfo.mHandler.sendMessage(msg);
- }
+ postInvalidateDelayed(0, left, top, right, bottom);
}
/**
@@ -4477,16 +4578,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* @param right The right coordinate of the rectangle to invalidate.
* @param bottom The bottom coordinate of the rectangle to invalidate.
*/
- public void postInvalidateDelayed(long delayMilliseconds, int left, int top
- , int right, int bottom) {
+ public void postInvalidateDelayed(long delayMilliseconds, int left, int top,
+ int right, int bottom) {
+
// We try only with the AttachInfo because there's no point in invalidating
// if we are not attached to our window
if (mAttachInfo != null) {
- Message msg = Message.obtain();
+ final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire();
+ info.target = this;
+ info.left = left;
+ info.top = top;
+ info.right = right;
+ info.bottom = bottom;
+
+ final Message msg = Message.obtain();
msg.what = AttachInfo.INVALIDATE_RECT_MSG;
- msg.obj = this;
- msg.arg1 = (left << 16) | (top & 0xFFFF);
- msg.arg2 = (right << 16) | (bottom & 0xFFFF);
+ msg.obj = info;
mAttachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
}
}
@@ -4865,7 +4972,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
final boolean drawHorizontalScrollBar =
(viewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL;
final boolean drawVerticalScrollBar =
- (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL;
+ (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL
+ && !isVerticalScrollBarHidden();
if (drawVerticalScrollBar || drawHorizontalScrollBar) {
final int width = mRight - mLeft;
@@ -4887,6 +4995,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
}
}
+
+ /**
+ * Override this if the vertical scrollbar needs to be hidden in a subclass, like when
+ * FastScroller is visible.
+ * @return whether to temporarily hide the vertical scrollbar
+ * @hide
+ */
+ protected boolean isVerticalScrollBarHidden() {
+ return false;
+ }
/**
* <p>Draw the horizontal scrollbar if
@@ -4924,7 +5042,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
(viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL ?
getVerticalScrollbarWidth() : 0;
- scrollBar.setBounds(scrollX + (mPaddingLeft & inside) + getScrollBarPaddingLeft(), top,
+ scrollBar.setBounds(scrollX + (mPaddingLeft & inside), top,
scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap, top + size);
scrollBar.setParameters(
computeHorizontalScrollRange(),
@@ -5022,6 +5140,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
if (mPendingCheckForLongPress != null) {
removeCallbacks(mPendingCheckForLongPress);
}
+ destroyDrawingCache();
}
/**
@@ -5332,11 +5451,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) {
return null;
}
- if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED &&
- ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mDrawingCache == null)) {
+ if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) {
buildDrawingCache();
}
- return mDrawingCache;
+ return mDrawingCache == null ? null : mDrawingCache.get();
}
/**
@@ -5351,7 +5469,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
*/
public void destroyDrawingCache() {
if (mDrawingCache != null) {
- mDrawingCache.recycle();
+ final Bitmap bitmap = mDrawingCache.get();
+ if (bitmap != null) bitmap.recycle();
mDrawingCache = null;
}
}
@@ -5391,7 +5510,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* @see #destroyDrawingCache()
*/
public void buildDrawingCache() {
- if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mDrawingCache == null) {
+ if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mDrawingCache == null ||
+ mDrawingCache.get() == null) {
+
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
}
@@ -5408,16 +5529,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
if (width <= 0 || height <= 0 ||
(width * height * (opaque ? 2 : 4) >= // Projected bitmap size in bytes
- ViewConfiguration.getMaximumDrawingCacheSize())) {
- if (mDrawingCache != null) {
- mDrawingCache.recycle();
- }
- mDrawingCache = null;
+ ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
+ destroyDrawingCache();
return;
}
boolean clear = true;
- Bitmap bitmap = mDrawingCache;
+ Bitmap bitmap = mDrawingCache == null ? null : mDrawingCache.get();
if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
@@ -5442,12 +5560,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
// Try to cleanup memory
- if (mDrawingCache != null) {
- mDrawingCache.recycle();
- }
+ if (bitmap != null) bitmap.recycle();
try {
- mDrawingCache = bitmap = Bitmap.createBitmap(width, height, quality);
+ bitmap = Bitmap.createBitmap(width, height, quality);
+ mDrawingCache = new SoftReference<Bitmap>(bitmap);
} catch (OutOfMemoryError e) {
// If there is not enough memory to create the bitmap cache, just
// ignore the issue as bitmap caches are not required to draw the
@@ -5485,9 +5602,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
final int restoreCount = canvas.save();
canvas.translate(-mScrollX, -mScrollY);
+ mPrivateFlags |= DRAWN;
+
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
- mPrivateFlags |= DRAWN;
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
}
@@ -5616,6 +5734,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
}
+ mPrivateFlags |= DRAWN;
+
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
@@ -5656,7 +5776,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
// Step 3, draw the content
- mPrivateFlags |= DRAWN;
onDraw(canvas);
// Step 4, draw the children
@@ -5760,7 +5879,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
}
// Step 3, draw the content
- mPrivateFlags |= DRAWN;
onDraw(canvas);
// Step 4, draw the children
@@ -6411,32 +6529,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
return mBGDrawable;
}
- private int getScrollBarPaddingLeft() {
- // TODO: Deal with RTL languages
- return 0;
- }
-
- /*
- * Returns the pixels occupied by the vertical scrollbar, if not overlaid
- */
- private int getScrollBarPaddingRight() {
- // TODO: Deal with RTL languages
- if ((mViewFlags & SCROLLBARS_VERTICAL) == 0) {
- return 0;
- }
- return (mViewFlags & SCROLLBARS_INSET_MASK) == 0 ? 0 : getVerticalScrollbarWidth();
- }
-
- /*
- * Returns the pixels occupied by the horizontal scrollbar, if not overlaid
- */
- private int getScrollBarPaddingBottom() {
- if ((mViewFlags & SCROLLBARS_HORIZONTAL) == 0) {
- return 0;
- }
- return (mViewFlags & SCROLLBARS_INSET_MASK) == 0 ? 0 : getHorizontalScrollbarHeight();
- }
-
/**
* Sets the padding. The view may add on the space required to display
* the scrollbars, depending on the style and visibility of the scrollbars.
@@ -6460,7 +6552,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
mUserPaddingRight = right;
mUserPaddingBottom = bottom;
- if (mPaddingLeft != left + getScrollBarPaddingLeft()) {
+ final int viewFlags = mViewFlags;
+
+ // Common case is there are no scroll bars.
+ if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) {
+ // TODO: Deal with RTL languages to adjust left padding instead of right.
+ if ((viewFlags & SCROLLBARS_VERTICAL) != 0) {
+ right += (viewFlags & SCROLLBARS_INSET_MASK) == 0
+ ? 0 : getVerticalScrollbarWidth();
+ }
+ if ((viewFlags & SCROLLBARS_HORIZONTAL) == 0) {
+ bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0
+ ? 0 : getHorizontalScrollbarHeight();
+ }
+ }
+
+ if (mPaddingLeft != left) {
changed = true;
mPaddingLeft = left;
}
@@ -6468,13 +6575,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
changed = true;
mPaddingTop = top;
}
- if (mPaddingRight != right + getScrollBarPaddingRight()) {
+ if (mPaddingRight != right) {
changed = true;
- mPaddingRight = right + getScrollBarPaddingRight();
+ mPaddingRight = right;
}
- if (mPaddingBottom != bottom + getScrollBarPaddingBottom()) {
+ if (mPaddingBottom != bottom) {
changed = true;
- mPaddingBottom = bottom + getScrollBarPaddingBottom();
+ mPaddingBottom = bottom;
}
if (changed) {
@@ -7275,20 +7382,57 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
/**
* Play a sound effect for this view.
*
- * The framework will play sound effects for some built in actions, such as
+ * <p>The framework will play sound effects for some built in actions, such as
* clicking, but you may wish to play these effects in your widget,
* for instance, for internal navigation.
*
- * The sound effect will only be played if sound effects are enabled by the user, and
+ * <p>The sound effect will only be played if sound effects are enabled by the user, and
* {@link #isSoundEffectsEnabled()} is true.
*
* @param soundConstant One of the constants defined in {@link SoundEffectConstants}
*/
- protected void playSoundEffect(int soundConstant) {
- if (mAttachInfo == null || mAttachInfo.mSoundEffectPlayer == null || !isSoundEffectsEnabled()) {
+ public void playSoundEffect(int soundConstant) {
+ if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) {
return;
}
- mAttachInfo.mSoundEffectPlayer.playSoundEffect(soundConstant);
+ mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant);
+ }
+
+ /**
+ * Provide haptic feedback to the user for this view.
+ *
+ * <p>The framework will provide haptic feedback for some built in actions,
+ * such as long presses, but you may wish to provide feedback for your
+ * own widget.
+ *
+ * <p>The feedback will only be performed if
+ * {@link #isHapticFeedbackEnabled()} is true.
+ *
+ * @param feedbackConstant One of the constants defined in
+ * {@link HapticFeedbackConstants}
+ */
+ public boolean performHapticFeedback(int feedbackConstant) {
+ return performHapticFeedback(feedbackConstant, 0);
+ }
+
+ /**
+ * Like {@link #performHapticFeedback(int)}, with additional options.
+ *
+ * @param feedbackConstant One of the constants defined in
+ * {@link HapticFeedbackConstants}
+ * @param flags Additional flags as per {@link HapticFeedbackConstants}.
+ */
+ public boolean performHapticFeedback(int feedbackConstant, int flags) {
+ if (mAttachInfo == null) {
+ return false;
+ }
+ if ((flags&HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
+ && !isHapticFeedbackEnabled()) {
+ return false;
+ }
+ return mAttachInfo.mRootCallbacks.performHapticFeedback(
+ feedbackConstant,
+ (flags&HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
}
/**
@@ -7667,8 +7811,70 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
*/
static class AttachInfo {
- interface SoundEffectPlayer {
+ interface Callbacks {
void playSoundEffect(int effectId);
+ boolean performHapticFeedback(int effectId, boolean always);
+ }
+
+ /**
+ * InvalidateInfo is used to post invalidate(int, int, int, int) messages
+ * to a Handler. This class contains the target (View) to invalidate and
+ * the coordinates of the dirty rectangle.
+ *
+ * For performance purposes, this class also implements a pool of up to
+ * POOL_LIMIT objects that get reused. This reduces memory allocations
+ * whenever possible.
+ *
+ * The pool is implemented as a linked list of InvalidateInfo object with
+ * the root pointing to the next available InvalidateInfo. If the root
+ * is null (i.e. when all instances from the pool have been acquired),
+ * then a new InvalidateInfo is created and returned to the caller.
+ *
+ * An InvalidateInfo is sent back to the pool by calling its release()
+ * method. If the pool is full the object is simply discarded.
+ *
+ * This implementation follows the object pool pattern used in the
+ * MotionEvent class.
+ */
+ static class InvalidateInfo {
+ private static final int POOL_LIMIT = 10;
+ private static final Object sLock = new Object();
+
+ private static int sAcquiredCount = 0;
+ private static InvalidateInfo sRoot;
+
+ private InvalidateInfo next;
+
+ View target;
+
+ int left;
+ int top;
+ int right;
+ int bottom;
+
+ static InvalidateInfo acquire() {
+ synchronized (sLock) {
+ if (sRoot == null) {
+ return new InvalidateInfo();
+ }
+
+ InvalidateInfo info = sRoot;
+ sRoot = info.next;
+ sAcquiredCount--;
+
+ return info;
+ }
+ }
+
+ void release() {
+ synchronized (sLock) {
+ if (sAcquiredCount < POOL_LIMIT) {
+ sAcquiredCount++;
+ next = sRoot;
+ sRoot = this;
+ }
+ }
+ }
}
final IWindowSession mSession;
@@ -7677,7 +7883,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
final IBinder mWindowToken;
- final SoundEffectPlayer mSoundEffectPlayer;
+ final Callbacks mRootCallbacks;
/**
* The top view of the hierarchy.
@@ -7771,6 +7977,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
boolean mViewVisibilityChanged;
/**
+ * Set to true if a view has been scrolled.
+ */
+ boolean mViewScrollChanged;
+
+ /**
* Global to the view hierarchy used as a temporary for dealing with
* x/y points in the transparent region computations.
*/
@@ -7824,12 +8035,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* @param handler the events handler the view must use
*/
AttachInfo(IWindowSession session, IWindow window,
- Handler handler, SoundEffectPlayer effectPlayer) {
+ Handler handler, Callbacks effectPlayer) {
mSession = session;
mWindow = window;
mWindowToken = window.asBinder();
mHandler = handler;
- mSoundEffectPlayer = effectPlayer;
+ mRootCallbacks = effectPlayer;
}
}
@@ -7839,18 +8050,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
* instances of View.</p>
*/
private static class ScrollabilityCache {
- public int fadingEdgeLength = ViewConfiguration.getFadingEdgeLength();
+ public int fadingEdgeLength;
- public int scrollBarSize = ViewConfiguration.getScrollBarSize();
+ public int scrollBarSize;
public ScrollBarDrawable scrollBar;
public final Paint paint;
public final Matrix matrix;
public Shader shader;
- private int mLastColor = 0;
+ private int mLastColor;
+
+ public ScrollabilityCache(ViewConfiguration configuration) {
+ fadingEdgeLength = configuration.getScaledFadingEdgeLength();
+ scrollBarSize = configuration.getScaledScrollBarSize();
- public ScrollabilityCache() {
paint = new Paint();
matrix = new Matrix();
// use use a height of 1, and then wack the matrix each time we
@@ -7869,7 +8083,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
shader = new LinearGradient(0, 0, 0, 1, color, 0, Shader.TileMode.CLAMP);
paint.setShader(shader);
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
+ // Restore the default transfer mode (src_over)
+ paint.setXfermode(null);
}
}
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index b7110ce..d3f48c6 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -16,17 +16,19 @@
package android.view;
+import android.content.Context;
+import android.util.DisplayMetrics;
+import android.util.SparseArray;
+
/**
* Contains methods to standard constants used in the UI for timeouts, sizes, and distances.
- *
*/
public class ViewConfiguration {
-
/**
* Defines the width of the horizontal scrollbar and the height of the vertical scrollbar in
* pixels
*/
- private static final int SCROLL_BAR_SIZE = 6;
+ private static final int SCROLL_BAR_SIZE = 10;
/**
* Defines the length of the fading edges in pixels
@@ -54,7 +56,7 @@ public class ViewConfiguration {
/**
* Defines the duration in milliseconds we will wait to see if a touch event
- * is a top or a scroll. If the user does not move within this interval, it is
+ * is a tap or a scroll. If the user does not move within this interval, it is
* considered to be a tap.
*/
private static final int TAP_TIMEOUT = 100;
@@ -65,6 +67,13 @@ public class ViewConfiguration {
* considered to be a tap.
*/
private static final int JUMP_TAP_TIMEOUT = 500;
+
+ /**
+ * Defines the duration in milliseconds between the first tap's up event and
+ * the second tap's down event for an interaction to be considered a
+ * double-tap.
+ */
+ private static final int DOUBLE_TAP_TIMEOUT = 300;
/**
* Defines the duration in milliseconds we want to display zoom controls in response
@@ -80,7 +89,12 @@ public class ViewConfiguration {
/**
* Distance a touch can wander before we think the user is scrolling in pixels
*/
- private static final int TOUCH_SLOP = 12;
+ private static final int TOUCH_SLOP = 25;
+
+ /**
+ * Distance between the first touch and second touch to still be considered a double tap
+ */
+ private static final int DOUBLE_TAP_SLOP = 100;
/**
* Distance a touch needs to be outside of a window's bounds for it to
@@ -97,30 +111,126 @@ public class ViewConfiguration {
* The maximum size of View's drawing cache, expressed in bytes. This size
* should be at least equal to the size of the screen in ARGB888 format.
*/
- private static final int MAXIMUM_DRAWING_CACHE_SIZE = 320 * 480 * 4; // One HVGA screen, ARGB8888
+ @Deprecated
+ private static final int MAXIMUM_DRAWING_CACHE_SIZE = 320 * 480 * 4; // HVGA screen, ARGB8888
/**
* The coefficient of friction applied to flings/scrolls.
*/
private static float SCROLL_FRICTION = 0.015f;
+ private final int mEdgeSlop;
+ private final int mFadingEdgeLength;
+ private final int mMinimumFlingVelocity;
+ private final int mScrollbarSize;
+ private final int mTouchSlop;
+ private final int mDoubleTapSlop;
+ private final int mWindowTouchSlop;
+ private final int mMaximumDrawingCacheSize;
+
+ private static final SparseArray<ViewConfiguration> sConfigurations =
+ new SparseArray<ViewConfiguration>(2);
+
+ /**
+ * @deprecated Use {@link android.view.ViewConfiguration#get(android.content.Context)} instead.
+ */
+ @Deprecated
+ public ViewConfiguration() {
+ mEdgeSlop = EDGE_SLOP;
+ mFadingEdgeLength = FADING_EDGE_LENGTH;
+ mMinimumFlingVelocity = MINIMUM_FLING_VELOCITY;
+ mScrollbarSize = SCROLL_BAR_SIZE;
+ mTouchSlop = TOUCH_SLOP;
+ mDoubleTapSlop = DOUBLE_TAP_SLOP;
+ mWindowTouchSlop = WINDOW_TOUCH_SLOP;
+ //noinspection deprecation
+ mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE;
+ }
+
+ /**
+ * Creates a new configuration for the specified context. The configuration depends on
+ * various parameters of the context, like the dimension of the display or the density
+ * of the display.
+ *
+ * @param context The application context used to initialize this view configuration.
+ *
+ * @see #get(android.content.Context)
+ * @see android.util.DisplayMetrics
+ */
+ private ViewConfiguration(Context context) {
+ final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ final float density = metrics.density;
+
+ mEdgeSlop = (int) (density * EDGE_SLOP + 0.5f);
+ mFadingEdgeLength = (int) (density * FADING_EDGE_LENGTH + 0.5f);
+ mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f);
+ mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
+ mTouchSlop = (int) (density * TOUCH_SLOP + 0.5f);
+ mDoubleTapSlop = (int) (density * DOUBLE_TAP_SLOP + 0.5f);
+ mWindowTouchSlop = (int) (density * WINDOW_TOUCH_SLOP + 0.5f);
+
+ // Size of the screen in bytes, in ARGB_8888 format
+ mMaximumDrawingCacheSize = 4 * metrics.widthPixels * metrics.heightPixels;
+ }
+
+ /**
+ * Returns a configuration for the specified context. The configuration depends on
+ * various parameters of the context, like the dimension of the display or the
+ * density of the display.
+ *
+ * @param context The application context used to initialize the view configuration.
+ */
+ public static ViewConfiguration get(Context context) {
+ final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ final int density = (int) (100.0f * metrics.density);
+
+ ViewConfiguration configuration = sConfigurations.get(density);
+ if (configuration == null) {
+ configuration = new ViewConfiguration(context);
+ sConfigurations.put(density, configuration);
+ }
+
+ return configuration;
+ }
+
/**
* @return The width of the horizontal scrollbar and the height of the vertical
* scrollbar in pixels
+ *
+ * @deprecated Use {@link #getScaledScrollBarSize()} instead.
*/
+ @Deprecated
public static int getScrollBarSize() {
return SCROLL_BAR_SIZE;
}
/**
- * @return Defines the length of the fading edges in pixels
+ * @return The width of the horizontal scrollbar and the height of the vertical
+ * scrollbar in pixels
*/
+ public int getScaledScrollBarSize() {
+ return mScrollbarSize;
+ }
+
+ /**
+ * @return the length of the fading edges in pixels
+ *
+ * @deprecated Use {@link #getScaledFadingEdgeLength()} instead.
+ */
+ @Deprecated
public static int getFadingEdgeLength() {
return FADING_EDGE_LENGTH;
}
-
+
/**
- * @return Defines the duration in milliseconds of the pressed state in child
+ * @return the length of the fading edges in pixels
+ */
+ public int getScaledFadingEdgeLength() {
+ return mFadingEdgeLength;
+ }
+
+ /**
+ * @return the duration in milliseconds of the pressed state in child
* components.
*/
public static int getPressedStateDuration() {
@@ -128,7 +238,7 @@ public class ViewConfiguration {
}
/**
- * @return Defines the duration in milliseconds before a press turns into
+ * @return the duration in milliseconds before a press turns into
* a long press
*/
public static int getLongPressTimeout() {
@@ -136,8 +246,8 @@ public class ViewConfiguration {
}
/**
- * @return Defines the duration in milliseconds we will wait to see if a touch event
- * is a top or a scroll. If the user does not move within this interval, it is
+ * @return the duration in milliseconds we will wait to see if a touch event
+ * is a tap or a scroll. If the user does not move within this interval, it is
* considered to be a tap.
*/
public static int getTapTimeout() {
@@ -145,7 +255,7 @@ public class ViewConfiguration {
}
/**
- * @return Defines the duration in milliseconds we will wait to see if a touch event
+ * @return the duration in milliseconds we will wait to see if a touch event
* is a jump tap. If the user does not move within this interval, it is
* considered to be a tap.
*/
@@ -154,46 +264,133 @@ public class ViewConfiguration {
}
/**
+ * @return the duration in milliseconds between the first tap's up event and
+ * the second tap's down event for an interaction to be considered a
+ * double-tap.
+ * @hide pending API council
+ */
+ public static int getDoubleTapTimeout() {
+ return DOUBLE_TAP_TIMEOUT;
+ }
+
+ /**
* @return Inset in pixels to look for touchable content when the user touches the edge of the
* screen
+ *
+ * @deprecated Use {@link #getScaledEdgeSlop()} instead.
*/
+ @Deprecated
public static int getEdgeSlop() {
return EDGE_SLOP;
}
-
+
+ /**
+ * @return Inset in pixels to look for touchable content when the user touches the edge of the
+ * screen
+ */
+ public int getScaledEdgeSlop() {
+ return mEdgeSlop;
+ }
+
/**
* @return Distance a touch can wander before we think the user is scrolling in pixels
+ *
+ * @deprecated Use {@link #getScaledTouchSlop()} instead.
*/
+ @Deprecated
public static int getTouchSlop() {
return TOUCH_SLOP;
}
+
+ /**
+ * @return Distance a touch can wander before we think the user is scrolling in pixels
+ */
+ public int getScaledTouchSlop() {
+ return mTouchSlop;
+ }
+
+ /**
+ * @return Distance between the first touch and second touch to still be
+ * considered a double tap
+ * @deprecated Use {@link #getScaledDoubleTapSlop()} instead.
+ * @hide The only client of this should be GestureDetector, which needs this
+ * for clients that still use its deprecated constructor.
+ */
+ @Deprecated
+ public static int getDoubleTapSlop() {
+ return DOUBLE_TAP_SLOP;
+ }
/**
+ * @return Distance between the first touch and second touch to still be
+ * considered a double tap
+ * @hide pending API council
+ */
+ public int getScaledDoubleTapSlop() {
+ return mDoubleTapSlop;
+ }
+
+ /**
* @return Distance a touch must be outside the bounds of a window for it
* to be counted as outside the window for purposes of dismissing that
* window.
+ *
+ * @deprecated Use {@link #getScaledWindowTouchSlop()} instead.
*/
+ @Deprecated
public static int getWindowTouchSlop() {
return WINDOW_TOUCH_SLOP;
}
+
+ /**
+ * @return Distance a touch must be outside the bounds of a window for it
+ * to be counted as outside the window for purposes of dismissing that
+ * window.
+ */
+ public int getScaledWindowTouchSlop() {
+ return mWindowTouchSlop;
+ }
/**
- * Minimum velocity to initiate a fling, as measured in pixels per second
+ * @return Minimum velocity to initiate a fling, as measured in pixels per second.
+ *
+ * @deprecated Use {@link #getScaledMinimumFlingVelocity()} instead.
*/
- public static int getMinimumFlingVelocity() {
- return MINIMUM_FLING_VELOCITY;
+ @Deprecated
+ public static int getMinimumFlingVelocity() {
+ return MINIMUM_FLING_VELOCITY;
+ }
+
+ /**
+ * @return Minimum velocity to initiate a fling, as measured in pixels per second.
+ */
+ public int getScaledMinimumFlingVelocity() {
+ return mMinimumFlingVelocity;
}
/**
* The maximum drawing cache size expressed in bytes.
*
* @return the maximum size of View's drawing cache expressed in bytes
+ *
+ * @deprecated Use {@link #getScaledMaximumDrawingCacheSize()} instead.
*/
+ @Deprecated
public static int getMaximumDrawingCacheSize() {
+ //noinspection deprecation
return MAXIMUM_DRAWING_CACHE_SIZE;
}
/**
+ * The maximum drawing cache size expressed in bytes.
+ *
+ * @return the maximum size of View's drawing cache expressed in bytes
+ */
+ public int getScaledMaximumDrawingCacheSize() {
+ return mMaximumDrawingCacheSize;
+ }
+
+ /**
* The amount of time that the zoom controls should be
* displayed on the screen expressed in milliseconds.
*
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 883c7bd..6ea7a82 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -17,9 +17,12 @@
package android.view;
import android.util.Log;
+import android.util.DisplayMetrics;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.os.Environment;
+import android.os.Debug;
import java.io.File;
import java.io.BufferedWriter;
@@ -43,6 +46,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.AccessibleObject;
/**
* Various debugging/tracing tools related to {@link View} and the view hierarchy.
@@ -73,7 +77,7 @@ public class ViewDebug {
* when it is set, we log key events, touch/motion and trackball events
*/
static final String SYSTEM_PROPERTY_CAPTURE_EVENT = "debug.captureevent";
-
+
/**
* This annotation can be used to mark fields and methods to be dumped by
* the view server. Only non-void methods with no arguments can be annotated
@@ -113,6 +117,27 @@ public class ViewDebug {
IntToString[] mapping() default { };
/**
+ * A mapping can be defined to map array indices to specific strings.
+ * A mapping can be used to see human readable values for the indices
+ * of an array:
+ *
+ * <pre>
+ * @ViewDebug.ExportedProperty(mapping = {
+ * @ViewDebug.IntToString(from = 0, to = "INVALID"),
+ * @ViewDebug.IntToString(from = 1, to = "FIRST"),
+ * @ViewDebug.IntToString(from = 2, to = "SECOND")
+ * })
+ * private int[] mElements;
+ * <pre>
+ *
+ * @return An array of int to String mappings
+ *
+ * @see android.view.ViewDebug.IntToString
+ * @see #mapping()
+ */
+ IntToString[] indexMapping() default { };
+
+ /**
* When deep export is turned on, this property is not dumped. Instead, the
* properties contained in this property are dumped. Each child property
* is prefixed with the name of this property.
@@ -187,10 +212,12 @@ public class ViewDebug {
private static final String REMOTE_COMMAND_DUMP = "DUMP";
private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE";
private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT";
+ private static final String REMOTE_PROFILE = "PROFILE";
private static HashMap<Class<?>, Field[]> sFieldsForClasses;
private static HashMap<Class<?>, Method[]> sMethodsForClasses;
-
+ private static HashMap<AccessibleObject, ExportedProperty> sAnnotations;
+
/**
* Defines the type of hierarhcy trace to output to the hierarchy traces file.
*/
@@ -347,6 +374,7 @@ public class ViewDebug {
}
File recyclerDump = new File(Environment.getExternalStorageDirectory(), "view-recycler/");
+ //noinspection ResultOfMethodCallIgnored
recyclerDump.mkdirs();
recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".recycler");
@@ -450,6 +478,7 @@ public class ViewDebug {
}
File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/");
+ //noinspection ResultOfMethodCallIgnored
hierarchyDump.mkdirs();
hierarchyDump = new File(hierarchyDump, prefix + ".traces");
@@ -497,6 +526,7 @@ public class ViewDebug {
sHierarchyTraces = null;
File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "view-hierarchy/");
+ //noinspection ResultOfMethodCallIgnored
hierarchyDump.mkdirs();
hierarchyDump = new File(hierarchyDump, sHierarchyTracePrefix + ".tree");
@@ -538,32 +568,41 @@ public class ViewDebug {
invalidate(view, params[0]);
} else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) {
requestLayout(view, params[0]);
+ } else if (REMOTE_PROFILE.equalsIgnoreCase(command)) {
+ profile(view, clientStream, params[0]);
}
}
}
- private static View findViewByHashCode(View root, String parameter) {
- final String[] ids = parameter.split("@");
- final String className = ids[0];
- final int hashCode = Integer.parseInt(ids[1], 16);
+ private static View findView(View root, String parameter) {
+ // Look by type/hashcode
+ if (parameter.indexOf('@') != -1) {
+ final String[] ids = parameter.split("@");
+ final String className = ids[0];
+ final int hashCode = Integer.parseInt(ids[1], 16);
- View view = root.getRootView();
- if (view instanceof ViewGroup) {
- return findView((ViewGroup) view, className, hashCode);
+ View view = root.getRootView();
+ if (view instanceof ViewGroup) {
+ return findView((ViewGroup) view, className, hashCode);
+ }
+ } else {
+ // Look by id
+ final int id = root.getResources().getIdentifier(parameter, null, null);
+ return root.getRootView().findViewById(id);
}
return null;
}
private static void invalidate(View root, String parameter) {
- final View view = findViewByHashCode(root, parameter);
+ final View view = findView(root, parameter);
if (view != null) {
view.postInvalidate();
}
}
private static void requestLayout(View root, String parameter) {
- final View view = findViewByHashCode(root, parameter);
+ final View view = findView(root, parameter);
if (view != null) {
root.post(new Runnable() {
public void run() {
@@ -573,19 +612,139 @@ public class ViewDebug {
}
}
- private static void capture(View root, final OutputStream clientStream, String parameter)
+ private static void profile(View root, OutputStream clientStream, String parameter)
throws IOException {
+ final View view = findView(root, parameter);
+ BufferedWriter out = null;
+ try {
+ out = new BufferedWriter(new OutputStreamWriter(clientStream), 32 * 1024);
+
+ if (view != null) {
+ final long durationMeasure = profileViewOperation(view, new ViewOperation<Void>() {
+ public Void[] pre() {
+ forceLayout(view);
+ return null;
+ }
+
+ private void forceLayout(View view) {
+ view.forceLayout();
+ if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) view;
+ final int count = group.getChildCount();
+ for (int i = 0; i < count; i++) {
+ forceLayout(group.getChildAt(i));
+ }
+ }
+ }
+
+ public void run(Void... data) {
+ view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec);
+ }
+
+ public void post(Void... data) {
+ }
+ });
+
+ final long durationLayout = profileViewOperation(view, new ViewOperation<Void>() {
+ public Void[] pre() {
+ return null;
+ }
+
+ public void run(Void... data) {
+ view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom);
+ }
+
+ public void post(Void... data) {
+ }
+ });
+
+ final long durationDraw = profileViewOperation(view, new ViewOperation<Object>() {
+ public Object[] pre() {
+ final DisplayMetrics metrics = view.getResources().getDisplayMetrics();
+ final Bitmap bitmap = Bitmap.createBitmap(metrics.widthPixels,
+ metrics.heightPixels, Bitmap.Config.RGB_565);
+ final Canvas canvas = new Canvas(bitmap);
+ return new Object[] { bitmap, canvas };
+ }
+
+ public void run(Object... data) {
+ view.draw((Canvas) data[1]);
+ }
+
+ public void post(Object... data) {
+ ((Bitmap) data[0]).recycle();
+ }
+ });
+
+ out.write(String.valueOf(durationMeasure));
+ out.write(' ');
+ out.write(String.valueOf(durationLayout));
+ out.write(' ');
+ out.write(String.valueOf(durationDraw));
+ out.newLine();
+ } else {
+ out.write("-1 -1 -1");
+ out.newLine();
+ }
+ } catch (Exception e) {
+ android.util.Log.w("View", "Problem profiling the view:", e);
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
+ }
+
+ interface ViewOperation<T> {
+ T[] pre();
+ void run(T... data);
+ void post(T... data);
+ }
+
+ private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) {
final CountDownLatch latch = new CountDownLatch(1);
- final View captureView = findViewByHashCode(root, parameter);
+ final long[] duration = new long[1];
+
+ view.post(new Runnable() {
+ public void run() {
+ try {
+ T[] data = operation.pre();
+ long start = Debug.threadCpuTimeNanos();
+ operation.run(data);
+ duration[0] = Debug.threadCpuTimeNanos() - start;
+ operation.post(data);
+ } finally {
+ latch.countDown();
+ }
+ }
+ });
+
+ try {
+ latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Log.w("View", "Could not complete the profiling of the view " + view);
+ Thread.currentThread().interrupt();
+ return -1;
+ }
+
+ return duration[0];
+ }
+
+ private static void capture(View root, final OutputStream clientStream, String parameter)
+ throws IOException {
+
+ final View captureView = findView(root, parameter);
if (captureView != null) {
+ final CountDownLatch latch = new CountDownLatch(1);
final Bitmap[] cache = new Bitmap[1];
final boolean hasCache = captureView.isDrawingCacheEnabled();
final boolean willNotCache = captureView.willNotCacheDrawing();
if (willNotCache) {
+ // TODO: Should happen on the UI thread
captureView.setWillNotCacheDrawing(false);
}
@@ -619,12 +778,15 @@ public class ViewDebug {
}
}
} catch (InterruptedException e) {
- Log.w("View", "Could not complete the capture of the view " + captureView);
+ Log.w("View", "Could not complete the capture of the view " + captureView);
+ Thread.currentThread().interrupt();
} finally {
if (willNotCache) {
+ // TODO: Should happen on the UI thread
captureView.setWillNotCacheDrawing(true);
}
if (!hasCache) {
+ // TODO: Should happen on the UI thread
captureView.destroyDrawingCache();
}
}
@@ -642,6 +804,8 @@ public class ViewDebug {
}
out.write("DONE.");
out.newLine();
+ } catch (Exception e) {
+ android.util.Log.w("View", "Problem dumping the view:", e);
} finally {
if (out != null) {
out.close();
@@ -713,7 +877,12 @@ public class ViewDebug {
if (sFieldsForClasses == null) {
sFieldsForClasses = new HashMap<Class<?>, Field[]>();
}
+ if (sAnnotations == null) {
+ sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512);
+ }
+
final HashMap<Class<?>, Field[]> map = sFieldsForClasses;
+ final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations;
Field[] fields = map.get(klass);
if (fields != null) {
@@ -729,6 +898,7 @@ public class ViewDebug {
if (field.isAnnotationPresent(ExportedProperty.class)) {
field.setAccessible(true);
foundFields.add(field);
+ annotations.put(field, field.getAnnotation(ExportedProperty.class));
}
}
@@ -740,9 +910,14 @@ public class ViewDebug {
private static Method[] getExportedPropertyMethods(Class<?> klass) {
if (sMethodsForClasses == null) {
- sMethodsForClasses = new HashMap<Class<?>, Method[]>();
+ sMethodsForClasses = new HashMap<Class<?>, Method[]>(100);
+ }
+ if (sAnnotations == null) {
+ sAnnotations = new HashMap<AccessibleObject, ExportedProperty>(512);
}
+
final HashMap<Class<?>, Method[]> map = sMethodsForClasses;
+ final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations;
Method[] methods = map.get(klass);
if (methods != null) {
@@ -756,10 +931,11 @@ public class ViewDebug {
for (int i = 0; i < count; i++) {
final Method method = methods[i];
if (method.getParameterTypes().length == 0 &&
- method.isAnnotationPresent(ExportedProperty.class) &&
- method.getReturnType() != Void.class) {
+ method.isAnnotationPresent(ExportedProperty.class) &&
+ method.getReturnType() != Void.class) {
method.setAccessible(true);
foundMethods.add(method);
+ annotations.put(method, method.getAnnotation(ExportedProperty.class));
}
}
@@ -799,20 +975,10 @@ public class ViewDebug {
final Class<?> returnType = method.getReturnType();
if (returnType == int.class) {
- ExportedProperty property = method.getAnnotation(ExportedProperty.class);
+ final ExportedProperty property = sAnnotations.get(method);
if (property.resolveId() && view instanceof View) {
- final Resources resources = ((View) view).getContext().getResources();
final int id = (Integer) methodValue;
- if (id >= 0) {
- try {
- methodValue = resources.getResourceTypeName(id) + '/' +
- resources.getResourceEntryName(id);
- } catch (Resources.NotFoundException e) {
- methodValue = "UNKNOWN";
- }
- } else {
- methodValue = "NO_ID";
- }
+ methodValue = resolveId(view, id);
} else {
final IntToString[] mapping = property.mapping();
if (mapping.length > 0) {
@@ -833,28 +999,22 @@ public class ViewDebug {
}
}
}
+ } else if (returnType == int[].class) {
+ final ExportedProperty property = sAnnotations.get(method);
+ final int[] array = (int[]) methodValue;
+ final String valuePrefix = prefix + method.getName() + '_';
+ final String suffix = "()";
+
+ exportUnrolledArray(view, out, property, array, valuePrefix, suffix);
} else if (!returnType.isPrimitive()) {
- ExportedProperty property = method.getAnnotation(ExportedProperty.class);
+ final ExportedProperty property = sAnnotations.get(method);
if (property.deepExport()) {
dumpViewProperties(methodValue, out, prefix + property.prefix());
continue;
}
}
- out.write(prefix);
- out.write(method.getName());
- out.write("()=");
-
- if (methodValue != null) {
- final String value = methodValue.toString().replace("\n", "\\n");
- out.write(String.valueOf(value.length()));
- out.write(",");
- out.write(value);
- } else {
- out.write("4,null");
- }
-
- out.write(' ');
+ writeEntry(out, prefix, method.getName(), "()", methodValue);
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
@@ -875,20 +1035,10 @@ public class ViewDebug {
final Class<?> type = field.getType();
if (type == int.class) {
- ExportedProperty property = field.getAnnotation(ExportedProperty.class);
+ final ExportedProperty property = sAnnotations.get(field);
if (property.resolveId() && view instanceof View) {
- final Resources resources = ((View) view).getContext().getResources();
final int id = field.getInt(view);
- if (id >= 0) {
- try {
- fieldValue = resources.getResourceTypeName(id) + '/' +
- resources.getResourceEntryName(id);
- } catch (Resources.NotFoundException e) {
- fieldValue = "UNKNOWN";
- }
- } else {
- fieldValue = "NO_ID";
- }
+ fieldValue = resolveId(view, id);
} else {
final IntToString[] mapping = property.mapping();
if (mapping.length > 0) {
@@ -907,8 +1057,18 @@ public class ViewDebug {
}
}
}
+ } else if (type == int[].class) {
+ final ExportedProperty property = sAnnotations.get(field);
+ final int[] array = (int[]) field.get(view);
+ final String valuePrefix = prefix + field.getName() + '_';
+ final String suffix = "";
+
+ exportUnrolledArray(view, out, property, array, valuePrefix, suffix);
+
+ // We exit here!
+ return;
} else if (!type.isPrimitive()) {
- ExportedProperty property = field.getAnnotation(ExportedProperty.class);
+ final ExportedProperty property = sAnnotations.get(field);
if (property.deepExport()) {
dumpViewProperties(field.get(view), out, prefix + property.prefix());
continue;
@@ -917,24 +1077,100 @@ public class ViewDebug {
if (fieldValue == null) {
fieldValue = field.get(view);
- }
+ }
- out.write(prefix);
- out.write(field.getName());
- out.write('=');
+ writeEntry(out, prefix, field.getName(), "", fieldValue);
+ } catch (IllegalAccessException e) {
+ }
+ }
+ }
- if (fieldValue != null) {
- final String value = fieldValue.toString().replace("\n", "\\n");
- out.write(String.valueOf(value.length()));
- out.write(",");
- out.write(value);
- } else {
- out.write("4,null");
+ private static void writeEntry(BufferedWriter out, String prefix, String name,
+ String suffix, Object value) throws IOException {
+
+ out.write(prefix);
+ out.write(name);
+ out.write(suffix);
+ out.write("=");
+ writeValue(out, value);
+ out.write(' ');
+ }
+
+ private static void exportUnrolledArray(Object view, BufferedWriter out,
+ ExportedProperty property, int[] array, String prefix, String suffix)
+ throws IOException {
+
+ final IntToString[] indexMapping = property.indexMapping();
+ final boolean hasIndexMapping = indexMapping.length > 0;
+
+ final IntToString[] mapping = property.mapping();
+ final boolean hasMapping = mapping.length > 0;
+
+ final boolean resolveId = property.resolveId() && view instanceof View;
+ final int valuesCount = array.length;
+
+ for (int j = 0; j < valuesCount; j++) {
+ String name;
+ String value;
+
+ final int intValue = array[j];
+
+ name = String.valueOf(j);
+ if (hasIndexMapping) {
+ int mappingCount = indexMapping.length;
+ for (int k = 0; k < mappingCount; k++) {
+ final IntToString mapped = indexMapping[k];
+ if (mapped.from() == j) {
+ name = mapped.to();
+ break;
+ }
}
+ }
- out.write(' ');
- } catch (IllegalAccessException e) {
+ value = String.valueOf(intValue);
+ if (hasMapping) {
+ int mappingCount = mapping.length;
+ for (int k = 0; k < mappingCount; k++) {
+ final IntToString mapped = mapping[k];
+ if (mapped.from() == intValue) {
+ value = mapped.to();
+ break;
+ }
+ }
+ }
+
+ if (resolveId) {
+ value = (String) resolveId(view, intValue);
}
+
+ writeEntry(out, prefix, name, suffix, value);
+ }
+ }
+
+ private static Object resolveId(Object view, int id) {
+ Object fieldValue;
+ final Resources resources = ((View) view).getContext().getResources();
+ if (id >= 0) {
+ try {
+ fieldValue = resources.getResourceTypeName(id) + '/' +
+ resources.getResourceEntryName(id);
+ } catch (Resources.NotFoundException e) {
+ fieldValue = "id/0x" + Integer.toHexString(id);
+ }
+ } else {
+ fieldValue = "NO_ID";
+ }
+ return fieldValue;
+ }
+
+ private static void writeValue(BufferedWriter out, Object value) throws IOException {
+ if (value != null) {
+ String output = value.toString().replace("\n", "\\n");
+ out.write(String.valueOf(output.length()));
+ out.write(",");
+ out.write(output);
+ } else {
+ out.write("4,null");
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e26a19e..dc7b299 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -25,7 +25,9 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.RectF;
import android.os.Parcelable;
+import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
@@ -74,6 +76,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// The current transformation to apply on the child being drawn
private Transformation mChildTransformation;
+ private RectF mInvalidateRegion;
// Target of Motion events
private View mMotionTarget;
@@ -1021,6 +1024,20 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
@Override
void dispatchDetachedFromWindow() {
+ // If we still have a motion target, we are still in the process of
+ // dispatching motion events to a child; we need to get rid of that
+ // child to avoid dispatching events to it after the window is torn
+ // down. To make sure we keep the child in a consistent state, we
+ // first send it an ACTION_CANCEL motion event.
+ if (mMotionTarget != null) {
+ final long now = SystemClock.uptimeMillis();
+ final MotionEvent event = MotionEvent.obtain(now, now,
+ MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+ mMotionTarget.dispatchTouchEvent(event);
+ event.recycle();
+ mMotionTarget = null;
+ }
+
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
@@ -1199,6 +1216,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
+ // We will draw our child's animation, let's reset the flag
+ mPrivateFlags &= ~DRAW_ANIMATION;
mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
boolean more = false;
@@ -1327,9 +1346,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final Animation a = child.getAnimation();
boolean concatMatrix = false;
+ final int childWidth = cr - cl;
+ final int childHeight = cb - ct;
+
if (a != null) {
- if (!a.isInitialized()) {
- a.initialize(cr - cl, cb - ct, getWidth(), getHeight());
+ if (mInvalidateRegion == null) {
+ mInvalidateRegion = new RectF();
+ }
+ final RectF region = mInvalidateRegion;
+
+ final boolean initialized = a.isInitialized();
+ if (!initialized) {
+ a.initialize(childWidth, childHeight, getWidth(), getHeight());
+ a.initializeInvalidateRegion(0, 0, childWidth, childHeight);
child.onAnimationStart();
}
@@ -1347,10 +1376,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
FLAG_OPTIMIZE_INVALIDATE) {
mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
} else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) {
+ // The child need to draw an animation, potentially offscreen, so
+ // make sure we do not cancel invalidate requests
+ mPrivateFlags |= DRAW_ANIMATION;
invalidate(cl, ct, cr, cb);
}
} else {
- mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
+ a.getInvalidateRegion(0, 0, childWidth, childHeight, region, transformToApply);
+
+ // The child need to draw an animation, potentially offscreen, so
+ // make sure we do not cancel invalidate requests
+ mPrivateFlags |= DRAW_ANIMATION;
+
+ final int left = cl + (int) region.left;
+ final int top = ct + (int) region.top;
+ invalidate(left, top, left + (int) region.width(), top + (int) region.height());
}
}
} else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
@@ -1367,7 +1407,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
- if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW)) {
+ if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
+ (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
return more;
}
@@ -1429,16 +1470,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
if (hasNoCache) {
- canvas.clipRect(sx, sy, sx + cr - cl, sy + cb - ct);
+ canvas.clipRect(sx, sy, sx + childWidth, sy + childHeight);
} else {
- canvas.clipRect(0, 0, cr - cl, cb - ct);
+ canvas.clipRect(0, 0, childWidth, childHeight);
}
}
+ // Clear the flag as early as possible to allow draw() implementations
+ // to call invalidate() successfully when doing animations
+ child.mPrivateFlags |= DRAWN;
+
if (hasNoCache) {
// Fast path for layouts with no backgrounds
if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
- child.mPrivateFlags |= DRAWN;
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
}
@@ -1455,7 +1499,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
cachePaint.setAlpha(255);
mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
}
- child.mPrivateFlags |= DRAWN;
if (ViewRoot.PROFILE_DRAWING) {
EventLog.writeEvent(60003, hashCode());
}
@@ -1922,8 +1965,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
LayoutAnimationController.AnimationParameters animationParams =
params.layoutAnimationParameters;
if (animationParams == null) {
- animationParams =
- new LayoutAnimationController.AnimationParameters();
+ animationParams = new LayoutAnimationController.AnimationParameters();
params.layoutAnimationParameters = animationParams;
}
@@ -2278,8 +2320,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final int[] location = attachInfo.mInvalidateChildLocation;
location[CHILD_LEFT_INDEX] = child.mLeft;
location[CHILD_TOP_INDEX] = child.mTop;
+
+ // If the child is drawing an animation, we want to copy this flag onto
+ // ourselves and the parent to make sure the invalidate request goes
+ // through
+ final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
do {
+ if (drawAnimation && parent instanceof View) {
+ ((View) parent).mPrivateFlags |= DRAW_ANIMATION;
+ }
parent = parent.invalidateChildInParent(location, dirty);
} while (parent != null);
}
@@ -2307,7 +2357,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final int left = mLeft;
final int top = mTop;
- if (dirty.intersect(0, 0, mRight - left, mBottom - top)) {
+ if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
+ (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
mPrivateFlags &= ~DRAWING_CACHE_VALID;
location[CHILD_LEFT_INDEX] = left;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 9e0289a..dd2b154 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -33,6 +33,7 @@ import android.util.Config;
import android.util.Log;
import android.util.EventLog;
import android.util.SparseArray;
+import android.util.DisplayMetrics;
import android.view.View.MeasureSpec;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
@@ -61,7 +62,7 @@ import static javax.microedition.khronos.opengles.GL10.*;
*/
@SuppressWarnings({"EmptyCatchBlock"})
public final class ViewRoot extends Handler implements ViewParent,
- View.AttachInfo.SoundEffectPlayer {
+ View.AttachInfo.Callbacks {
private static final String TAG = "ViewRoot";
private static final boolean DBG = false;
@SuppressWarnings({"ConstantConditionalExpression"})
@@ -142,6 +143,7 @@ public final class ViewRoot extends Handler implements ViewParent,
boolean mFullRedrawNeeded;
boolean mNewSurfaceNeeded;
boolean mHasHadWindowFocus;
+ boolean mLastWasImTarget;
boolean mWindowAttributesChanged = false;
@@ -177,12 +179,14 @@ public final class ViewRoot extends Handler implements ViewParent,
boolean mUseGL;
boolean mGlWanted;
+ final ViewConfiguration mViewConfiguration;
+
/**
* see {@link #playSoundEffect(int)}
*/
AudioManager mAudioManager;
-
+ private final float mDensity;
public ViewRoot(Context context) {
super();
@@ -215,7 +219,7 @@ public final class ViewRoot extends Handler implements ViewParent,
mVisRect = new Rect();
mVisPoint = new Point();
mWinFrame = new Rect();
- mWindow = new W(this);
+ mWindow = new W(this, context);
mInputMethodCallback = new InputMethodCallback(this);
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
@@ -224,6 +228,8 @@ public final class ViewRoot extends Handler implements ViewParent,
mSurface = new Surface();
mAdded = false;
mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
+ mViewConfiguration = ViewConfiguration.get(context);
+ mDensity = context.getResources().getDisplayMetrics().density;
}
@Override
@@ -993,6 +999,21 @@ public final class ViewRoot extends Handler implements ViewParent,
mNewSurfaceNeeded = false;
mViewVisibility = viewVisibility;
+ if (mAttachInfo.mHasWindowFocus) {
+ final boolean imTarget = WindowManager.LayoutParams
+ .mayUseInputMethod(mWindowAttributes.flags);
+ if (imTarget != mLastWasImTarget) {
+ mLastWasImTarget = imTarget;
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null && imTarget) {
+ imm.startGettingWindowFocus(mView);
+ imm.onWindowFocus(mView, mView.findFocus(),
+ mWindowAttributes.softInputMode,
+ !mHasHadWindowFocus, mWindowAttributes.flags);
+ }
+ }
+ }
+
boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();
if (!cancelDraw && !newSurface) {
@@ -1075,6 +1096,11 @@ public final class ViewRoot extends Handler implements ViewParent,
}
scrollToRectOrFocus(null, false);
+
+ if (mAttachInfo.mViewScrollChanged) {
+ mAttachInfo.mViewScrollChanged = false;
+ mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
+ }
int yoff;
final boolean scrolling = mScroller != null
@@ -1088,7 +1114,7 @@ public final class ViewRoot extends Handler implements ViewParent,
mCurScrollY = yoff;
fullRedrawNeeded = true;
}
-
+
Rect dirty = mDirty;
if (mUseGL) {
if (!dirty.isEmpty()) {
@@ -1101,6 +1127,7 @@ public final class ViewRoot extends Handler implements ViewParent,
mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
canvas.translate(0, -yoff);
+ mView.mPrivateFlags |= View.DRAWN;
mView.draw(canvas);
canvas.translate(0, yoff);
@@ -1123,7 +1150,6 @@ public final class ViewRoot extends Handler implements ViewParent,
return;
}
-
if (fullRedrawNeeded)
dirty.union(0, 0, mWidth, mHeight);
@@ -1135,20 +1161,22 @@ public final class ViewRoot extends Handler implements ViewParent,
+ surface + " surface.isValid()=" + surface.isValid());
}
- if (!dirty.isEmpty()) {
- Canvas canvas;
- try {
- canvas = surface.lockCanvas(dirty);
- } catch (Surface.OutOfResourcesException e) {
- Log.e("ViewRoot", "OutOfResourcesException locking surface", e);
- // TODO: we should ask the window manager to do something!
- // for now we just do nothing
- return;
- }
+ Canvas canvas;
+ try {
+ canvas = surface.lockCanvas(dirty);
+ // TODO: Do this in native
+ canvas.setDensityScale(mDensity);
+ } catch (Surface.OutOfResourcesException e) {
+ Log.e("ViewRoot", "OutOfResourcesException locking surface", e);
+ // TODO: we should ask the window manager to do something!
+ // for now we just do nothing
+ return;
+ }
- long startTime;
+ try {
+ if (!dirty.isEmpty()) {
+ long startTime;
- try {
if (DEBUG_ORIENTATION || DEBUG_DRAW) {
Log.v("ViewRoot", "Surface " + surface + " drawing to bitmap w="
+ canvas.getWidth() + ", h=" + canvas.getHeight());
@@ -1164,7 +1192,7 @@ public final class ViewRoot extends Handler implements ViewParent,
// properly re-composite its drawing on a transparent
// background. This automatically respects the clip/dirty region
if (!canvas.isOpaque()) {
- canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+ canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
} else if (yoff != 0) {
// If we are applying an offset, we need to clear the area
// where the offset doesn't appear to avoid having garbage
@@ -1175,6 +1203,7 @@ public final class ViewRoot extends Handler implements ViewParent,
dirty.setEmpty();
mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
canvas.translate(0, -yoff);
+ mView.mPrivateFlags |= View.DRAWN;
mView.draw(canvas);
canvas.translate(0, yoff);
@@ -1186,17 +1215,17 @@ public final class ViewRoot extends Handler implements ViewParent,
sDrawTime = now;
}
- } finally {
- surface.unlockCanvasAndPost(canvas);
- }
-
- if (PROFILE_DRAWING) {
- EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
+ if (PROFILE_DRAWING) {
+ EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
+ }
}
+
+ } finally {
+ surface.unlockCanvasAndPost(canvas);
+ }
- if (LOCAL_LOGV) {
- Log.v("ViewRoot", "Surface " + surface + " unlockCanvasAndPost");
- }
+ if (LOCAL_LOGV) {
+ Log.v("ViewRoot", "Surface " + surface + " unlockCanvasAndPost");
}
if (scrolling) {
@@ -1378,14 +1407,22 @@ public final class ViewRoot extends Handler implements ViewParent,
void dispatchDetachedFromWindow() {
if (Config.LOGV) Log.v("ViewRoot", "Detaching in " + this + " of " + mSurface);
+
if (mView != null) {
mView.dispatchDetachedFromWindow();
}
+
mView = null;
mAttachInfo.mRootView = null;
+
if (mUseGL) {
destroyGL();
}
+
+ try {
+ sWindowSession.remove(mWindow);
+ } catch (RemoteException e) {
+ }
}
/**
@@ -1414,6 +1451,7 @@ public final class ViewRoot extends Handler implements ViewParent,
public final static int FINISHED_EVENT = 1010;
public final static int DISPATCH_KEY_FROM_IME = 1011;
public final static int FINISH_INPUT_CONNECTION = 1012;
+ public final static int CHECK_FOCUS = 1013;
@Override
public void handleMessage(Message msg) {
@@ -1422,11 +1460,9 @@ public final class ViewRoot extends Handler implements ViewParent,
((View) msg.obj).invalidate();
break;
case View.AttachInfo.INVALIDATE_RECT_MSG:
- int left = msg.arg1 >>> 16;
- int top = msg.arg1 & 0xFFFF;
- int right = msg.arg2 >>> 16;
- int bottom = msg.arg2 & 0xFFFF;
- ((View) msg.obj).invalidate(left, top, right, bottom);
+ final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
+ info.target.invalidate(info.left, info.top, info.right, info.bottom);
+ info.release();
break;
case DO_TRAVERSAL:
if (mProfile) {
@@ -1478,7 +1514,7 @@ public final class ViewRoot extends Handler implements ViewParent,
event.offsetLocation(0, mCurScrollY);
handled = mView.dispatchTouchEvent(event);
if (!handled && isDown) {
- int edgeSlop = ViewConfiguration.getEdgeSlop();
+ int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
final int edgeFlags = event.getEdgeFlags();
int direction = View.FOCUS_UP;
@@ -1587,16 +1623,23 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
}
+
+ mLastWasImTarget = WindowManager.LayoutParams
+ .mayUseInputMethod(mWindowAttributes.flags);
+
+ InputMethodManager imm = InputMethodManager.peekInstance();
if (mView != null) {
+ if (hasWindowFocus && imm != null && mLastWasImTarget) {
+ imm.startGettingWindowFocus(mView);
+ }
mView.dispatchWindowFocusChanged(hasWindowFocus);
}
// Note: must be done after the focus change callbacks,
// so all of the view state is set up correctly.
if (hasWindowFocus) {
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) {
- imm.onWindowFocus(mView.findFocus(),
+ if (imm != null && mLastWasImTarget) {
+ imm.onWindowFocus(mView, mView.findFocus(),
mWindowAttributes.softInputMode,
!mHasHadWindowFocus, mWindowAttributes.flags);
}
@@ -1626,6 +1669,12 @@ public final class ViewRoot extends Handler implements ViewParent,
imm.reportFinishInputConnection((InputConnection)msg.obj);
}
} break;
+ case CHECK_FOCUS: {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ imm.checkFocus();
+ }
+ } break;
}
}
@@ -1787,6 +1836,11 @@ public final class ViewRoot extends Handler implements ViewParent,
if (event != null) {
event.recycle();
}
+ // If we reach this, we delivered a trackball event to mView and
+ // mView consumed it. Because we will not translate the trackball
+ // event into a key event, touch mode will not exit, so we exit
+ // touch mode here.
+ ensureTouchMode(false);
//noinspection ReturnInsideFinallyBlock
return;
}
@@ -1941,6 +1995,9 @@ public final class ViewRoot extends Handler implements ViewParent,
if (event.getAction() != KeyEvent.ACTION_DOWN) {
return false;
}
+ if ((event.getFlags()&KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) {
+ return false;
+ }
// only relevant if we are in touch mode
if (!mAttachInfo.mInTouchMode) {
@@ -2042,8 +2099,10 @@ public final class ViewRoot extends Handler implements ViewParent,
}
private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
- boolean handled = false;
- handled = mView.dispatchKeyEventPreIme(event);
+ // If mView is null, we just consume the key event because it doesn't
+ // make sense to do anything else with it.
+ boolean handled = mView != null
+ ? mView.dispatchKeyEventPreIme(event) : true;
if (handled) {
if (sendDone) {
if (LOCAL_LOGV) Log.v(
@@ -2058,10 +2117,9 @@ public final class ViewRoot extends Handler implements ViewParent,
// If it is possible for this window to interact with the input
// method window, then we want to first dispatch our key events
// to the input method.
- if (WindowManager.LayoutParams.mayUseInputMethod(
- mWindowAttributes.flags)) {
+ if (mLastWasImTarget) {
InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null && mView != null && imm.isActive()) {
+ if (imm != null && mView != null) {
int seq = enqueuePendingEvent(event, sendDone);
if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
+ seq + " event=" + event);
@@ -2089,6 +2147,10 @@ public final class ViewRoot extends Handler implements ViewParent,
sWindowSession.finishKey(mWindow);
} catch (RemoteException e) {
}
+ } else {
+ Log.w("ViewRoot", "handleFinishedEvent(seq=" + seq
+ + " handled=" + handled + " ev=" + event
+ + ") neither delivering nor finishing key");
}
}
}
@@ -2108,7 +2170,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
boolean keyHandled = mView.dispatchKeyEvent(event);
- if ((!keyHandled && isDown) || (action == KeyEvent.ACTION_MULTIPLE)) {
+ if (!keyHandled && isDown) {
int direction = 0;
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_LEFT:
@@ -2208,6 +2270,17 @@ public final class ViewRoot extends Handler implements ViewParent,
/**
* {@inheritDoc}
*/
+ public boolean performHapticFeedback(int effectId, boolean always) {
+ try {
+ return sWindowSession.performHapticFeedback(mWindow, effectId, always);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public View focusSearch(View focused, int direction) {
checkThread();
if (!(mView instanceof ViewGroup)) {
@@ -2248,10 +2321,6 @@ public final class ViewRoot extends Handler implements ViewParent,
}
if (mAdded) {
mAdded = false;
- try {
- sWindowSession.remove(mWindow);
- } catch (RemoteException e) {
- }
if (immediate) {
dispatchDetachedFromWindow();
} else if (mView != null) {
@@ -2384,11 +2453,71 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
+ static class EventCompletion extends Handler {
+ final IWindow mWindow;
+ final KeyEvent mKeyEvent;
+ final boolean mIsPointer;
+ final MotionEvent mMotionEvent;
+
+ EventCompletion(Looper looper, IWindow window, KeyEvent key,
+ boolean isPointer, MotionEvent motion) {
+ super(looper);
+ mWindow = window;
+ mKeyEvent = key;
+ mIsPointer = isPointer;
+ mMotionEvent = motion;
+ sendEmptyMessage(0);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mKeyEvent != null) {
+ try {
+ sWindowSession.finishKey(mWindow);
+ } catch (RemoteException e) {
+ }
+ } else if (mIsPointer) {
+ boolean didFinish;
+ MotionEvent event = mMotionEvent;
+ if (event == null) {
+ try {
+ event = sWindowSession.getPendingPointerMove(mWindow);
+ } catch (RemoteException e) {
+ }
+ didFinish = true;
+ } else {
+ didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
+ }
+ if (!didFinish) {
+ try {
+ sWindowSession.finishKey(mWindow);
+ } catch (RemoteException e) {
+ }
+ }
+ } else {
+ MotionEvent event = mMotionEvent;
+ if (event == null) {
+ try {
+ event = sWindowSession.getPendingTrackballMove(mWindow);
+ } catch (RemoteException e) {
+ }
+ } else {
+ try {
+ sWindowSession.finishKey(mWindow);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+ }
+
static class W extends IWindow.Stub {
- private WeakReference<ViewRoot> mViewRoot;
+ private final WeakReference<ViewRoot> mViewRoot;
+ private final Looper mMainLooper;
- public W(ViewRoot viewRoot) {
+ public W(ViewRoot viewRoot, Context context) {
mViewRoot = new WeakReference<ViewRoot>(viewRoot);
+ mMainLooper = context.getMainLooper();
}
public void resized(int w, int h, Rect coveredInsets,
@@ -2404,6 +2533,9 @@ public final class ViewRoot extends Handler implements ViewParent,
final ViewRoot viewRoot = mViewRoot.get();
if (viewRoot != null) {
viewRoot.dispatchKey(event);
+ } else {
+ Log.w("ViewRoot.W", "Key event " + event + " but no ViewRoot available!");
+ new EventCompletion(mMainLooper, this, event, false, null);
}
}
@@ -2411,6 +2543,8 @@ public final class ViewRoot extends Handler implements ViewParent,
final ViewRoot viewRoot = mViewRoot.get();
if (viewRoot != null) {
viewRoot.dispatchPointer(event, eventTime);
+ } else {
+ new EventCompletion(mMainLooper, this, null, true, event);
}
}
@@ -2418,6 +2552,8 @@ public final class ViewRoot extends Handler implements ViewParent,
final ViewRoot viewRoot = mViewRoot.get();
if (viewRoot != null) {
viewRoot.dispatchTrackball(event, eventTime);
+ } else {
+ new EventCompletion(mMainLooper, this, null, false, event);
}
}
@@ -2502,7 +2638,7 @@ public final class ViewRoot extends Handler implements ViewParent,
* for us to consider the user to be doing fast trackball movements,
* and thus apply an acceleration.
*/
- static final long FAST_MOVE_TIME = 100;
+ static final long FAST_MOVE_TIME = 150;
/**
* Scaling factor to the time (in milliseconds) between events to how
@@ -2510,7 +2646,7 @@ public final class ViewRoot extends Handler implements ViewParent,
* is < FAST_MOVE_TIME this multiplies the acceleration; when >
* FAST_MOVE_TIME it divides it.
*/
- static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/50);
+ static final float ACCEL_MOVE_SCALING_FACTOR = (1.0f/40);
float position;
float absPosition;
@@ -2748,7 +2884,6 @@ public final class ViewRoot extends Handler implements ViewParent,
synchronized (mActions) {
final ArrayList<HandlerAction> actions = mActions;
- final int count = actions.size();
while (actions.remove(handlerAction)) {
// Keep going
@@ -2776,7 +2911,20 @@ public final class ViewRoot extends Handler implements ViewParent,
@Override
public boolean equals(Object o) {
- return action.equals(o);
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ HandlerAction that = (HandlerAction) o;
+
+ return !(action != null ? !action.equals(that.action) : that.action != null);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = action != null ? action.hashCode() : 0;
+ result = 31 * result + (int) (delay ^ (delay >>> 32));
+ return result;
}
}
}
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 05f5fa2..47b52e4 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -35,6 +35,7 @@ public final class ViewTreeObserver {
private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
private ArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
private ArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
+ private ArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
private boolean mAlive = true;
@@ -99,6 +100,20 @@ public final class ViewTreeObserver {
}
/**
+ * Interface definition for a callback to be invoked when
+ * something in the view tree has been scrolled.
+ *
+ * @hide pending API council approval
+ */
+ public interface OnScrollChangedListener {
+ /**
+ * Callback method to be invoked when something in the view tree
+ * has been scrolled.
+ */
+ public void onScrollChanged();
+ }
+
+ /**
* Parameters used with OnComputeInternalInsetsListener.
* {@hide pending API Council approval}
*/
@@ -361,6 +376,44 @@ public final class ViewTreeObserver {
}
/**
+ * Register a callback to be invoked when a view has been scrolled.
+ *
+ * @param listener The callback to add
+ *
+ * @throws IllegalStateException If {@link #isAlive()} returns false
+ *
+ * @hide pending API council approval
+ */
+ public void addOnScrollChangedListener(OnScrollChangedListener listener) {
+ checkIsAlive();
+
+ if (mOnScrollChangedListeners == null) {
+ mOnScrollChangedListeners = new ArrayList<OnScrollChangedListener>();
+ }
+
+ mOnScrollChangedListeners.add(listener);
+ }
+
+ /**
+ * Remove a previously installed scroll-changed callback
+ *
+ * @param victim The callback to remove
+ *
+ * @throws IllegalStateException If {@link #isAlive()} returns false
+ *
+ * @see #addOnScrollChangedListener(OnScrollChangedListener)
+ *
+ * @hide pending API council approval
+ */
+ public void removeOnScrollChangedListener(OnScrollChangedListener victim) {
+ checkIsAlive();
+ if (mOnScrollChangedListeners == null) {
+ return;
+ }
+ mOnScrollChangedListeners.remove(victim);
+ }
+
+ /**
* Register a callback to be invoked when the invoked when the touch mode changes.
*
* @param listener The callback to add
@@ -525,6 +578,19 @@ public final class ViewTreeObserver {
}
/**
+ * Notifies registered listeners that something has scrolled.
+ */
+ final void dispatchOnScrollChanged() {
+ final ArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
+
+ if (listeners != null) {
+ for (OnScrollChangedListener scl : mOnScrollChangedListeners) {
+ scl.onScrollChanged();
+ }
+ }
+ }
+
+ /**
* Returns whether there are listeners for computing internal insets.
*/
final boolean hasComputeInternalInsetsListeners() {
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index f4d0fde..a573983 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -16,18 +16,17 @@
package android.view;
-import android.media.ToneGenerator;
-import android.media.AudioManager;
-import android.media.AudioService;
-import android.media.AudioSystem;
+import android.bluetooth.HeadsetBase;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.res.Resources;
+import android.media.AudioManager;
+import android.media.AudioService;
+import android.media.AudioSystem;
+import android.media.ToneGenerator;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
-import android.text.TextUtils;
import android.util.Config;
import android.util.Log;
import android.widget.ImageView;
@@ -39,7 +38,7 @@ import android.widget.Toast;
* Handle the volume up and down keys.
*
* This code really should be moved elsewhere.
- *
+ *
* @hide
*/
public class VolumePanel extends Handler
@@ -54,7 +53,7 @@ public class VolumePanel extends Handler
* PhoneWindow will implement this part.
*/
public static final int PLAY_SOUND_DELAY = 300;
-
+
/**
* The delay before vibrating. This small period exists so if the user is
* moving to silent mode, it will not emit a short vibrate (it normally
@@ -64,28 +63,30 @@ public class VolumePanel extends Handler
public static final int VIBRATE_DELAY = 300;
private static final int VIBRATE_DURATION = 300;
- private static final int BEEP_DURATION = 150;
+ private static final int BEEP_DURATION = 150;
private static final int MAX_VOLUME = 100;
private static final int FREE_DELAY = 10000;
-
+
private static final int MSG_VOLUME_CHANGED = 0;
private static final int MSG_FREE_RESOURCES = 1;
private static final int MSG_PLAY_SOUND = 2;
private static final int MSG_STOP_SOUNDS = 3;
private static final int MSG_VIBRATE = 4;
-
+
private static final int RINGTONE_VOLUME_TEXT = com.android.internal.R.string.volume_ringtone;
private static final int MUSIC_VOLUME_TEXT = com.android.internal.R.string.volume_music;
private static final int INCALL_VOLUME_TEXT = com.android.internal.R.string.volume_call;
private static final int ALARM_VOLUME_TEXT = com.android.internal.R.string.volume_alarm;
private static final int UNKNOWN_VOLUME_TEXT = com.android.internal.R.string.volume_unknown;
private static final int NOTIFICATION_VOLUME_TEXT =
- com.android.internal.R.string.volume_notification;
-
+ com.android.internal.R.string.volume_notification;
+ private static final int BLUETOOTH_INCALL_VOLUME_TEXT =
+ com.android.internal.R.string.volume_bluetooth_call;
+
protected Context mContext;
private AudioManager mAudioManager;
protected AudioService mAudioService;
-
+
private final Toast mToast;
private final View mView;
private final TextView mMessage;
@@ -117,13 +118,13 @@ public class VolumePanel extends Handler
mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
mVibrator = new Vibrator();
}
-
+
public void postVolumeChanged(int streamType, int flags) {
if (hasMessages(MSG_VOLUME_CHANGED)) return;
removeMessages(MSG_FREE_RESOURCES);
obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget();
}
-
+
/**
* Override this if you have other work to do when the volume changes (for
* example, vibrating, playing a sound, etc.). Make sure to call through to
@@ -132,31 +133,31 @@ public class VolumePanel extends Handler
protected void onVolumeChanged(int streamType, int flags) {
if (LOGD) Log.d(TAG, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
-
+
if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
onShowVolumeChanged(streamType, flags);
}
-
+
if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0) {
removeMessages(MSG_PLAY_SOUND);
sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY);
}
-
+
if ((flags & AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE) != 0) {
removeMessages(MSG_PLAY_SOUND);
removeMessages(MSG_VIBRATE);
onStopSounds();
}
-
+
removeMessages(MSG_FREE_RESOURCES);
- sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
+ sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
}
protected void onShowVolumeChanged(int streamType, int flags) {
int index = mAudioService.getStreamVolume(streamType);
int message = UNKNOWN_VOLUME_TEXT;
int additionalMessage = 0;
-
+
if (LOGD) {
Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
+ ", flags: " + flags + "), index: " + index);
@@ -166,13 +167,13 @@ public class VolumePanel extends Handler
int max = mAudioService.getStreamMaxVolume(streamType);
switch (streamType) {
-
+
case AudioManager.STREAM_RING: {
message = RINGTONE_VOLUME_TEXT;
setRingerIcon(index);
break;
}
-
+
case AudioManager.STREAM_MUSIC: {
message = MUSIC_VOLUME_TEXT;
if (mAudioManager.isBluetoothA2dpOn()) {
@@ -184,7 +185,7 @@ public class VolumePanel extends Handler
}
break;
}
-
+
case AudioManager.STREAM_VOICE_CALL: {
/*
* For in-call voice call volume, there is no inaudible volume.
@@ -194,13 +195,7 @@ public class VolumePanel extends Handler
index++;
max++;
message = INCALL_VOLUME_TEXT;
- if (mAudioManager.isBluetoothScoOn()) {
- additionalMessage =
- com.android.internal.R.string.volume_call_hint_playing_through_bluetooth;
- setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_in_call);
- } else {
- setSmallIcon(index);
- }
+ setSmallIcon(index);
break;
}
@@ -209,12 +204,25 @@ public class VolumePanel extends Handler
setSmallIcon(index);
break;
}
-
+
case AudioManager.STREAM_NOTIFICATION: {
message = NOTIFICATION_VOLUME_TEXT;
setSmallIcon(index);
break;
}
+
+ case AudioManager.STREAM_BLUETOOTH_SCO: {
+ /*
+ * For in-call voice call volume, there is no inaudible volume.
+ * Rescale the UI control so the progress bar doesn't go all
+ * the way to zero and don't show the mute icon.
+ */
+ index++;
+ max++;
+ message = BLUETOOTH_INCALL_VOLUME_TEXT;
+ setLargeIcon(com.android.internal.R.drawable.ic_volume_bluetooth_in_call);
+ break;
+ }
}
String messageString = Resources.getSystem().getString(message);
@@ -228,25 +236,25 @@ public class VolumePanel extends Handler
mAdditionalMessage.setVisibility(View.VISIBLE);
mAdditionalMessage.setText(Resources.getSystem().getString(additionalMessage));
}
-
+
if (max != mLevel.getMax()) {
mLevel.setMax(max);
}
mLevel.setProgress(index);
-
+
mToast.setView(mView);
mToast.setDuration(Toast.LENGTH_SHORT);
mToast.setGravity(Gravity.TOP, 0, 0);
mToast.show();
-
+
// Do a little vibrate if applicable (only when going into vibrate mode)
- if ((flags & AudioManager.FLAG_VIBRATE) != 0 &&
+ if ((flags & AudioManager.FLAG_VIBRATE) != 0 &&
mAudioService.isStreamAffectedByRingerMode(streamType) &&
mAudioService.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE &&
mAudioService.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER)) {
sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY);
}
-
+
}
protected void onPlaySound(int streamType, int flags) {
@@ -256,7 +264,7 @@ public class VolumePanel extends Handler
// Force stop right now
onStopSounds();
}
-
+
synchronized (this) {
ToneGenerator toneGen = getOrCreateToneGenerator(streamType);
toneGen.startTone(ToneGenerator.TONE_PROP_BEEP);
@@ -266,7 +274,7 @@ public class VolumePanel extends Handler
}
protected void onStopSounds() {
-
+
synchronized (this) {
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int i = numStreamTypes - 1; i >= 0; i--) {
@@ -277,17 +285,17 @@ public class VolumePanel extends Handler
}
}
}
-
+
protected void onVibrate() {
-
+
// Make sure we ended up in vibrate ringer mode
if (mAudioService.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) {
return;
}
-
+
mVibrator.vibrate(VIBRATE_DURATION);
}
-
+
/**
* Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
*/
@@ -303,13 +311,13 @@ public class VolumePanel extends Handler
/**
* Makes the small icon visible, and hides the large icon.
- *
+ *
* @param index The volume index, where 0 means muted.
*/
private void setSmallIcon(int index) {
mLargeStreamIcon.setVisibility(View.GONE);
mSmallStreamIcon.setVisibility(View.VISIBLE);
-
+
mSmallStreamIcon.setImageResource(index == 0
? com.android.internal.R.drawable.ic_volume_off_small
: com.android.internal.R.drawable.ic_volume_small);
@@ -317,7 +325,7 @@ public class VolumePanel extends Handler
/**
* Makes the large image view visible with the given icon.
- *
+ *
* @param resId The icon to display.
*/
private void setLargeIcon(int resId) {
@@ -329,7 +337,7 @@ public class VolumePanel extends Handler
/**
* Makes the ringer icon visible with an icon that is chosen
* based on the current ringer mode.
- *
+ *
* @param index
*/
private void setRingerIcon(int index) {
@@ -350,13 +358,13 @@ public class VolumePanel extends Handler
}
mLargeStreamIcon.setImageResource(icon);
}
-
+
protected void onFreeResources() {
// We'll keep the views, just ditch the cached drawable and hence
// bitmaps
mSmallStreamIcon.setImageDrawable(null);
mLargeStreamIcon.setImageDrawable(null);
-
+
synchronized (this) {
for (int i = mToneGenerators.length - 1; i >= 0; i--) {
if (mToneGenerators[i] != null) {
@@ -366,26 +374,26 @@ public class VolumePanel extends Handler
}
}
}
-
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
-
+
case MSG_VOLUME_CHANGED: {
onVolumeChanged(msg.arg1, msg.arg2);
break;
}
-
+
case MSG_FREE_RESOURCES: {
onFreeResources();
break;
}
-
+
case MSG_STOP_SOUNDS: {
onStopSounds();
break;
}
-
+
case MSG_PLAY_SOUND: {
onPlaySound(msg.arg1, msg.arg2);
break;
@@ -395,8 +403,8 @@ public class VolumePanel extends Handler
onVibrate();
break;
}
-
+
}
}
-
+
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index a68436b..428de67 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -525,6 +525,21 @@ public abstract class Window {
}
/**
+ * Specify custom animations to use for the window, as per
+ * {@link WindowManager.LayoutParams#windowAnimations
+ * WindowManager.LayoutParams.windowAnimations}. Providing anything besides
+ * 0 here will override the animations the window would
+ * normally retrieve from its theme.
+ */
+ public void setWindowAnimations(int resId) {
+ final WindowManager.LayoutParams attrs = getAttributes();
+ attrs.windowAnimations = resId;
+ if (mCallback != null) {
+ mCallback.onWindowAttributesChanged(attrs);
+ }
+ }
+
+ /**
* Specify an explicit soft input mode to use for the window, as per
* {@link WindowManager.LayoutParams#softInputMode
* WindowManager.LayoutParams.softInputMode}. Providing anything besides
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 7e47ad1..b87cc42 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -16,6 +16,7 @@
package android.view;
+import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.os.Parcel;
@@ -126,8 +127,6 @@ public interface WindowManager extends ViewManager {
* @see #TYPE_APPLICATION_MEDIA
* @see #TYPE_APPLICATION_SUB_PANEL
* @see #TYPE_APPLICATION_ATTACHED_DIALOG
- * @see #TYPE_INPUT_METHOD
- * @see #TYPE_INPUT_METHOD_DIALOG
* @see #TYPE_STATUS_BAR
* @see #TYPE_SEARCH_BAR
* @see #TYPE_PHONE
@@ -514,26 +513,33 @@ public interface WindowManager extends ViewManager {
/**
* Visibility state for {@link #softInputMode}: please hide any soft input
- * area.
+ * area when normally appropriate (when the user is navigating
+ * forward to your window).
*/
public static final int SOFT_INPUT_STATE_HIDDEN = 2;
/**
+ * Visibility state for {@link #softInputMode}: please always hide any
+ * soft input area when this window receives focus.
+ */
+ public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
+
+ /**
* Visibility state for {@link #softInputMode}: please show the soft
* input area when normally appropriate (when the user is navigating
* forward to your window).
*/
- public static final int SOFT_INPUT_STATE_VISIBLE = 3;
+ public static final int SOFT_INPUT_STATE_VISIBLE = 4;
/**
* Visibility state for {@link #softInputMode}: please always make the
* soft input area visible when this window receives input focus.
*/
- public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 4;
+ public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
/**
* Mask for {@link #softInputMode} of the bits that determine the
- * way that the window should be adjusted to accomodate the soft
+ * way that the window should be adjusted to accommodate the soft
* input window.
*/
public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;
@@ -635,6 +641,14 @@ public interface WindowManager extends ViewManager {
public float dimAmount = 1.0f;
/**
+ * This can be used to override the user's preferred brightness of
+ * the screen. A value of less than 0, the default, means to use the
+ * preferred screen brightness. 0 to 1 adjusts the brightness from
+ * dark to full bright.
+ */
+ public float screenBrightness = -1.0f;
+
+ /**
* Identifier for this window. This will usually be filled in for
* you.
*/
@@ -645,6 +659,17 @@ public interface WindowManager extends ViewManager {
*/
public String packageName = null;
+ /**
+ * Specific orientation value for a window.
+ * May be any of the same values allowed
+ * for {@link android.content.pm.ActivityInfo#screenOrientation}.
+ * If not set, a default value of
+ * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}
+ * will be used.
+ */
+ public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
+
public LayoutParams() {
super(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
type = TYPE_APPLICATION;
@@ -719,9 +744,11 @@ public interface WindowManager extends ViewManager {
out.writeInt(windowAnimations);
out.writeFloat(alpha);
out.writeFloat(dimAmount);
+ out.writeFloat(screenBrightness);
out.writeStrongBinder(token);
out.writeString(packageName);
TextUtils.writeToParcel(mTitle, out, parcelableFlags);
+ out.writeInt(screenOrientation);
}
public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -752,9 +779,11 @@ public interface WindowManager extends ViewManager {
windowAnimations = in.readInt();
alpha = in.readFloat();
dimAmount = in.readFloat();
+ screenBrightness = in.readFloat();
token = in.readStrongBinder();
packageName = in.readString();
mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ screenOrientation = in.readInt();
}
public static final int LAYOUT_CHANGED = 1<<0;
@@ -767,6 +796,8 @@ public interface WindowManager extends ViewManager {
public static final int ALPHA_CHANGED = 1<<7;
public static final int MEMORY_TYPE_CHANGED = 1<<8;
public static final int SOFT_INPUT_MODE_CHANGED = 1<<9;
+ public static final int SCREEN_ORIENTATION_CHANGED = 1<<10;
+ public static final int SCREEN_BRIGHTNESS_CHANGED = 1<<11;
public final int copyFrom(LayoutParams o) {
int changes = 0;
@@ -861,7 +892,15 @@ public interface WindowManager extends ViewManager {
dimAmount = o.dimAmount;
changes |= DIM_AMOUNT_CHANGED;
}
+ if (screenBrightness != o.screenBrightness) {
+ screenBrightness = o.screenBrightness;
+ changes |= SCREEN_BRIGHTNESS_CHANGED;
+ }
+ if (screenOrientation != o.screenOrientation) {
+ screenOrientation = o.screenOrientation;
+ changes |= SCREEN_ORIENTATION_CHANGED;
+ }
return changes;
}
@@ -907,6 +946,10 @@ public interface WindowManager extends ViewManager {
sb.append(" wanim=0x");
sb.append(Integer.toHexString(windowAnimations));
}
+ if (screenOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
+ sb.append(" or=");
+ sb.append(screenOrientation);
+ }
sb.append('}');
return sb.toString();
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 6af4915..220869c 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -54,7 +54,7 @@ import android.view.animation.Animation;
* window manager is a very low-level system service, there are few other
* system services you can call with this lock held. It is explicitly okay to
* make calls into the package manager and power manager; it is explicitly not
- * okay to make calls into the activity manager. Note that
+ * okay to make calls into the activity manager or most other services. Note that
* {@link android.content.Context#checkPermission(String, int, int)} and
* variations require calling into the activity manager.
* <dt> Li <dd> Called with the input thread lock held. This lock can be
@@ -129,14 +129,22 @@ public interface WindowManagerPolicy {
Rect contentFrame, Rect visibleFrame);
/**
- * Retrieve the current frame of the window. Must be called with the
- * window manager lock held.
+ * Retrieve the current frame of the window that has been assigned by
+ * the window manager. Must be called with the window manager lock held.
*
* @return Rect The rectangle holding the window frame.
*/
public Rect getFrameLw();
/**
+ * Retrieve the current frame of the window that is actually shown.
+ * Must be called with the window manager lock held.
+ *
+ * @return Rect The rectangle holding the shown window frame.
+ */
+ public Rect getShownFrameLw();
+
+ /**
* Retrieve the frame of the display that this window was last
* laid out in. Must be called with the
* window manager lock held.
@@ -273,9 +281,12 @@ public interface WindowManagerPolicy {
* false, this is based on the currently requested
* frame, which any current animation will be moving
* towards.
+ * @param onlyOpaque If true, this will only pass if the window is
+ * also opaque.
* @return Returns true if the window is both full screen and opaque
*/
- public boolean fillsScreenLw(int width, int height, boolean shownFrame);
+ public boolean fillsScreenLw(int width, int height, boolean shownFrame,
+ boolean onlyOpaque);
/**
* Returns true if this window has been shown on screen at some time in
@@ -289,16 +300,18 @@ public interface WindowManagerPolicy {
* Can be called by the policy to force a window to be hidden,
* regardless of whether the client or window manager would like
* it shown. Must be called with the window manager lock held.
+ * Returns true if {@link #showLw} was last called for the window.
*/
- public void hideLw(boolean doAnimation);
+ public boolean hideLw(boolean doAnimation);
/**
* Can be called to undo the effect of {@link #hideLw}, allowing a
* window to be shown as long as the window manager and client would
* also like it to be shown. Must be called with the window manager
* lock held.
+ * Returns true if {@link #hideLw} was last called for the window.
*/
- public void showLw(boolean doAnimation);
+ public boolean showLw(boolean doAnimation);
}
/** No transition happening. */
@@ -735,10 +748,17 @@ public interface WindowManagerPolicy {
* ActivityInfo.SCREEN_ORIENTATION_PORTRAIT}), return a surface
* rotation.
*/
- public int rotationForOrientation(int orientation);
+ public int rotationForOrientationLw(int orientation, int lastRotation,
+ boolean displayEnabled);
+
+ /**
+ * Called when the system is mostly done booting to dentermine whether
+ * the system should go into safe mode.
+ */
+ public boolean detectSafeMode();
/**
- * Called when the system is mostly done booting
+ * Called when the system is mostly done booting.
*/
public void systemReady();
@@ -761,5 +781,16 @@ public interface WindowManagerPolicy {
*/
public boolean isCheekPressedAgainstScreen(MotionEvent ev);
- public void setCurrentOrientation(int newOrientation);
+ public void setCurrentOrientationLw(int newOrientation);
+
+ /**
+ * Call from application to perform haptic feedback on its window.
+ */
+ public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always);
+
+ /**
+ * Called when we have stopped keeping the screen on because a window
+ * requesting this is no longer visible.
+ */
+ public void screenOnStoppedLw();
}
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
new file mode 100755
index 0000000..f1f5f70
--- /dev/null
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -0,0 +1,196 @@
+/*
+ * 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 android.view;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.util.Config;
+import android.util.Log;
+
+/**
+ * A special helper class used by the WindowManager
+ * for receiving notifications from the SensorManager when
+ * the orientation of the device has changed.
+ * @hide
+ */
+public abstract class WindowOrientationListener {
+ private static final String TAG = "WindowOrientationListener";
+ private static final boolean DEBUG = false;
+ private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
+ private SensorManager mSensorManager;
+ private boolean mEnabled = false;
+ private int mRate;
+ private Sensor mSensor;
+ private SensorEventListener mSensorEventListener;
+ private int mSensorRotation = -1;
+
+ /**
+ * Creates a new WindowOrientationListener.
+ *
+ * @param context for the WindowOrientationListener.
+ */
+ public WindowOrientationListener(Context context) {
+ this(context, SensorManager.SENSOR_DELAY_NORMAL);
+ }
+
+ /**
+ * Creates a new WindowOrientationListener.
+ *
+ * @param context for the WindowOrientationListener.
+ * @param rate at which sensor events are processed (see also
+ * {@link android.hardware.SensorManager SensorManager}). Use the default
+ * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL
+ * SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
+ */
+ public WindowOrientationListener(Context context, int rate) {
+ mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+ mRate = rate;
+ mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ if (mSensor != null) {
+ // Create listener only if sensors do exist
+ mSensorEventListener = new SensorEventListenerImpl();
+ }
+ }
+
+ /**
+ * Enables the WindowOrientationListener so it will monitor the sensor and call
+ * {@link #onOrientationChanged} when the device orientation changes.
+ */
+ public void enable() {
+ if (mSensor == null) {
+ Log.w(TAG, "Cannot detect sensors. Not enabled");
+ return;
+ }
+ if (mEnabled == false) {
+ if (localLOGV) Log.d(TAG, "WindowOrientationListener enabled");
+ mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
+ mEnabled = true;
+ }
+ }
+
+ /**
+ * Disables the WindowOrientationListener.
+ */
+ public void disable() {
+ if (mSensor == null) {
+ Log.w(TAG, "Cannot detect sensors. Invalid disable");
+ return;
+ }
+ if (mEnabled == true) {
+ if (localLOGV) Log.d(TAG, "WindowOrientationListener disabled");
+ mSensorManager.unregisterListener(mSensorEventListener);
+ mEnabled = false;
+ }
+ }
+
+ class SensorEventListenerImpl implements SensorEventListener {
+ private static final int _DATA_X = 0;
+ private static final int _DATA_Y = 1;
+ private static final int _DATA_Z = 2;
+ // Angle around x-axis thats considered almost perfect vertical to hold
+ // the device
+ private static final int PIVOT = 30;
+ // Angle around x-asis that's considered almost too vertical. Beyond
+ // this angle will not result in any orientation changes. f phone faces uses,
+ // the device is leaning backward.
+ private static final int PIVOT_UPPER = 65;
+ // Angle about x-axis that's considered negative vertical. Beyond this
+ // angle will not result in any orientation changes. If phone faces uses,
+ // the device is leaning forward.
+ private static final int PIVOT_LOWER = 0;
+ // Upper threshold limit for switching from portrait to landscape
+ private static final int PL_UPPER = 280;
+ // Lower threshold limit for switching from landscape to portrait
+ private static final int LP_LOWER = 320;
+ // Lower threshold limt for switching from portrait to landscape
+ private static final int PL_LOWER = 240;
+ // Upper threshold limit for switching from landscape to portrait
+ private static final int LP_UPPER = 360;
+
+ // Internal value used for calculating linear variant
+ private static final float PL_LINEAR_FACTOR =
+ ((float)(PL_UPPER-PL_LOWER))/((float)(PIVOT_UPPER-PIVOT_LOWER));
+ // Internal value used for calculating linear variant
+ private static final float LP_LINEAR_FACTOR =
+ ((float)(LP_UPPER - LP_LOWER))/((float)(PIVOT_UPPER-PIVOT_LOWER));
+
+ public void onSensorChanged(SensorEvent event) {
+ float[] values = event.values;
+ float X = values[_DATA_X];
+ float Y = values[_DATA_Y];
+ float Z = values[_DATA_Z];
+ float OneEightyOverPi = 57.29577957855f;
+ float gravity = (float) Math.sqrt(X*X+Y*Y+Z*Z);
+ float zyangle = Math.abs((float)Math.asin(Z/gravity)*OneEightyOverPi);
+ int rotation = mSensorRotation;
+ if ((zyangle <= PIVOT_UPPER) && (zyangle >= PIVOT_LOWER)) {
+ // Check orientation only if the phone is flat enough
+ // Don't trust the angle if the magnitude is small compared to the y value
+ float angle = (float)Math.atan2(Y, -X) * OneEightyOverPi;
+ int orientation = 90 - (int)Math.round(angle);
+ // normalize to 0 - 359 range
+ while (orientation >= 360) {
+ orientation -= 360;
+ }
+ while (orientation < 0) {
+ orientation += 360;
+ }
+
+ float delta = (float)Math.abs(zyangle - PIVOT);
+ if (((orientation >= 0) && (orientation <= LP_UPPER)) ||
+ (orientation >= PL_LOWER)) {
+ float threshold;
+ if (mSensorRotation == Surface.ROTATION_90) {
+ threshold = LP_LOWER + (LP_LINEAR_FACTOR * delta) ;
+ } else {
+ threshold = PL_UPPER - (PL_LINEAR_FACTOR * delta);
+ }
+ rotation = (orientation >= PL_LOWER &&
+ orientation <= threshold) ? Surface.ROTATION_90 : Surface.ROTATION_0;
+ }
+
+ }
+ if (rotation != mSensorRotation) {
+ mSensorRotation = rotation;
+ onOrientationChanged(mSensorRotation);
+ }
+ }
+
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+
+ }
+ }
+
+ /*
+ * Returns true if sensor is enabled and false otherwise
+ */
+ public boolean canDetectOrientation() {
+ return mSensor != null;
+ }
+
+ /**
+ * Called when the rotation view of the device has changed.
+ * Can be either Surface.ROTATION_90 or Surface.ROTATION_0.
+ * @param rotation The new orientation of the device.
+ *
+ * @see #ORIENTATION_UNKNOWN
+ */
+ abstract public void onOrientationChanged(int rotation);
+}
diff --git a/core/java/android/view/animation/AlphaAnimation.java b/core/java/android/view/animation/AlphaAnimation.java
index 16a10a4..651fe45 100644
--- a/core/java/android/view/animation/AlphaAnimation.java
+++ b/core/java/android/view/animation/AlphaAnimation.java
@@ -31,7 +31,7 @@ public class AlphaAnimation extends Animation {
private float mToAlpha;
/**
- * Constructor used whan an AlphaAnimation is loaded from a resource.
+ * Constructor used when an AlphaAnimation is loaded from a resource.
*
* @param context Application context to use
* @param attrs Attribute set from which to read values
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 9264398..a662760 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -20,13 +20,14 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.TypedValue;
+import android.graphics.RectF;
/**
* Abstraction for an Animation that can be applied to Views, Surfaces, or
* other objects. See the {@link android.view.animation animation package
* description file}.
*/
-public abstract class Animation {
+public abstract class Animation implements Cloneable {
/**
* Repeat the animation indefinitely.
*/
@@ -174,8 +175,13 @@ public abstract class Animation {
*/
private int mZAdjustment;
- // Indicates what was the last value returned by getTransformation()
private boolean mMore = true;
+ private boolean mOneMoreTime = true;
+
+ RectF mPreviousRegion = new RectF();
+ RectF mRegion = new RectF();
+ Transformation mTransformation = new Transformation();
+ Transformation mPreviousTransformation = new Transformation();
/**
* Creates a new animation with a duration of 0ms, the default interpolator, with
@@ -217,16 +223,29 @@ public abstract class Animation {
a.recycle();
}
+ @Override
+ protected Animation clone() throws CloneNotSupportedException {
+ final Animation animation = (Animation) super.clone();
+ animation.mPreviousRegion = new RectF();
+ animation.mRegion = new RectF();
+ animation.mTransformation = new Transformation();
+ animation.mPreviousTransformation = new Transformation();
+ return animation;
+ }
+
/**
* Reset the initialization state of this animation.
*
* @see #initialize(int, int, int, int)
*/
public void reset() {
+ mPreviousRegion.setEmpty();
+ mPreviousTransformation.clear();
mInitialized = false;
mCycleFlip = false;
mRepeated = 0;
mMore = true;
+ mOneMoreTime = true;
}
/**
@@ -255,10 +274,8 @@ public abstract class Animation {
* @param parentHeight Height of the animated object's parent
*/
public void initialize(int width, int height, int parentWidth, int parentHeight) {
+ reset();
mInitialized = true;
- mCycleFlip = false;
- mRepeated = 0;
- mMore = true;
}
/**
@@ -323,6 +340,7 @@ public abstract class Animation {
* to run.
*/
public void restrictDuration(long durationMillis) {
+ // If we start after the duration, then we just won't run.
if (mStartOffset > durationMillis) {
mStartOffset = durationMillis;
mDuration = 0;
@@ -332,11 +350,26 @@ public abstract class Animation {
long dur = mDuration + mStartOffset;
if (dur > durationMillis) {
- mDuration = dur = durationMillis-mStartOffset;
+ mDuration = durationMillis-mStartOffset;
+ dur = durationMillis;
+ }
+ // If the duration is 0 or less, then we won't run.
+ if (mDuration <= 0) {
+ mDuration = 0;
+ mRepeatCount = 0;
+ return;
}
+ // Reduce the number of repeats to keep below the maximum duration.
+ // The comparison between mRepeatCount and duration is to catch
+ // overflows after multiplying them.
if (mRepeatCount < 0 || mRepeatCount > durationMillis
|| (dur*mRepeatCount) > durationMillis) {
- mRepeatCount = (int)(durationMillis/dur);
+ // Figure out how many times to do the animation. Subtract 1 since
+ // repeat count is the number of times to repeat so 0 runs once.
+ mRepeatCount = (int)(durationMillis/dur) - 1;
+ if (mRepeatCount < 0) {
+ mRepeatCount = 0;
+ }
}
}
@@ -399,7 +432,7 @@ public abstract class Animation {
* Sets how many times the animation should be repeated. If the repeat
* count is 0, the animation is never repeated. If the repeat count is
* greater than 0 or {@link #INFINITE}, the repeat mode will be taken
- * into account. The repeat count if 0 by default.
+ * into account. The repeat count is 0 by default.
*
* @param repeatCount the number of times the animation should be repeated
* @attr ref android.R.styleable#Animation_repeatCount
@@ -707,6 +740,11 @@ public abstract class Animation {
}
}
+ if (!mMore && mOneMoreTime) {
+ mOneMoreTime = false;
+ return true;
+ }
+
return mMore;
}
@@ -765,7 +803,59 @@ public abstract class Animation {
return value;
}
}
-
+
+ /**
+ * @param left
+ * @param top
+ * @param right
+ * @param bottom
+ * @param invalidate
+ * @param transformation
+ *
+ * @hide
+ */
+ public void getInvalidateRegion(int left, int top, int right, int bottom,
+ RectF invalidate, Transformation transformation) {
+
+ final RectF tempRegion = mRegion;
+ final RectF previousRegion = mPreviousRegion;
+
+ invalidate.set(left, top, right, bottom);
+ transformation.getMatrix().mapRect(invalidate);
+ // Enlarge the invalidate region to account for rounding errors
+ invalidate.inset(-1.0f, -1.0f);
+ tempRegion.set(invalidate);
+ invalidate.union(previousRegion);
+
+ previousRegion.set(tempRegion);
+
+ final Transformation tempTransformation = mTransformation;
+ final Transformation previousTransformation = mPreviousTransformation;
+
+ tempTransformation.set(transformation);
+ transformation.set(previousTransformation);
+ previousTransformation.set(tempTransformation);
+ }
+
+ /**
+ * @param left
+ * @param top
+ * @param right
+ * @param bottom
+ *
+ * @hide
+ */
+ public void initializeInvalidateRegion(int left, int top, int right, int bottom) {
+ final RectF region = mPreviousRegion;
+ region.set(left, top, right, bottom);
+ // Enlarge the invalidate region to account for rounding errors
+ region.inset(-1.0f, -1.0f);
+ if (mFillBefore) {
+ final Transformation previousTransformation = mPreviousTransformation;
+ applyTransformation(0.0f, previousTransformation);
+ }
+ }
+
/**
* Utility class to parse a string description of a size.
*/
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index 688da70..98b2594 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -19,6 +19,7 @@ package android.view.animation;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import android.graphics.RectF;
import java.util.ArrayList;
import java.util.List;
@@ -39,6 +40,7 @@ public class AnimationSet extends Animation {
private static final int PROPERTY_SHARE_INTERPOLATOR_MASK = 0x10;
private static final int PROPERTY_DURATION_MASK = 0x20;
private static final int PROPERTY_MORPH_MATRIX_MASK = 0x40;
+ private static final int PROPERTY_CHANGE_BOUNDS_MASK = 0x80;
private int mFlags = 0;
@@ -51,7 +53,7 @@ public class AnimationSet extends Animation {
private long[] mStoredOffsets;
/**
- * Constructor used whan an AnimationSet is loaded from a resource.
+ * Constructor used when an AnimationSet is loaded from a resource.
*
* @param context Application context to use
* @param attrs Attribute set from which to read values
@@ -82,6 +84,22 @@ public class AnimationSet extends Animation {
init();
}
+ @Override
+ protected AnimationSet clone() throws CloneNotSupportedException {
+ final AnimationSet animation = (AnimationSet) super.clone();
+ animation.mTempTransformation = new Transformation();
+ animation.mAnimations = new ArrayList<Animation>();
+
+ final int count = mAnimations.size();
+ final ArrayList<Animation> animations = mAnimations;
+
+ for (int i = 0; i < count; i++) {
+ animation.mAnimations.add(animations.get(i).clone());
+ }
+
+ return animation;
+ }
+
private void setFlag(int mask, boolean value) {
if (value) {
mFlags |= mask;
@@ -145,6 +163,11 @@ public class AnimationSet extends Animation {
mFlags |= PROPERTY_MORPH_MATRIX_MASK;
}
+ boolean changeBounds = (mFlags & PROPERTY_CHANGE_BOUNDS_MASK) == 0;
+ if (changeBounds && a.willChangeTransformationMatrix()) {
+ mFlags |= PROPERTY_CHANGE_BOUNDS_MASK;
+ }
+
if (mAnimations.size() == 1) {
mDuration = a.getStartOffset() + a.getDuration();
mLastEnd = mStartOffset + mDuration;
@@ -239,7 +262,32 @@ public class AnimationSet extends Animation {
}
return duration;
}
-
+
+ /**
+ * @hide
+ */
+ public void initializeInvalidateRegion(int left, int top, int right, int bottom) {
+ final RectF region = mPreviousRegion;
+ region.set(left, top, right, bottom);
+ region.inset(-1.0f, -1.0f);
+
+ if (mFillBefore) {
+ final int count = mAnimations.size();
+ final ArrayList<Animation> animations = mAnimations;
+ final Transformation temp = mTempTransformation;
+
+ final Transformation previousTransformation = mPreviousTransformation;
+
+ for (int i = count - 1; i >= 0; --i) {
+ final Animation a = animations.get(i);
+
+ temp.clear();
+ a.applyTransformation(0.0f, temp);
+ previousTransformation.compose(temp);
+ }
+ }
+ }
+
/**
* The transformation of an animation set is the concatenation of all of its
* component animations.
@@ -313,7 +361,7 @@ public class AnimationSet extends Animation {
== PROPERTY_SHARE_INTERPOLATOR_MASK;
boolean startOffsetSet = (mFlags & PROPERTY_START_OFFSET_MASK)
== PROPERTY_START_OFFSET_MASK;
-
+
if (shareInterpolator) {
ensureInterpolator();
}
@@ -327,7 +375,17 @@ public class AnimationSet extends Animation {
final int repeatMode = mRepeatMode;
final Interpolator interpolator = mInterpolator;
final long startOffset = mStartOffset;
-
+
+
+ long[] storedOffsets = mStoredOffsets;
+ if (startOffsetSet) {
+ if (storedOffsets == null || storedOffsets.length != count) {
+ storedOffsets = mStoredOffsets = new long[count];
+ }
+ } else if (storedOffsets != null) {
+ storedOffsets = mStoredOffsets = null;
+ }
+
for (int i = 0; i < count; i++) {
Animation a = children.get(i);
if (durationSet) {
@@ -346,42 +404,35 @@ public class AnimationSet extends Animation {
a.setInterpolator(interpolator);
}
if (startOffsetSet) {
- a.setStartOffset(startOffset);
+ long offset = a.getStartOffset();
+ a.setStartOffset(offset + startOffset);
+ storedOffsets[i] = offset;
}
a.initialize(width, height, parentWidth, parentHeight);
}
}
- /**
- * @hide
- * @param startOffset the startOffset to add to the children's startOffset
- */
- void saveChildrenStartOffset(long startOffset) {
- final ArrayList<Animation> children = mAnimations;
- final int count = children.size();
- long[] storedOffsets = mStoredOffsets = new long[count];
-
- for (int i = 0; i < count; i++) {
- Animation animation = children.get(i);
- long offset = animation.getStartOffset();
- animation.setStartOffset(offset + startOffset);
- storedOffsets[i] = offset;
- }
+ @Override
+ public void reset() {
+ super.reset();
+ restoreChildrenStartOffset();
}
/**
* @hide
*/
void restoreChildrenStartOffset() {
+ final long[] offsets = mStoredOffsets;
+ if (offsets == null) return;
+
final ArrayList<Animation> children = mAnimations;
final int count = children.size();
- final long[] offsets = mStoredOffsets;
for (int i = 0; i < count; i++) {
children.get(i).setStartOffset(offsets[i]);
}
}
-
+
/**
* @return All the child animations in this AnimationSet. Note that
* this may include other AnimationSets, which are not expanded.
@@ -394,4 +445,9 @@ public class AnimationSet extends Animation {
public boolean willChangeTransformationMatrix() {
return (mFlags & PROPERTY_MORPH_MATRIX_MASK) == PROPERTY_MORPH_MATRIX_MASK;
}
+
+ @Override
+ public boolean willChangeBounds() {
+ return (mFlags & PROPERTY_CHANGE_BOUNDS_MASK) == PROPERTY_CHANGE_BOUNDS_MASK;
+ }
}
diff --git a/core/java/android/view/animation/LayoutAnimationController.java b/core/java/android/view/animation/LayoutAnimationController.java
index 9cfa8d7..882e738 100644
--- a/core/java/android/view/animation/LayoutAnimationController.java
+++ b/core/java/android/view/animation/LayoutAnimationController.java
@@ -318,9 +318,16 @@ public class LayoutAnimationController {
* @see #getDelayForView(android.view.View)
*/
public final Animation getAnimationForView(View view) {
- final long delay = getDelayForView(view);
+ final long delay = getDelayForView(view) + mAnimation.getStartOffset();
mMaxDelay = Math.max(mMaxDelay, delay);
- return new DelayedAnimation(delay, mAnimation);
+
+ try {
+ final Animation animation = mAnimation.clone();
+ animation.setStartOffset(delay);
+ return animation;
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
}
/**
@@ -425,149 +432,4 @@ public class LayoutAnimationController {
*/
public int index;
}
-
- /**
- * Encapsulates an animation and delays its start offset by a specified
- * amount. This allows to reuse the same base animation for various views
- * and get the effect of running multiple instances of the animation at
- * different times.
- */
- private static class DelayedAnimation extends Animation {
- private final long mDelay;
- private final Animation mAnimation;
-
- /**
- * Creates a new delayed animation that will delay the controller's
- * animation by the specified delay in milliseconds.
- *
- * @param delay the delay in milliseconds by which to offset the
- * @param animation the animation to delay
- */
- private DelayedAnimation(long delay, Animation animation) {
- mDelay = delay;
- mAnimation = animation;
- }
-
- @Override
- public boolean isInitialized() {
- return mAnimation.isInitialized();
- }
-
- @Override
- public void initialize(int width, int height, int parentWidth, int parentHeight) {
- mAnimation.initialize(width, height, parentWidth, parentHeight);
- }
-
- @Override
- public void reset() {
- mAnimation.reset();
- }
-
- @Override
- public boolean getTransformation(long currentTime, Transformation outTransformation) {
- final long oldOffset = mAnimation.getStartOffset();
- final boolean isSet = mAnimation instanceof AnimationSet;
- if (isSet) {
- AnimationSet set = ((AnimationSet) mAnimation);
- set.saveChildrenStartOffset(mDelay);
- }
- mAnimation.setStartOffset(oldOffset + mDelay);
-
- boolean result = mAnimation.getTransformation(currentTime,
- outTransformation);
-
- if (isSet) {
- AnimationSet set = ((AnimationSet) mAnimation);
- set.restoreChildrenStartOffset();
- }
- mAnimation.setStartOffset(oldOffset);
-
- return result;
- }
-
- @Override
- public void setStartTime(long startTimeMillis) {
- mAnimation.setStartTime(startTimeMillis);
- }
-
- @Override
- public long getStartTime() {
- return mAnimation.getStartTime();
- }
-
- @Override
- public void setInterpolator(Interpolator i) {
- mAnimation.setInterpolator(i);
- }
-
- @Override
- public void setStartOffset(long startOffset) {
- mAnimation.setStartOffset(startOffset);
- }
-
- @Override
- public void setDuration(long durationMillis) {
- mAnimation.setDuration(durationMillis);
- }
-
- @Override
- public void scaleCurrentDuration(float scale) {
- mAnimation.scaleCurrentDuration(scale);
- }
-
- @Override
- public void setRepeatMode(int repeatMode) {
- mAnimation.setRepeatMode(repeatMode);
- }
-
- @Override
- public void setFillBefore(boolean fillBefore) {
- mAnimation.setFillBefore(fillBefore);
- }
-
- @Override
- public void setFillAfter(boolean fillAfter) {
- mAnimation.setFillAfter(fillAfter);
- }
-
- @Override
- public Interpolator getInterpolator() {
- return mAnimation.getInterpolator();
- }
-
- @Override
- public long getDuration() {
- return mAnimation.getDuration();
- }
-
- @Override
- public long getStartOffset() {
- return mAnimation.getStartOffset() + mDelay;
- }
-
- @Override
- public int getRepeatMode() {
- return mAnimation.getRepeatMode();
- }
-
- @Override
- public boolean getFillBefore() {
- return mAnimation.getFillBefore();
- }
-
- @Override
- public boolean getFillAfter() {
- return mAnimation.getFillAfter();
- }
-
- @Override
- public boolean willChangeTransformationMatrix() {
- return mAnimation.willChangeTransformationMatrix();
- }
-
- @Override
- public boolean willChangeBounds() {
- return mAnimation.willChangeBounds();
- }
- }
}
diff --git a/core/java/android/view/animation/RotateAnimation.java b/core/java/android/view/animation/RotateAnimation.java
index 2f51b91..284ccce 100644
--- a/core/java/android/view/animation/RotateAnimation.java
+++ b/core/java/android/view/animation/RotateAnimation.java
@@ -40,7 +40,7 @@ public class RotateAnimation extends Animation {
private float mPivotY;
/**
- * Constructor used whan an RotateAnimation is loaded from a resource.
+ * Constructor used when a RotateAnimation is loaded from a resource.
*
* @param context Application context to use
* @param attrs Attribute set from which to read values
diff --git a/core/java/android/view/animation/ScaleAnimation.java b/core/java/android/view/animation/ScaleAnimation.java
index 122ed6d..1a56c8b 100644
--- a/core/java/android/view/animation/ScaleAnimation.java
+++ b/core/java/android/view/animation/ScaleAnimation.java
@@ -40,7 +40,7 @@ public class ScaleAnimation extends Animation {
private float mPivotY;
/**
- * Constructor used whan an ScaleAnimation is loaded from a resource.
+ * Constructor used when a ScaleAnimation is loaded from a resource.
*
* @param context Application context to use
* @param attrs Attribute set from which to read values
diff --git a/core/java/android/view/animation/TranslateAnimation.java b/core/java/android/view/animation/TranslateAnimation.java
index bb13972..a785d43 100644
--- a/core/java/android/view/animation/TranslateAnimation.java
+++ b/core/java/android/view/animation/TranslateAnimation.java
@@ -45,7 +45,7 @@ public class TranslateAnimation extends Animation {
private float mToYDelta;
/**
- * Constructor used when an TranslateAnimation is loaded from a resource.
+ * Constructor used when a TranslateAnimation is loaded from a resource.
*
* @param context Application context to use
* @param attrs Attribute set from which to read values
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index a6ce293..deca910 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -17,34 +17,386 @@
package android.view.inputmethod;
import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Bundle;
import android.os.Handler;
-import android.os.Message;
+import android.os.SystemClock;
+import android.text.Editable;
+import android.text.NoCopySpan;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.method.MetaKeyKeyListener;
+import android.util.Log;
+import android.util.LogPrinter;
+import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewRoot;
+class ComposingText implements NoCopySpan {
+}
+
/**
* Base class for implementors of the InputConnection interface, taking care
- * of implementing common system-oriented parts of the functionality.
+ * of most of the common behavior for providing a connection to an Editable.
+ * Implementors of this class will want to be sure to implement
+ * {@link #getEditable} to provide access to their own editable object.
*/
-public abstract class BaseInputConnection implements InputConnection {
+public class BaseInputConnection implements InputConnection {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "BaseInputConnection";
+ static final Object COMPOSING = new ComposingText();
+
final InputMethodManager mIMM;
final Handler mH;
final View mTargetView;
+ final boolean mDummyMode;
- BaseInputConnection(InputMethodManager mgr) {
+ private Object[] mDefaultComposingSpans;
+
+ Editable mEditable;
+ KeyCharacterMap mKeyCharacterMap;
+
+ BaseInputConnection(InputMethodManager mgr, boolean dummyMode) {
mIMM = mgr;
mTargetView = null;
mH = null;
+ mDummyMode = dummyMode;
}
- public BaseInputConnection(View targetView) {
+ public BaseInputConnection(View targetView, boolean dummyMode) {
mIMM = (InputMethodManager)targetView.getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
mH = targetView.getHandler();
mTargetView = targetView;
+ mDummyMode = dummyMode;
}
+ public static final void removeComposingSpans(Spannable text) {
+ text.removeSpan(COMPOSING);
+ Object[] sps = text.getSpans(0, text.length(), Object.class);
+ if (sps != null) {
+ for (int i=sps.length-1; i>=0; i--) {
+ Object o = sps[i];
+ if ((text.getSpanFlags(o)&Spanned.SPAN_COMPOSING) != 0) {
+ text.removeSpan(o);
+ }
+ }
+ }
+ }
+
+ public static void setComposingSpans(Spannable text) {
+ final Object[] sps = text.getSpans(0, text.length(), Object.class);
+ if (sps != null) {
+ for (int i=sps.length-1; i>=0; i--) {
+ final Object o = sps[i];
+ if (o == COMPOSING) {
+ text.removeSpan(o);
+ continue;
+ }
+ final int fl = text.getSpanFlags(o);
+ if ((fl&(Spanned.SPAN_COMPOSING|Spanned.SPAN_POINT_MARK_MASK))
+ != (Spanned.SPAN_COMPOSING|Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)) {
+ text.setSpan(o, text.getSpanStart(o), text.getSpanEnd(o),
+ (fl&Spanned.SPAN_POINT_MARK_MASK)
+ | Spanned.SPAN_COMPOSING
+ | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+ }
+
+ text.setSpan(COMPOSING, 0, text.length(),
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
+ }
+
+ public static int getComposingSpanStart(Spannable text) {
+ return text.getSpanStart(COMPOSING);
+ }
+
+ public static int getComposingSpanEnd(Spannable text) {
+ return text.getSpanEnd(COMPOSING);
+ }
+
+ /**
+ * Return the target of edit operations. The default implementation
+ * returns its own fake editable that is just used for composing text;
+ * subclasses that are real text editors should override this and
+ * supply their own.
+ */
+ public Editable getEditable() {
+ if (mEditable == null) {
+ mEditable = Editable.Factory.getInstance().newEditable("");
+ Selection.setSelection(mEditable, 0);
+ }
+ return mEditable;
+ }
+
+ /**
+ * Default implementation does nothing.
+ */
+ public boolean beginBatchEdit() {
+ return false;
+ }
+
+ /**
+ * Default implementation does nothing.
+ */
+ public boolean endBatchEdit() {
+ return false;
+ }
+
+ /**
+ * Default implementation uses
+ * {@link MetaKeyKeyListener#clearMetaKeyState(long, int)
+ * MetaKeyKeyListener.clearMetaKeyState(long, int)} to clear the state.
+ */
+ public boolean clearMetaKeyStates(int states) {
+ final Editable content = getEditable();
+ if (content == null) return false;
+ MetaKeyKeyListener.clearMetaKeyState(content, states);
+ return true;
+ }
+
+ /**
+ * Default implementation does nothing.
+ */
+ public boolean commitCompletion(CompletionInfo text) {
+ return false;
+ }
+
+ /**
+ * Default implementation replaces any existing composing text with
+ * the given text. In addition, only if dummy mode, a key event is
+ * sent for the new text and the current editable buffer cleared.
+ */
+ public boolean commitText(CharSequence text, int newCursorPosition) {
+ if (DEBUG) Log.v(TAG, "commitText " + text);
+ replaceText(text, newCursorPosition, false);
+ sendCurrentText();
+ return true;
+ }
+
+ /**
+ * The default implementation performs the deletion around the current
+ * selection position of the editable text.
+ */
+ public boolean deleteSurroundingText(int leftLength, int rightLength) {
+ if (DEBUG) Log.v(TAG, "deleteSurroundingText " + leftLength
+ + " / " + rightLength);
+ final Editable content = getEditable();
+ if (content == null) return false;
+
+ beginBatchEdit();
+
+ int a = Selection.getSelectionStart(content);
+ int b = Selection.getSelectionEnd(content);
+
+ if (a > b) {
+ int tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ // ignore the composing text.
+ int ca = getComposingSpanStart(content);
+ int cb = getComposingSpanEnd(content);
+ if (cb < ca) {
+ int tmp = ca;
+ ca = cb;
+ cb = tmp;
+ }
+ if (ca != -1 && cb != -1) {
+ if (ca < a) a = ca;
+ if (cb > b) b = cb;
+ }
+
+ int deleted = 0;
+
+ if (leftLength > 0) {
+ int start = a - leftLength;
+ if (start < 0) start = 0;
+ content.delete(start, a);
+ deleted = a - start;
+ }
+
+ if (rightLength > 0) {
+ b = b - deleted;
+
+ int end = b + rightLength;
+ if (end > content.length()) end = content.length();
+
+ content.delete(b, end);
+ }
+
+ endBatchEdit();
+
+ return true;
+ }
+
+ /**
+ * The default implementation removes the composing state from the
+ * current editable text. In addition, only if dummy mode, a key event is
+ * sent for the new text and the current editable buffer cleared.
+ */
+ public boolean finishComposingText() {
+ if (DEBUG) Log.v(TAG, "finishComposingText");
+ final Editable content = getEditable();
+ if (content != null) {
+ beginBatchEdit();
+ removeComposingSpans(content);
+ endBatchEdit();
+ sendCurrentText();
+ }
+ return true;
+ }
+
+ /**
+ * The default implementation uses TextUtils.getCapsMode to get the
+ * cursor caps mode for the current selection position in the editable
+ * text, unless in dummy mode in which case 0 is always returned.
+ */
+ public int getCursorCapsMode(int reqModes) {
+ if (mDummyMode) return 0;
+
+ final Editable content = getEditable();
+ if (content == null) return 0;
+
+ int a = Selection.getSelectionStart(content);
+ int b = Selection.getSelectionEnd(content);
+
+ if (a > b) {
+ int tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ return TextUtils.getCapsMode(content, a, reqModes);
+ }
+
+ /**
+ * The default implementation always returns null.
+ */
+ public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
+ return null;
+ }
+
+ /**
+ * The default implementation returns the given amount of text from the
+ * current cursor position in the buffer.
+ */
+ public CharSequence getTextBeforeCursor(int length, int flags) {
+ final Editable content = getEditable();
+ if (content == null) return null;
+
+ int a = Selection.getSelectionStart(content);
+ int b = Selection.getSelectionEnd(content);
+
+ if (a > b) {
+ int tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ if (length > a) {
+ length = a;
+ }
+
+ if ((flags&GET_TEXT_WITH_STYLES) != 0) {
+ return content.subSequence(a - length, a);
+ }
+ return TextUtils.substring(content, a - length, a);
+ }
+
+ /**
+ * The default implementation returns the given amount of text from the
+ * current cursor position in the buffer.
+ */
+ public CharSequence getTextAfterCursor(int length, int flags) {
+ final Editable content = getEditable();
+ if (content == null) return null;
+
+ int a = Selection.getSelectionStart(content);
+ int b = Selection.getSelectionEnd(content);
+
+ if (a > b) {
+ int tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ if (b + length > content.length()) {
+ length = content.length() - b;
+ }
+
+
+ if ((flags&GET_TEXT_WITH_STYLES) != 0) {
+ return content.subSequence(b, b + length);
+ }
+ return TextUtils.substring(content, b, b + length);
+ }
+
+ /**
+ * The default implementation does nothing.
+ */
+ public boolean performEditorAction(int actionCode) {
+ return false;
+ }
+
+ /**
+ * The default implementation does nothing.
+ */
+ public boolean performContextMenuAction(int id) {
+ return false;
+ }
+
+ /**
+ * The default implementation does nothing.
+ */
+ public boolean performPrivateCommand(String action, Bundle data) {
+ return false;
+ }
+
+ /**
+ * The default implementation places the given text into the editable,
+ * replacing any existing composing text. The new text is marked as
+ * in a composing state with the composing style.
+ */
+ public boolean setComposingText(CharSequence text, int newCursorPosition) {
+ if (DEBUG) Log.v(TAG, "setComposingText " + text);
+ replaceText(text, newCursorPosition, true);
+ return true;
+ }
+
+ /**
+ * The default implementation changes the selection position in the
+ * current editable text.
+ */
+ public boolean setSelection(int start, int end) {
+ if (DEBUG) Log.v(TAG, "setSelection " + start + ", " + end);
+ final Editable content = getEditable();
+ if (content == null) return false;
+ int len = content.length();
+ if (start > len || end > len) {
+ // If the given selection is out of bounds, just ignore it.
+ // Most likely the text was changed out from under the IME,
+ // the the IME is going to have to update all of its state
+ // anyway.
+ return true;
+ }
+ if (start == end && MetaKeyKeyListener.getMetaState(content,
+ MetaKeyKeyListener.META_SELECTING) != 0) {
+ // If we are in selection mode, then we want to extend the
+ // selection instead of replacing it.
+ Selection.extendSelection(content, start);
+ } else {
+ Selection.setSelection(content, start, end);
+ }
+ return true;
+ }
+
/**
* Provides standard implementation for sending a key event to the window
* attached to the input connection's view.
@@ -66,20 +418,161 @@ public abstract class BaseInputConnection implements InputConnection {
}
/**
- * Provides standard implementation for hiding the status icon associated
- * with the current input method.
+ * Updates InputMethodManager with the current fullscreen mode.
*/
- public boolean hideStatusIcon() {
- mIMM.updateStatusIcon(0, null);
+ public boolean reportFullscreenMode(boolean enabled) {
+ mIMM.setFullscreenMode(enabled);
return true;
}
- /**
- * Provides standard implementation for showing the status icon associated
- * with the current input method.
- */
- public boolean showStatusIcon(String packageName, int resId) {
- mIMM.updateStatusIcon(resId, packageName);
- return true;
+ private void sendCurrentText() {
+ if (!mDummyMode) {
+ return;
+ }
+
+ Editable content = getEditable();
+ if (content != null) {
+ final int N = content.length();
+ if (N == 0) {
+ return;
+ }
+ if (N == 1) {
+ // If it's 1 character, we have a chance of being
+ // able to generate normal key events...
+ if (mKeyCharacterMap == null) {
+ mKeyCharacterMap = KeyCharacterMap.load(
+ KeyCharacterMap.BUILT_IN_KEYBOARD);
+ }
+ char[] chars = new char[1];
+ content.getChars(0, 1, chars, 0);
+ KeyEvent[] events = mKeyCharacterMap.getEvents(chars);
+ if (events != null) {
+ for (int i=0; i<events.length; i++) {
+ if (DEBUG) Log.v(TAG, "Sending: " + events[i]);
+ sendKeyEvent(events[i]);
+ }
+ content.clear();
+ return;
+ }
+ }
+
+ // Otherwise, revert to the special key event containing
+ // the actual characters.
+ KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(),
+ content.toString(), KeyCharacterMap.BUILT_IN_KEYBOARD, 0);
+ sendKeyEvent(event);
+ content.clear();
+ }
+ }
+
+ private void replaceText(CharSequence text, int newCursorPosition,
+ boolean composing) {
+ final Editable content = getEditable();
+ if (content == null) {
+ return;
+ }
+
+ beginBatchEdit();
+
+ // delete composing text set previously.
+ int a = getComposingSpanStart(content);
+ int b = getComposingSpanEnd(content);
+
+ if (DEBUG) Log.v(TAG, "Composing span: " + a + " to " + b);
+
+ if (b < a) {
+ int tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ if (a != -1 && b != -1) {
+ removeComposingSpans(content);
+ } else {
+ a = Selection.getSelectionStart(content);
+ b = Selection.getSelectionEnd(content);
+ if (a >=0 && b>= 0 && a != b) {
+ if (b < a) {
+ int tmp = a;
+ a = b;
+ b = tmp;
+ }
+ }
+ }
+
+ if (composing) {
+ Spannable sp = null;
+ if (!(text instanceof Spannable)) {
+ sp = new SpannableStringBuilder(text);
+ text = sp;
+ if (mDefaultComposingSpans == null) {
+ Context context;
+ if (mTargetView != null) {
+ context = mTargetView.getContext();
+ } else if (mIMM.mServedView != null) {
+ context = mIMM.mServedView.getContext();
+ } else {
+ context = null;
+ }
+ if (context != null) {
+ TypedArray ta = context.getTheme()
+ .obtainStyledAttributes(new int[] {
+ com.android.internal.R.attr.candidatesTextStyleSpans
+ });
+ CharSequence style = ta.getText(0);
+ ta.recycle();
+ if (style != null && style instanceof Spanned) {
+ mDefaultComposingSpans = ((Spanned)style).getSpans(
+ 0, style.length(), Object.class);
+ }
+ }
+ }
+ if (mDefaultComposingSpans != null) {
+ for (int i = 0; i < mDefaultComposingSpans.length; ++i) {
+ sp.setSpan(mDefaultComposingSpans[i], 0, sp.length(),
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+ } else {
+ sp = (Spannable)text;
+ }
+ setComposingSpans(sp);
+ }
+
+ if (DEBUG) Log.v(TAG, "Replacing from " + a + " to " + b + " with \""
+ + text + "\", composing=" + composing
+ + ", type=" + text.getClass().getCanonicalName());
+
+ if (DEBUG) {
+ LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG);
+ lp.println("Current text:");
+ TextUtils.dumpSpans(content, lp, " ");
+ lp.println("Composing text:");
+ TextUtils.dumpSpans(text, lp, " ");
+ }
+
+ // Position the cursor appropriately, so that after replacing the
+ // desired range of text it will be located in the correct spot.
+ // This allows us to deal with filters performing edits on the text
+ // we are providing here.
+ if (newCursorPosition > 0) {
+ newCursorPosition += b - 1;
+ } else {
+ newCursorPosition += a;
+ }
+ if (newCursorPosition < 0) newCursorPosition = 0;
+ if (newCursorPosition > content.length())
+ newCursorPosition = content.length();
+ Selection.setSelection(content, newCursorPosition);
+
+ content.replace(a, b, text);
+
+ if (DEBUG) {
+ LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG);
+ lp.println("Final text:");
+ TextUtils.dumpSpans(content, lp, " ");
+ }
+
+ endBatchEdit();
}
}
diff --git a/core/java/android/view/inputmethod/DefaultInputMethod.java b/core/java/android/view/inputmethod/DefaultInputMethod.java
deleted file mode 100644
index 073b01c..0000000
--- a/core/java/android/view/inputmethod/DefaultInputMethod.java
+++ /dev/null
@@ -1,239 +0,0 @@
-package android.view.inputmethod;
-
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethod;
-import com.android.internal.view.IInputMethodCallback;
-import com.android.internal.view.IInputMethodSession;
-import com.android.internal.view.InputConnectionWrapper;
-
-/**
- * This is the default input method that runs in the same context of the
- * application that requests text input. It does nothing but returns false for
- * any key events, so that all key events will be processed by the key listener
- * of the focused text box.
- * {@hide}
- */
-public class DefaultInputMethod implements InputMethod, InputMethodSession {
- private static IInputMethod sInstance = new SimpleInputMethod(
- new DefaultInputMethod());
-
- private static InputMethodInfo sProperty = new InputMethodInfo(
- "android.text.inputmethod", DefaultInputMethod.class.getName(),
- "Default", "android.text.inputmethod.defaultImeSettings");
-
- private InputConnection mInputConnection;
-
- public static IInputMethod getInstance() {
- return sInstance;
- }
-
- public static InputMethodInfo getMetaInfo() {
- return sProperty;
- }
-
- public void bindInput(InputBinding binding) {
- mInputConnection = binding.getConnection();
- }
-
- public void unbindInput() {
- }
-
- public void createSession(SessionCallback callback) {
- callback.sessionCreated(this);
- }
-
- public void setSessionEnabled(InputMethodSession session, boolean enabled) {
- }
-
- public void revokeSession(InputMethodSession session) {
- }
-
- public void finishInput() {
- mInputConnection.hideStatusIcon();
- }
-
- public void displayCompletions(CompletionInfo[] completions) {
- }
-
- public void updateExtractedText(int token, ExtractedText text) {
- }
-
- public void updateSelection(int oldSelStart, int oldSelEnd,
- int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
- }
-
- public void updateCursor(Rect newCursor) {
- }
-
- public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) {
- callback.finishedEvent(seq, false);
- }
-
- public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback) {
- callback.finishedEvent(seq, false);
- }
-
- public void restartInput(EditorInfo attribute) {
- }
-
- public void attachToken(IBinder token) {
- }
-
- public void startInput(EditorInfo attribute) {
- mInputConnection
- .showStatusIcon("android", com.android.internal.R.drawable.ime_qwerty);
- }
-
- public void appPrivateCommand(String action, Bundle data) {
- }
-
- public void hideSoftInput() {
- }
-
- public void showSoftInput(int flags) {
- }
-}
-
-// ----------------------------------------------------------------------
-
-class SimpleInputMethod extends IInputMethod.Stub {
- final InputMethod mInputMethod;
-
- static class Session extends IInputMethodSession.Stub {
- final InputMethodSession mSession;
-
- Session(InputMethodSession session) {
- mSession = session;
- }
-
- public void finishInput() {
- mSession.finishInput();
- }
-
- public void updateSelection(int oldSelStart, int oldSelEnd,
- int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
- mSession.updateSelection(oldSelStart, oldSelEnd,
- newSelStart, newSelEnd, candidatesStart, candidatesEnd);
- }
-
- public void updateCursor(Rect newCursor) {
- mSession.updateCursor(newCursor);
- }
-
- static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback {
- final IInputMethodCallback mCb;
- InputMethodEventCallbackWrapper(IInputMethodCallback cb) {
- mCb = cb;
- }
- public void finishedEvent(int seq, boolean handled) {
- try {
- mCb.finishedEvent(seq, handled);
- } catch (RemoteException e) {
- }
- }
- }
-
- public void dispatchKeyEvent(int seq, KeyEvent event, IInputMethodCallback callback) {
- mSession.dispatchKeyEvent(seq, event,
- new InputMethodEventCallbackWrapper(callback));
- }
-
- public void dispatchTrackballEvent(int seq, MotionEvent event, IInputMethodCallback callback) {
- mSession.dispatchTrackballEvent(seq, event,
- new InputMethodEventCallbackWrapper(callback));
- }
-
- public void displayCompletions(CompletionInfo[] completions) {
- mSession.displayCompletions(completions);
- }
-
- public void updateExtractedText(int token, ExtractedText text) {
- mSession.updateExtractedText(token, text);
- }
-
- public void appPrivateCommand(String action, Bundle data) {
- mSession.appPrivateCommand(action, data);
- }
- }
-
- public SimpleInputMethod(InputMethod inputMethod) {
- mInputMethod = inputMethod;
- }
-
- public InputMethod getInternalInputMethod() {
- return mInputMethod;
- }
-
- public void attachToken(IBinder token) {
- mInputMethod.attachToken(token);
- }
-
- public void bindInput(InputBinding binding) {
- InputConnectionWrapper ic = new InputConnectionWrapper(
- IInputContext.Stub.asInterface(binding.getConnectionToken()));
- InputBinding nu = new InputBinding(ic, binding);
- mInputMethod.bindInput(nu);
- }
-
- public void unbindInput() {
- mInputMethod.unbindInput();
- }
-
- public void restartInput(EditorInfo attribute) {
- mInputMethod.restartInput(attribute);
- }
-
- public void startInput(EditorInfo attribute) {
- mInputMethod.startInput(attribute);
- }
-
- static class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback {
- final IInputMethodCallback mCb;
- InputMethodSessionCallbackWrapper(IInputMethodCallback cb) {
- mCb = cb;
- }
-
- public void sessionCreated(InputMethodSession session) {
- try {
- mCb.sessionCreated(new Session(session));
- } catch (RemoteException e) {
- }
- }
- }
-
- public void createSession(IInputMethodCallback callback) throws RemoteException {
- mInputMethod.createSession(new InputMethodSessionCallbackWrapper(callback));
- }
-
- public void setSessionEnabled(IInputMethodSession session, boolean enabled) throws RemoteException {
- try {
- InputMethodSession ls = ((Session)session).mSession;
- mInputMethod.setSessionEnabled(ls, enabled);
- } catch (ClassCastException e) {
- Log.w("SimpleInputMethod", "Incoming session not of correct type: " + session, e);
- }
- }
-
- public void revokeSession(IInputMethodSession session) throws RemoteException {
- try {
- InputMethodSession ls = ((Session)session).mSession;
- mInputMethod.revokeSession(ls);
- } catch (ClassCastException e) {
- Log.w("SimpleInputMethod", "Incoming session not of correct type: " + session, e);
- }
- }
-
- public void showSoftInput(boolean blah) {
- }
-
- public void hideSoftInput() {
- }
-}
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index c050691..b00e565 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -5,6 +5,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.InputType;
import android.text.TextUtils;
+import android.util.Printer;
/**
* An EditorInfo describes several attributes of a text editing object
@@ -21,20 +22,109 @@ public class EditorInfo implements InputType, Parcelable {
* @see #TYPE_MASK_VARIATION
* @see #TYPE_MASK_FLAGS
*/
- public int inputType = TYPE_CLASS_TEXT;
+ public int inputType = TYPE_NULL;
/**
- * A string supplying additional information about the content type that
- * is private to a particular IME implementation. The string must be
+ * Set of bits in {@link #imeOptions} that provide alternative actions
+ * associated with the "enter" key. This both helps the IME provide
+ * better feedback about what the enter key will do, and also allows it
+ * to provide alternative mechanisms for providing that command.
+ */
+ public static final int IME_MASK_ACTION = 0x000000ff;
+
+ /**
+ * Bits of {@link #IME_MASK_ACTION}: no specific action has been
+ * associated with this editor, let the editor come up with its own if
+ * it can.
+ */
+ public static final int IME_ACTION_UNSPECIFIED = 0x00000000;
+
+ /**
+ * Bits of {@link #IME_MASK_ACTION}: there is no available action.
+ */
+ public static final int IME_ACTION_NONE = 0x00000001;
+
+ /**
+ * Bits of {@link #IME_MASK_ACTION}: the action key performs a "go"
+ * operation to take the user to the target of the text they typed.
+ * Typically used, for example, when entering a URL.
+ */
+ public static final int IME_ACTION_GO = 0x00000002;
+
+ /**
+ * Bits of {@link #IME_MASK_ACTION}: the action key performs a "search"
+ * operation, taking the user to the results of searching for the text
+ * the have typed (in whatever context is appropriate).
+ */
+ public static final int IME_ACTION_SEARCH = 0x00000003;
+
+ /**
+ * Bits of {@link #IME_MASK_ACTION}: the action key performs a "send"
+ * operation, delivering the text to its target. This is typically used
+ * when composing a message.
+ */
+ public static final int IME_ACTION_SEND = 0x00000004;
+
+ /**
+ * Bits of {@link #IME_MASK_ACTION}: the action key performs a "next"
+ * operation, taking the user to the next field that will accept text.
+ */
+ public static final int IME_ACTION_NEXT = 0x00000005;
+
+ /**
+ * Bits of {@link #IME_MASK_ACTION}: the action key performs a "done"
+ * operation, typically meaning the IME will be closed.
+ */
+ public static final int IME_ACTION_DONE = 0x00000006;
+
+ /**
+ * 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
+ * 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.
+ */
+ public static final int IME_FLAG_NO_ENTER_ACTION = 0x40000000;
+
+ /**
+ * Generic unspecified type for {@link #imeOptions}.
+ */
+ public static final int IME_NULL = 0x00000000;
+
+ /**
+ * Extended type information for the editor, to help the IME better
+ * integrate with it.
+ */
+ public int imeOptions = IME_NULL;
+
+ /**
+ * A string supplying additional information options that are
+ * private to a particular IME implementation. The string must be
* scoped to a package owned by the implementation, to ensure there are
* no conflicts between implementations, but other than that you can put
* whatever you want in it to communicate with the IME. For example,
* you could have a string that supplies an argument like
* <code>"com.example.myapp.SpecialMode=3"</code>. This field is can be
- * filled in from the {@link android.R.attr#editorPrivateContentType}
+ * filled in from the {@link android.R.attr#privateImeOptions}
* attribute of a TextView.
*/
- public String privateContentType = null;
+ public String privateImeOptions = null;
+
+ /**
+ * In some cases an IME may be able to display an arbitrary label for
+ * a command the user can perform, which you can specify here. You can
+ * not count on this being used.
+ */
+ public CharSequence actionLabel = null;
+
+ /**
+ * If {@link #actionLabel} has been given, this is the id for that command
+ * when the user presses its button that is delivered back with
+ * {@link InputConnection#performEditorAction(int)
+ * InputConnection.performEditorAction()}.
+ */
+ public int actionId = 0;
/**
* The text offset of the start of the selection at the time editing
@@ -71,6 +161,26 @@ public class EditorInfo implements InputType, Parcelable {
public CharSequence label;
/**
+ * Name of the package that owns this editor.
+ */
+ public String packageName;
+
+ /**
+ * Identifier for the editor's field. This is optional, and may be
+ * 0. By default it is filled in with the result of
+ * {@link android.view.View#getId() View.getId()} on the View that
+ * is being edited.
+ */
+ public int fieldId;
+
+ /**
+ * Additional name for the editor's field. This can supply additional
+ * name information for the field. By default it is null. The actual
+ * contents have no meaning.
+ */
+ public String fieldName;
+
+ /**
* Any extra data to supply to the input method. This is for extended
* communication with specific input methods; the name fields in the
* bundle should be scoped (such as "com.mydomain.im.SOME_FIELD") so
@@ -81,6 +191,27 @@ public class EditorInfo implements InputType, Parcelable {
public Bundle extras;
/**
+ * Write debug output of this object.
+ */
+ public void dump(Printer pw, String prefix) {
+ pw.println(prefix + "inputType=0x" + Integer.toHexString(inputType)
+ + " imeOptions=0x" + Integer.toHexString(imeOptions)
+ + " privateImeOptions=" + privateImeOptions);
+ pw.println(prefix + "actionLabel=" + actionLabel
+ + " actionId=" + actionId);
+ pw.println(prefix + "initialSelStart=" + initialSelStart
+ + " initialSelEnd=" + initialSelEnd
+ + " initialCapsMode=0x"
+ + Integer.toHexString(initialCapsMode));
+ pw.println(prefix + "hintText=" + hintText
+ + " label=" + label);
+ pw.println(prefix + "packageName=" + packageName
+ + " fieldId=" + fieldId
+ + " fieldName=" + fieldName);
+ pw.println(prefix + "extras=" + extras);
+ }
+
+ /**
* Used to package this object into a {@link Parcel}.
*
* @param dest The {@link Parcel} to be written.
@@ -88,12 +219,18 @@ public class EditorInfo implements InputType, Parcelable {
*/
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(inputType);
- dest.writeString(privateContentType);
+ dest.writeInt(imeOptions);
+ dest.writeString(privateImeOptions);
+ TextUtils.writeToParcel(actionLabel, dest, flags);
+ dest.writeInt(actionId);
dest.writeInt(initialSelStart);
dest.writeInt(initialSelEnd);
dest.writeInt(initialCapsMode);
TextUtils.writeToParcel(hintText, dest, flags);
TextUtils.writeToParcel(label, dest, flags);
+ dest.writeString(packageName);
+ dest.writeInt(fieldId);
+ dest.writeString(fieldName);
dest.writeBundle(extras);
}
@@ -104,12 +241,18 @@ public class EditorInfo implements InputType, Parcelable {
public EditorInfo createFromParcel(Parcel source) {
EditorInfo res = new EditorInfo();
res.inputType = source.readInt();
- res.privateContentType = source.readString();
+ res.imeOptions = source.readInt();
+ res.privateImeOptions = source.readString();
+ res.actionLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+ res.actionId = source.readInt();
res.initialSelStart = source.readInt();
res.initialSelEnd = source.readInt();
res.initialCapsMode = source.readInt();
res.hintText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
res.label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+ res.packageName = source.readString();
+ res.fieldId = source.readInt();
+ res.fieldName = source.readString();
res.extras = source.readBundle();
return res;
}
diff --git a/core/java/android/view/inputmethod/ExtractedText.java b/core/java/android/view/inputmethod/ExtractedText.java
index 0ca3c79..c2851d6 100644
--- a/core/java/android/view/inputmethod/ExtractedText.java
+++ b/core/java/android/view/inputmethod/ExtractedText.java
@@ -19,6 +19,22 @@ public class ExtractedText implements Parcelable {
public int startOffset;
/**
+ * If the content is a report of a partial text change, this is the
+ * offset where the change starts and it runs until
+ * {@link #partialEndOffset}. If the content is the full text, this
+ * field is -1.
+ */
+ public int partialStartOffset;
+
+ /**
+ * If the content is a report of a partial text change, this is the offset
+ * where the change ends. Note that the actual text may be larger or
+ * smaller than the difference between this and {@link #partialEndOffset},
+ * meaning a reduction or increase, respectively, in the total text.
+ */
+ public int partialEndOffset;
+
+ /**
* The offset where the selection currently starts within the extracted
* text. The real selection start position is at
* <var>startOffset</var>+<var>selectionStart</var>.
@@ -39,6 +55,11 @@ public class ExtractedText implements Parcelable {
public static final int FLAG_SINGLE_LINE = 0x0001;
/**
+ * Bit for {@link #flags}: set if the editor is currently in selection mode.
+ */
+ public static final int FLAG_SELECTING = 0x0002;
+
+ /**
* Additional bit flags of information about the edited text.
*/
public int flags;
@@ -52,9 +73,11 @@ public class ExtractedText implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
TextUtils.writeToParcel(text, dest, flags);
dest.writeInt(startOffset);
+ dest.writeInt(partialStartOffset);
+ dest.writeInt(partialEndOffset);
dest.writeInt(selectionStart);
dest.writeInt(selectionEnd);
- dest.writeInt(flags);
+ dest.writeInt(this.flags);
}
/**
@@ -65,6 +88,8 @@ public class ExtractedText implements Parcelable {
ExtractedText res = new ExtractedText();
res.text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
res.startOffset = source.readInt();
+ res.partialStartOffset = source.readInt();
+ res.partialEndOffset = source.readInt();
res.selectionStart = source.readInt();
res.selectionEnd = source.readInt();
res.flags = source.readInt();
diff --git a/core/java/android/view/inputmethod/ExtractedTextRequest.java b/core/java/android/view/inputmethod/ExtractedTextRequest.java
index d962329..e84b094 100644
--- a/core/java/android/view/inputmethod/ExtractedTextRequest.java
+++ b/core/java/android/view/inputmethod/ExtractedTextRequest.java
@@ -16,6 +16,13 @@ public class ExtractedTextRequest implements Parcelable {
public int token;
/**
+ * Additional request flags, having the same possible values as the
+ * flags parameter of {@link InputConnection#getTextBeforeCursor
+ * InputConnection.getTextBeforeCursor()}.
+ */
+ public int flags;
+
+ /**
* Hint for the maximum number of lines to return.
*/
public int hintMaxLines;
@@ -33,6 +40,7 @@ public class ExtractedTextRequest implements Parcelable {
*/
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(token);
+ dest.writeInt(this.flags);
dest.writeInt(hintMaxLines);
dest.writeInt(hintMaxChars);
}
@@ -45,6 +53,7 @@ public class ExtractedTextRequest implements Parcelable {
public ExtractedTextRequest createFromParcel(Parcel source) {
ExtractedTextRequest res = new ExtractedTextRequest();
res.token = source.readInt();
+ res.flags = source.readInt();
res.hintMaxLines = source.readInt();
res.hintMaxChars = source.readInt();
return res;
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index bd7b050..8b6831e 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -17,7 +17,6 @@
package android.view.inputmethod;
import android.os.Bundle;
-import android.text.Spanned;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -32,6 +31,21 @@ import android.view.KeyEvent;
*/
public interface InputConnection {
/**
+ * Flag for use with {@link #getTextAfterCursor} and
+ * {@link #getTextBeforeCursor} to have style information returned along
+ * with the text. If not set, you will receive only the raw text. If
+ * set, you may receive a complex CharSequence of both text and style
+ * spans.
+ */
+ static final int GET_TEXT_WITH_STYLES = 0x0001;
+
+ /**
+ * Flag for use with {@link #getExtractedText} to indicate you would
+ * like to receive updates when the extracted text changes.
+ */
+ public static final int GET_EXTRACTED_TEXT_MONITOR = 0x0001;
+
+ /**
* Get <var>n</var> characters of text before the current cursor position.
*
* <p>This method may fail either if the input connection has become invalid
@@ -40,11 +54,13 @@ public interface InputConnection {
* In either case, a null is returned.
*
* @param n The expected length of the text.
+ * @param flags Supplies additional options controlling how the text is
+ * returned. May be either 0 or {@link #GET_TEXT_WITH_STYLES}.
*
* @return Returns the text before the cursor position; the length of the
* returned text might be less than <var>n</var>.
*/
- public CharSequence getTextBeforeCursor(int n);
+ public CharSequence getTextBeforeCursor(int n, int flags);
/**
* Get <var>n</var> characters of text after the current cursor position.
@@ -55,11 +71,13 @@ public interface InputConnection {
* In either case, a null is returned.
*
* @param n The expected length of the text.
+ * @param flags Supplies additional options controlling how the text is
+ * returned. May be either 0 or {@link #GET_TEXT_WITH_STYLES}.
*
* @return Returns the text after the cursor position; the length of the
* returned text might be less than <var>n</var>.
*/
- public CharSequence getTextAfterCursor(int n);
+ public CharSequence getTextAfterCursor(int n, int flags);
/**
* Retrieve the current capitalization mode in effect at the current
@@ -82,8 +100,6 @@ public interface InputConnection {
*/
public int getCursorCapsMode(int reqModes);
- public static final int EXTRACTED_TEXT_MONITOR = 0x0001;
-
/**
* Retrieve the current text in the input connection's editor, and monitor
* for any changes to it. This function returns with the current text,
@@ -97,7 +113,7 @@ public interface InputConnection {
*
* @param request Description of how the text should be returned.
* @param flags Additional options to control the client, either 0 or
- * {@link #EXTRACTED_TEXT_MONITOR}.
+ * {@link #GET_EXTRACTED_TEXT_MONITOR}.
*
* @return Returns an ExtractedText object describing the state of the
* text view and containing the extracted text itself.
@@ -118,7 +134,7 @@ public interface InputConnection {
* @return Returns true on success, false if the input connection is no longer
* valid.
*/
- boolean deleteSurroundingText(int leftLength, int rightLength);
+ public boolean deleteSurroundingText(int leftLength, int rightLength);
/**
* Set composing text around the current cursor position with the given text,
@@ -131,8 +147,14 @@ public interface InputConnection {
* object to the text. {#link android.text.SpannableString} and
* {#link android.text.SpannableStringBuilder} are two
* implementations of the interface {#link android.text.Spanned}.
- * @param newCursorPosition The new cursor position within the
- * <var>text</var>.
+ * @param newCursorPosition The new cursor position around the text. If
+ * > 0, this is relative to the end of the text - 1; if <= 0, this
+ * is relative to the start of the text. So a value of 1 will
+ * always advance you to the position after the full text being
+ * inserted. Note that this means you can't position the cursor
+ * within the text, because the editor can make modifications to
+ * the text you are providing so it is not possible to correctly
+ * specify locations there.
*
* @return Returns true on success, false if the input connection is no longer
* valid.
@@ -141,7 +163,7 @@ public interface InputConnection {
/**
* Have the text editor finish whatever composing text is currently
- * active. This simple leaves the text as-is, removing any special
+ * active. This simply leaves the text as-is, removing any special
* composing styling or other state that was around it. The cursor
* position remains unchanged.
*/
@@ -153,8 +175,14 @@ public interface InputConnection {
* automatically.
*
* @param text The committed text.
- * @param newCursorPosition The new cursor position within the
- * <var>text</var>.
+ * @param newCursorPosition The new cursor position around the text. If
+ * > 0, this is relative to the end of the text - 1; if <= 0, this
+ * is relative to the start of the text. So a value of 1 will
+ * always advance you to the position after the full text being
+ * inserted. Note that this means you can't position the cursor
+ * within the text, because the editor can make modifications to
+ * the text you are providing so it is not possible to correctly
+ * specify locations there.
*
*
* @return Returns true on success, false if the input connection is no longer
@@ -177,6 +205,36 @@ public interface InputConnection {
public boolean commitCompletion(CompletionInfo text);
/**
+ * Set the selection of the text editor. To set the cursor position,
+ * start and end should have the same value.
+ * @return Returns true on success, false if the input connection is no longer
+ * valid.
+ */
+ public boolean setSelection(int start, int end);
+
+ /**
+ * Have the editor perform an action it has said it can do.
+ *
+ * @param editorAction This must be one of the action constants for
+ * {@link EditorInfo#imeOptions EditorInfo.editorType}, such as
+ * {@link EditorInfo#IME_ACTION_GO EditorInfo.EDITOR_ACTION_GO}.
+ *
+ * @return Returns true on success, false if the input connection is no longer
+ * valid.
+ */
+ public boolean performEditorAction(int editorAction);
+
+ /**
+ * Perform a context menu action on the field. The given id may be one of:
+ * {@link android.R.id#selectAll},
+ * {@link android.R.id#startSelectingText}, {@link android.R.id#stopSelectingText},
+ * {@link android.R.id#cut}, {@link android.R.id#copy},
+ * {@link android.R.id#paste}, {@link android.R.id#copyUrl},
+ * or {@link android.R.id#switchInputMethod}
+ */
+ public boolean performContextMenuAction(int id);
+
+ /**
* Tell the editor that you are starting a batch of editor operations.
* The editor will try to avoid sending you updates about its state
* until {@link #endBatchEdit} is called.
@@ -234,6 +292,13 @@ public interface InputConnection {
public boolean clearMetaKeyStates(int states);
/**
+ * Called by the IME to tell the client when it switches between fullscreen
+ * and normal modes. This will normally be called for you by the standard
+ * implementation of {@link android.inputmethodservice.InputMethodService}.
+ */
+ public boolean reportFullscreenMode(boolean enabled);
+
+ /**
* API to send private commands from an input method to its connected
* editor. This can be used to provide domain-specific features that are
* only known between certain input methods and their clients. Note that
@@ -251,23 +316,4 @@ public interface InputConnection {
* valid.
*/
public boolean performPrivateCommand(String action, Bundle data);
-
- /**
- * Show an icon in the status bar.
- *
- * @param packageName The package holding the icon resource to be shown.
- * @param resId The resource id of the icon to show.
- *
- * @return Returns true on success, false if the input connection is no longer
- * valid.
- */
- public boolean showStatusIcon(String packageName, int resId);
-
- /**
- * Hide the icon shown in the status bar.
- *
- * @return Returns true on success, false if the input connection is no longer
- * valid.
- */
- public boolean hideStatusIcon();
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index f65b2a1..e3d5e62 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -20,88 +20,86 @@ import android.os.Bundle;
import android.view.KeyEvent;
/**
- * Wrapper around InputConnection interface, calling through to another
- * implementation of it.
+ * <p>Wrapper class for proxying calls to another InputConnection. Subclass
+ * and have fun!
*/
public class InputConnectionWrapper implements InputConnection {
- InputConnection mBase;
+ private final InputConnection mTarget;
- /**
- * Create a new wrapper around an existing InputConnection implementation.
- */
- public InputConnectionWrapper(InputConnection base) {
- mBase = base;
+ public InputConnectionWrapper(InputConnection target) {
+ mTarget = target;
}
- /**
- * Return the base InputConnection that this class is wrapping.
- */
- InputConnection getBase() {
- return mBase;
+ public CharSequence getTextBeforeCursor(int n, int flags) {
+ return mTarget.getTextBeforeCursor(n, flags);
}
- public CharSequence getTextBeforeCursor(int n) {
- return mBase.getTextBeforeCursor(n);
- }
-
- public CharSequence getTextAfterCursor(int n) {
- return mBase.getTextAfterCursor(n);
+ public CharSequence getTextAfterCursor(int n, int flags) {
+ return mTarget.getTextAfterCursor(n, flags);
}
public int getCursorCapsMode(int reqModes) {
- return mBase.getCursorCapsMode(reqModes);
+ return mTarget.getCursorCapsMode(reqModes);
}
public ExtractedText getExtractedText(ExtractedTextRequest request,
int flags) {
- return mBase.getExtractedText(request, flags);
+ return mTarget.getExtractedText(request, flags);
}
public boolean deleteSurroundingText(int leftLength, int rightLength) {
- return mBase.deleteSurroundingText(leftLength, rightLength);
+ return mTarget.deleteSurroundingText(leftLength, rightLength);
}
public boolean setComposingText(CharSequence text, int newCursorPosition) {
- return mBase.setComposingText(text, newCursorPosition);
+ return mTarget.setComposingText(text, newCursorPosition);
}
public boolean finishComposingText() {
- return mBase.finishComposingText();
+ return mTarget.finishComposingText();
}
public boolean commitText(CharSequence text, int newCursorPosition) {
- return mBase.commitText(text, newCursorPosition);
+ return mTarget.commitText(text, newCursorPosition);
}
public boolean commitCompletion(CompletionInfo text) {
- return mBase.commitCompletion(text);
+ return mTarget.commitCompletion(text);
+ }
+
+ public boolean setSelection(int start, int end) {
+ return mTarget.setSelection(start, end);
+ }
+
+ public boolean performEditorAction(int editorAction) {
+ return mTarget.performEditorAction(editorAction);
+ }
+
+ public boolean performContextMenuAction(int id) {
+ return mTarget.performContextMenuAction(id);
}
public boolean beginBatchEdit() {
- return mBase.beginBatchEdit();
+ return mTarget.beginBatchEdit();
}
public boolean endBatchEdit() {
- return mBase.endBatchEdit();
+ return mTarget.endBatchEdit();
}
public boolean sendKeyEvent(KeyEvent event) {
- return mBase.sendKeyEvent(event);
+ return mTarget.sendKeyEvent(event);
}
public boolean clearMetaKeyStates(int states) {
- return mBase.clearMetaKeyStates(states);
- }
-
- public boolean performPrivateCommand(String action, Bundle data) {
- return mBase.performPrivateCommand(action, data);
+ return mTarget.clearMetaKeyStates(states);
}
- public boolean showStatusIcon(String packageName, int resId) {
- return mBase.showStatusIcon(packageName, resId);
+ public boolean reportFullscreenMode(boolean enabled) {
+ return mTarget.reportFullscreenMode(enabled);
}
- public boolean hideStatusIcon() {
- return mBase.hideStatusIcon();
+ public boolean performPrivateCommand(String action, Bundle data) {
+ return mTarget.performPrivateCommand(action, data);
}
}
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index c0e6590..a5e0e94 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -18,6 +18,7 @@ package android.view.inputmethod;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
+import android.os.ResultReceiver;
/**
* The InputMethod interface represents an input method which can generate key
@@ -113,12 +114,15 @@ public interface InputMethod {
* is ready for this input method to process received events and send result
* text back to the application.
*
- * @param attribute The attribute of the text box (typically, a EditText)
+ * @param inputConnection Optional specific input connection for
+ * communicating with the text box; if null, you should use the generic
+ * bound input connection.
+ * @param info Information about the text box (typically, an EditText)
* that requests input.
*
* @see EditorInfo
*/
- public void startInput(EditorInfo attribute);
+ public void startInput(InputConnection inputConnection, EditorInfo info);
/**
* This method is called when the state of this input method needs to be
@@ -128,12 +132,15 @@ public interface InputMethod {
* Typically, this method is called when the input focus is moved from one
* text box to another.
*
+ * @param inputConnection Optional specific input connection for
+ * communicating with the text box; if null, you should use the generic
+ * bound input connection.
* @param attribute The attribute of the text box (typically, a EditText)
* that requests input.
*
* @see EditorInfo
*/
- public void restartInput(EditorInfo attribute);
+ public void restartInput(InputConnection inputConnection, EditorInfo attribute);
/**
* Create a new {@link InputMethodSession} that can be handed to client
@@ -165,7 +172,7 @@ public interface InputMethod {
public void revokeSession(InputMethodSession session);
/**
- * Flag for {@link #showSoftInput(int)}: this show has been explicitly
+ * Flag for {@link #showSoftInput}: this show has been explicitly
* requested by the user. If not set, the system has decided it may be
* a good idea to show the input method based on a navigation operation
* in the UI.
@@ -173,15 +180,38 @@ public interface InputMethod {
public static final int SHOW_EXPLICIT = 0x00001;
/**
+ * Flag for {@link #showSoftInput}: this show has been forced to
+ * happen by the user. If set, the input method should remain visible
+ * until deliberated dismissed by the user in its UI.
+ */
+ public static final int SHOW_FORCED = 0x00002;
+
+ /**
* Request that any soft input part of the input method be shown to the user.
*
- * @param flags Provide additional information about the show request.
+ * @param flags Provides additional information about the show request.
* Currently may be 0 or have the bit {@link #SHOW_EXPLICIT} set.
+ * @param resultReceiver The client requesting the show may wish to
+ * be told the impact of their request, which should be supplied here.
+ * The result code should be
+ * {@link InputMethodManager#RESULT_UNCHANGED_SHOWN InputMethodManager.RESULT_UNCHANGED_SHOWN},
+ * {@link InputMethodManager#RESULT_UNCHANGED_HIDDEN InputMethodManager.RESULT_UNCHANGED_HIDDEN},
+ * {@link InputMethodManager#RESULT_SHOWN InputMethodManager.RESULT_SHOWN}, or
+ * {@link InputMethodManager#RESULT_HIDDEN InputMethodManager.RESULT_HIDDEN}.
*/
- public void showSoftInput(int flags);
+ public void showSoftInput(int flags, ResultReceiver resultReceiver);
/**
* Request that any soft input part of the input method be hidden from the user.
+ * @param flags Provides additional information about the show request.
+ * Currently always 0.
+ * @param resultReceiver The client requesting the show may wish to
+ * be told the impact of their request, which should be supplied here.
+ * The result code should be
+ * {@link InputMethodManager#RESULT_UNCHANGED_SHOWN InputMethodManager.RESULT_UNCHANGED_SHOWN},
+ * {@link InputMethodManager#RESULT_UNCHANGED_HIDDEN InputMethodManager.RESULT_UNCHANGED_HIDDEN},
+ * {@link InputMethodManager#RESULT_SHOWN InputMethodManager.RESULT_SHOWN}, or
+ * {@link InputMethodManager#RESULT_HIDDEN InputMethodManager.RESULT_HIDDEN}.
*/
- public void hideSoftInput();
+ public void hideSoftInput(int flags, ResultReceiver resultReceiver);
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index e8f4b54..b4c5b72 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -174,6 +174,14 @@ public final class InputMethodInfo implements Parcelable {
}
/**
+ * Return the raw information about the Service implementing this
+ * input method. Do not modify the returned object.
+ */
+ public ServiceInfo getServiceInfo() {
+ return mService.serviceInfo;
+ }
+
+ /**
* Return the component of the service that implements this input
* method.
*/
@@ -225,15 +233,6 @@ public final class InputMethodInfo implements Parcelable {
return mIsDefaultResId;
}
- /**
- * Returns true if this input method is one of the components that is
- * built in to the system.
- */
- public boolean isBuiltin() {
- return mService.serviceInfo.packageName.equals(
- InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE);
- }
-
public void dump(Printer pw, String prefix) {
pw.println(prefix + "mId=" + mId
+ " mSettingsActivityName=" + mSettingsActivityName);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index a9a9594..4de9eef 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -24,13 +24,17 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.util.Log;
+import android.util.PrintWriterPrinter;
+import android.util.Printer;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewRoot;
+import com.android.internal.os.HandlerCaller;
import com.android.internal.view.IInputConnectionWrapper;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodCallback;
@@ -39,7 +43,11 @@ import com.android.internal.view.IInputMethodManager;
import com.android.internal.view.IInputMethodSession;
import com.android.internal.view.InputBindResult;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Central system API to the overall input method framework (IMF) architecture,
@@ -183,12 +191,6 @@ public final class InputMethodManager {
static final boolean DEBUG = false;
static final String TAG = "InputMethodManager";
- /**
- * The package name of the build-in input method.
- * {@hide}
- */
- public static final String BUILDIN_INPUTMETHOD_PACKAGE = "android.text.inputmethod";
-
static final Object mInstanceSync = new Object();
static InputMethodManager mInstance;
@@ -199,8 +201,7 @@ public final class InputMethodManager {
// global lock.
final H mH;
- // The currently active input connection.
- final MutableInputConnectionWrapper mInputConnectionWrapper;
+ // Our generic input connection if the current target does not have its own.
final IInputContext mIInputContext;
/**
@@ -209,22 +210,38 @@ public final class InputMethodManager {
boolean mActive = false;
/**
- * The current base input connection, used when mActive is true.
+ * Set whenever this client becomes inactive, to know we need to reset
+ * state with the IME then next time we receive focus.
*/
- InputConnection mCurrentInputConnection;
-
+ boolean mHasBeenInactive = true;
+
+ /**
+ * As reported by IME through InputConnection.
+ */
+ boolean mFullscreenMode;
+
// -----------------------------------------------------------
/**
+ * This is the root view of the overall window that currently has input
+ * method focus.
+ */
+ View mCurRootView;
+ /**
* This is the view that should currently be served by an input method,
* regardless of the state of setting that up.
*/
View mServedView;
/**
- * For evaluating the state after a focus change, this is the view that
- * had focus.
+ * This is then next view that will be served by the input method, when
+ * we get around to updating things.
*/
- View mLastServedView;
+ View mNextServedView;
+ /**
+ * True if we should restart input in the next served view, even if the
+ * view hasn't actually changed from the current serve view.
+ */
+ boolean mNextServedNeedsStart;
/**
* This is set when we are in the process of connecting, to determine
* when we have actually finished.
@@ -270,7 +287,10 @@ public final class InputMethodManager {
// -----------------------------------------------------------
- static final int MSG_CHECK_FOCUS = 1;
+ static final int MSG_DUMP = 1;
+ static final int MSG_BIND = 2;
+ static final int MSG_UNBIND = 3;
+ static final int MSG_SET_ACTIVE = 4;
class H extends Handler {
H(Looper looper) {
@@ -280,185 +300,140 @@ public final class InputMethodManager {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_CHECK_FOCUS:
- checkFocus();
+ case MSG_DUMP: {
+ HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
+ try {
+ doDump((FileDescriptor)args.arg1,
+ (PrintWriter)args.arg2, (String[])args.arg3);
+ } catch (RuntimeException e) {
+ ((PrintWriter)args.arg2).println("Exception: " + e);
+ }
+ synchronized (args.arg4) {
+ ((CountDownLatch)args.arg4).countDown();
+ }
return;
+ }
+ case MSG_BIND: {
+ final InputBindResult res = (InputBindResult)msg.obj;
+ synchronized (mH) {
+ if (mBindSequence < 0 || mBindSequence != res.sequence) {
+ Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
+ + ", given seq=" + res.sequence);
+ return;
+ }
+
+ mCurMethod = res.method;
+ mCurId = res.id;
+ mBindSequence = res.sequence;
+ }
+ startInputInner();
+ return;
+ }
+ case MSG_UNBIND: {
+ final int sequence = msg.arg1;
+ synchronized (mH) {
+ if (mBindSequence == sequence) {
+ if (false) {
+ // XXX the server has already unbound!
+ if (mCurMethod != null && mCurrentTextBoxAttribute != null) {
+ try {
+ mCurMethod.finishInput();
+ } catch (RemoteException e) {
+ Log.w(TAG, "IME died: " + mCurId, e);
+ }
+ }
+ }
+ clearBindingLocked();
+
+ // If we were actively using the last input method, then
+ // we would like to re-connect to the next input method.
+ if (mServedView != null && mServedView.isFocused()) {
+ mServedConnecting = true;
+ }
+ }
+ startInputInner();
+ }
+ return;
+ }
+ case MSG_SET_ACTIVE: {
+ final boolean active = msg.arg1 != 0;
+ synchronized (mH) {
+ mActive = active;
+ mFullscreenMode = false;
+ if (!active) {
+ // Some other client has starting using the IME, so note
+ // that this happened and make sure our own editor's
+ // state is reset.
+ mHasBeenInactive = true;
+ try {
+ // Note that finishComposingText() is allowed to run
+ // even when we are not active.
+ mIInputContext.finishComposingText();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ return;
+ }
}
}
}
- static class NoOpInputConnection implements InputConnection {
-
- public boolean clearMetaKeyStates(int states) {
- return false;
- }
-
- public boolean beginBatchEdit() {
- return false;
- }
-
- public boolean endBatchEdit() {
- return false;
- }
-
- public boolean commitCompletion(CompletionInfo text) {
- return false;
+ class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
+ public ControlledInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
+ super(mainLooper, conn);
}
- public boolean commitText(CharSequence text, int newCursorPosition) {
- return false;
- }
-
- public boolean deleteSurroundingText(int leftLength, int rightLength) {
- return false;
- }
-
- public int getCursorCapsMode(int reqModes) {
- return 0;
- }
-
- public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
- return null;
- }
-
- public CharSequence getTextAfterCursor(int n) {
- return null;
- }
-
- public CharSequence getTextBeforeCursor(int n) {
- return null;
- }
-
- public boolean hideStatusIcon() {
- return false;
- }
-
- public boolean performPrivateCommand(String action, Bundle data) {
- return false;
- }
-
- public boolean sendKeyEvent(KeyEvent event) {
- return false;
- }
-
- public boolean setComposingText(CharSequence text, int newCursorPosition) {
- return false;
- }
-
- public boolean finishComposingText() {
- return false;
- }
-
- public boolean showStatusIcon(String packageName, int resId) {
- return false;
+ public boolean isActive() {
+ return mActive;
}
}
- final NoOpInputConnection mNoOpInputConnection = new NoOpInputConnection();
-
final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() {
- public void setUsingInputMethod(boolean state) {
+ @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ // No need to check for dump permission, since we only give this
+ // interface to the system.
+ CountDownLatch latch = new CountDownLatch(1);
+ HandlerCaller.SomeArgs sargs = new HandlerCaller.SomeArgs();
+ sargs.arg1 = fd;
+ sargs.arg2 = fout;
+ sargs.arg3 = args;
+ sargs.arg4 = latch;
+ mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs));
+ try {
+ if (!latch.await(5, TimeUnit.SECONDS)) {
+ fout.println("Timeout waiting for dump");
+ }
+ } catch (InterruptedException e) {
+ fout.println("Interrupted waiting for dump");
+ }
+ }
+
+ public void setUsingInputMethod(boolean state) {
}
public void onBindMethod(InputBindResult res) {
- synchronized (mH) {
- if (mBindSequence < 0 || mBindSequence != res.sequence) {
- Log.w(TAG, "Ignoring onBind: cur seq=" + mBindSequence
- + ", given seq=" + res.sequence);
- return;
- }
-
- mCurMethod = res.method;
- mCurId = res.id;
- mBindSequence = res.sequence;
- }
- startInputInner();
+ mH.sendMessage(mH.obtainMessage(MSG_BIND, res));
}
public void onUnbindMethod(int sequence) {
- synchronized (mH) {
- if (mBindSequence == sequence) {
- if (false) {
- // XXX the server has already unbound!
- if (mCurMethod != null && mCurrentTextBoxAttribute != null) {
- try {
- mCurMethod.finishInput();
- } catch (RemoteException e) {
- Log.w(TAG, "IME died: " + mCurId, e);
- }
- }
- }
- clearBindingLocked();
-
- // If we were actively using the last input method, then
- // we would like to re-connect to the next input method.
- if (mServedView != null && mServedView.isFocused()) {
- mServedConnecting = true;
- }
- }
- startInputInner();
- }
+ mH.sendMessage(mH.obtainMessage(MSG_UNBIND, sequence, 0));
}
public void setActive(boolean active) {
- mActive = active;
- mInputConnectionWrapper.setBaseInputConnection(active
- ? mCurrentInputConnection : mNoOpInputConnection);
+ mH.sendMessage(mH.obtainMessage(MSG_SET_ACTIVE, active ? 1 : 0, 0));
}
};
- final InputConnection mDummyInputConnection = new BaseInputConnection(this) {
- public boolean beginBatchEdit() {
- return false;
- }
- public boolean endBatchEdit() {
- return false;
- }
- public boolean commitText(CharSequence text, int newCursorPosition) {
- return false;
- }
- public boolean commitCompletion(CompletionInfo text) {
- return false;
- }
- public boolean deleteSurroundingText(int leftLength, int rightLength) {
- return false;
- }
- public ExtractedText getExtractedText(ExtractedTextRequest request,
- int flags) {
- return null;
- }
- public CharSequence getTextAfterCursor(int n) {
- return null;
- }
- public CharSequence getTextBeforeCursor(int n) {
- return null;
- }
- public int getCursorCapsMode(int reqModes) {
- return 0;
- }
- public boolean clearMetaKeyStates(int states) {
- return false;
- }
- public boolean performPrivateCommand(String action, Bundle data) {
- return false;
- }
- public boolean setComposingText(CharSequence text, int newCursorPosition) {
- return false;
- }
- public boolean finishComposingText() {
- return false;
- }
- };
+ final InputConnection mDummyInputConnection = new BaseInputConnection(this, true);
InputMethodManager(IInputMethodManager service, Looper looper) {
mService = service;
mMainLooper = looper;
mH = new H(looper);
- mInputConnectionWrapper = new MutableInputConnectionWrapper(mNoOpInputConnection);
- mIInputContext = new IInputConnectionWrapper(looper,
- mInputConnectionWrapper);
- setCurrentInputConnection(mDummyInputConnection);
+ mIInputContext = new ControlledInputConnectionWrapper(looper,
+ mDummyInputConnection);
if (mInstance == null) {
mInstance = this;
@@ -517,21 +492,47 @@ public final class InputMethodManager {
}
}
- public void updateStatusIcon(int iconId, String iconPackage) {
+ public void showStatusIcon(IBinder imeToken, String packageName, int iconId) {
+ try {
+ mService.updateStatusIcon(imeToken, packageName, iconId);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void hideStatusIcon(IBinder imeToken) {
try {
- mService.updateStatusIcon(iconId, iconPackage);
+ mService.updateStatusIcon(imeToken, null, 0);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
+ /** @hide */
+ public void setFullscreenMode(boolean fullScreen) {
+ mFullscreenMode = fullScreen;
+ }
+
+ /**
+ * Allows you to discover whether the attached input method is running
+ * in fullscreen mode. Return true if it is fullscreen, entirely covering
+ * your UI, else returns false.
+ */
+ public boolean isFullscreenMode() {
+ return mFullscreenMode;
+ }
+
/**
* Return true if the given view is the currently active view for the
* input method.
*/
public boolean isActive(View view) {
+ checkFocus();
synchronized (mH) {
- return mServedView == view && mCurrentTextBoxAttribute != null;
+ return (mServedView == view
+ || (mServedView != null
+ && mServedView.checkInputConnectionProxy(view)))
+ && mCurrentTextBoxAttribute != null;
}
}
@@ -539,6 +540,7 @@ public final class InputMethodManager {
* Return true if any view is currently active in the input method.
*/
public boolean isActive() {
+ checkFocus();
synchronized (mH) {
return mServedView != null && mCurrentTextBoxAttribute != null;
}
@@ -549,6 +551,7 @@ public final class InputMethodManager {
* If false, it has no input connection, so can only handle raw key events.
*/
public boolean isAcceptingText() {
+ checkFocus();
return mServedInputConnection != null;
}
@@ -563,31 +566,21 @@ public final class InputMethodManager {
}
/**
- * Record the desired input connection, but only set it if mActive is true.
- */
- void setCurrentInputConnection(InputConnection connection) {
- mCurrentInputConnection = connection;
- mInputConnectionWrapper.setBaseInputConnection(mActive
- ? connection : mNoOpInputConnection);
- }
-
- /**
* Reset all of the state associated with a served view being connected
* to an input method
*/
void clearConnectionLocked() {
mCurrentTextBoxAttribute = null;
mServedInputConnection = null;
- setCurrentInputConnection(mDummyInputConnection);
}
/**
* Disconnect any existing input connection, clearing the served view.
*/
void finishInputLocked() {
+ mNextServedView = null;
if (mServedView != null) {
if (DEBUG) Log.v(TAG, "FINISH INPUT: " + mServedView);
- updateStatusIcon(0, null);
if (mCurrentTextBoxAttribute != null) {
try {
@@ -628,8 +621,10 @@ public final class InputMethodManager {
}
public void displayCompletions(View view, CompletionInfo[] completions) {
+ checkFocus();
synchronized (mH) {
- if (mServedView != view) {
+ if (mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view))) {
return;
}
@@ -644,8 +639,10 @@ public final class InputMethodManager {
}
public void updateExtractedText(View view, int token, ExtractedText text) {
+ checkFocus();
synchronized (mH) {
- if (mServedView != view) {
+ if (mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view))) {
return;
}
@@ -659,13 +656,66 @@ public final class InputMethodManager {
}
/**
- * Flag for {@link #showSoftInput} to indicate that the this is an implicit
+ * Flag for {@link #showSoftInput} to indicate that this is an implicit
* request to show the input window, not as the result of a direct request
* by the user. The window may not be shown in this case.
*/
public static final int SHOW_IMPLICIT = 0x0001;
/**
+ * Flag for {@link #showSoftInput} to indicate that the user has forced
+ * the input method open (such as by long-pressing menu) so it should
+ * not be closed until they explicitly do so.
+ */
+ public static final int SHOW_FORCED = 0x0002;
+
+ /**
+ * Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without
+ * a result receiver: explicitly request that the current input method's
+ * soft input area be shown to the user, if needed.
+ *
+ * @param view The currently focused view, which would like to receive
+ * soft keyboard input.
+ * @param flags Provides additional operating flags. Currently may be
+ * 0 or have the {@link #SHOW_IMPLICIT} bit set.
+ */
+ public boolean showSoftInput(View view, int flags) {
+ return showSoftInput(view, flags, null);
+ }
+
+ /**
+ * Flag for the {@link ResultReceiver} result code from
+ * {@link #showSoftInput(View, int, ResultReceiver)} and
+ * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
+ * state of the soft input window was unchanged and remains shown.
+ */
+ public static final int RESULT_UNCHANGED_SHOWN = 0;
+
+ /**
+ * Flag for the {@link ResultReceiver} result code from
+ * {@link #showSoftInput(View, int, ResultReceiver)} and
+ * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
+ * state of the soft input window was unchanged and remains hidden.
+ */
+ public static final int RESULT_UNCHANGED_HIDDEN = 1;
+
+ /**
+ * Flag for the {@link ResultReceiver} result code from
+ * {@link #showSoftInput(View, int, ResultReceiver)} and
+ * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
+ * state of the soft input window changed from hidden to shown.
+ */
+ public static final int RESULT_SHOWN = 2;
+
+ /**
+ * Flag for the {@link ResultReceiver} result code from
+ * {@link #showSoftInput(View, int, ResultReceiver)} and
+ * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}: the
+ * state of the soft input window changed from shown to hidden.
+ */
+ public static final int RESULT_HIDDEN = 3;
+
+ /**
* Explicitly request that the current input method's soft input area be
* shown to the user, if needed. Call this if the user interacts with
* your view in such a way that they have expressed they would like to
@@ -675,17 +725,35 @@ public final class InputMethodManager {
* soft keyboard input.
* @param flags Provides additional operating flags. Currently may be
* 0 or have the {@link #SHOW_IMPLICIT} bit set.
+ * @param resultReceiver If non-null, this will be called by the IME when
+ * it has processed your request to tell you what it has done. The result
+ * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
+ * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
+ * {@link #RESULT_HIDDEN}.
*/
- public void showSoftInput(View view, int flags) {
+ public boolean showSoftInput(View view, int flags,
+ ResultReceiver resultReceiver) {
+ checkFocus();
synchronized (mH) {
- if (mServedView != view) {
- return;
+ if (mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view))) {
+ return false;
}
try {
- mService.showSoftInput(mClient, flags);
+ return mService.showSoftInput(mClient, flags, resultReceiver);
} catch (RemoteException e) {
}
+
+ return false;
+ }
+ }
+
+ /** @hide */
+ public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
+ try {
+ mService.showSoftInput(mClient, flags, resultReceiver);
+ } catch (RemoteException e) {
}
}
@@ -697,6 +765,27 @@ public final class InputMethodManager {
public static final int HIDE_IMPLICIT_ONLY = 0x0001;
/**
+ * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
+ * input window should normally be hidden, unless it was originally
+ * shown with {@link #SHOW_FORCED}.
+ */
+ public static final int HIDE_NOT_ALWAYS = 0x0002;
+
+ /**
+ * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)
+ * without a result: request to hide the soft input window from the
+ * context of the window that is currently accepting input.
+ *
+ * @param windowToken The token of the window that is making the request,
+ * as returned by {@link View#getWindowToken() View.getWindowToken()}.
+ * @param flags Provides additional operating flags. Currently may be
+ * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
+ */
+ public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) {
+ return hideSoftInputFromWindow(windowToken, flags, null);
+ }
+
+ /**
* Request to hide the soft input window from the context of the window
* that is currently accepting input. This should be called as a result
* of the user doing some actually than fairly explicitly requests to
@@ -706,20 +795,77 @@ public final class InputMethodManager {
* as returned by {@link View#getWindowToken() View.getWindowToken()}.
* @param flags Provides additional operating flags. Currently may be
* 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
+ * @param resultReceiver If non-null, this will be called by the IME when
+ * it has processed your request to tell you what it has done. The result
+ * code you receive may be either {@link #RESULT_UNCHANGED_SHOWN},
+ * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or
+ * {@link #RESULT_HIDDEN}.
*/
- public void hideSoftInputFromWindow(IBinder windowToken, int flags) {
+ public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
+ ResultReceiver resultReceiver) {
+ checkFocus();
synchronized (mH) {
if (mServedView == null || mServedView.getWindowToken() != windowToken) {
- return;
+ return false;
}
try {
- mService.hideSoftInput(mClient, flags);
+ return mService.hideSoftInput(mClient, flags, resultReceiver);
} catch (RemoteException e) {
}
+ return false;
}
}
+
+ /**
+ * This method toggles the input method window display.
+ * If the input window is already displayed, it gets hidden.
+ * If not the input window will be displayed.
+ * @param windowToken The token of the window that is making the request,
+ * as returned by {@link View#getWindowToken() View.getWindowToken()}.
+ * @param showFlags Provides additional operating flags. May be
+ * 0 or have the {@link #SHOW_IMPLICIT},
+ * {@link #SHOW_FORCED} bit set.
+ * @param hideFlags Provides additional operating flags. May be
+ * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
+ * {@link #HIDE_NOT_ALWAYS} bit set.
+ **/
+ public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) {
+ synchronized (mH) {
+ if (mServedView == null || mServedView.getWindowToken() != windowToken) {
+ return;
+ }
+ if (mCurMethod != null) {
+ try {
+ mCurMethod.toggleSoftInput(showFlags, hideFlags);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
+ /*
+ * This method toggles the input method window display.
+ * If the input window is already displayed, it gets hidden.
+ * If not the input window will be displayed.
+ * @param showFlags Provides additional operating flags. May be
+ * 0 or have the {@link #SHOW_IMPLICIT},
+ * {@link #SHOW_FORCED} bit set.
+ * @param hideFlags Provides additional operating flags. May be
+ * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
+ * {@link #HIDE_NOT_ALWAYS} bit set.
+ * @hide
+ */
+ public void toggleSoftInput(int showFlags, int hideFlags) {
+ if (mCurMethod != null) {
+ try {
+ mCurMethod.toggleSoftInput(showFlags, hideFlags);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
/**
* If the input method is currently connected to the given view,
* restart it with its new contents. You should call this when the text
@@ -729,8 +875,10 @@ public final class InputMethodManager {
* @param view The view whose text has changed.
*/
public void restartInput(View view) {
+ checkFocus();
synchronized (mH) {
- if (mServedView != view) {
+ if (mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view))) {
return;
}
@@ -773,12 +921,15 @@ public final class InputMethodManager {
startInputInner();
}
});
+ return;
}
// Okay we are now ready to call into the served view and have it
// do its stuff.
// Life is good: let's hook everything up!
EditorInfo tba = new EditorInfo();
+ tba.packageName = view.getContext().getPackageName();
+ tba.fieldId = view.getId();
InputConnection ic = view.onCreateInputConnection(tba);
if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
@@ -801,22 +952,23 @@ public final class InputMethodManager {
mCurrentTextBoxAttribute = tba;
mServedConnecting = false;
mServedInputConnection = ic;
+ IInputContext servedContext;
if (ic != null) {
mCursorSelStart = tba.initialSelStart;
mCursorSelEnd = tba.initialSelEnd;
mCursorCandStart = -1;
mCursorCandEnd = -1;
mCursorRect.setEmpty();
- setCurrentInputConnection(ic);
+ servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic);
} else {
- setCurrentInputConnection(mDummyInputConnection);
+ servedContext = null;
}
try {
if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
+ ic + " tba=" + tba + " initial=" + initial);
- InputBindResult res = mService.startInput(mClient, tba, initial,
- mCurMethod == null);
+ InputBindResult res = mService.startInput(mClient,
+ servedContext, tba, initial, mCurMethod == null);
if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
if (res != null) {
if (res.id != null) {
@@ -846,6 +998,7 @@ public final class InputMethodManager {
* @hide
*/
public void windowDismissed(IBinder appWindowToken) {
+ checkFocus();
synchronized (mH) {
if (mServedView != null &&
mServedView.getWindowToken() == appWindowToken) {
@@ -860,17 +1013,22 @@ public final class InputMethodManager {
*/
public void focusIn(View view) {
synchronized (mH) {
- if (DEBUG) Log.v(TAG, "focusIn: " + view);
- // Okay we have a new view that is being served.
- if (mServedView != view) {
- mCurrentTextBoxAttribute = null;
- }
- mServedView = view;
- mCompletions = null;
- mServedConnecting = true;
+ focusInLocked(view);
}
+ }
+
+ void focusInLocked(View view) {
+ if (DEBUG) Log.v(TAG, "focusIn: " + view);
- startInputInner();
+ if (mCurRootView != view.getRootView()) {
+ // This is a request from a window that isn't in the window with
+ // IME focus, so ignore it.
+ if (DEBUG) Log.v(TAG, "Not IME target window, ignoring");
+ return;
+ }
+
+ mNextServedView = view;
+ scheduleCheckFocusLocked(view);
}
/**
@@ -878,77 +1036,132 @@ public final class InputMethodManager {
* @hide
*/
public void focusOut(View view) {
- InputConnection ic = null;
synchronized (mH) {
if (DEBUG) Log.v(TAG, "focusOut: " + view
+ " mServedView=" + mServedView
+ " winFocus=" + view.hasWindowFocus());
- if (mServedView == view) {
- ic = mServedInputConnection;
- if (view.hasWindowFocus()) {
- mLastServedView = view;
- mH.removeMessages(MSG_CHECK_FOCUS);
- mH.sendEmptyMessage(MSG_CHECK_FOCUS);
+ if (mServedView != view) {
+ // The following code would auto-hide the IME if we end up
+ // with no more views with focus. This can happen, however,
+ // whenever we go into touch mode, so it ends up hiding
+ // at times when we don't really want it to. For now it
+ // seems better to just turn it all off.
+ if (false && view.hasWindowFocus()) {
+ mNextServedView = null;
+ scheduleCheckFocusLocked(view);
}
}
}
-
- if (ic != null) {
- ic.finishComposingText();
- }
}
- void checkFocus() {
+ void scheduleCheckFocusLocked(View view) {
+ Handler vh = view.getHandler();
+ if (vh != null && !vh.hasMessages(ViewRoot.CHECK_FOCUS)) {
+ // This will result in a call to checkFocus() below.
+ vh.sendMessage(vh.obtainMessage(ViewRoot.CHECK_FOCUS));
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void checkFocus() {
+ // This is called a lot, so short-circuit before locking.
+ if (mServedView == mNextServedView && !mNextServedNeedsStart) {
+ return;
+ }
+
+ InputConnection ic = null;
synchronized (mH) {
+ if (mServedView == mNextServedView && !mNextServedNeedsStart) {
+ return;
+ }
if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
- + " last=" + mLastServedView);
- if (mServedView == mLastServedView) {
+ + " next=" + mNextServedView
+ + " restart=" + mNextServedNeedsStart);
+
+ mNextServedNeedsStart = false;
+ if (mNextServedView == null) {
finishInputLocked();
// In this case, we used to have a focused view on the window,
// but no longer do. We should make sure the input method is
// no longer shown, since it serves no purpose.
closeCurrentInput();
+ return;
}
- mLastServedView = null;
+
+ ic = mServedInputConnection;
+
+ mServedView = mNextServedView;
+ mCurrentTextBoxAttribute = null;
+ mCompletions = null;
+ mServedConnecting = true;
+ }
+
+ if (ic != null) {
+ ic.finishComposingText();
}
+
+ startInputInner();
}
void closeCurrentInput() {
try {
- mService.hideSoftInput(mClient, 0);
+ mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null);
} catch (RemoteException e) {
}
}
/**
- * Called by ViewRoot the first time it gets window focus.
+ * Called by ViewRoot when its window gets input focus.
* @hide
*/
- public void onWindowFocus(View focusedView, int softInputMode,
+ public void onWindowFocus(View rootView, View focusedView, int softInputMode,
boolean first, int windowFlags) {
synchronized (mH) {
if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
+ " softInputMode=" + softInputMode
+ " first=" + first + " flags=#"
+ Integer.toHexString(windowFlags));
+ if (mHasBeenInactive) {
+ if (DEBUG) Log.v(TAG, "Has been inactive! Starting fresh");
+ mHasBeenInactive = false;
+ mNextServedNeedsStart = true;
+ }
+ focusInLocked(focusedView != null ? focusedView : rootView);
+ }
+
+ checkFocus();
+
+ synchronized (mH) {
try {
final boolean isTextEditor = focusedView != null &&
- focusedView.onCheckIsTextEditor();
- mService.windowGainedFocus(mClient, focusedView != null,
- isTextEditor, softInputMode, first, windowFlags);
+ focusedView.onCheckIsTextEditor();
+ mService.windowGainedFocus(mClient, rootView.getWindowToken(),
+ focusedView != null, isTextEditor, softInputMode, first,
+ windowFlags);
} catch (RemoteException e) {
}
}
}
+ /** @hide */
+ public void startGettingWindowFocus(View rootView) {
+ synchronized (mH) {
+ mCurRootView = rootView;
+ }
+ }
+
/**
* Report the current selection range.
*/
public void updateSelection(View view, int selStart, int selEnd,
int candidatesStart, int candidatesEnd) {
+ checkFocus();
synchronized (mH) {
- if (mServedView != view || mCurrentTextBoxAttribute == null
- || mCurMethod == null) {
+ if ((mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view)))
+ || mCurrentTextBoxAttribute == null || mCurMethod == null) {
return;
}
@@ -984,9 +1197,11 @@ public final class InputMethodManager {
* Report the current cursor location in its window.
*/
public void updateCursor(View view, int left, int top, int right, int bottom) {
+ checkFocus();
synchronized (mH) {
- if (mServedView != view || mCurrentTextBoxAttribute == null
- || mCurMethod == null) {
+ if ((mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view)))
+ || mCurrentTextBoxAttribute == null || mCurMethod == null) {
return;
}
@@ -1006,6 +1221,34 @@ public final class InputMethodManager {
}
/**
+ * Call {@link InputMethodSession#appPrivateCommand(String, Bundle)
+ * InputMethodSession.appPrivateCommand()} on the current Input Method.
+ * @param view Optional View that is sending the command, or null if
+ * you want to send the command regardless of the view that is attached
+ * to the input method.
+ * @param action Name of the command to be performed. This <em>must</em>
+ * be a scoped name, i.e. prefixed with a package name you own, so that
+ * different developers will not create conflicting commands.
+ * @param data Any data to include with the command.
+ */
+ public void sendAppPrivateCommand(View view, String action, Bundle data) {
+ checkFocus();
+ synchronized (mH) {
+ if ((mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view)))
+ || mCurrentTextBoxAttribute == null || mCurMethod == null) {
+ return;
+ }
+ try {
+ if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data);
+ mCurMethod.appPrivateCommand(action, data);
+ } catch (RemoteException e) {
+ Log.w(TAG, "IME died: " + mCurId, e);
+ }
+ }
+ }
+
+ /**
* Force switch to a new input method component. This can only be called
* from the currently active input method, as validated by the given token.
* @param token Supplies the identifying token given to an input method
@@ -1030,7 +1273,8 @@ public final class InputMethodManager {
* when it was started, which allows it to perform this operation on
* itself.
* @param flags Provides additional operating flags. Currently may be
- * 0 or have the {@link #HIDE_IMPLICIT_ONLY} bit set.
+ * 0 or have the {@link #HIDE_IMPLICIT_ONLY},
+ * {@link #HIDE_NOT_ALWAYS} bit set.
*/
public void hideSoftInputFromInputMethod(IBinder token, int flags) {
try {
@@ -1041,6 +1285,27 @@ public final class InputMethodManager {
}
/**
+ * Show the input method's soft input area, so the user
+ * sees the input method window and can interact with it.
+ * This can only be called from the currently active input method,
+ * as validated by the given token.
+ *
+ * @param token Supplies the identifying token given to an input method
+ * when it was started, which allows it to perform this operation on
+ * itself.
+ * @param flags Provides additional operating flags. Currently may be
+ * 0 or have the {@link #SHOW_IMPLICIT} or
+ * {@link #SHOW_FORCED} bit set.
+ */
+ public void showSoftInputFromInputMethod(IBinder token, int flags) {
+ try {
+ mService.showMySoftInput(token, flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
* @hide
*/
public void dispatchKeyEvent(Context context, int seq, KeyEvent key,
@@ -1048,7 +1313,7 @@ public final class InputMethodManager {
synchronized (mH) {
if (DEBUG) Log.d(TAG, "dispatchKeyEvent");
- if (mCurMethod == null || mCurrentTextBoxAttribute == null) {
+ if (mCurMethod == null) {
try {
callback.finishedEvent(seq, false);
} catch (RemoteException e) {
@@ -1116,4 +1381,36 @@ public final class InputMethodManager {
}
}
}
+
+ void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ final Printer p = new PrintWriterPrinter(fout);
+ p.println("Input method client state for " + this + ":");
+
+ p.println(" mService=" + mService);
+ p.println(" mMainLooper=" + mMainLooper);
+ p.println(" mIInputContext=" + mIInputContext);
+ p.println(" mActive=" + mActive
+ + " mHasBeenInactive=" + mHasBeenInactive
+ + " mBindSequence=" + mBindSequence
+ + " mCurId=" + mCurId);
+ p.println(" mCurMethod=" + mCurMethod);
+ p.println(" mCurRootView=" + mCurRootView);
+ p.println(" mServedView=" + mServedView);
+ p.println(" mNextServedNeedsStart=" + mNextServedNeedsStart
+ + " mNextServedView=" + mNextServedView);
+ p.println(" mServedConnecting=" + mServedConnecting);
+ if (mCurrentTextBoxAttribute != null) {
+ p.println(" mCurrentTextBoxAttribute:");
+ mCurrentTextBoxAttribute.dump(p, " ");
+ } else {
+ p.println(" mCurrentTextBoxAttribute: null");
+ }
+ p.println(" mServedInputConnection=" + mServedInputConnection);
+ p.println(" mCompletions=" + mCompletions);
+ p.println(" mCursorRect=" + mCursorRect);
+ p.println(" mCursorSelStart=" + mCursorSelStart
+ + " mCursorSelEnd=" + mCursorSelEnd
+ + " mCursorCandStart=" + mCursorCandStart
+ + " mCursorCandEnd=" + mCursorCandEnd);
+ }
}
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index b5bbaff..bb03afa 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -139,4 +139,16 @@ public interface InputMethodSession {
* @param data Any data to include with the command.
*/
public void appPrivateCommand(String action, Bundle data);
+
+ /**
+ * Toggle the soft input window.
+ * Applications can toggle the state of the soft input window.
+ * @param showFlags Provides additional operating flags. May be
+ * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT},
+ * {@link InputMethodManager#SHOW_FORCED} bit set.
+ * @param hideFlags Provides additional operating flags. May be
+ * 0 or have the {@link InputMethodManager#HIDE_IMPLICIT_ONLY},
+ * {@link InputMethodManager#HIDE_NOT_ALWAYS} bit set.
+ */
+ public void toggleSoftInput(int showFlags, int hideFlags);
}
diff --git a/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java b/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java
deleted file mode 100644
index 025a059..0000000
--- a/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2007-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 android.view.inputmethod;
-
-
-/**
- * Special version of {@link InputConnectionWrapper} that allows the base
- * input connection to be modified after it is initially set.
- */
-public class MutableInputConnectionWrapper extends InputConnectionWrapper {
- public MutableInputConnectionWrapper(InputConnection base) {
- super(base);
- }
-
- /**
- * Change the base InputConnection for this wrapper. All calls will then be
- * delegated to the base input connection.
- *
- * @param base The new base InputConnection for this wrapper.
- */
- public void setBaseInputConnection(InputConnection base) {
- mBase = base;
- }
-}
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 1dd37be..5401a6e 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -51,7 +51,7 @@ class BrowserFrame extends Handler {
private final Context mContext;
private final WebViewDatabase mDatabase;
private final WebViewCore mWebViewCore;
- private boolean mLoadInitFromJava;
+ /* package */ boolean mLoadInitFromJava;
private int mLoadType;
private boolean mFirstLayoutDone = true;
private boolean mCommitted = true;
@@ -201,10 +201,14 @@ class BrowserFrame extends Handler {
final String failingUrl) {
// As this is called for the main resource and loading will be stopped
// after, reset the state variables.
+ resetLoadingStates();
+ mCallbackProxy.onReceivedError(errorCode, description, failingUrl);
+ }
+
+ private void resetLoadingStates() {
mCommitted = true;
mWebViewCore.mEndScaleZoom = mFirstLayoutDone == false;
mFirstLayoutDone = true;
- mCallbackProxy.onReceivedError(errorCode, description, failingUrl);
}
/* package */boolean committed() {
@@ -290,6 +294,7 @@ class BrowserFrame extends Handler {
if (isMainFrame || loadType == FRAME_LOADTYPE_STANDARD) {
if (isMainFrame) {
+ resetLoadingStates();
mCallbackProxy.switchOutDrawHistory();
mCallbackProxy.onPageFinished(url);
}
@@ -555,8 +560,11 @@ class BrowserFrame extends Handler {
method, isHighPriority);
loader.setHeaders(headers);
loader.setPostData(postData);
- loader.setCacheMode(cacheMode); // Set the load mode to the mode used
- // for the current page.
+ // Set the load mode to the mode used for the current page.
+ // If WebKit wants validation, go to network directly.
+ loader.setCacheMode(headers.containsKey("If-Modified-Since")
+ || headers.containsKey("If-None-Match") ?
+ WebSettings.LOAD_NO_CACHE : cacheMode);
// Set referrer to current URL?
if (!loader.executeLoad()) {
checker.responseAlert("startLoadingResource fail");
@@ -751,7 +759,14 @@ class BrowserFrame extends Handler {
/**
* Stop loading the current page.
*/
- public native void stopLoading();
+ public void stopLoading() {
+ if (mIsMainFrame) {
+ resetLoadingStates();
+ }
+ nativeStopLoading();
+ }
+
+ private native void nativeStopLoading();
/**
* Return true if the document has images.
diff --git a/core/java/android/webkit/ByteArrayBuilder.java b/core/java/android/webkit/ByteArrayBuilder.java
index 16d663c..806b458 100644
--- a/core/java/android/webkit/ByteArrayBuilder.java
+++ b/core/java/android/webkit/ByteArrayBuilder.java
@@ -94,6 +94,14 @@ class ByteArrayBuilder {
return mChunks.isEmpty();
}
+ public synchronized void clear() {
+ Chunk c = getFirstChunk();
+ while (c != null) {
+ releaseChunk(c);
+ c = getFirstChunk();
+ }
+ }
+
private Chunk appendChunk(int length) {
if (length < mMinCapacity) {
length = mMinCapacity;
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index d12940d..dcf68cd 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -52,6 +52,7 @@ public final class CacheManager {
private static final String NO_STORE = "no-store";
private static final String NO_CACHE = "no-cache";
+ private static final String PRIVATE = "private";
private static final String MAX_AGE = "max-age";
private static long CACHE_THRESHOLD = 6 * 1024 * 1024;
@@ -612,7 +613,7 @@ public final class CacheManager {
// must be re-validated on every load. It does not mean that
// the content can not be cached. set to expire 0 means it
// can only be used in CACHE_MODE_CACHE_ONLY case
- if (NO_CACHE.equals(controls[i])) {
+ if (NO_CACHE.equals(controls[i]) || PRIVATE.equals(controls[i])) {
ret.expires = 0;
} else if (controls[i].startsWith(MAX_AGE)) {
int separator = controls[i].indexOf('=');
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 4f8e5e4..0f9f29c 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -29,6 +29,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
+import android.provider.Browser;
import android.util.Config;
import android.util.Log;
import android.view.KeyEvent;
@@ -175,6 +176,11 @@ class CallbackProxy extends Handler {
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse(overrideUrl));
intent.addCategory(Intent.CATEGORY_BROWSABLE);
+ // If another application is running a WebView and launches the
+ // Browser through this Intent, we want to reuse the same window if
+ // possible.
+ intent.putExtra(Browser.EXTRA_APPLICATION_ID,
+ mContext.getPackageName());
try {
mContext.startActivity(intent);
override = true;
@@ -907,10 +913,12 @@ class CallbackProxy extends Handler {
}
public void onReceivedIcon(Bitmap icon) {
- if (Config.DEBUG && mBackForwardList.getCurrentItem() == null) {
- throw new AssertionError();
+ // The current item might be null if the icon was already stored in the
+ // database and this is a new WebView.
+ WebHistoryItem i = mBackForwardList.getCurrentItem();
+ if (i != null) {
+ i.setFavicon(icon);
}
- mBackForwardList.getCurrentItem().setFavicon(icon);
// Do an unsynchronized quick check to avoid posting if no callback has
// been set.
if (mWebChromeClient == null) {
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 5a37f04..d90a2fd 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -171,6 +171,10 @@ public final class CookieManager {
boolean pathMatch(String urlPath) {
if (urlPath.startsWith(path)) {
int len = path.length();
+ if (len == 0) {
+ Log.w(LOGTAG, "Empty cookie path");
+ return false;
+ }
int urlLen = urlPath.length();
if (path.charAt(len-1) != PATH_DELIM && urlLen > len) {
// make sure /wee doesn't match /we
@@ -739,11 +743,16 @@ public final class CookieManager {
* Note: in the case of "foo=bluh, bar=bluh;path=/", we interpret
* it as one cookie instead of two cookies.
*/
+ int semicolonIndex = cookieString.indexOf(SEMICOLON, index);
int equalIndex = cookieString.indexOf(EQUAL, index);
if (equalIndex == -1) {
// bad format, force return
break;
}
+ if (semicolonIndex > -1 && semicolonIndex < equalIndex) {
+ // empty cookie, like "; path=/", return
+ break;
+ }
cookie = new Cookie(host, path);
cookie.name = cookieString.substring(index, equalIndex);
if (cookieString.charAt(equalIndex + 1) == QUOTATION) {
@@ -753,7 +762,7 @@ public final class CookieManager {
break;
}
}
- int semicolonIndex = cookieString.indexOf(SEMICOLON, index);
+ semicolonIndex = cookieString.indexOf(SEMICOLON, index);
if (semicolonIndex == -1) {
semicolonIndex = length;
}
@@ -864,7 +873,10 @@ public final class CookieManager {
"illegal format for max-age: " + value);
}
} else if (name.equals(PATH)) {
- cookie.path = value;
+ // only allow non-empty path value
+ if (value.length() > 0) {
+ cookie.path = value;
+ }
} else if (name.equals(DOMAIN)) {
int lastPeriod = value.lastIndexOf(PERIOD);
if (lastPeriod == 0) {
diff --git a/core/java/android/webkit/FileLoader.java b/core/java/android/webkit/FileLoader.java
index 10343b2..54a4c1d 100644
--- a/core/java/android/webkit/FileLoader.java
+++ b/core/java/android/webkit/FileLoader.java
@@ -76,8 +76,12 @@ class FileLoader extends StreamLoader {
protected boolean setupStreamAndSendStatus() {
try {
if (mIsAsset) {
- mDataStream = mContext.getAssets().open(mPath,
- AssetManager.ACCESS_STREAMING);
+ try {
+ mDataStream = mContext.getAssets().open(mPath);
+ } catch (java.io.FileNotFoundException ex) {
+ // try the rest files included in the package
+ mDataStream = mContext.getAssets().openNonAsset(mPath);
+ }
} else {
if (!mAllowFileAccess) {
mHandler.error(EventHandler.FILE_ERROR,
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index 7a3bbe6..42d03f0 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -21,7 +21,6 @@ import android.net.http.RequestHandle;
import android.util.Config;
import android.util.Log;
import android.webkit.CacheManager.CacheResult;
-import android.webkit.UrlInterceptRegistry;
import java.util.HashMap;
import java.util.Map;
@@ -220,6 +219,7 @@ class FrameLoader {
// Tell the Listener respond with the cache file
CacheLoader cacheLoader =
new CacheLoader(mListener, result);
+ mListener.setCacheLoader(cacheLoader);
cacheLoader.load();
}
@@ -233,12 +233,14 @@ class FrameLoader {
private boolean handleUrlIntercept() {
// Check if the URL can be served from UrlIntercept. If
// successful, return the data just like a cache hit.
- CacheResult result = UrlInterceptRegistry.getSurrogate(
+
+ PluginData data = UrlInterceptRegistry.getPluginData(
mListener.url(), mHeaders);
- if(result != null) {
- // Intercepted. The data is stored in result.stream. Setup
- // a load from the CacheResult.
- startCacheLoad(result);
+
+ if(data != null) {
+ PluginContentLoader loader =
+ new PluginContentLoader(mListener, data);
+ loader.load();
return true;
}
// Not intercepted. Carry on as normal.
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 3f2bbe5..f9fb0b0 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -33,6 +33,8 @@ import android.util.Config;
import android.util.Log;
import android.webkit.CacheManager.CacheResult;
+import com.android.internal.R;
+
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -56,6 +58,9 @@ class LoadListener extends Handler implements EventHandler {
private static final int MSG_CONTENT_ERROR = 130;
private static final int MSG_LOCATION_CHANGED = 140;
private static final int MSG_LOCATION_CHANGED_REQUEST = 150;
+ private static final int MSG_STATUS = 160;
+ private static final int MSG_SSL_CERTIFICATE = 170;
+ private static final int MSG_SSL_ERROR = 180;
// Standard HTTP status codes in a more representative format
private static final int HTTP_OK = 200;
@@ -166,9 +171,7 @@ class LoadListener extends Handler implements EventHandler {
* available. The headers are sent onto WebCore to see what we
* should do with them.
*/
- if (mNativeLoader != 0) {
- commitHeadersCheckRedirect();
- }
+ handleHeaders((Headers) msg.obj);
break;
case MSG_CONTENT_DATA:
@@ -177,7 +180,7 @@ class LoadListener extends Handler implements EventHandler {
* in it's data buffer. This data buffer could be filled from a
* file (this thread) or from http (Network thread).
*/
- if (mNativeLoader != 0) {
+ if (mNativeLoader != 0 && !ignoreCallbacks()) {
commitLoad();
}
break;
@@ -189,7 +192,7 @@ class LoadListener extends Handler implements EventHandler {
* error.
*
*/
- tearDown();
+ handleEndData();
break;
case MSG_CONTENT_ERROR:
@@ -197,8 +200,7 @@ class LoadListener extends Handler implements EventHandler {
* This message is sent when a load error has occured. The
* LoadListener will clean itself up.
*/
- notifyError();
- tearDown();
+ handleError(msg.arg1, (String) msg.obj);
break;
case MSG_LOCATION_CHANGED:
@@ -224,6 +226,33 @@ class LoadListener extends Handler implements EventHandler {
stopMsg, contMsg);
break;
+ case MSG_STATUS:
+ /*
+ * This message is sent from the network thread when the http
+ * stack has received the status response from the server.
+ */
+ HashMap status = (HashMap) msg.obj;
+ handleStatus(((Integer) status.get("major")).intValue(),
+ ((Integer) status.get("minor")).intValue(),
+ ((Integer) status.get("code")).intValue(),
+ (String) status.get("reason"));
+ break;
+
+ case MSG_SSL_CERTIFICATE:
+ /*
+ * This message is sent when the network thread receives a ssl
+ * certificate.
+ */
+ handleCertificate((SslCertificate) msg.obj);
+ break;
+
+ case MSG_SSL_ERROR:
+ /*
+ * This message is sent when the network thread encounters a
+ * ssl error.
+ */
+ handleSslError((SslError) msg.obj);
+ break;
}
}
@@ -257,6 +286,11 @@ class LoadListener extends Handler implements EventHandler {
*/
public void headers(Headers headers) {
if (Config.LOGV) Log.v(LOGTAG, "LoadListener.headers");
+ sendMessageInternal(obtainMessage(MSG_CONTENT_HEADERS, headers));
+ }
+
+ // Does the header parsing work on the WebCore thread.
+ private void handleHeaders(Headers headers) {
if (mCancelled) return;
mHeaders = headers;
mMimeType = "";
@@ -342,6 +376,11 @@ 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;
@@ -375,7 +414,11 @@ class LoadListener extends Handler implements EventHandler {
mCacheResult.encoding = mEncoding;
}
}
- sendMessageInternal(obtainMessage(MSG_CONTENT_HEADERS));
+ commitHeadersCheckRedirect();
+
+ if (needToCommit) {
+ commitLoad();
+ }
}
/**
@@ -404,11 +447,20 @@ class LoadListener extends Handler implements EventHandler {
+ " code: " + code
+ " reason: " + reasonPhrase);
}
+ HashMap status = new HashMap();
+ status.put("major", majorVersion);
+ status.put("minor", minorVersion);
+ status.put("code", code);
+ status.put("reason", reasonPhrase);
+ sendMessageInternal(obtainMessage(MSG_STATUS, status));
+ }
+ // Handle the status callback on the WebCore thread.
+ private void handleStatus(int major, int minor, int code, String reason) {
if (mCancelled) return;
mStatusCode = code;
- mStatusText = reasonPhrase;
+ mStatusText = reason;
mPermanent = false;
}
@@ -418,8 +470,15 @@ class LoadListener extends Handler implements EventHandler {
* connection. In this context, can be called multiple
* times if we have redirects
* @param certificate The SSL certifcate
+ * IMPORTANT: as this is called from network thread, can't call native
+ * directly
*/
public void certificate(SslCertificate certificate) {
+ sendMessageInternal(obtainMessage(MSG_SSL_CERTIFICATE, certificate));
+ }
+
+ // Handle the certificate on the WebCore thread.
+ private void handleCertificate(SslCertificate certificate) {
// if this is the top-most main-frame page loader
if (mIsMainPageLoader) {
// update the browser frame (ie, the main frame)
@@ -436,14 +495,20 @@ class LoadListener extends Handler implements EventHandler {
* directly
*/
public void error(int id, String description) {
- mErrorID = id;
- mErrorDescription = description;
- sendMessageInternal(obtainMessage(MSG_CONTENT_ERROR));
if (Config.LOGV) {
Log.v(LOGTAG, "LoadListener.error url:" +
url() + " id:" + id + " description:" + description);
}
+ sendMessageInternal(obtainMessage(MSG_CONTENT_ERROR, id, 0, description));
+ }
+
+ // Handle the error on the WebCore thread.
+ private void handleError(int id, String description) {
+ mErrorID = id;
+ mErrorDescription = description;
detachRequestHandle();
+ notifyError();
+ tearDown();
}
/**
@@ -453,11 +518,15 @@ class LoadListener extends Handler implements EventHandler {
* @param length The length of data.
* IMPORTANT: as this is called from network thread, can't call native
* directly
+ * XXX: Unlike the other network thread methods, this method can do the
+ * work of decoding the data and appending it to the data builder because
+ * mDataBuilder is a thread-safe structure.
*/
public void data(byte[] data, int length) {
if (Config.LOGV) {
Log.v(LOGTAG, "LoadListener.data(): url: " + url());
}
+
// Decode base64 data
// Note: It's fine that we only decode base64 here and not in the other
// data call because the only caller of the stream version is not
@@ -479,7 +548,7 @@ class LoadListener extends Handler implements EventHandler {
sendMessage = mDataBuilder.isEmpty();
mDataBuilder.append(data, 0, length);
}
- if (sendMessage && !ignoreCallbacks()) {
+ if (sendMessage) {
// Send a message whenever data comes in after a write to WebCore
sendMessageInternal(obtainMessage(MSG_CONTENT_DATA));
}
@@ -495,7 +564,11 @@ class LoadListener extends Handler implements EventHandler {
if (Config.LOGV) {
Log.v(LOGTAG, "LoadListener.endData(): url: " + url());
}
+ sendMessageInternal(obtainMessage(MSG_CONTENT_FINISHED));
+ }
+ // Handle the end of data.
+ private void handleEndData() {
if (mCancelled) return;
switch (mStatusCode) {
@@ -505,17 +578,13 @@ class LoadListener extends Handler implements EventHandler {
case HTTP_FOUND:
case HTTP_SEE_OTHER:
case HTTP_TEMPORARY_REDIRECT:
- if (mMethod == null && mRequestHandle == null) {
- Log.e(LOGTAG, "LoadListener.endData(): method is null!");
- Log.e(LOGTAG, "LoadListener.endData(): url = " + url());
- }
// 301, 302, 303, and 307 - redirect
if (mStatusCode == HTTP_TEMPORARY_REDIRECT) {
if (mRequestHandle != null &&
mRequestHandle.getMethod().equals("POST")) {
sendMessageInternal(obtainMessage(
MSG_LOCATION_CHANGED_REQUEST));
- } else if (mMethod != null && mMethod.equals("POST")) {
+ } else if (mMethod != null && mMethod.equals("POST")) {
sendMessageInternal(obtainMessage(
MSG_LOCATION_CHANGED_REQUEST));
} else {
@@ -558,9 +627,14 @@ class LoadListener extends Handler implements EventHandler {
default:
break;
}
-
- sendMessageInternal(obtainMessage(MSG_CONTENT_FINISHED));
detachRequestHandle();
+ tearDown();
+ }
+
+ /* This method is called from CacheLoader when the initial request is
+ * serviced by the Cache. */
+ /* package */ void setCacheLoader(CacheLoader c) {
+ mCacheLoader = c;
}
/**
@@ -574,9 +648,16 @@ class LoadListener extends Handler implements EventHandler {
CacheResult result = CacheManager.getCacheFile(url(),
headers);
+ // Go ahead and set the cache loader to null in case the result is
+ // null.
+ mCacheLoader = null;
+
if (result != null) {
- CacheLoader cacheLoader =
- new CacheLoader(this, result);
+ // The contents of the cache may need to be revalidated so just
+ // remember the cache loader in the case that the server responds
+ // positively to the cached content. This is also used to detect if
+ // a redirect came from the cache.
+ mCacheLoader = new CacheLoader(this, result);
// If I got a cachedUrl and the revalidation header was not
// added, then the cached content valid, we should use it.
@@ -589,14 +670,8 @@ class LoadListener extends Handler implements EventHandler {
"and usable: " + url());
}
// Load the cached file
- cacheLoader.load();
+ mCacheLoader.load();
return true;
- } else {
- // The contents of the cache need to be revalidated
- // so just provide the listener with the cache loader
- // in the case that the server response positively to
- // the cached content.
- setCacheLoader(cacheLoader);
}
}
return false;
@@ -615,7 +690,11 @@ class LoadListener extends Handler implements EventHandler {
" primary error: " + error.getPrimaryError() +
" certificate: " + error.getCertificate());
}
+ sendMessageInternal(obtainMessage(MSG_SSL_ERROR, error));
+ }
+ // Handle the ssl error on the WebCore thread.
+ private void handleSslError(SslError error) {
if (!mCancelled) {
mSslError = error;
Network.getInstance(mContext).handleSslErrorRequest(this);
@@ -705,14 +784,6 @@ class LoadListener extends Handler implements EventHandler {
}
/**
- * Set the CacheLoader for the case where we might want to load from cache
- * @param result
- */
- void setCacheLoader(CacheLoader result) {
- mCacheLoader = result;
- }
-
- /**
* This is called when a request can be satisfied by the cache, however,
* the cache result could be a redirect. In this case we need to issue
* the network request.
@@ -1002,6 +1073,11 @@ class LoadListener extends Handler implements EventHandler {
clearNativeLoader();
}
+ // This count is transferred from RequestHandle to LoadListener when
+ // loading from the cache so that we can detect redirect loops that switch
+ // between the network and the cache.
+ private int mCacheRedirectCount;
+
/*
* Perform the actual redirection. This involves setting up the new URL,
* informing WebCore and then telling the Network to start loading again.
@@ -1014,6 +1090,14 @@ class LoadListener extends Handler implements EventHandler {
return;
}
+ // Do the same check for a redirect loop that
+ // RequestHandle.setupRedirect does.
+ if (mCacheRedirectCount >= RequestHandle.MAX_REDIRECT_COUNT) {
+ handleError(EventHandler.ERROR_REDIRECT_LOOP, mContext.getString(
+ R.string.httpErrorRedirectLoop));
+ return;
+ }
+
String redirectTo = mHeaders.getLocation();
if (redirectTo != null) {
int nativeResponse = createNativeResponse();
@@ -1031,7 +1115,7 @@ class LoadListener extends Handler implements EventHandler {
return;
} else if (!URLUtil.isNetworkUrl(redirectTo)) {
final String text = mContext
- .getString(com.android.internal.R.string.open_permission_deny)
+ .getString(R.string.open_permission_deny)
+ "\n" + redirectTo;
nativeAddData(text.getBytes(), text.length());
nativeFinished();
@@ -1051,36 +1135,58 @@ class LoadListener extends Handler implements EventHandler {
mCacheResult = null;
}
+ // This will strip the anchor
setUrl(redirectTo);
// Redirect may be in the cache
if (mRequestHeaders == null) {
mRequestHeaders = new HashMap<String, String>();
}
+ boolean fromCache = false;
+ if (mCacheLoader != null) {
+ // This is a redirect from the cache loader. Increment the
+ // redirect count to avoid redirect loops.
+ mCacheRedirectCount++;
+ fromCache = true;
+ }
if (!checkCache(mRequestHeaders)) {
// mRequestHandle can be null when the request was satisfied
// by the cache, and the cache returned a redirect
if (mRequestHandle != null) {
- mRequestHandle.setupRedirect(redirectTo, mStatusCode,
+ mRequestHandle.setupRedirect(mUrl, mStatusCode,
mRequestHeaders);
} else {
- String method = mMethod;
-
- if (method == null) {
+ // If the original request came from the cache, there is no
+ // RequestHandle, we have to create a new one through
+ // Network.requestURL.
+ Network network = Network.getInstance(getContext());
+ if (!network.requestURL(mMethod, mRequestHeaders,
+ mPostData, this, mIsHighPriority)) {
+ // Signal a bad url error if we could not load the
+ // redirection.
+ handleError(EventHandler.ERROR_BAD_URL,
+ mContext.getString(R.string.httpErrorBadUrl));
return;
}
-
- Network network = Network.getInstance(getContext());
- network.requestURL(method, mRequestHeaders,
- mPostData, this, mIsHighPriority);
}
+ if (fromCache) {
+ // If we are coming from a cache load, we need to transfer
+ // the redirect count to the new (or old) RequestHandle to
+ // keep the redirect count in sync.
+ mRequestHandle.setRedirectCount(mCacheRedirectCount);
+ }
+ } else if (!fromCache) {
+ // Switching from network to cache means we need to grab the
+ // redirect count from the RequestHandle to keep the count in
+ // 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 {
- // With a null redirect, commit the original headers, the buffered
- // data, and then finish the load.
commitHeaders();
commitLoad();
- nativeFinished();
+ tearDown();
}
if (Config.LOGV) {
@@ -1167,14 +1273,16 @@ class LoadListener extends Handler implements EventHandler {
quoted = !quoted;
} else {
if (!quoted) {
- if (header.startsWith(
- HttpAuthHeader.BASIC_TOKEN, i)) {
+ if (header.regionMatches(true, i,
+ HttpAuthHeader.BASIC_TOKEN, 0,
+ HttpAuthHeader.BASIC_TOKEN.length())) {
pos[posLen++] = i;
continue;
}
- if (header.startsWith(
- HttpAuthHeader.DIGEST_TOKEN, i)) {
+ if (header.regionMatches(true, i,
+ HttpAuthHeader.DIGEST_TOKEN, 0,
+ HttpAuthHeader.DIGEST_TOKEN.length())) {
pos[posLen++] = i;
continue;
}
@@ -1186,8 +1294,9 @@ class LoadListener extends Handler implements EventHandler {
if (posLen > 0) {
// consider all digest schemes first (if any)
for (int i = 0; i < posLen; i++) {
- if (header.startsWith(HttpAuthHeader.DIGEST_TOKEN,
- pos[i])) {
+ if (header.regionMatches(true, pos[i],
+ HttpAuthHeader.DIGEST_TOKEN, 0,
+ HttpAuthHeader.DIGEST_TOKEN.length())) {
String sub = header.substring(pos[i],
(i + 1 < posLen ? pos[i + 1] : headerLen));
@@ -1201,7 +1310,9 @@ class LoadListener extends Handler implements EventHandler {
// ...then consider all basic schemes (if any)
for (int i = 0; i < posLen; i++) {
- if (header.startsWith(HttpAuthHeader.BASIC_TOKEN, pos[i])) {
+ if (header.regionMatches(true, pos[i],
+ HttpAuthHeader.BASIC_TOKEN, 0,
+ HttpAuthHeader.BASIC_TOKEN.length())) {
String sub = header.substring(pos[i],
(i + 1 < posLen ? pos[i + 1] : headerLen));
@@ -1235,19 +1346,16 @@ class LoadListener extends Handler implements EventHandler {
*/
void setUrl(String url) {
if (url != null) {
- if (URLUtil.isDataUrl(url)) {
- // Don't strip anchor as that is a valid part of the URL
- mUrl = url;
- } else {
- mUrl = URLUtil.stripAnchor(url);
- }
mUri = null;
- if (URLUtil.isNetworkUrl(mUrl)) {
+ if (URLUtil.isNetworkUrl(url)) {
+ mUrl = URLUtil.stripAnchor(url);
try {
mUri = new WebAddress(mUrl);
} catch (ParseException e) {
e.printStackTrace();
}
+ } else {
+ mUrl = url;
}
}
}
@@ -1262,9 +1370,8 @@ class LoadListener extends Handler implements EventHandler {
// type (implying text/plain).
if (URLUtil.isDataUrl(mUrl) && mMimeType.length() != 0) {
cancel();
- final String text = mContext.getString(
- com.android.internal.R.string.httpErrorBadUrl);
- error(EventHandler.ERROR_BAD_URL, text);
+ final String text = mContext.getString(R.string.httpErrorBadUrl);
+ handleError(EventHandler.ERROR_BAD_URL, text);
} else {
// Note: This is ok because this is used only for the main content
// of frames. If no content-type was specified, it is fine to
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index 685e352..c9cc208 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -480,6 +480,7 @@ public /* package */ class MimeTypeMap {
sMimeTypeMap.loadEntry("video/mpeg", "mpg", false);
sMimeTypeMap.loadEntry("video/mpeg", "mpe", false);
sMimeTypeMap.loadEntry("video/mp4", "mp4", false);
+ sMimeTypeMap.loadEntry("video/mpeg", "VOB", false);
sMimeTypeMap.loadEntry("video/quicktime", "qt", false);
sMimeTypeMap.loadEntry("video/quicktime", "mov", false);
sMimeTypeMap.loadEntry("video/vnd.mpegurl", "mxu", false);
diff --git a/core/java/android/webkit/PluginContentLoader.java b/core/java/android/webkit/PluginContentLoader.java
new file mode 100644
index 0000000..2069599
--- /dev/null
+++ b/core/java/android/webkit/PluginContentLoader.java
@@ -0,0 +1,96 @@
+/*
+ * 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 android.webkit;
+
+import android.net.http.Headers;
+
+import java.io.InputStream;
+import java.util.*;
+
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ * This class is a concrete implementation of StreamLoader that uses a
+ * PluginData object as the source for the stream.
+ */
+class PluginContentLoader extends StreamLoader {
+
+ private PluginData mData; // Content source
+
+ /**
+ * Constructs a PluginDataLoader for use when loading content from
+ * a plugin.
+ *
+ * @param loadListener LoadListener to pass the content to
+ * @param data PluginData used as the source for the content.
+ */
+ PluginContentLoader(LoadListener loadListener, PluginData data) {
+ super(loadListener);
+ mData = data;
+ }
+
+ @Override
+ protected boolean setupStreamAndSendStatus() {
+ mDataStream = mData.getInputStream();
+ mContentLength = mData.getContentLength();
+ mHandler.status(1, 1, mData.getStatusCode(), "OK");
+ return true;
+ }
+
+ @Override
+ protected void buildHeaders(Headers headers) {
+ // Crate a CharArrayBuffer with an arbitrary initial capacity.
+ CharArrayBuffer buffer = new CharArrayBuffer(100);
+ Iterator<Map.Entry<String, String[]>> responseHeadersIt =
+ mData.getHeaders().entrySet().iterator();
+ while (responseHeadersIt.hasNext()) {
+ Map.Entry<String, String[]> entry = responseHeadersIt.next();
+ // Headers.parseHeader() expects lowercase keys, so keys
+ // such as "Accept-Ranges" will fail to parse.
+ //
+ // UrlInterceptHandler instances supply a mapping of
+ // lowercase key to [ unmodified key, value ], so for
+ // Headers.parseHeader() to succeed, we need to construct
+ // a string using the key (i.e. entry.getKey()) and the
+ // element denoting the header value in the
+ // [ unmodified key, value ] pair (i.e. entry.getValue()[1).
+ //
+ // The reason why UrlInterceptHandler instances supply such a
+ // mapping in the first place is historical. Early versions of
+ // the Gears plugin used java.net.HttpURLConnection, which always
+ // returned headers names as capitalized strings. When these were
+ // fed back into webkit, they failed to parse.
+ //
+ // Mewanwhile, Gears was modified to use Apache HTTP library
+ // instead, so this design is now obsolete. Changing it however,
+ // would require changes to the Gears C++ codebase and QA-ing and
+ // submitting a new binary to the Android tree. Given the
+ // timelines for the next Android release, we will not do this
+ // for now.
+ //
+ // TODO: fix C++ Gears to remove the need for this
+ // design.
+ String keyValue = entry.getKey() + ": " + entry.getValue()[1];
+ buffer.ensureCapacity(keyValue.length());
+ buffer.append(keyValue);
+ // Parse it into the header container.
+ headers.parseHeader(buffer);
+ // Clear the buffer
+ buffer.clear();
+ }
+ }
+}
diff --git a/core/java/android/webkit/PluginData.java b/core/java/android/webkit/PluginData.java
new file mode 100644
index 0000000..2b539fe
--- /dev/null
+++ b/core/java/android/webkit/PluginData.java
@@ -0,0 +1,116 @@
+/*
+ * 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 android.webkit;
+
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * This class encapsulates the content generated by a plugin. The
+ * data itself is meant to be loaded into webkit via the
+ * PluginContentLoader class, which needs to be able to construct an
+ * HTTP response. For this, it needs a stream with the response body,
+ * the length of the body, the response headers, and the response
+ * status code. The PluginData class is the container for all these
+ * parts.
+ *
+ */
+public final class PluginData {
+ /**
+ * The content stream.
+ */
+ private InputStream mStream;
+ /**
+ * The content length.
+ */
+ private long mContentLength;
+ /**
+ * The associated HTTP response headers stored as a map of
+ * lowercase header name to [ unmodified header name, header value].
+ * TODO: This design was always a hack. Remove (involves updating
+ * the Gears C++ side).
+ */
+ private Map<String, String[]> mHeaders;
+
+ /**
+ * The index of the header value in the above mapping.
+ */
+ private int mHeaderValueIndex;
+ /**
+ * The associated HTTP response code.
+ */
+ private int mStatusCode;
+
+ /**
+ * Creates a PluginData instance.
+ *
+ * @param stream The stream that supplies content for the plugin.
+ * @param length The length of the plugin content.
+ * @param headers The response headers. Map of
+ * lowercase header name to [ unmodified header name, header value]
+ * @param length The HTTP response status code.
+ */
+ public PluginData(
+ InputStream stream,
+ long length,
+ Map<String, String[]> headers,
+ int code) {
+ mStream = stream;
+ mContentLength = length;
+ mHeaders = headers;
+ mStatusCode = code;
+ }
+
+ /**
+ * Returns the input stream that contains the plugin content.
+ *
+ * @return An InputStream instance with the plugin content.
+ */
+ public InputStream getInputStream() {
+ return mStream;
+ }
+
+ /**
+ * Returns the length of the plugin content.
+ *
+ * @return the length of the plugin content.
+ */
+ public long getContentLength() {
+ return mContentLength;
+ }
+
+ /**
+ * Returns the HTTP response headers associated with the plugin
+ * content.
+ *
+ * @return A Map<String, String[]> containing all headers. The
+ * mapping is 'lowercase header name' to ['unmodified header
+ * name', header value].
+ */
+ public Map<String, String[]> getHeaders() {
+ return mHeaders;
+ }
+
+ /**
+ * Returns the HTTP status code for the response.
+ *
+ * @return The HTTP statue code, e.g 200.
+ */
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+}
diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java
index b7b40b1..9de97c9 100644
--- a/core/java/android/webkit/TextDialog.java
+++ b/core/java/android/webkit/TextDialog.java
@@ -25,18 +25,13 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
-import android.os.Handler;
-import android.os.Message;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextPaint;
import android.text.TextUtils;
-import android.text.method.MetaKeyKeyListener;
import android.text.method.MovementMethod;
-import android.text.method.PasswordTransformationMethod;
-import android.text.method.TextKeyListener;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.KeyCharacterMap;
@@ -44,8 +39,6 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.View.MeasureSpec;
-import android.view.ViewConfiguration;
import android.widget.AbsoluteLayout.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
@@ -69,10 +62,8 @@ import java.util.ArrayList;
// on the enter key. The method for blocking unmatched key ups prevents
// the shift key from working properly.
private boolean mGotEnterDown;
- // Determines whether we allow calls to requestRectangleOnScreen to
- // propagate. We only want to scroll if the user is typing. If the
- // user is simply navigating through a textfield, we do not want to
- // scroll.
+ // mScrollToAccommodateCursor being set to false prevents us from scrolling
+ // the cursor on screen when using the trackball to select a textfield.
private boolean mScrollToAccommodateCursor;
private int mMaxLength;
// Keep track of the text before the change so we know whether we actually
@@ -86,22 +77,6 @@ import java.util.ArrayList;
// FIXME: This can be replaced with TextView.NO_FILTERS if that
// is made public/protected.
private static final InputFilter[] NO_FILTERS = new InputFilter[0];
- // The time of the last enter down, so we know whether to perform a long
- // press.
- private long mDownTime;
-
- private boolean mTrackballDown = false;
- private static int LONGPRESS = 1;
- private Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- if (msg.what == LONGPRESS) {
- if (mTrackballDown) {
- performLongClick();
- mTrackballDown = false;
- }
- }
- }
- };
/**
* Create a new TextDialog.
@@ -136,6 +111,7 @@ import java.util.ArrayList;
// that other applications that use embedded WebViews will properly
// display the text in textfields.
setTextColor(Color.BLACK);
+ setImeOptions(EditorInfo.IME_ACTION_NONE);
}
@Override
@@ -156,38 +132,33 @@ import java.util.ArrayList;
return true;
}
- // For single-line textfields, return key should not be handled
- // here. Instead, the WebView is passed the key up, so it may fire a
- // submit/onClick.
- // Center key should always be passed to a potential onClick
- if ((mSingle && KeyEvent.KEYCODE_ENTER == keyCode)
- || KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
+ if ((mSingle && KeyEvent.KEYCODE_ENTER == keyCode)) {
if (isPopupShowing()) {
- super.dispatchKeyEvent(event);
- return true;
+ return super.dispatchKeyEvent(event);
}
- if (down) {
- if (event.getRepeatCount() == 0) {
- mGotEnterDown = true;
- mDownTime = event.getEventTime();
- // Send the keydown when the up comes, so that we have
- // a chance to handle a long press.
- } else if (mGotEnterDown && event.getEventTime() - mDownTime >
- ViewConfiguration.getLongPressTimeout()) {
- performLongClick();
- mGotEnterDown = false;
- }
- } else if (mGotEnterDown) {
- mGotEnterDown = false;
- if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
- mWebView.shortPressOnTextField();
- return true;
- }
+ if (!down) {
+ // Hide the keyboard, since the user has just submitted this
+ // form. The submission happens thanks to the two calls
+ // to sendDomEvent.
+ InputMethodManager.getInstance(mContext)
+ .hideSoftInputFromWindow(getWindowToken(), 0);
sendDomEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
sendDomEvent(event);
}
- return true;
+ return super.dispatchKeyEvent(event);
+ } else if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) {
+ // Note that this handles center key and trackball.
+ if (isPopupShowing()) {
+ return super.dispatchKeyEvent(event);
+ }
+ // Center key should be passed to a potential onClick
+ if (!down) {
+ mWebView.shortPressOnTextField();
+ }
+ // Pass to super to handle longpress.
+ return super.dispatchKeyEvent(event);
}
+
// Ensure there is a layout so arrow keys are handled properly.
if (getLayout() == null) {
measure(mWidthSpec, mHeightSpec);
@@ -224,9 +195,8 @@ import java.util.ArrayList;
case KeyEvent.KEYCODE_DPAD_DOWN:
isArrowKey = true;
break;
- case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
- // For multi-line text boxes, newlines and dpad center will
+ // For multi-line text boxes, newlines will
// trigger onTextChanged for key down (which will send both
// key up and key down) but not key up.
mGotEnterDown = true;
@@ -268,7 +238,7 @@ import java.util.ArrayList;
// with WebCore's notion of the current selection, reset the selection
// to what it was before the key event.
Selection.setSelection(text, oldStart, oldEnd);
- // Ignore the key up event for newlines or dpad center. This prevents
+ // Ignore the key up event for newlines. This prevents
// multiple newlines in the native textarea.
if (mGotEnterDown && !down) {
return true;
@@ -290,6 +260,25 @@ import java.util.ArrayList;
}
/**
+ * Create a fake touch up event at (x,y) with respect to this TextDialog.
+ * This is used by WebView to act as though a touch event which happened
+ * before we placed the TextDialog actually hit it, so that it can place
+ * the cursor accordingly.
+ */
+ /* package */ void fakeTouchEvent(float x, float y) {
+ // We need to ensure that there is a Layout, since the Layout is used
+ // in determining where to place the cursor.
+ if (getLayout() == null) {
+ measure(mWidthSpec, mHeightSpec);
+ }
+ // Create a fake touch up, which is used to place the cursor.
+ MotionEvent ev = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP,
+ x, y, 0);
+ onTouchEvent(ev);
+ ev.recycle();
+ }
+
+ /**
* Determine whether this TextDialog currently represents the node
* represented by ptr.
* @param ptr Pointer to a node to compare to.
@@ -371,27 +360,8 @@ import java.util.ArrayList;
if (isPopupShowing()) {
return super.onTrackballEvent(event);
}
- int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- if (!mTrackballDown) {
- mTrackballDown = true;
- mHandler.sendEmptyMessageDelayed(LONGPRESS,
- ViewConfiguration.getLongPressTimeout());
- }
- return true;
- case MotionEvent.ACTION_UP:
- if (mTrackballDown) {
- mWebView.shortPressOnTextField();
- mTrackballDown = false;
- mHandler.removeMessages(LONGPRESS);
- }
- return true;
- case MotionEvent.ACTION_CANCEL:
- mTrackballDown = false;
- return true;
- case MotionEvent.ACTION_MOVE:
- // fall through
+ if (event.getAction() != MotionEvent.ACTION_MOVE) {
+ return false;
}
Spannable text = (Spannable) getText();
MovementMethod move = getMovementMethod();
@@ -405,6 +375,12 @@ import java.util.ArrayList;
//mWebView.setSelection(start, end);
return true;
}
+ // If the user is in a textfield, and the movement method is not
+ // handling the trackball events, it means they are at the end of the
+ // field and continuing to move the trackball. In this case, we should
+ // not scroll the cursor on screen bc the user may be attempting to
+ // scroll the page, possibly in the opposite direction of the cursor.
+ mScrollToAccommodateCursor = false;
return false;
}
@@ -416,9 +392,19 @@ import java.util.ArrayList;
// hide the soft keyboard when the edit text is out of focus
InputMethodManager.getInstance(mContext).hideSoftInputFromWindow(
getWindowToken(), 0);
- mHandler.removeMessages(LONGPRESS);
mWebView.removeView(this);
mWebView.requestFocus();
+ mScrollToAccommodateCursor = false;
+ }
+
+ /* package */ void enableScrollOnScreen(boolean enable) {
+ mScrollToAccommodateCursor = enable;
+ }
+
+ /* package */ void bringIntoView() {
+ if (getLayout() != null) {
+ bringPointIntoView(Selection.getSelectionEnd(getText()));
+ }
}
@Override
@@ -437,8 +423,15 @@ import java.util.ArrayList;
mWebView.passToJavaScript(getText().toString(), event);
}
+ /**
+ * Always use this instead of setAdapter, as this has features specific to
+ * the TextDialog.
+ */
public void setAdapterCustom(AutoCompleteAdapter adapter) {
- adapter.setTextView(this);
+ if (adapter != null) {
+ setInputType(EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE);
+ adapter.setTextView(this);
+ }
super.setAdapter(adapter);
}
@@ -480,15 +473,10 @@ import java.util.ArrayList;
* @param inPassword True if the textfield is a password field.
*/
/* package */ void setInPassword(boolean inPassword) {
- PasswordTransformationMethod method;
if (inPassword) {
- method = PasswordTransformationMethod.getInstance();
- } else {
- method = null;
+ setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.
+ TYPE_TEXT_VARIATION_PASSWORD);
}
- setTransformationMethod(method);
- setInputType(inPassword ? EditorInfo.TYPE_TEXT_VARIATION_PASSWORD :
- EditorInfo.TYPE_CLASS_TEXT);
}
/* package */ void setMaxLength(int maxLength) {
@@ -539,7 +527,6 @@ import java.util.ArrayList;
// Set up a measure spec so a layout can always be recreated.
mWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
mHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
- mScrollToAccommodateCursor = false;
requestFocus();
}
@@ -547,19 +534,19 @@ import java.util.ArrayList;
* Set whether this is a single-line textfield or a multi-line textarea.
* Textfields scroll horizontally, and do not handle the enter key.
* Textareas behave oppositely.
+ * Do NOT call this after calling setInPassword(true). This will result in
+ * removing the password input type.
*/
public void setSingleLine(boolean single) {
- if (mSingle != single) {
- TextKeyListener.Capitalize cap;
- if (single) {
- cap = TextKeyListener.Capitalize.NONE;
- } else {
- cap = TextKeyListener.Capitalize.SENTENCES;
- }
- setKeyListener(TextKeyListener.getInstance(!single, cap));
- mSingle = single;
- setHorizontallyScrolling(single);
+ int inputType = EditorInfo.TYPE_CLASS_TEXT;
+ if (!single) {
+ inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
+ | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
}
+ mSingle = single;
+ setHorizontallyScrolling(single);
+ setInputType(inputType);
}
/**
diff --git a/core/java/android/webkit/UrlInterceptHandler.java b/core/java/android/webkit/UrlInterceptHandler.java
index e1c9d61..9216413 100644
--- a/core/java/android/webkit/UrlInterceptHandler.java
+++ b/core/java/android/webkit/UrlInterceptHandler.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.webkit.CacheManager.CacheResult;
+import android.webkit.PluginData;
import java.util.Map;
public interface UrlInterceptHandler {
@@ -29,6 +30,20 @@ public interface UrlInterceptHandler {
* @param url URL string.
* @param headers The headers associated with the request. May be null.
* @return The CacheResult containing the surrogate response.
+ * @Deprecated Use PluginData getPluginData(String url,
+ * Map<String, String> headers); instead
*/
+ @Deprecated
public CacheResult service(String url, Map<String, String> headers);
+
+ /**
+ * Given an URL, returns the PluginData which contains the
+ * surrogate response for the request, or null if the handler is
+ * not interested.
+ *
+ * @param url URL string.
+ * @param headers The headers associated with the request. May be null.
+ * @return The PluginData containing the surrogate response.
+ */
+ public PluginData getPluginData(String url, Map<String, String> headers);
}
diff --git a/core/java/android/webkit/UrlInterceptRegistry.java b/core/java/android/webkit/UrlInterceptRegistry.java
index a218191..6051f29 100644
--- a/core/java/android/webkit/UrlInterceptRegistry.java
+++ b/core/java/android/webkit/UrlInterceptRegistry.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.webkit.CacheManager.CacheResult;
+import android.webkit.PluginData;
import android.webkit.UrlInterceptHandler;
import java.util.Iterator;
@@ -82,17 +83,21 @@ public final class UrlInterceptRegistry {
UrlInterceptHandler handler) {
return getHandlers().remove(handler);
}
-
+
/**
* Given an url, returns the CacheResult of the first
* UrlInterceptHandler interested, or null if none are.
- *
+ *
* @return A CacheResult containing surrogate content.
+ * @Deprecated Use PluginData getPluginData( String url,
+ * Map<String, String> headers) instead.
*/
+ @Deprecated
public static synchronized CacheResult getSurrogate(
String url, Map<String, String> headers) {
- if (urlInterceptDisabled())
+ if (urlInterceptDisabled()) {
return null;
+ }
Iterator iter = getHandlers().listIterator();
while (iter.hasNext()) {
UrlInterceptHandler handler = (UrlInterceptHandler) iter.next();
@@ -103,4 +108,27 @@ public final class UrlInterceptRegistry {
}
return null;
}
+
+ /**
+ * Given an url, returns the PluginData of the first
+ * UrlInterceptHandler interested, or null if none are or if
+ * intercepts are disabled.
+ *
+ * @return A PluginData instance containing surrogate content.
+ */
+ public static synchronized PluginData getPluginData(
+ String url, Map<String, String> headers) {
+ if (urlInterceptDisabled()) {
+ return null;
+ }
+ Iterator iter = getHandlers().listIterator();
+ while (iter.hasNext()) {
+ UrlInterceptHandler handler = (UrlInterceptHandler) iter.next();
+ PluginData data = handler.getPluginData(url, headers);
+ if (data != null) {
+ return data;
+ }
+ }
+ return null;
+ }
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 308b6aa..44f382c 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -20,6 +20,8 @@ import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
+import android.provider.Checkin;
+
import java.lang.SecurityException;
import android.content.pm.PackageManager;
@@ -136,7 +138,7 @@ public class WebSettings {
private int mDefaultFixedFontSize = 13;
private boolean mLoadsImagesAutomatically = true;
private boolean mBlockNetworkImage = false;
- private boolean mBlockNetworkLoads = false;
+ private boolean mBlockNetworkLoads;
private boolean mJavaScriptEnabled = false;
private boolean mPluginsEnabled = false;
private boolean mJavaScriptCanOpenWindowsAutomatically = false;
@@ -250,7 +252,9 @@ public class WebSettings {
mUserAgent = getCurrentUserAgent();
mUseDefaultUserAgent = true;
- verifyNetworkAccess();
+ mBlockNetworkLoads = mContext.checkPermission(
+ "android.permission.INTERNET", android.os.Process.myPid(),
+ android.os.Process.myUid()) != PackageManager.PERMISSION_GRANTED;
}
/**
@@ -320,10 +324,15 @@ public class WebSettings {
buffer.append("en");
}
- final String device = Build.DEVICE;
- if (device.length() > 0) {
+ final String model = Build.MODEL;
+ if (model.length() > 0) {
buffer.append("; ");
- buffer.append(device);
+ buffer.append(model);
+ }
+ final String id = Build.ID;
+ if (id.length() > 0) {
+ buffer.append(" Build/");
+ buffer.append(id);
}
final String base = mContext.getResources().getText(
com.android.internal.R.string.web_user_agent).toString();
@@ -407,6 +416,10 @@ public class WebSettings {
* @see WebSettings.TextSize
*/
public synchronized void setTextSize(TextSize t) {
+ if (WebView.mLogEvent && mTextSize != t ) {
+ Checkin.updateStats(mContext.getContentResolver(),
+ Checkin.Stats.Tag.BROWSER_TEXT_SIZE_CHANGE, 1, 0.0);
+ }
mTextSize = t;
postSync();
}
@@ -827,7 +840,7 @@ public class WebSettings {
private void verifyNetworkAccess() {
if (!mBlockNetworkLoads) {
if (mContext.checkPermission("android.permission.INTERNET",
- android.os.Process.myPid(), 0) !=
+ android.os.Process.myPid(), android.os.Process.myUid()) !=
PackageManager.PERMISSION_GRANTED) {
throw new SecurityException
("Permission denied - " +
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index c7ba498..d404040 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -21,7 +21,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
-import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -38,13 +37,14 @@ import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.provider.Checkin;
import android.text.IClipboard;
import android.text.Selection;
import android.text.Spannable;
import android.util.AttributeSet;
import android.util.Config;
+import android.util.EventLog;
import android.util.Log;
-import android.view.animation.AlphaAnimation;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -64,10 +64,9 @@ import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
-import android.widget.RelativeLayout;
import android.widget.Scroller;
import android.widget.Toast;
-import android.widget.ZoomControls;
+import android.widget.ZoomButtonsController;
import android.widget.AdapterView.OnItemClickListener;
import java.io.File;
@@ -207,60 +206,6 @@ public class WebView extends AbsoluteLayout
static final boolean DEBUG = false;
static final boolean LOGV_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
- private class ExtendedZoomControls extends RelativeLayout {
- 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.
*/
@@ -358,6 +303,11 @@ public class WebView extends AbsoluteLayout
// Whether to forward the touch events to WebCore
private boolean mForwardTouchEvents = false;
+ // Whether to prevent drag during touch. The initial value depends on
+ // mForwardTouchEvents. If WebCore wants touch events, we assume it will
+ // take control of touch events unless it says no for touch down event.
+ private boolean mPreventDrag;
+
// If updateTextEntry gets called while we are out of focus, use this
// variable to remember to do it next time we gain focus.
private boolean mNeedsUpdateTextEntry = false;
@@ -368,26 +318,20 @@ public class WebView extends AbsoluteLayout
/**
* Customizable constant
*/
- // pre-computed square of ViewConfiguration.getTouchSlop()
- private static final int TOUCH_SLOP_SQUARE =
- ViewConfiguration.getTouchSlop() * ViewConfiguration.getTouchSlop();
+ // pre-computed square of ViewConfiguration.getScaledTouchSlop()
+ private int mTouchSlopSquare;
+ // pre-computed density adjusted navigation slop
+ private int mNavSlop;
// This should be ViewConfiguration.getTapTimeout()
// But system time out is 100ms, which is too short for the browser.
// In the browser, if it switches out of tap too soon, jump tap won't work.
private static final int TAP_TIMEOUT = 200;
- // The duration in milliseconds we will wait to see if it is a double tap.
- // With a limited survey, the time between the first tap up and the second
- // tap down in the double tap case is around 70ms - 120ms.
- private static final int DOUBLE_TAP_TIMEOUT = 200;
// This should be ViewConfiguration.getLongPressTimeout()
// But system time out is 500ms, which is too short for the browser.
// With a short timeout, it's difficult to treat trigger a short press.
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;
@@ -422,10 +366,6 @@ public class WebView extends AbsoluteLayout
private boolean mWrapContent;
- // The View containing the zoom controls
- private ExtendedZoomControls mZoomControls;
- private Runnable mZoomControlRunnable;
-
// true if we should call webcore to draw the content, false means we have
// requested something but it isn't ready to draw yet.
private WebViewCore.FocusData mFocusData;
@@ -436,7 +376,6 @@ public class WebView extends AbsoluteLayout
private static final int NEVER_REMEMBER_PASSWORD = 2;
private static final int SWITCH_TO_SHORTPRESS = 3;
private static final int SWITCH_TO_LONGPRESS = 4;
- private static final int RELEASE_SINGLE_TAP = 5;
private static final int UPDATE_TEXT_ENTRY_ADAPTER = 6;
private static final int SWITCH_TO_ENTER = 7;
private static final int RESUME_WEBCORE_UPDATE = 8;
@@ -460,19 +399,54 @@ public class WebView extends AbsoluteLayout
static final int LONG_PRESS_ENTER = 23;
static final int PREVENT_TOUCH_ID = 24;
static final int WEBCORE_NEED_TOUCH_EVENTS = 25;
+ // obj=Rect in doc coordinates
+ static final int INVAL_RECT_MSG_ID = 26;
+
+ static final String[] HandlerDebugString = {
+ "REMEMBER_PASSWORD", // = 1;
+ "NEVER_REMEMBER_PASSWORD", // = 2;
+ "SWITCH_TO_SHORTPRESS", // = 3;
+ "SWITCH_TO_LONGPRESS", // = 4;
+ "5",
+ "UPDATE_TEXT_ENTRY_ADAPTER", // = 6;
+ "SWITCH_TO_ENTER", // = 7;
+ "RESUME_WEBCORE_UPDATE", // = 8;
+ "9",
+ "SCROLL_TO_MSG_ID", // = 10;
+ "SCROLL_BY_MSG_ID", // = 11;
+ "SPAWN_SCROLL_TO_MSG_ID", // = 12;
+ "SYNC_SCROLL_TO_MSG_ID", // = 13;
+ "NEW_PICTURE_MSG_ID", // = 14;
+ "UPDATE_TEXT_ENTRY_MSG_ID", // = 15;
+ "WEBCORE_INITIALIZED_MSG_ID", // = 16;
+ "UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 17;
+ "DID_FIRST_LAYOUT_MSG_ID", // = 18;
+ "RECOMPUTE_FOCUS_MSG_ID", // = 19;
+ "NOTIFY_FOCUS_SET_MSG_ID", // = 20;
+ "MARK_NODE_INVALID_ID", // = 21;
+ "UPDATE_CLIPBOARD", // = 22;
+ "LONG_PRESS_ENTER", // = 23;
+ "PREVENT_TOUCH_ID", // = 24;
+ "WEBCORE_NEED_TOUCH_EVENTS", // = 25;
+ "INVAL_RECT_MSG_ID" // = 26;
+ };
// width which view is considered to be fully zoomed out
- static final int ZOOM_OUT_WIDTH = 1024;
+ static final int ZOOM_OUT_WIDTH = 1008;
- private static final float DEFAULT_MAX_ZOOM_SCALE = 4;
+ private static final float DEFAULT_MAX_ZOOM_SCALE = 4.0f;
private static final float DEFAULT_MIN_ZOOM_SCALE = 0.25f;
// scale limit, which can be set through viewport meta tag in the web page
private float mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
private float mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+ private boolean mMinZoomScaleFixed = false;
// initial scale in percent. 0 means using default.
private int mInitialScale = 0;
+ // set to true temporarily while the zoom control is being dragged
+ private boolean mPreviewZoomOnly = false;
+
// computed scale and inverse, from mZoomWidth.
private float mActualScale = 1;
private float mInvActualScale = 1;
@@ -496,6 +470,13 @@ public class WebView extends AbsoluteLayout
// Used to match key downs and key ups
private boolean mGotKeyDown;
+ /* package */ static boolean mLogEvent = true;
+ private static final int EVENT_LOG_ZOOM_LEVEL_CHANGE = 70101;
+ private static final int EVENT_LOG_DOUBLE_TAP_DURATION = 70102;
+
+ // for event log
+ private long mLastTouchUpTime = 0;
+
/**
* URI scheme for telephone number
*/
@@ -591,6 +572,41 @@ public class WebView extends AbsoluteLayout
}
}
+ private ZoomButtonsController mZoomButtonsController;
+ private ImageView mZoomOverviewButton;
+ private ImageView mZoomFitPageButton;
+
+ // These keep track of the center point of the zoom. They are used to
+ // determine the point around which we should zoom.
+ private float mZoomCenterX;
+ private float mZoomCenterY;
+
+ 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();
+ updateZoomButtonsEnabled();
+ }
+ }
+
+ public void onZoom(boolean zoomIn) {
+ if (zoomIn) {
+ zoomIn();
+ } else {
+ zoomOut();
+ }
+
+ updateZoomButtonsEnabled();
+ }
+ };
+
/**
* Construct a new WebView with a Context object.
* @param context A Context object used to access application assets.
@@ -618,11 +634,6 @@ public class WebView extends AbsoluteLayout
super(context, attrs, defStyle);
init();
- TypedArray a = context.obtainStyledAttributes(
- com.android.internal.R.styleable.View);
- initializeScrollbars(a);
- a.recycle();
-
mCallbackProxy = new CallbackProxy(context, this);
mWebViewCore = new WebViewCore(context, this, mCallbackProxy);
mDatabase = WebViewDatabase.getInstance(context);
@@ -632,6 +643,49 @@ public class WebView extends AbsoluteLayout
mFocusData.mX = 0;
mFocusData.mY = 0;
mScroller = new Scroller(context);
+
+ initZoomController(context);
+ }
+
+ private void initZoomController(Context context) {
+ // Create the buttons controller
+ mZoomButtonsController = new ZoomButtonsController(this);
+ mZoomButtonsController.setOnZoomListener(mZoomListener);
+
+ // Create the accessory buttons
+ LayoutInflater inflater =
+ (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ ViewGroup container = mZoomButtonsController.getContainer();
+ inflater.inflate(com.android.internal.R.layout.zoom_browser_accessory_buttons, container);
+ mZoomOverviewButton =
+ (ImageView) container.findViewById(com.android.internal.R.id.zoom_page_overview);
+ mZoomOverviewButton.setOnClickListener(
+ new View.OnClickListener() {
+ public void onClick(View v) {
+ mZoomButtonsController.setVisible(false);
+ zoomScrollOut();
+ if (mLogEvent) {
+ Checkin.updateStats(mContext.getContentResolver(),
+ Checkin.Stats.Tag.BROWSER_ZOOM_OVERVIEW, 1, 0.0);
+ }
+ }
+ });
+ mZoomFitPageButton =
+ (ImageView) container.findViewById(com.android.internal.R.id.zoom_fit_page);
+ mZoomFitPageButton.setOnClickListener(
+ new View.OnClickListener() {
+ public void onClick(View v) {
+ zoomWithPreview(1f);
+ updateZoomButtonsEnabled();
+ }
+ });
+ }
+
+ private void updateZoomButtonsEnabled() {
+ mZoomButtonsController.setZoomInEnabled(mActualScale < mMaxZoomScale);
+ mZoomButtonsController.setZoomOutEnabled(mActualScale > mMinZoomScale);
+ mZoomFitPageButton.setEnabled(mActualScale != 1);
+ mZoomOverviewButton.setEnabled(canZoomScrollOut());
}
private void init() {
@@ -641,9 +695,13 @@ public class WebView extends AbsoluteLayout
setClickable(true);
setLongClickable(true);
- // should be conditional on if we're in the browser activity?
- setHorizontalScrollBarEnabled(true);
- setVerticalScrollBarEnabled(true);
+ final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+ mTouchSlopSquare = slop * slop;
+ mMinLockSnapReverseDistance = slop;
+ // use one line height, 16 based on our current default font, for how
+ // far we allow a touch be away from the edge of a link
+ mNavSlop = (int) (16 * getContext().getResources()
+ .getDisplayMetrics().density);
}
/* package */ boolean onSavePassword(String schemePlusHost, String username,
@@ -748,7 +806,7 @@ public class WebView extends AbsoluteLayout
* to.
*/
private int getViewWidth() {
- if (mOverlayVerticalScrollbar) {
+ if (!isVerticalScrollBarEnabled() || mOverlayVerticalScrollbar) {
return getWidth();
} else {
return getWidth() - getVerticalScrollbarWidth();
@@ -760,7 +818,7 @@ public class WebView extends AbsoluteLayout
* to.
*/
private int getViewHeight() {
- if (mOverlayHorizontalScrollbar) {
+ if (!isHorizontalScrollBarEnabled() || mOverlayHorizontalScrollbar) {
return getHeight();
} else {
return getHeight() - getHorizontalScrollbarHeight();
@@ -832,7 +890,6 @@ public class WebView extends AbsoluteLayout
*/
public void destroy() {
clearTextEntry();
- getViewTreeObserver().removeOnGlobalFocusChangeListener(this);
if (mWebViewCore != null) {
// Set the handlers to null before destroying WebViewCore so no
// more messages will be posted.
@@ -1265,7 +1322,7 @@ public class WebView extends AbsoluteLayout
nativeClearFocus(-1, -1);
if (top) {
// go to the top of the document
- return pinScrollTo(mScrollX, 0, true);
+ return pinScrollTo(mScrollX, 0, true, 0);
}
// Page up
int h = getHeight();
@@ -1276,7 +1333,7 @@ public class WebView extends AbsoluteLayout
y = -h / 2;
}
mUserScroll = true;
- return mScroller.isFinished() ? pinScrollBy(0, y, true)
+ return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
: extendScroll(y);
}
@@ -1291,7 +1348,7 @@ public class WebView extends AbsoluteLayout
}
nativeClearFocus(-1, -1);
if (bottom) {
- return pinScrollTo(mScrollX, mContentHeight, true);
+ return pinScrollTo(mScrollX, mContentHeight, true, 0);
}
// Page down.
int h = getHeight();
@@ -1302,7 +1359,7 @@ public class WebView extends AbsoluteLayout
y = h / 2;
}
mUserScroll = true;
- return mScroller.isFinished() ? pinScrollBy(0, y, true)
+ return mScroller.isFinished() ? pinScrollBy(0, y, true, 0)
: extendScroll(y);
}
@@ -1375,13 +1432,7 @@ public class WebView extends AbsoluteLayout
return;
}
clearTextEntry();
- ExtendedZoomControls zoomControls = (ExtendedZoomControls)
- getZoomControls();
- zoomControls.show(true, canZoomScrollOut());
- zoomControls.requestFocus();
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- mPrivateHandler.postDelayed(mZoomControlRunnable,
- ZOOM_CONTROLS_TIMEOUT);
+ mZoomButtonsController.setVisible(true);
}
/**
@@ -1493,7 +1544,8 @@ public class WebView extends AbsoluteLayout
private static int pinLoc(int x, int viewMax, int docMax) {
// Log.d(LOGTAG, "-- pinLoc " + x + " " + viewMax + " " + docMax);
if (docMax < viewMax) { // the doc has room on the sides for "blank"
- x = -(viewMax - docMax) >> 1;
+ // pin the short document to the top/left of the screen
+ x = 0;
// Log.d(LOGTAG, "--- center " + x);
} else if (x < 0) {
x = 0;
@@ -1585,12 +1637,14 @@ public class WebView extends AbsoluteLayout
if (mDrawHistory) {
// If history Picture is drawn, don't update scroll. They will
// be updated when we get out of that mode.
- if (scale != mActualScale) {
+ if (scale != mActualScale && !mPreviewZoomOnly) {
mCallbackProxy.onScaleChanged(mActualScale, scale);
}
mActualScale = scale;
mInvActualScale = 1 / scale;
- sendViewSizeZoom();
+ if (!mPreviewZoomOnly) {
+ sendViewSizeZoom();
+ }
} else {
// update our scroll so we don't appear to jump
// i.e. keep the center of the doc in the center of the view
@@ -1598,11 +1652,11 @@ public class WebView extends AbsoluteLayout
int oldX = mScrollX;
int oldY = mScrollY;
float ratio = scale * mInvActualScale; // old inverse
- float sx = ratio * oldX + (ratio - 1) * getViewWidth() * 0.5f;
- float sy = ratio * oldY + (ratio - 1) * getViewHeight() * 0.5f;
+ float sx = ratio * oldX + (ratio - 1) * mZoomCenterX;
+ float sy = ratio * oldY + (ratio - 1) * mZoomCenterY;
// now update our new scale and inverse
- if (scale != mActualScale) {
+ if (scale != mActualScale && !mPreviewZoomOnly) {
mCallbackProxy.onScaleChanged(mActualScale, scale);
}
mActualScale = scale;
@@ -1614,8 +1668,10 @@ public class WebView extends AbsoluteLayout
mScrollX = pinLocX(Math.round(sx));
mScrollY = pinLocY(Math.round(sy));
- sendViewSizeZoom();
- sendOurVisibleRect();
+ if (!mPreviewZoomOnly) {
+ sendViewSizeZoom();
+ sendOurVisibleRect();
+ }
}
}
}
@@ -1817,8 +1873,8 @@ public class WebView extends AbsoluteLayout
*/
public void clearFormData() {
if (inEditingMode()) {
- ArrayAdapter<String> adapter = null;
- mTextEntry.setAdapter(adapter);
+ AutoCompleteAdapter adapter = null;
+ mTextEntry.setAdapterCustom(adapter);
}
}
@@ -1913,7 +1969,7 @@ public class WebView extends AbsoluteLayout
nativeSetFindIsDown();
// Now that the dialog has been removed, ensure that we scroll to a
// location that is not beyond the end of the page.
- pinScrollTo(mScrollX, mScrollY, false);
+ pinScrollTo(mScrollX, mScrollY, false, 0);
invalidate();
}
@@ -1956,13 +2012,13 @@ public class WebView extends AbsoluteLayout
// helper to pin the scrollBy parameters (already in view coordinates)
// returns true if the scroll was changed
- private boolean pinScrollBy(int dx, int dy, boolean animate) {
- return pinScrollTo(mScrollX + dx, mScrollY + dy, animate);
+ private boolean pinScrollBy(int dx, int dy, boolean animate, int animationDuration) {
+ return pinScrollTo(mScrollX + dx, mScrollY + dy, animate, animationDuration);
}
// helper to pin the scrollTo parameters (already in view coordinates)
// returns true if the scroll was changed
- private boolean pinScrollTo(int x, int y, boolean animate) {
+ private boolean pinScrollTo(int x, int y, boolean animate, int animationDuration) {
x = pinLocX(x);
y = pinLocY(y);
int dx = x - mScrollX;
@@ -1976,7 +2032,7 @@ public class WebView extends AbsoluteLayout
// Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
mScroller.startScroll(mScrollX, mScrollY, dx, dy,
- computeDuration(dx, dy));
+ animationDuration > 0 ? animationDuration : computeDuration(dx, dy));
invalidate();
} else {
mScroller.abortAnimation(); // just in case
@@ -1987,7 +2043,7 @@ public class WebView extends AbsoluteLayout
// Scale from content to view coordinates, and pin.
// Also called by jni webview.cpp
- private void setContentScrollBy(int cx, int cy) {
+ private void setContentScrollBy(int cx, int cy, boolean animate) {
if (mDrawHistory) {
// disallow WebView to change the scroll position as History Picture
// is used in the view system.
@@ -2011,10 +2067,10 @@ public class WebView extends AbsoluteLayout
// vertical scroll?
// Log.d(LOGTAG, "setContentScrollBy cy=" + cy);
if (cy == 0 && cx != 0) {
- pinScrollBy(cx, 0, true);
+ pinScrollBy(cx, 0, animate, 0);
}
} else {
- pinScrollBy(cx, cy, true);
+ pinScrollBy(cx, cy, animate, 0);
}
}
@@ -2034,7 +2090,7 @@ public class WebView extends AbsoluteLayout
int vy = contentToView(cy);
// Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" +
// vx + " " + vy + "]");
- pinScrollTo(vx, vy, false);
+ pinScrollTo(vx, vy, false, 0);
if (mScrollX != vx || mScrollY != vy) {
return true;
} else {
@@ -2051,7 +2107,7 @@ public class WebView extends AbsoluteLayout
}
int vx = contentToView(cx);
int vy = contentToView(cy);
- pinScrollTo(vx, vy, true);
+ pinScrollTo(vx, vy, true, 0);
}
/**
@@ -2140,8 +2196,19 @@ public class WebView extends AbsoluteLayout
/**
* Use this function to bind an object to Javascript so that the
* methods can be accessed from Javascript.
- * IMPORTANT, the object that is bound runs in another thread and
- * not in the thread that it was constructed in.
+ * <p><strong>IMPORTANT:</strong>
+ * <ul>
+ * <li> Using addJavascriptInterface() allows JavaScript to control your
+ * application. This can be a very useful feature or a dangerous security
+ * issue. When the HTML in the WebView is untrustworthy (for example, part
+ * or all of the HTML is provided by some person or process), then an
+ * attacker could inject HTML that will execute your code and possibly any
+ * code of the attacker's choosing.<br>
+ * Do not use addJavascriptInterface() unless all of the HTML in this
+ * WebView was written by you.</li>
+ * <li> The Java object that is bound runs in another thread and not in
+ * the thread that it was constructed in.</li>
+ * </ul></p>
* @param obj The class instance to bind to Javascript
* @param interfaceName The name to used to expose the class in Javascript
*/
@@ -2224,7 +2291,8 @@ public class WebView extends AbsoluteLayout
// state.
// If mNativeClass is 0, we should not reach here, so we do not
// need to check it again.
- nativeRecordButtons(mTouchMode == TOUCH_SHORTPRESS_START_MODE
+ nativeRecordButtons(hasFocus() && hasWindowFocus(),
+ mTouchMode == TOUCH_SHORTPRESS_START_MODE
|| mTrackballDown || mGotEnterDown, false);
drawCoreAndFocusRing(canvas, mBackgroundColor, mDrawFocusRing);
}
@@ -2273,10 +2341,12 @@ public class WebView extends AbsoluteLayout
invalidate();
} else {
zoomScale = mZoomScale;
+ // set mZoomScale to be 0 as we have done animation
+ mZoomScale = 0;
}
float scale = (mActualScale - zoomScale) * mInvActualScale;
- float tx = scale * ((getLeft() + getRight()) * 0.5f + mScrollX);
- float ty = scale * ((getTop() + getBottom()) * 0.5f + mScrollY);
+ float tx = scale * (mZoomCenterX + mScrollX);
+ float ty = scale * (mZoomCenterY + mScrollY);
// this block pins the translate to "legal" bounds. This makes the
// animation a bit non-obvious, but it means we won't pop when the
@@ -2566,11 +2636,8 @@ public class WebView extends AbsoluteLayout
private void startZoomScrollOut() {
setHorizontalScrollBarEnabled(false);
setVerticalScrollBarEnabled(false);
- if (mZoomControlRunnable != null) {
- mPrivateHandler.removeCallbacks(mZoomControlRunnable);
- }
- if (mZoomControls != null) {
- mZoomControls.hide();
+ if (mZoomButtonsController.isVisible()) {
+ mZoomButtonsController.setVisible(false);
}
int width = getViewWidth();
int height = getViewHeight();
@@ -2773,6 +2840,7 @@ public class WebView extends AbsoluteLayout
* @param end End of selection to delete.
*/
/* package */ void deleteSelection(int start, int end) {
+ mTextGeneration++;
mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end,
new WebViewCore.FocusData(mFocusData));
}
@@ -2793,12 +2861,20 @@ public class WebView extends AbsoluteLayout
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mTextEntry, 0);
+ mTextEntry.enableScrollOnScreen(true);
+ // Now we need to fake a touch event to place the cursor where the
+ // user touched.
+ AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams)
+ mTextEntry.getLayoutParams();
+ if (lp != null) {
+ // Take the last touch and adjust for the location of the
+ // TextDialog.
+ float x = mLastTouchX + (float) (mScrollX - lp.x);
+ float y = mLastTouchY + (float) (mScrollY - lp.y);
+ mTextEntry.fakeTouchEvent(x, y);
+ }
}
- // Used to register the global focus change listener one time to avoid
- // multiple references to WebView
- private boolean mGlobalFocusChangeListenerAdded;
-
private void updateTextEntry() {
if (mTextEntry == null) {
mTextEntry = new TextDialog(mContext, WebView.this);
@@ -2831,9 +2907,6 @@ public class WebView extends AbsoluteLayout
// Note that sendOurVisibleRect calls viewToContent, so the coordinates
// should be in content coordinates.
if (!Rect.intersects(node.mBounds, visibleRect)) {
- if (alreadyThere) {
- mTextEntry.remove();
- }
// Node is not on screen, so do not bother.
return;
}
@@ -2886,21 +2959,32 @@ public class WebView extends AbsoluteLayout
}
}
mTextEntry.setMaxLength(maxLength);
- ArrayAdapter<String> adapter = null;
- mTextEntry.setAdapter(adapter);
- mTextEntry.setInPassword(node.mIsPassword);
+ AutoCompleteAdapter adapter = null;
+ mTextEntry.setAdapterCustom(adapter);
mTextEntry.setSingleLine(node.mIsTextField);
+ mTextEntry.setInPassword(node.mIsPassword);
if (null == text) {
mTextEntry.setText("", 0, 0);
} else {
- mTextEntry.setText(text, 0, text.length());
+ // Change to true to enable the old style behavior, where
+ // entering a textfield/textarea always set the selection to the
+ // whole field. This was desirable for the case where the user
+ // intends to scroll past the field using the trackball.
+ // However, it causes a problem when replying to emails - the
+ // user expects the cursor to be at the beginning of the
+ // textarea. Testing out a new behavior, where textfields set
+ // selection at the end, and textareas at the beginning.
+ if (false) {
+ mTextEntry.setText(text, 0, text.length());
+ } else if (node.mIsTextField) {
+ int length = text.length();
+ mTextEntry.setText(text, length, length);
+ } else {
+ mTextEntry.setText(text, 0, 0);
+ }
}
mTextEntry.requestFocus();
}
- if (!mGlobalFocusChangeListenerAdded) {
- getViewTreeObserver().addOnGlobalFocusChangeListener(this);
- mGlobalFocusChangeListenerAdded = true;
- }
}
private class UpdateTextEntryAdapter implements Runnable {
@@ -2980,6 +3064,9 @@ public class WebView extends AbsoluteLayout
mSelectX = mScrollX + (int) mLastTouchX;
mSelectY = mScrollY + (int) mLastTouchY;
}
+ int contentX = viewToContent((int) mLastTouchX + mScrollX);
+ int contentY = viewToContent((int) mLastTouchY + mScrollY);
+ nativeClearFocus(contentX, contentY);
}
if (keyCode >= KeyEvent.KEYCODE_DPAD_UP
@@ -3001,7 +3088,9 @@ public class WebView extends AbsoluteLayout
mGotEnterDown = true;
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(LONG_PRESS_ENTER), LONG_PRESS_TIMEOUT);
- nativeRecordButtons(true, true);
+ // Already checked mNativeClass, so we do not need to check it
+ // again.
+ nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
return true;
}
// Bubble up the key event as WebView doesn't handle it
@@ -3031,8 +3120,8 @@ public class WebView extends AbsoluteLayout
(keyCode == KeyEvent.KEYCODE_7) ? 1 : 0, 0);
break;
case KeyEvent.KEYCODE_9:
- debugDump();
- break;
+ nativeInstrumentReport();
+ return true;
}
}
@@ -3167,7 +3256,11 @@ public class WebView extends AbsoluteLayout
* @hide
*/
public void emulateShiftHeld() {
+ mExtendSelection = false;
mShiftIsPressed = true;
+ int contentX = viewToContent((int) mLastTouchX + mScrollX);
+ int contentY = viewToContent((int) mLastTouchY + mScrollY);
+ nativeClearFocus(contentX, contentY);
}
private boolean commitCopy() {
@@ -3182,6 +3275,7 @@ public class WebView extends AbsoluteLayout
mWebViewCore.sendMessage(EventHub.GET_SELECTION, selection);
copiedSomething = true;
}
+ mExtendSelection = false;
}
mShiftIsPressed = false;
if (mTouchMode == TOUCH_SELECT_MODE) {
@@ -3210,29 +3304,31 @@ public class WebView extends AbsoluteLayout
ViewGroup p = (ViewGroup) parent;
p.setOnHierarchyChangeListener(null);
}
+
+ // Clean up the zoom controller
+ mZoomButtonsController.setVisible(false);
+ ZoomButtonsController.finishZoomTutorial(mContext, false);
}
// Implementation for OnHierarchyChangeListener
public void onChildViewAdded(View parent, View child) {}
- // When we are removed, remove this as a global focus change listener.
public void onChildViewRemoved(View p, View child) {
if (child == this) {
- p.getViewTreeObserver().removeOnGlobalFocusChangeListener(this);
- mGlobalFocusChangeListenerAdded = false;
+ if (inEditingMode()) {
+ clearTextEntry();
+ mNeedsUpdateTextEntry = true;
+ }
}
}
-
- // Use this to know when the textview has lost focus, and something other
- // than the webview has gained focus. Stop drawing the focus ring, remove
- // the TextView, and set a flag to put it back when we regain focus.
+
+ /**
+ * @deprecated WebView should not have implemented
+ * ViewTreeObserver.OnGlobalFocusChangeListener. This method
+ * does nothing now.
+ */
+ @Deprecated
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
- if (oldFocus == mTextEntry && newFocus != this) {
- mDrawFocusRing = false;
- mTextEntry.updateCachedTextfield();
- removeView(mTextEntry);
- mNeedsUpdateTextEntry = true;
- }
}
// To avoid drawing the focus ring, and remove the TextView when our window
@@ -3248,21 +3344,33 @@ public class WebView extends AbsoluteLayout
if (mNeedsUpdateTextEntry) {
updateTextEntry();
}
+ if (mNativeClass != 0) {
+ nativeRecordButtons(true, false, true);
+ }
} else {
// If our window gained focus, but we do not have it, do not
// draw the focus ring.
mDrawFocusRing = false;
+ // We do not call nativeRecordButtons here because we assume
+ // that when we lost focus, or window focus, it got called with
+ // false for the first parameter
}
} else {
- // If our window has lost focus, stop drawing the focus ring, and
- // remove the TextView if displayed, and flag it to be added when
- // we regain focus.
- mDrawFocusRing = false;
+ if (!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
+ * our window is not focused, but this is an exception since
+ * the user can still navigate the web page with the zoom
+ * controls showing.
+ */
+ // If our window has lost focus, stop drawing the focus ring
+ mDrawFocusRing = false;
+ }
mGotKeyDown = false;
mShiftIsPressed = false;
- if (inEditingMode()) {
- clearTextEntry();
- mNeedsUpdateTextEntry = true;
+ if (mNativeClass != 0) {
+ nativeRecordButtons(false, false, true);
}
}
invalidate();
@@ -3284,12 +3392,22 @@ public class WebView extends AbsoluteLayout
updateTextEntry();
mNeedsUpdateTextEntry = false;
}
+ if (mNativeClass != 0) {
+ nativeRecordButtons(true, false, true);
+ }
+ //} else {
+ // The WebView has gained focus while we do not have
+ // windowfocus. When our window lost focus, we should have
+ // called nativeRecordButtons(false...)
}
} else {
// When we lost focus, unless focus went to the TextView (which is
// true if we are in editing mode), stop drawing the focus ring.
if (!inEditingMode()) {
mDrawFocusRing = false;
+ if (mNativeClass != 0) {
+ nativeRecordButtons(false, false, true);
+ }
}
mGotKeyDown = false;
}
@@ -3300,6 +3418,15 @@ public class WebView extends AbsoluteLayout
@Override
protected void onSizeChanged(int w, int h, int ow, int oh) {
super.onSizeChanged(w, h, ow, oh);
+ // Center zooming to the center of the screen.
+ mZoomCenterX = getViewWidth() * .5f;
+ mZoomCenterY = getViewHeight() * .5f;
+
+ // update mMinZoomScale if the minimum zoom scale is not fixed
+ if (!mMinZoomScaleFixed) {
+ mMinZoomScale = (float) getViewWidth()
+ / Math.max(ZOOM_OUT_WIDTH, mContentWidth);
+ }
// we always force, in case our height changed, in which case we still
// want to send the notification over to webkit
@@ -3346,9 +3473,8 @@ public class WebView extends AbsoluteLayout
// 3. If there is a same direction back and forth, lock it.
// adjustable parameters
+ private int mMinLockSnapReverseDistance;
private static final float MAX_SLOPE_FOR_DIAG = 1.5f;
- private static final int MIN_LOCK_SNAP_REVERSE_DISTANCE =
- ViewConfiguration.getTouchSlop();
private static final int MIN_BREAK_SNAP_CROSS_DISTANCE = 80;
@Override
@@ -3387,11 +3513,14 @@ public class WebView extends AbsoluteLayout
WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
ted.mAction = action;
ted.mX = viewToContent((int) x + mScrollX);
- ted.mY = viewToContent((int) y + mScrollY);;
+ ted.mY = viewToContent((int) y + mScrollY);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mLastSentTouchTime = eventTime;
}
+ int deltaX = (int) (mLastTouchX - x);
+ int deltaY = (int) (mLastTouchY - y);
+
switch (action) {
case MotionEvent.ACTION_DOWN: {
if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN
@@ -3418,7 +3547,13 @@ public class WebView extends AbsoluteLayout
mTouchSelection = mExtendSelection = true;
} else {
mTouchMode = TOUCH_INIT_MODE;
+ mPreventDrag = mForwardTouchEvents;
+ if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
+ EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION,
+ (eventTime - mLastTouchUpTime), eventTime);
+ }
}
+ // Trigger the link
if (mTouchMode == TOUCH_INIT_MODE) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT);
@@ -3445,9 +3580,6 @@ public class WebView extends AbsoluteLayout
}
mVelocityTracker.addMovement(ev);
- int deltaX = (int) (mLastTouchX - x);
- int deltaY = (int) (mLastTouchY - y);
-
if (mTouchMode != TOUCH_DRAG_MODE) {
if (mTouchMode == TOUCH_SELECT_MODE) {
mSelectX = mScrollX + (int) x;
@@ -3460,8 +3592,8 @@ public class WebView extends AbsoluteLayout
invalidate();
break;
}
- if ((deltaX * deltaX + deltaY * deltaY)
- < TOUCH_SLOP_SQUARE) {
+ if (mPreventDrag || (deltaX * deltaX + deltaY * deltaY)
+ < mTouchSlopSquare) {
break;
}
@@ -3496,6 +3628,12 @@ public class WebView extends AbsoluteLayout
mWebViewCore
.sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0);
}
+ if (getSettings().supportZoom()
+ && !mZoomButtonsController.isVisible()
+ && (canZoomScrollOut() ||
+ mMinZoomScale < mMaxZoomScale)) {
+ mZoomButtonsController.setVisible(true);
+ }
}
// do pan
@@ -3519,9 +3657,9 @@ public class WebView extends AbsoluteLayout
// reverse direction means lock in the snap mode
if ((ax > MAX_SLOPE_FOR_DIAG * ay) &&
((mSnapPositive &&
- deltaX < -MIN_LOCK_SNAP_REVERSE_DISTANCE)
+ deltaX < -mMinLockSnapReverseDistance)
|| (!mSnapPositive &&
- deltaX > MIN_LOCK_SNAP_REVERSE_DISTANCE))) {
+ deltaX > mMinLockSnapReverseDistance))) {
mSnapScrollMode = SNAP_X_LOCK;
}
} else {
@@ -3533,9 +3671,9 @@ public class WebView extends AbsoluteLayout
// reverse direction means lock in the snap mode
if ((ay > MAX_SLOPE_FOR_DIAG * ax) &&
((mSnapPositive &&
- deltaY < -MIN_LOCK_SNAP_REVERSE_DISTANCE)
+ deltaY < -mMinLockSnapReverseDistance)
|| (!mSnapPositive &&
- deltaY > MIN_LOCK_SNAP_REVERSE_DISTANCE))) {
+ deltaY > mMinLockSnapReverseDistance))) {
mSnapScrollMode = SNAP_Y_LOCK;
}
}
@@ -3557,18 +3695,6 @@ public class WebView extends AbsoluteLayout
mLastTouchTime = eventTime;
mUserScroll = true;
}
-
- 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
@@ -3577,22 +3703,19 @@ public class WebView extends AbsoluteLayout
break;
}
case MotionEvent.ACTION_UP: {
+ mLastTouchUpTime = eventTime;
switch (mTouchMode) {
case TOUCH_INIT_MODE: // tap
+ case TOUCH_SHORTPRESS_START_MODE:
+ case TOUCH_SHORTPRESS_MODE:
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
- if (getSettings().supportZoom()) {
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(RELEASE_SINGLE_TAP),
- DOUBLE_TAP_TIMEOUT);
- } else {
- // do short press now
- mTouchMode = TOUCH_DONE_MODE;
- doShortPress();
- }
+ mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
+ mTouchMode = TOUCH_DONE_MODE;
+ doShortPress();
break;
case TOUCH_SELECT_MODE:
commitCopy();
- mTouchSelection = mExtendSelection = false;
+ mTouchSelection = false;
break;
case SCROLL_ZOOM_ANIMATION_IN:
case SCROLL_ZOOM_ANIMATION_OUT:
@@ -3616,28 +3739,6 @@ public class WebView extends AbsoluteLayout
invalidate();
}
break;
- case TOUCH_SHORTPRESS_START_MODE:
- case TOUCH_SHORTPRESS_MODE: {
- mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- if (eventTime - mLastTouchTime < TAP_TIMEOUT
- && getSettings().supportZoom()) {
- // Note: window manager will not release ACTION_UP
- // until all the previous action events are
- // returned. If GC happens, it can cause
- // SWITCH_TO_SHORTPRESS message fired before
- // ACTION_UP sent even time stamp of ACTION_UP is
- // less than the tap time out. We need to treat this
- // as tap instead of short press.
- mTouchMode = TOUCH_INIT_MODE;
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(RELEASE_SINGLE_TAP),
- DOUBLE_TAP_TIMEOUT);
- } else {
- mTouchMode = TOUCH_DONE_MODE;
- doShortPress();
- }
- break;
- }
case TOUCH_DRAG_MODE:
// if the user waits a while w/o moving before the
// up, we don't want to do a fling
@@ -3678,7 +3779,6 @@ public class WebView extends AbsoluteLayout
}
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
mTouchMode = TOUCH_DONE_MODE;
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
@@ -3705,6 +3805,7 @@ public class WebView extends AbsoluteLayout
private static final int TRACKBALL_WAIT = 100;
private static final int TRACKBALL_SCALE = 400;
private static final int TRACKBALL_SCROLL_COUNT = 5;
+ private static final int TRACKBALL_MOVE_COUNT = 10;
private static final int TRACKBALL_MULTIPLIER = 3;
private static final int SELECT_CURSOR_OFFSET = 16;
private int mSelectX = 0;
@@ -3740,7 +3841,7 @@ public class WebView extends AbsoluteLayout
mPrivateHandler.removeMessages(SWITCH_TO_ENTER);
mTrackballDown = true;
if (mNativeClass != 0) {
- nativeRecordButtons(true, true);
+ nativeRecordButtons(hasFocus() && hasWindowFocus(), true, true);
}
if (time - mLastFocusTime <= TRACKBALL_TIMEOUT
&& !mLastFocusBounds.equals(nativeGetFocusRingBounds())) {
@@ -3751,6 +3852,7 @@ public class WebView extends AbsoluteLayout
+ " time=" + time
+ " mLastFocusTime=" + mLastFocusTime);
}
+ if (isInTouchMode()) requestFocusFromTouch();
return false; // let common code in onKeyDown at it
}
if (ev.getAction() == MotionEvent.ACTION_UP) {
@@ -3759,7 +3861,11 @@ public class WebView extends AbsoluteLayout
mTrackballDown = false;
mTrackballUpTime = time;
if (mShiftIsPressed) {
- mExtendSelection = true;
+ if (mExtendSelection) {
+ commitCopy();
+ } else {
+ mExtendSelection = true;
+ }
}
if (LOGV_ENABLED) {
Log.v(LOGTAG, "onTrackballEvent up ev=" + ev
@@ -3836,7 +3942,7 @@ public class WebView extends AbsoluteLayout
int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
: mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
: 0;
- pinScrollBy(scrollX, scrollY, true);
+ pinScrollBy(scrollX, scrollY, true, 0);
Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
requestRectangleOnScreen(select);
invalidate();
@@ -3942,6 +4048,7 @@ public class WebView extends AbsoluteLayout
KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN :
mTrackballRemainsX < 0 ? KeyEvent.KEYCODE_DPAD_LEFT :
KeyEvent.KEYCODE_DPAD_RIGHT;
+ count = Math.min(count, TRACKBALL_MOVE_COUNT);
if (LOGV_ENABLED) {
Log.v(LOGTAG, "doTrackball keyCode=" + selectKeyCode
+ " count=" + count
@@ -3971,7 +4078,7 @@ public class WebView extends AbsoluteLayout
yMove = 0;
}
if (xMove != 0 || yMove != 0) {
- pinScrollBy(xMove, yMove, true);
+ pinScrollBy(xMove, yMove, true, 0);
}
mUserScroll = true;
}
@@ -4044,43 +4151,30 @@ 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.
+ * <p/>
+ * From 1.5, WebView change to use ZoomButtonsController. This will return
+ * an invisible dummy view for backwards compatibility.
*/
public View getZoomControls() {
- 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;
+ return mZoomButtonsController.getDummyZoomControls();
+ }
+
+ /**
+ * Gets the {@link ZoomButtonsController} which can be used to add
+ * additional buttons to the zoom controls window.
+ *
+ * @return The instance of {@link ZoomButtonsController} used by this class,
+ * or null if it is unavailable.
+ * @hide pending API council
+ */
+ public ZoomButtonsController getZoomButtonsController() {
+ return mZoomButtonsController;
}
/**
@@ -4103,38 +4197,6 @@ public class WebView extends AbsoluteLayout
return zoomWithPreview(mActualScale * 0.8f);
}
- 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;
- }
-
private void updateSelection() {
if (mNativeClass == 0) {
return;
@@ -4142,9 +4204,8 @@ public class WebView extends AbsoluteLayout
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
- int contentSize = ViewConfiguration.getTouchSlop();
- Rect rect = new Rect(contentX - contentSize, contentY - contentSize,
- contentX + contentSize, contentY + contentSize);
+ Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
+ contentX + mNavSlop, contentY + mNavSlop);
// If we were already focused on a textfield, update its cache.
if (inEditingMode()) {
mTextEntry.updateCachedTextfield();
@@ -4157,8 +4218,7 @@ public class WebView extends AbsoluteLayout
View v = mTextEntry;
int x = viewToContent((v.getLeft() + v.getRight()) >> 1);
int y = viewToContent((v.getTop() + v.getBottom()) >> 1);
- int contentSize = ViewConfiguration.getTouchSlop();
- nativeMotionUp(x, y, contentSize, true);
+ nativeMotionUp(x, y, mNavSlop, true);
}
}
@@ -4167,22 +4227,25 @@ public class WebView extends AbsoluteLayout
return;
}
switchOutDrawHistory();
- // call uiOverride to check whether it is a special node,
- // phone/email/address, which are not handled by WebKit
- if (nativeUpdateFocusNode()) {
- FocusNode node = mFocusNode;
- if (!node.mIsTextField && !node.mIsTextArea) {
- if (mCallbackProxy.uiOverrideUrlLoading(node.mText)) {
- return;
- }
- }
- playSoundEffect(SoundEffectConstants.CLICK);
- }
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
- int contentSize = ViewConfiguration.getTouchSlop();
- nativeMotionUp(contentX, contentY, contentSize, true);
+ if (nativeMotionUp(contentX, contentY, mNavSlop, true)) {
+ if (mLogEvent) {
+ Checkin.updateStats(mContext.getContentResolver(),
+ Checkin.Stats.Tag.BROWSER_SNAP_CENTER, 1, 0.0);
+ }
+ }
+ if (nativeUpdateFocusNode() && !mFocusNode.mIsTextField
+ && !mFocusNode.mIsTextArea) {
+ playSoundEffect(SoundEffectConstants.CLICK);
+ }
+ }
+
+ // Called by JNI to handle a touch on a node representing an email address,
+ // address, or phone number
+ private void overrideLoading(String url) {
+ mCallbackProxy.uiOverrideUrlLoading(url);
}
@Override
@@ -4309,7 +4372,7 @@ public class WebView extends AbsoluteLayout
}
if ((scrollYDelta | scrollXDelta) != 0) {
- return pinScrollBy(scrollXDelta, scrollYDelta, !immediate);
+ return pinScrollBy(scrollXDelta, scrollYDelta, !immediate, 0);
}
return false;
@@ -4322,6 +4385,7 @@ public class WebView extends AbsoluteLayout
arg.put("replace", replace);
arg.put("start", new Integer(newStart));
arg.put("end", new Integer(newEnd));
+ mTextGeneration++;
mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg);
}
@@ -4357,6 +4421,11 @@ public class WebView extends AbsoluteLayout
class PrivateHandler extends Handler {
@Override
public void handleMessage(Message msg) {
+ if (LOGV_ENABLED) {
+ Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what
+ > INVAL_RECT_MSG_ID ? Integer.toString(msg.what)
+ : HandlerDebugString[msg.what - REMEMBER_PASSWORD]);
+ }
switch (msg.what) {
case REMEMBER_PASSWORD: {
mDatabase.setUsernamePassword(
@@ -4385,11 +4454,6 @@ public class WebView extends AbsoluteLayout
updateTextEntry();
break;
}
- case RELEASE_SINGLE_TAP: {
- mTouchMode = TOUCH_DONE_MODE;
- doShortPress();
- break;
- }
case SWITCH_TO_ENTER:
if (LOGV_ENABLED) Log.v(LOGTAG, "SWITCH_TO_ENTER");
mTouchMode = TOUCH_DONE_MODE;
@@ -4398,7 +4462,7 @@ public class WebView extends AbsoluteLayout
, KeyEvent.KEYCODE_ENTER));
break;
case SCROLL_BY_MSG_ID:
- setContentScrollBy(msg.arg1, msg.arg2);
+ setContentScrollBy(msg.arg1, msg.arg2, (Boolean) msg.obj);
break;
case SYNC_SCROLL_TO_MSG_ID:
if (mUserScroll) {
@@ -4436,6 +4500,10 @@ public class WebView extends AbsoluteLayout
0, 0);
}
}
+ if (!mMinZoomScaleFixed) {
+ mMinZoomScale = (float) getViewWidth()
+ / Math.max(ZOOM_OUT_WIDTH, draw.mWidthHeight.x);
+ }
// We update the layout (i.e. request a layout from the
// view system) if the last view size that we sent to
// WebCore matches the view size of the picture we just
@@ -4494,8 +4562,10 @@ public class WebView extends AbsoluteLayout
int minScale = (Integer) scaleLimit.get("minScale");
if (minScale == 0) {
mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+ mMinZoomScaleFixed = false;
} else {
mMinZoomScale = (float) (minScale / 100.0);
+ mMinZoomScaleFixed = true;
}
int maxScale = (Integer) scaleLimit.get("maxScale");
if (maxScale == 0) {
@@ -4544,6 +4614,15 @@ public class WebView extends AbsoluteLayout
}
break;
case UPDATE_TEXT_ENTRY_MSG_ID:
+ // this is sent after finishing resize in WebViewCore. Make
+ // sure the text edit box is still on the screen.
+ boolean alreadyThere = inEditingMode();
+ if (alreadyThere && nativeUpdateFocusNode()) {
+ FocusNode node = mFocusNode;
+ if (node.mIsTextField || node.mIsTextArea) {
+ mTextEntry.bringIntoView();
+ }
+ }
updateTextEntry();
break;
case RECOMPUTE_FOCUS_MSG_ID:
@@ -4551,6 +4630,17 @@ public class WebView extends AbsoluteLayout
nativeRecomputeFocus();
}
break;
+ case INVAL_RECT_MSG_ID: {
+ Rect r = (Rect)msg.obj;
+ if (r == null) {
+ invalidate();
+ } else {
+ // we need to scale r from content into view coords,
+ // which viewInvalidate() does for us
+ viewInvalidate(r.left, r.top, r.right, r.bottom);
+ }
+ break;
+ }
case UPDATE_TEXT_ENTRY_ADAPTER:
HashMap data = (HashMap) msg.obj;
if (mTextEntry.isSameTextField(msg.arg1)) {
@@ -4595,12 +4685,12 @@ public class WebView extends AbsoluteLayout
break;
case PREVENT_TOUCH_ID:
- // update may have already been paused by touch; restore since
- // this effectively aborts touch and skips logic in touch up
- if (mTouchMode == TOUCH_DRAG_MODE) {
- WebViewCore.resumeUpdate(mWebViewCore);
+ if (msg.arg1 == MotionEvent.ACTION_DOWN) {
+ mPreventDrag = msg.arg2 == 1;
+ if (mPreventDrag) {
+ mTouchMode = TOUCH_DONE_MODE;
+ }
}
- mTouchMode = TOUCH_DONE_MODE;
break;
default:
@@ -4764,8 +4854,16 @@ public class WebView extends AbsoluteLayout
});
if (mSelection != -1) {
listView.setSelection(mSelection);
+ listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ listView.setItemChecked(mSelection, true);
}
}
+ dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ mWebViewCore.sendMessage(
+ EventHub.SINGLE_LISTBOX_CHOICE, -2, 0);
+ }
+ });
dialog.show();
}
}
@@ -4910,11 +5008,11 @@ public class WebView extends AbsoluteLayout
// FIXME: Necessary because ScrollView/ListView do not scroll left/right
int maxH = Math.min(viewFocus.right - visRect.right, maxXScroll);
if (maxH > 0) {
- pinScrollBy(maxH, 0, true);
+ pinScrollBy(maxH, 0, true, 0);
} else {
maxH = Math.max(viewFocus.left - visRect.left, -maxXScroll);
if (maxH < 0) {
- pinScrollBy(maxH, 0, true);
+ pinScrollBy(maxH, 0, true, 0);
}
}
if (mLastFocusBounds.isEmpty()) return keyHandled;
@@ -4967,8 +5065,10 @@ public class WebView extends AbsoluteLayout
private native boolean nativeUpdateFocusNode();
private native Rect nativeGetFocusRingBounds();
private native Rect nativeGetNavBounds();
+ private native void nativeInstrumentReport();
private native void nativeMarkNodeInvalid(int node);
- private native void nativeMotionUp(int x, int y, int slop, boolean isClick);
+ // return true if the page has been scrolled
+ private native boolean nativeMotionUp(int x, int y, int slop, boolean isClick);
// returns false if it handled the key
private native boolean nativeMoveFocus(int keyCode, int count,
boolean noScroll);
@@ -4976,8 +5076,8 @@ public class WebView extends AbsoluteLayout
private native void nativeRecomputeFocus();
// Like many other of our native methods, you must make sure that
// mNativeClass is not null before calling this method.
- private native void nativeRecordButtons(boolean pressed,
- boolean invalidate);
+ private native void nativeRecordButtons(boolean focused,
+ boolean pressed, boolean invalidate);
private native void nativeResetFocus();
private native void nativeResetNavClipBounds();
private native void nativeSelectBestAt(Rect rect);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 323b44d..3e4daf7 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -317,7 +317,7 @@ final class WebViewCore {
should this be called nativeSetViewPortSize?
*/
private native void nativeSetSize(int width, int height, int screenWidth,
- float scale);
+ float scale, int realScreenWidth, int screenHeight);
private native int nativeGetContentMinPrefWidth();
@@ -330,8 +330,7 @@ final class WebViewCore {
String currentText, int keyCode, int keyValue, boolean down,
boolean cap, boolean fn, boolean sym);
- private native void nativeSaveDocumentState(int frame, int node, int x,
- int y);
+ private native void nativeSaveDocumentState(int frame);
private native void nativeSetFinalFocus(int framePtr, int nodePtr, int x,
int y, boolean block);
@@ -502,6 +501,51 @@ final class WebViewCore {
int mY;
}
+ static final String[] HandlerDebugString = {
+ "LOAD_URL", // = 100;
+ "STOP_LOADING", // = 101;
+ "RELOAD", // = 102;
+ "KEY_DOWN", // = 103;
+ "KEY_UP", // = 104;
+ "VIEW_SIZE_CHANGED", // = 105;
+ "GO_BACK_FORWARD", // = 106;
+ "SET_SCROLL_OFFSET", // = 107;
+ "RESTORE_STATE", // = 108;
+ "PAUSE_TIMERS", // = 109;
+ "RESUME_TIMERS", // = 110;
+ "CLEAR_CACHE", // = 111;
+ "CLEAR_HISTORY", // = 112;
+ "SET_SELECTION", // = 113;
+ "REPLACE_TEXT", // = 114;
+ "PASS_TO_JS", // = 115;
+ "SET_GLOBAL_BOUNDS", // = 116;
+ "UPDATE_CACHE_AND_TEXT_ENTRY", // = 117;
+ "CLICK", // = 118;
+ "119",
+ "DOC_HAS_IMAGES", // = 120;
+ "SET_SNAP_ANCHOR", // = 121;
+ "DELETE_SELECTION", // = 122;
+ "LISTBOX_CHOICES", // = 123;
+ "SINGLE_LISTBOX_CHOICE", // = 124;
+ "125",
+ "SET_BACKGROUND_COLOR", // = 126;
+ "UNBLOCK_FOCUS", // = 127;
+ "SAVE_DOCUMENT_STATE", // = 128;
+ "GET_SELECTION", // = 129;
+ "WEBKIT_DRAW", // = 130;
+ "SYNC_SCROLL", // = 131;
+ "REFRESH_PLUGINS", // = 132;
+ "SPLIT_PICTURE_SET", // = 133;
+ "CLEAR_CONTENT", // = 134;
+ "SET_FINAL_FOCUS", // = 135;
+ "SET_KIT_FOCUS", // = 136;
+ "REQUEST_FOCUS_HREF", // = 137;
+ "ADD_JS_INTERFACE", // = 138;
+ "LOAD_DATA", // = 139;
+ "TOUCH_UP", // = 140;
+ "TOUCH_EVENT", // = 141;
+ };
+
class EventHub {
// Message Ids
static final int LOAD_URL = 100;
@@ -596,6 +640,11 @@ final class WebViewCore {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
+ if (LOGV_ENABLED) {
+ Log.v(LOGTAG, msg.what < LOAD_URL || msg.what
+ > TOUCH_EVENT ? Integer.toString(msg.what)
+ : HandlerDebugString[msg.what - LOAD_URL]);
+ }
switch (msg.what) {
case WEBKIT_DRAW:
webkitDraw();
@@ -777,8 +826,7 @@ final class WebViewCore {
case SAVE_DOCUMENT_STATE: {
FocusData fDat = (FocusData) msg.obj;
- nativeSaveDocumentState(fDat.mFrame, fDat.mNode,
- fDat.mX, fDat.mY);
+ nativeSaveDocumentState(fDat.mFrame);
break;
}
@@ -799,12 +847,11 @@ final class WebViewCore {
case TOUCH_EVENT: {
TouchEventData ted = (TouchEventData) msg.obj;
- if (nativeHandleTouchEvent(ted.mAction, ted.mX,
- ted.mY)) {
- Message.obtain(mWebView.mPrivateHandler,
- WebView.PREVENT_TOUCH_ID)
- .sendToTarget();
- }
+ Message.obtain(
+ mWebView.mPrivateHandler,
+ WebView.PREVENT_TOUCH_ID, ted.mAction,
+ nativeHandleTouchEvent(ted.mAction, ted.mX,
+ ted.mY) ? 1 : 0).sendToTarget();
break;
}
@@ -1137,6 +1184,10 @@ final class WebViewCore {
// notify webkit that our virtual view size changed size (after inv-zoom)
private void viewSizeChanged(int w, int h, float scale) {
if (LOGV_ENABLED) Log.v(LOGTAG, "CORE onSizeChanged");
+ if (w == 0) {
+ Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
+ return;
+ }
if (mSettings.getUseWideViewPort()
&& (w < mViewportWidth || mViewportWidth == -1)) {
int width = mViewportWidth;
@@ -1160,9 +1211,10 @@ final class WebViewCore {
width = Math.max(w, nativeGetContentMinPrefWidth());
}
}
- nativeSetSize(width, Math.round((float) width * h / w), w, scale);
+ nativeSetSize(width, Math.round((float) width * h / w), w, scale,
+ w, h);
} else {
- nativeSetSize(w, h, w, scale);
+ nativeSetSize(w, h, w, scale, w, h);
}
// Remember the current width and height
boolean needInvalidate = (mCurrentViewWidth == 0);
@@ -1327,7 +1379,9 @@ final class WebViewCore {
for (int i = 0; i < size; i++) {
list.getItemAtIndex(i).inflate(mBrowserFrame.mNativeFrame);
}
+ mBrowserFrame.mLoadInitFromJava = true;
list.restoreIndex(mBrowserFrame.mNativeFrame, index);
+ mBrowserFrame.mLoadInitFromJava = false;
}
//-------------------------------------------------------------------------
@@ -1352,14 +1406,15 @@ final class WebViewCore {
}
// called by JNI
- private void contentScrollBy(int dx, int dy) {
+ private void contentScrollBy(int dx, int dy, boolean animate) {
if (!mBrowserFrame.firstLayoutDone()) {
// Will this happen? If yes, we need to do something here.
return;
}
if (mWebView != null) {
Message.obtain(mWebView.mPrivateHandler,
- WebView.SCROLL_BY_MSG_ID, dx, dy).sendToTarget();
+ WebView.SCROLL_BY_MSG_ID, dx, dy,
+ new Boolean(animate)).sendToTarget();
}
}
@@ -1434,10 +1489,15 @@ final class WebViewCore {
}
}
- // called by JNI
+ /* Called by JNI. The coordinates are in doc coordinates, so they need to
+ be scaled before they can be used by the view system, which happens
+ in WebView since it (and its thread) know the current scale factor.
+ */
private void sendViewInvalidate(int left, int top, int right, int bottom) {
if (mWebView != null) {
- mWebView.postInvalidate(left, top, right, bottom);
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.INVAL_RECT_MSG_ID,
+ new Rect(left, top, right, bottom)).sendToTarget();
}
}
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 96f3698..1004e30 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -531,33 +531,34 @@ public class WebViewDatabase {
* @param url The url
* @return CacheResult The CacheManager.CacheResult
*/
- @SuppressWarnings("deprecation")
CacheResult getCache(String url) {
if (url == null || mCacheDatabase == null) {
return null;
}
- CacheResult ret = null;
- final String s = "SELECT filepath, lastmodify, etag, expires, mimetype, encoding, httpstatus, location, contentlength FROM cache WHERE url = ";
- StringBuilder sb = new StringBuilder(256);
- sb.append(s);
- DatabaseUtils.appendEscapedSQLString(sb, url);
- Cursor cursor = mCacheDatabase.rawQuery(sb.toString(), null);
+ Cursor cursor = mCacheDatabase.rawQuery("SELECT filepath, lastmodify, etag, expires, "
+ + "mimetype, encoding, httpstatus, location, contentlength "
+ + "FROM cache WHERE url = ?",
+ new String[] { url });
- if (cursor.moveToFirst()) {
- ret = new CacheResult();
- ret.localPath = cursor.getString(0);
- ret.lastModified = cursor.getString(1);
- ret.etag = cursor.getString(2);
- ret.expires = cursor.getLong(3);
- ret.mimeType = cursor.getString(4);
- ret.encoding = cursor.getString(5);
- ret.httpStatusCode = cursor.getInt(6);
- ret.location = cursor.getString(7);
- ret.contentLength = cursor.getLong(8);
+ try {
+ if (cursor.moveToFirst()) {
+ CacheResult ret = new CacheResult();
+ ret.localPath = cursor.getString(0);
+ ret.lastModified = cursor.getString(1);
+ ret.etag = cursor.getString(2);
+ ret.expires = cursor.getLong(3);
+ ret.mimeType = cursor.getString(4);
+ ret.encoding = cursor.getString(5);
+ ret.httpStatusCode = cursor.getInt(6);
+ ret.location = cursor.getString(7);
+ ret.contentLength = cursor.getLong(8);
+ return ret;
+ }
+ } finally {
+ if (cursor != null) cursor.close();
}
- cursor.close();
- return ret;
+ return null;
}
/**
@@ -565,16 +566,12 @@ public class WebViewDatabase {
*
* @param url The url
*/
- @SuppressWarnings("deprecation")
void removeCache(String url) {
if (url == null || mCacheDatabase == null) {
return;
}
- StringBuilder sb = new StringBuilder(256);
- sb.append("DELETE FROM cache WHERE url = ");
- DatabaseUtils.appendEscapedSQLString(sb, url);
- mCacheDatabase.execSQL(sb.toString());
+ mCacheDatabase.execSQL("DELETE FROM cache WHERE url = ?", new String[] { url });
}
/**
diff --git a/core/java/android/webkit/gears/DesktopAndroid.java b/core/java/android/webkit/gears/DesktopAndroid.java
index ee8ca49..a7a144b 100644
--- a/core/java/android/webkit/gears/DesktopAndroid.java
+++ b/core/java/android/webkit/gears/DesktopAndroid.java
@@ -31,6 +31,7 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
+import android.provider.Browser;
import android.util.Log;
import android.webkit.WebView;
@@ -78,7 +79,10 @@ public class DesktopAndroid {
Intent viewWebPage = new Intent(Intent.ACTION_VIEW);
viewWebPage.setData(Uri.parse(url));
- viewWebPage.addCategory(Intent.CATEGORY_BROWSABLE);
+ long urlHash = url.hashCode();
+ long uniqueId = (urlHash << 32) | viewWebPage.hashCode();
+ viewWebPage.putExtra(Browser.EXTRA_APPLICATION_ID,
+ Long.toString(uniqueId));
Intent intent = new Intent(ACTION_INSTALL_SHORTCUT);
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, viewWebPage);
diff --git a/core/java/android/webkit/gears/GearsPluginSettings.java b/core/java/android/webkit/gears/GearsPluginSettings.java
deleted file mode 100644
index d36d3fb..0000000
--- a/core/java/android/webkit/gears/GearsPluginSettings.java
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2008 The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.util.Log;
-import android.webkit.Plugin;
-import android.webkit.Plugin.PreferencesClickHandler;
-
-/**
- * Simple bridge class intercepting the click in the
- * browser plugin list and calling the Gears settings
- * dialog.
- */
-public class GearsPluginSettings {
-
- private static final String TAG = "Gears-J-GearsPluginSettings";
- private Context context;
-
- public GearsPluginSettings(Plugin plugin) {
- plugin.setClickHandler(new ClickHandler());
- }
-
- /**
- * We do not need to call the dialog synchronously here (doing so
- * actually cause a lot of problems as the main message loop is also
- * blocked), which is why we simply call it via a thread.
- */
- private class ClickHandler implements PreferencesClickHandler {
- public void handleClickEvent(Context aContext) {
- context = aContext;
- Thread startService = new Thread(new StartService());
- startService.run();
- }
- }
-
- private static native void runSettingsDialog(Context c);
-
- /**
- * StartService is the runnable we use to open the dialog.
- * We bind the service to serviceConnection; upon
- * onServiceConnected the dialog will be called from the
- * native side using the runSettingsDialog method.
- */
- private class StartService implements Runnable {
- public void run() {
- HtmlDialogAndroid.bindToService(context, serviceConnection);
- }
- }
-
- /**
- * ServiceConnection instance.
- * onServiceConnected is called upon connection with the service;
- * we can then safely open the dialog.
- */
- private ServiceConnection serviceConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- IGearsDialogService gearsDialogService =
- IGearsDialogService.Stub.asInterface(service);
- HtmlDialogAndroid.setGearsDialogService(gearsDialogService);
- runSettingsDialog(context);
- context.unbindService(serviceConnection);
- HtmlDialogAndroid.setGearsDialogService(null);
- }
- public void onServiceDisconnected(ComponentName className) {
- HtmlDialogAndroid.setGearsDialogService(null);
- }
- };
-}
diff --git a/core/java/android/webkit/gears/HtmlDialogAndroid.java b/core/java/android/webkit/gears/HtmlDialogAndroid.java
deleted file mode 100644
index 6209ab9..0000000
--- a/core/java/android/webkit/gears/HtmlDialogAndroid.java
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2008 The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-import android.webkit.CacheManager;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-
-/**
- * Utility class to call a modal HTML dialog on Android
- */
-public class HtmlDialogAndroid {
-
- private static final String TAG = "Gears-J-HtmlDialog";
- private static final String DIALOG_PACKAGE = "com.android.browser";
- private static final String DIALOG_SERVICE = DIALOG_PACKAGE
- + ".GearsDialogService";
- private static final String DIALOG_INTERFACE = DIALOG_PACKAGE
- + ".IGearsDialogService";
-
- private static IGearsDialogService gearsDialogService;
-
- public static void setGearsDialogService(IGearsDialogService service) {
- gearsDialogService = service;
- }
-
- /**
- * Bind to the GearsDialogService.
- */
- public static boolean bindToService(Context context,
- ServiceConnection serviceConnection) {
- Intent dialogIntent = new Intent();
- dialogIntent.setClassName(DIALOG_PACKAGE, DIALOG_SERVICE);
- dialogIntent.setAction(DIALOG_INTERFACE);
- return context.bindService(dialogIntent, serviceConnection,
- Context.BIND_AUTO_CREATE);
- }
-
- /**
- * Bind to the GearsDialogService synchronously.
- * The service is started using our own defaultServiceConnection
- * handler, and we wait until the handler notifies us.
- */
- public void synchronousBindToService(Context context) {
- try {
- if (bindToService(context, defaultServiceConnection)) {
- if (gearsDialogService == null) {
- synchronized(defaultServiceConnection) {
- defaultServiceConnection.wait(3000); // timeout after 3s
- }
- }
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "exception: " + e);
- }
- }
-
- /**
- * Read the HTML content from the disk
- */
- public String readHTML(String filePath) {
- FileInputStream inputStream = null;
- String content = "";
- try {
- inputStream = new FileInputStream(filePath);
- StringBuffer out = new StringBuffer();
- byte[] buffer = new byte[4096];
- for (int n; (n = inputStream.read(buffer)) != -1;) {
- out.append(new String(buffer, 0, n));
- }
- content = out.toString();
- } catch (IOException e) {
- Log.e(TAG, "exception: " + e);
- } finally {
- if (inputStream != null) {
- try {
- inputStream.close();
- } catch (IOException e) {
- Log.e(TAG, "exception: " + e);
- }
- }
- }
- return content;
- }
-
- /**
- * Open an HTML dialog synchronously and waits for its completion.
- * The dialog is accessed through the GearsDialogService provided by
- * the Android Browser.
- * We can be called either directly, and then gearsDialogService will
- * not be set and we will bind to the service synchronously, and unbind
- * after calling the service, or called indirectly via GearsPluginSettings.
- * In the latter case, GearsPluginSettings does the binding/unbinding.
- */
- public String showDialog(Context context, String htmlFilePath,
- String arguments) {
-
- CacheManager.endCacheTransaction();
-
- String ret = null;
- boolean synchronousCall = false;
- if (gearsDialogService == null) {
- synchronousCall = true;
- synchronousBindToService(context);
- }
-
- try {
- if (gearsDialogService != null) {
- String htmlContent = readHTML(htmlFilePath);
- if (htmlContent.length() > 0) {
- ret = gearsDialogService.showDialog(htmlContent, arguments,
- !synchronousCall);
- }
- } else {
- Log.e(TAG, "Could not connect to the GearsDialogService!");
- }
- if (synchronousCall) {
- context.unbindService(defaultServiceConnection);
- gearsDialogService = null;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception: " + e);
- gearsDialogService = null;
- }
-
- CacheManager.startCacheTransaction();
-
- return ret;
- }
-
- private ServiceConnection defaultServiceConnection =
- new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- synchronized (defaultServiceConnection) {
- gearsDialogService = IGearsDialogService.Stub.asInterface(service);
- defaultServiceConnection.notify();
- }
- }
- public void onServiceDisconnected(ComponentName className) {
- gearsDialogService = null;
- }
- };
-}
diff --git a/core/java/android/webkit/gears/HttpRequestAndroid.java b/core/java/android/webkit/gears/HttpRequestAndroid.java
deleted file mode 100644
index 30f855f..0000000
--- a/core/java/android/webkit/gears/HttpRequestAndroid.java
+++ /dev/null
@@ -1,745 +0,0 @@
-// Copyright 2008, The Android Open Source Project
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// 3. Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-package android.webkit.gears;
-
-import android.net.http.Headers;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-import android.webkit.CacheManager;
-import android.webkit.CacheManager.CacheResult;
-import android.webkit.CookieManager;
-
-import org.apache.http.conn.ssl.StrictHostnameVerifier;
-import org.apache.http.impl.cookie.DateUtils;
-import org.apache.http.util.CharArrayBuffer;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import javax.net.ssl.*;
-
-/**
- * Performs the underlying HTTP/HTTPS GET and POST requests.
- * <p> These are performed synchronously (blocking). The caller should
- * ensure that it is in a background thread if asynchronous behavior
- * is required. All data is pushed, so there is no need for JNI native
- * callbacks.
- * <p> This uses the java.net.HttpURLConnection class to perform most
- * of the underlying network activity. The Android brower's cache,
- * android.webkit.CacheManager, is also used when caching is enabled,
- * and updated with new data. The android.webkit.CookieManager is also
- * queried and updated as necessary.
- * <p> The public interface is designed to be called by native code
- * through JNI, and to simplify coding none of the public methods will
- * surface a checked exception. Unchecked exceptions may still be
- * raised but only if the system is in an ill state, such as out of
- * memory.
- * <p> TODO: This isn't plumbed into LocalServer yet. Mutually
- * dependent on LocalServer - will attach the two together once both
- * are submitted.
- */
-public final class HttpRequestAndroid {
- /** Debug logging tag. */
- private static final String LOG_TAG = "Gears-J";
- /** HTTP response header line endings are CR-LF style. */
- private static final String HTTP_LINE_ENDING = "\r\n";
- /** Safe MIME type to use whenever it isn't specified. */
- private static final String DEFAULT_MIME_TYPE = "text/plain";
- /** Case-sensitive header keys */
- public static final String KEY_CONTENT_LENGTH = "Content-Length";
- public static final String KEY_EXPIRES = "Expires";
- public static final String KEY_LAST_MODIFIED = "Last-Modified";
- public static final String KEY_ETAG = "ETag";
- public static final String KEY_LOCATION = "Location";
- public static final String KEY_CONTENT_TYPE = "Content-Type";
- /** Number of bytes to send and receive on the HTTP connection in
- * one go. */
- private static final int BUFFER_SIZE = 4096;
- /** The first element of the String[] value in a headers map is the
- * unmodified (case-sensitive) key. */
- public static final int HEADERS_MAP_INDEX_KEY = 0;
- /** The second element of the String[] value in a headers map is the
- * associated value. */
- public static final int HEADERS_MAP_INDEX_VALUE = 1;
-
- /** Enable/disable all logging in this class. */
- private static boolean logEnabled = false;
- /** The underlying HTTP or HTTPS network connection. */
- private HttpURLConnection connection;
- /** HTTP body stream, setup after connection. */
- private InputStream inputStream;
- /** The complete response line e.g "HTTP/1.0 200 OK" */
- private String responseLine;
- /** Request headers, as a lowercase key -> [ unmodified key, value ] map. */
- private Map<String, String[]> requestHeaders =
- new HashMap<String, String[]>();
- /** Response headers, as a lowercase key -> [ unmodified key, value ] map. */
- private Map<String, String[]> responseHeaders;
- /** True if the child thread is in performing blocking IO. */
- private boolean inBlockingOperation = false;
- /** True when the thread acknowledges the abort. */
- private boolean abortReceived = false;
- /** The URL used for createCacheResult() */
- private String cacheResultUrl;
- /** CacheResult being saved into, if inserting a new cache entry. */
- private CacheResult cacheResult;
- /** Initialized by initChildThread(). Used to target abort(). */
- private Thread childThread;
-
- /**
- * Convenience debug function. Calls Android logging mechanism.
- * @param str String to log to the Android console.
- */
- private static void log(String str) {
- if (logEnabled) {
- Log.i(LOG_TAG, str);
- }
- }
-
- /**
- * Turn on/off logging in this class.
- * @param on Logging enable state.
- */
- public static void enableLogging(boolean on) {
- logEnabled = on;
- }
-
- /**
- * Initialize childThread using the TLS value of
- * Thread.currentThread(). Called on start up of the native child
- * thread.
- */
- public synchronized void initChildThread() {
- childThread = Thread.currentThread();
- }
-
- /**
- * Analagous to the native-side HttpRequest::open() function. This
- * initializes an underlying java.net.HttpURLConnection, but does
- * not go to the wire. On success, this enables a call to send() to
- * initiate the transaction.
- *
- * @param method The HTTP method, e.g GET or POST.
- * @param url The URL to open.
- * @return True on success with a complete HTTP response.
- * False on failure.
- */
- public synchronized boolean open(String method, String url) {
- if (logEnabled)
- log("open " + method + " " + url);
- // Reset the response between calls to open().
- inputStream = null;
- responseLine = null;
- responseHeaders = null;
- if (!method.equals("GET") && !method.equals("POST")) {
- log("Method " + method + " not supported");
- return false;
- }
- // Setup the connection. This doesn't go to the wire yet - it
- // doesn't block.
- try {
- URL url_object = new URL(url);
- // Check that the protocol is indeed HTTP(S).
- String protocol = url_object.getProtocol();
- if (protocol == null) {
- log("null protocol for URL " + url);
- return false;
- }
- protocol = protocol.toLowerCase();
- if (!"http".equals(protocol) && !"https".equals(protocol)) {
- log("Url has wrong protocol: " + url);
- return false;
- }
-
- connection = (HttpURLConnection) url_object.openConnection();
- connection.setRequestMethod(method);
- // Manually follow redirects.
- connection.setInstanceFollowRedirects(false);
- // Manually cache.
- connection.setUseCaches(false);
- // Enable data output in POST method requests.
- connection.setDoOutput(method.equals("POST"));
- // Enable data input in non-HEAD method requests.
- // TODO: HEAD requests not tested.
- connection.setDoInput(!method.equals("HEAD"));
- if (connection instanceof javax.net.ssl.HttpsURLConnection) {
- // Verify the certificate matches the origin.
- ((HttpsURLConnection) connection).setHostnameVerifier(
- new StrictHostnameVerifier());
- }
- return true;
- } catch (IOException e) {
- log("Got IOException in open: " + e.toString());
- return false;
- }
- }
-
- /**
- * Interrupt a blocking IO operation. This will cause the child
- * thread to expediently return from an operation if it was stuck at
- * the time. Note that this inherently races, and unfortunately
- * requires the caller to loop.
- */
- public synchronized void interrupt() {
- if (childThread == null) {
- log("interrupt() called but no child thread");
- return;
- }
- synchronized (this) {
- if (inBlockingOperation) {
- log("Interrupting blocking operation");
- childThread.interrupt();
- } else {
- log("Nothing to interrupt");
- }
- }
- }
-
- /**
- * Set a header to send with the HTTP request. Will not take effect
- * on a transaction already in progress. The key is associated
- * case-insensitive, but stored case-sensitive.
- * @param name The name of the header, e.g "Set-Cookie".
- * @param value The value for this header, e.g "text/html".
- */
- public synchronized void setRequestHeader(String name, String value) {
- String[] mapValue = { name, value };
- requestHeaders.put(name.toLowerCase(), mapValue);
- }
-
- /**
- * Returns the value associated with the given request header.
- * @param name The name of the request header, non-null, case-insensitive.
- * @return The value associated with the request header, or null if
- * not set, or error.
- */
- public synchronized String getRequestHeader(String name) {
- String[] value = requestHeaders.get(name.toLowerCase());
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- }
-
- /**
- * Returns the value associated with the given response header.
- * @param name The name of the response header, non-null, case-insensitive.
- * @return The value associated with the response header, or null if
- * not set or error.
- */
- public synchronized String getResponseHeader(String name) {
- if (responseHeaders != null) {
- String[] value = responseHeaders.get(name.toLowerCase());
- if (value != null) {
- return value[HEADERS_MAP_INDEX_VALUE];
- } else {
- return null;
- }
- } else {
- log("getResponseHeader() called but response not received");
- return null;
- }
- }
-
- /**
- * Set a response header and associated value. The key is associated
- * case-insensitively, but stored case-sensitively.
- * @param name Case sensitive request header key.
- * @param value The associated value.
- */
- private void setResponseHeader(String name, String value) {
- if (logEnabled)
- log("Set response header " + name + ": " + value);
- String mapValue[] = { name, value };
- responseHeaders.put(name.toLowerCase(), mapValue);
- }
-
- /**
- * Apply the contents of the Map requestHeaders to the connection
- * object. Calls to setRequestHeader() after this will not affect
- * the connection.
- */
- private synchronized void applyRequestHeadersToConnection() {
- Iterator<String[]> it = requestHeaders.values().iterator();
- while (it.hasNext()) {
- // Set the key case-sensitive.
- String[] entry = it.next();
- connection.setRequestProperty(
- entry[HEADERS_MAP_INDEX_KEY],
- entry[HEADERS_MAP_INDEX_VALUE]);
- }
- }
-
- /**
- * Return all response headers, separated by CR-LF line endings, and
- * ending with a trailing blank line. This mimics the format of the
- * raw response header up to but not including the body.
- * @return A string containing the entire response header.
- */
- public synchronized String getAllResponseHeaders() {
- if (responseHeaders == null) {
- log("getAllResponseHeaders() called but response not received");
- return null;
- }
- String result = new String();
- Iterator<String[]> it = responseHeaders.values().iterator();
- while (it.hasNext()) {
- String[] entry = it.next();
- // Output the "key: value" lines.
- result += entry[HEADERS_MAP_INDEX_KEY] + ": "
- + entry[HEADERS_MAP_INDEX_VALUE] + HTTP_LINE_ENDING;
- }
- result += HTTP_LINE_ENDING;
- return result;
- }
-
- /**
- * Get the complete response line of the HTTP request. Only valid on
- * completion of the transaction.
- * @return The complete HTTP response line, e.g "HTTP/1.0 200 OK".
- */
- public synchronized String getResponseLine() {
- return responseLine;
- }
-
- /**
- * Get the cookie for the given URL.
- * @param url The fully qualified URL.
- * @return A string containing the cookie for the URL if it exists,
- * or null if not.
- */
- public static String getCookieForUrl(String url) {
- // Get the cookie for this URL, set as a header
- return CookieManager.getInstance().getCookie(url);
- }
-
- /**
- * Set the cookie for the given URL.
- * @param url The fully qualified URL.
- * @param cookie The new cookie value.
- * @return A string containing the cookie for the URL if it exists,
- * or null if not.
- */
- public static void setCookieForUrl(String url, String cookie) {
- // Get the cookie for this URL, set as a header
- CookieManager.getInstance().setCookie(url, cookie);
- }
-
- /**
- * Perform a request using LocalServer if possible. Initializes
- * class members so that receive() will obtain data from the stream
- * provided by the response.
- * @param url The fully qualified URL to try in LocalServer.
- * @return True if the url was found and is now setup to receive.
- * False if not found, with no side-effect.
- */
- public synchronized boolean useLocalServerResult(String url) {
- UrlInterceptHandlerGears handler = UrlInterceptHandlerGears.getInstance();
- if (handler == null) {
- return false;
- }
- UrlInterceptHandlerGears.ServiceResponse serviceResponse =
- handler.getServiceResponse(url, requestHeaders);
- if (serviceResponse == null) {
- log("No response in LocalServer");
- return false;
- }
- // LocalServer will handle this URL. Initialize stream and
- // response.
- inputStream = serviceResponse.getInputStream();
- responseLine = serviceResponse.getStatusLine();
- responseHeaders = serviceResponse.getResponseHeaders();
- if (logEnabled)
- log("Got response from LocalServer: " + responseLine);
- return true;
- }
-
- /**
- * Perform a request using the cache result if present. Initializes
- * class members so that receive() will obtain data from the cache.
- * @param url The fully qualified URL to try in the cache.
- * @return True is the url was found and is now setup to receive
- * from cache. False if not found, with no side-effect.
- */
- public synchronized boolean useCacheResult(String url) {
- // Try the browser's cache. CacheManager wants a Map<String, String>.
- Map<String, String> cacheRequestHeaders = new HashMap<String, String>();
- Iterator<Map.Entry<String, String[]>> it =
- requestHeaders.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<String, String[]> entry = it.next();
- cacheRequestHeaders.put(
- entry.getKey(),
- entry.getValue()[HEADERS_MAP_INDEX_VALUE]);
- }
- CacheResult cacheResult =
- CacheManager.getCacheFile(url, cacheRequestHeaders);
- if (cacheResult == null) {
- if (logEnabled)
- log("No CacheResult for " + url);
- return false;
- }
- if (logEnabled)
- log("Got CacheResult from browser cache");
- // Check for expiry. -1 is "never", otherwise milliseconds since 1970.
- // Can be compared to System.currentTimeMillis().
- long expires = cacheResult.getExpires();
- if (expires >= 0 && System.currentTimeMillis() >= expires) {
- log("CacheResult expired "
- + (System.currentTimeMillis() - expires)
- + " milliseconds ago");
- // Cache hit has expired. Do not return it.
- return false;
- }
- // Setup the inputStream to come from the cache.
- inputStream = cacheResult.getInputStream();
- if (inputStream == null) {
- // Cache result may have gone away.
- log("No inputStream for CacheResult " + url);
- return false;
- }
- // Cache hit. Parse headers.
- synthesizeHeadersFromCacheResult(cacheResult);
- return true;
- }
-
- /**
- * Take the limited set of headers in a CacheResult and synthesize
- * response headers.
- * @param cacheResult A CacheResult to populate responseHeaders with.
- */
- private void synthesizeHeadersFromCacheResult(CacheResult cacheResult) {
- int statusCode = cacheResult.getHttpStatusCode();
- // The status message is informal, so we can greatly simplify it.
- String statusMessage;
- if (statusCode >= 200 && statusCode < 300) {
- statusMessage = "OK";
- } else if (statusCode >= 300 && statusCode < 400) {
- statusMessage = "MOVED";
- } else {
- statusMessage = "UNAVAILABLE";
- }
- // Synthesize the response line.
- responseLine = "HTTP/1.1 " + statusCode + " " + statusMessage;
- if (logEnabled)
- log("Synthesized " + responseLine);
- // Synthesize the returned headers from cache.
- responseHeaders = new HashMap<String, String[]>();
- String contentLength = Long.toString(cacheResult.getContentLength());
- setResponseHeader(KEY_CONTENT_LENGTH, contentLength);
- long expires = cacheResult.getExpires();
- if (expires >= 0) {
- // "Expires" header is valid and finite. Milliseconds since 1970
- // epoch, formatted as RFC-1123.
- String expiresString = DateUtils.formatDate(new Date(expires));
- setResponseHeader(KEY_EXPIRES, expiresString);
- }
- String lastModified = cacheResult.getLastModified();
- if (lastModified != null) {
- // Last modification time of the page. Passed end-to-end, but
- // not used by us.
- setResponseHeader(KEY_LAST_MODIFIED, lastModified);
- }
- String eTag = cacheResult.getETag();
- if (eTag != null) {
- // Entity tag. A kind of GUID to identify identical resources.
- setResponseHeader(KEY_ETAG, eTag);
- }
- String location = cacheResult.getLocation();
- if (location != null) {
- // If valid, refers to the location of a redirect.
- setResponseHeader(KEY_LOCATION, location);
- }
- String mimeType = cacheResult.getMimeType();
- if (mimeType == null) {
- // Use a safe default MIME type when none is
- // specified. "text/plain" is safe to render in the browser
- // window (even if large) and won't be intepreted as anything
- // that would cause execution.
- mimeType = DEFAULT_MIME_TYPE;
- }
- String encoding = cacheResult.getEncoding();
- // Encoding may not be specified. No default.
- String contentType = mimeType;
- if (encoding != null && encoding.length() > 0) {
- contentType += "; charset=" + encoding;
- }
- setResponseHeader(KEY_CONTENT_TYPE, contentType);
- }
-
- /**
- * Create a CacheResult for this URL. This enables the repsonse body
- * to be sent in calls to appendCacheResult().
- * @param url The fully qualified URL to add to the cache.
- * @param responseCode The response code returned for the request, e.g 200.
- * @param mimeType The MIME type of the body, e.g "text/plain".
- * @param encoding The encoding, e.g "utf-8". Use "" for unknown.
- */
- public synchronized boolean createCacheResult(
- String url, int responseCode, String mimeType, String encoding) {
- if (logEnabled)
- log("Making cache entry for " + url);
- // Take the headers and parse them into a format needed by
- // CacheManager.
- Headers cacheHeaders = new Headers();
- Iterator<Map.Entry<String, String[]>> it =
- responseHeaders.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<String, String[]> entry = it.next();
- // Headers.parseHeader() expects lowercase keys.
- String keyValue = entry.getKey() + ": "
- + entry.getValue()[HEADERS_MAP_INDEX_VALUE];
- CharArrayBuffer buffer = new CharArrayBuffer(keyValue.length());
- buffer.append(keyValue);
- // Parse it into the header container.
- cacheHeaders.parseHeader(buffer);
- }
- cacheResult = CacheManager.createCacheFile(
- url, responseCode, cacheHeaders, mimeType, true);
- if (cacheResult != null) {
- if (logEnabled)
- log("Saving into cache");
- cacheResult.setEncoding(encoding);
- cacheResultUrl = url;
- return true;
- } else {
- log("Couldn't create cacheResult");
- return false;
- }
- }
-
- /**
- * Add data from the response body to the CacheResult created with
- * createCacheResult().
- * @param data A byte array of the next sequential bytes in the
- * response body.
- * @param bytes The number of bytes to write from the start of
- * the array.
- * @return True if all bytes successfully written, false on failure.
- */
- public synchronized boolean appendCacheResult(byte[] data, int bytes) {
- if (cacheResult == null) {
- log("appendCacheResult() called without a CacheResult initialized");
- return false;
- }
- try {
- cacheResult.getOutputStream().write(data, 0, bytes);
- } catch (IOException ex) {
- log("Got IOException writing cache data: " + ex);
- return false;
- }
- return true;
- }
-
- /**
- * Save the completed CacheResult into the CacheManager. This must
- * have been created first with createCacheResult().
- * @return Returns true if the entry has been successfully saved.
- */
- public synchronized boolean saveCacheResult() {
- if (cacheResult == null || cacheResultUrl == null) {
- log("Tried to save cache result but createCacheResult not called");
- return false;
- }
- if (logEnabled)
- log("Saving cache result");
- CacheManager.saveCacheFile(cacheResultUrl, cacheResult);
- cacheResult = null;
- cacheResultUrl = null;
- return true;
- }
-
- /**
- * Perform an HTTP request on the network. The underlying
- * HttpURLConnection is connected to the remote server and the
- * response headers are received.
- * @return True if the connection succeeded and headers have been
- * received. False on connection failure.
- */
- public boolean connectToRemote() {
- synchronized (this) {
- // Transfer a snapshot of our internally maintained map of request
- // headers to the connection object.
- applyRequestHeadersToConnection();
- // Note blocking I/O so abort() can interrupt us.
- inBlockingOperation = true;
- }
- boolean success;
- try {
- if (logEnabled)
- log("Connecting to remote");
- connection.connect();
- if (logEnabled)
- log("Connected");
- success = true;
- } catch (IOException e) {
- log("Got IOException in connect(): " + e.toString());
- success = false;
- } finally {
- synchronized (this) {
- // No longer blocking.
- inBlockingOperation = false;
- }
- }
- return success;
- }
-
- /**
- * Receive all headers from the server and populate
- * responseHeaders. This converts from the slightly odd format
- * returned by java.net.HttpURLConnection to a simpler
- * java.util.Map.
- * @return True if headers are successfully received, False on
- * connection error.
- */
- public synchronized boolean parseHeaders() {
- responseHeaders = new HashMap<String, String[]>();
- /* HttpURLConnection contains a null terminated list of
- * key->value response pairs. If the key is null, then the value
- * contains the complete status line. If both key and value are
- * null for an index, we've reached the end.
- */
- for (int i = 0; ; ++i) {
- String key = connection.getHeaderFieldKey(i);
- String value = connection.getHeaderField(i);
- if (logEnabled)
- log("header " + key + " -> " + value);
- if (key == null && value == null) {
- // End of list.
- break;
- } else if (key == null) {
- // The pair with null key has the complete status line in
- // the value, e.g "HTTP/1.0 200 OK".
- responseLine = value;
- } else if (value != null) {
- // If key and value are non-null, this is a response pair, e.g
- // "Content-Length" -> "5". Use setResponseHeader() to
- // correctly deal with case-insensitivity of the key.
- setResponseHeader(key, value);
- } else {
- // The key is non-null but value is null. Unexpected
- // condition.
- return false;
- }
- }
- return true;
- }
-
- /**
- * Receive the next sequential bytes of the response body after
- * successful connection. This will receive up to the size of the
- * provided byte array. If there is no body, this will return 0
- * bytes on the first call after connection.
- * @param buf A pre-allocated byte array to receive data into.
- * @return The number of bytes from the start of the array which
- * have been filled, 0 on EOF, or negative on error.
- */
- public int receive(byte[] buf) {
- if (inputStream == null) {
- // If this is the first call, setup the InputStream. This may
- // fail if there were headers, but no body returned by the
- // server.
- try {
- inputStream = connection.getInputStream();
- } catch (IOException inputException) {
- log("Failed to connect InputStream: " + inputException);
- // Not unexpected. For example, 404 response return headers,
- // and sometimes a body with a detailed error. Try the error
- // stream.
- inputStream = connection.getErrorStream();
- if (inputStream == null) {
- // No error stream either. Treat as a 0 byte response.
- log("No InputStream");
- return 0; // EOF.
- }
- }
- }
- synchronized (this) {
- // Note blocking I/O so abort() can interrupt us.
- inBlockingOperation = true;
- }
- int ret;
- try {
- int got = inputStream.read(buf);
- if (got > 0) {
- // Got some bytes, not EOF.
- ret = got;
- } else {
- // EOF.
- inputStream.close();
- ret = 0;
- }
- } catch (IOException e) {
- // An abort() interrupts us by calling close() on our stream.
- log("Got IOException in inputStream.read(): " + e.toString());
- ret = -1;
- } finally {
- synchronized (this) {
- // No longer blocking.
- inBlockingOperation = false;
- }
- }
- return ret;
- }
-
- /**
- * For POST method requests, send a stream of data provided by the
- * native side in repeated callbacks.
- * @param data A byte array containing the data to sent, or null
- * if indicating EOF.
- * @param bytes The number of bytes from the start of the array to
- * send, or 0 if indicating EOF.
- * @return True if all bytes were successfully sent, false on error.
- */
- public boolean sendPostData(byte[] data, int bytes) {
- synchronized (this) {
- // Note blocking I/O so abort() can interrupt us.
- inBlockingOperation = true;
- }
- boolean success;
- try {
- OutputStream outputStream = connection.getOutputStream();
- if (data == null && bytes == 0) {
- outputStream.close();
- } else {
- outputStream.write(data, 0, bytes);
- }
- success = true;
- } catch (IOException e) {
- log("Got IOException in post: " + e.toString());
- success = false;
- } finally {
- synchronized (this) {
- // No longer blocking.
- inBlockingOperation = false;
- }
- }
- return success;
- }
-}
diff --git a/core/java/android/webkit/gears/IGearsDialogService.java b/core/java/android/webkit/gears/IGearsDialogService.java
deleted file mode 100644
index 82a3bd9..0000000
--- a/core/java/android/webkit/gears/IGearsDialogService.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * This file is auto-generated. DO NOT MODIFY.
- * Original file: android.webkit.gears/IGearsDialogService.aidl
- */
-package android.webkit.gears;
-import java.lang.String;
-import android.os.RemoteException;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.os.Binder;
-import android.os.Parcel;
-public interface IGearsDialogService extends android.os.IInterface
-{
-/** Local-side IPC implementation stub class. */
-public static abstract class Stub extends android.os.Binder implements android.webkit.gears.IGearsDialogService
-{
-private static final java.lang.String DESCRIPTOR = "com.android.browser.IGearsDialogService";
-/** Construct the stub at attach it to the interface. */
-public Stub()
-{
-this.attachInterface(this, DESCRIPTOR);
-}
-/**
- * Cast an IBinder object into an IGearsDialogService interface,
- * generating a proxy if needed.
- */
-public static android.webkit.gears.IGearsDialogService asInterface(android.os.IBinder obj)
-{
-if ((obj==null)) {
-return null;
-}
-android.webkit.gears.IGearsDialogService in = (android.webkit.gears.IGearsDialogService)obj.queryLocalInterface(DESCRIPTOR);
-if ((in!=null)) {
-return in;
-}
-return new android.webkit.gears.IGearsDialogService.Stub.Proxy(obj);
-}
-public android.os.IBinder asBinder()
-{
-return this;
-}
-public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
-{
-switch (code)
-{
-case INTERFACE_TRANSACTION:
-{
-reply.writeString(DESCRIPTOR);
-return true;
-}
-case TRANSACTION_showDialog:
-{
-data.enforceInterface(DESCRIPTOR);
-java.lang.String _arg0;
-_arg0 = data.readString();
-java.lang.String _arg1;
-_arg1 = data.readString();
-boolean _arg2;
-_arg2 = (0!=data.readInt());
-java.lang.String _result = this.showDialog(_arg0, _arg1, _arg2);
-reply.writeNoException();
-reply.writeString(_result);
-return true;
-}
-}
-return super.onTransact(code, data, reply, flags);
-}
-private static class Proxy implements android.webkit.gears.IGearsDialogService
-{
-private android.os.IBinder mRemote;
-Proxy(android.os.IBinder remote)
-{
-mRemote = remote;
-}
-public android.os.IBinder asBinder()
-{
-return mRemote;
-}
-public java.lang.String getInterfaceDescriptor()
-{
-return DESCRIPTOR;
-}
-public java.lang.String showDialog(java.lang.String htmlContent, java.lang.String dialogArguments, boolean inSettings) throws android.os.RemoteException
-{
-android.os.Parcel _data = android.os.Parcel.obtain();
-android.os.Parcel _reply = android.os.Parcel.obtain();
-java.lang.String _result;
-try {
-_data.writeInterfaceToken(DESCRIPTOR);
-_data.writeString(htmlContent);
-_data.writeString(dialogArguments);
-_data.writeInt(((inSettings)?(1):(0)));
-mRemote.transact(Stub.TRANSACTION_showDialog, _data, _reply, 0);
-_reply.readException();
-_result = _reply.readString();
-}
-finally {
-_reply.recycle();
-_data.recycle();
-}
-return _result;
-}
-}
-static final int TRANSACTION_showDialog = (IBinder.FIRST_CALL_TRANSACTION + 0);
-}
-public java.lang.String showDialog(java.lang.String htmlContent, java.lang.String dialogArguments, boolean inSettings) throws android.os.RemoteException;
-}
diff --git a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
index 288240e..43104bf 100644
--- a/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
+++ b/core/java/android/webkit/gears/UrlInterceptHandlerGears.java
@@ -25,16 +25,14 @@
package android.webkit.gears;
-import android.net.http.Headers;
import android.util.Log;
-import android.webkit.CacheManager;
import android.webkit.CacheManager.CacheResult;
import android.webkit.Plugin;
+import android.webkit.PluginData;
import android.webkit.UrlInterceptRegistry;
import android.webkit.UrlInterceptHandler;
import android.webkit.WebView;
-import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.util.CharArrayBuffer;
import java.io.*;
@@ -53,22 +51,16 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
private static final String LOG_TAG = "Gears-J";
/** Buffer size for reading/writing streams. */
private static final int BUFFER_SIZE = 4096;
- /**
- * Number of milliseconds to expire LocalServer temporary entries in
- * the browser's cache. Somewhat arbitrarily chosen as a compromise
- * between being a) long enough not to expire during page load and
- * b) short enough to evict entries during a session. */
- private static final int CACHE_EXPIRY_MS = 60000; // 1 minute.
/** Enable/disable all logging in this class. */
private static boolean logEnabled = false;
/** The unmodified (case-sensitive) key in the headers map is the
* same index as used by HttpRequestAndroid. */
public static final int HEADERS_MAP_INDEX_KEY =
- HttpRequestAndroid.HEADERS_MAP_INDEX_KEY;
+ ApacheHttpRequestAndroid.HEADERS_MAP_INDEX_KEY;
/** The associated value in the headers map is the same index as
* used by HttpRequestAndroid. */
public static final int HEADERS_MAP_INDEX_VALUE =
- HttpRequestAndroid.HEADERS_MAP_INDEX_VALUE;
+ ApacheHttpRequestAndroid.HEADERS_MAP_INDEX_VALUE;
/**
* Object passed to the native side, containing information about
@@ -140,6 +132,8 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
private String encoding;
// The stream which contains the body when read().
private InputStream inputStream;
+ // The length of the content body.
+ private long contentLength;
/**
* Initialize members using an in-memory array to return the body.
@@ -160,6 +154,7 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
this.mimeType = mimeType;
this.encoding = encoding;
// Setup a stream to read out of the byte array.
+ this.contentLength = body.length;
this.inputStream = new ByteArrayInputStream(body);
}
@@ -185,7 +180,9 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
this.encoding = encoding;
try {
// Setup a stream to read out of a file on disk.
- this.inputStream = new FileInputStream(new File(path));
+ File file = new File(path);
+ this.contentLength = file.length();
+ this.inputStream = new FileInputStream(file);
return true;
} catch (java.io.FileNotFoundException ex) {
log("File not found: " + path);
@@ -274,6 +271,13 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
public InputStream getInputStream() {
return inputStream;
}
+
+ /**
+ * @return The length of the response body.
+ */
+ public long getContentLength() {
+ return contentLength;
+ }
}
/**
@@ -319,44 +323,32 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
UrlInterceptRegistry.unregisterHandler(this);
}
- /**
- * Copy the entire InputStream to OutputStream.
- * @param inputStream The stream to read from.
- * @param outputStream The stream to write to.
- * @return True if the entire stream copied successfully, false on error.
- */
- private boolean copyStream(InputStream inputStream,
- OutputStream outputStream) {
- try {
- // Temporary buffer to copy stream through.
- byte[] buf = new byte[BUFFER_SIZE];
- for (;;) {
- // Read up to BUFFER_SIZE bytes.
- int bytes = inputStream.read(buf);
- if (bytes < 0) {
- break;
- }
- // Write the number of bytes we just read.
- outputStream.write(buf, 0, bytes);
- }
- } catch (IOException ex) {
- log("Got IOException copying stream: " + ex);
- return false;
+ /**
+ * Given an URL, returns the CacheResult which contains the
+ * surrogate response for the request, or null if the handler is
+ * not interested.
+ *
+ * @param url URL string.
+ * @param headers The headers associated with the request. May be null.
+ * @return The CacheResult containing the surrogate response.
+ * @Deprecated Use PluginData getPluginData(String url,
+ * Map<String, String> headers); instead
+ */
+ @Deprecated
+ public CacheResult service(String url, Map<String, String> headers) {
+ throw new UnsupportedOperationException("unimplemented");
}
- return true;
- }
/**
- * Given an URL, returns a CacheResult which contains the response
- * for the request. This implements the UrlInterceptHandler interface.
+ * Given an URL, returns a PluginData instance which contains the
+ * response for the request. This implements the UrlInterceptHandler
+ * interface.
*
- * @param url The fully qualified URL being requested.
+ * @param url The fully qualified URL being requested.
* @param requestHeaders The request headers for this URL.
- * @return If a response can be crafted, a CacheResult initialized
- * to return the surrogate response. If this URL cannot
- * be serviced, returns null.
+ * @return a PluginData object.
*/
- public CacheResult service(String url, Map<String, String> requestHeaders) {
+ public PluginData getPluginData(String url, Map<String, String> requestHeaders) {
// Thankfully the browser does call us with case-sensitive
// headers. We just need to map it case-insensitive.
Map<String, String[]> lowercaseRequestHeaders =
@@ -374,86 +366,10 @@ public class UrlInterceptHandlerGears implements UrlInterceptHandler {
// No result for this URL.
return null;
}
- // Translate the ServiceResponse to a CacheResult.
- // Translate http -> gears, https -> gearss, so we don't overwrite
- // existing entries.
- String gearsUrl = "gears" + url.substring("http".length());
- // Set the result to expire, so that entries don't pollute the
- // browser's cache for too long.
- long now_ms = System.currentTimeMillis();
- String expires = DateUtils.formatDate(new Date(now_ms + CACHE_EXPIRY_MS));
- response.setResponseHeader(HttpRequestAndroid.KEY_EXPIRES, expires);
- // The browser is only interested in a small subset of headers,
- // contained in a Headers object. Iterate the map of all headers
- // and add them to Headers.
- Headers headers = new Headers();
- Iterator<Map.Entry<String, String[]>> responseHeadersIt =
- response.getResponseHeaders().entrySet().iterator();
- while (responseHeadersIt.hasNext()) {
- Map.Entry<String, String[]> entry = responseHeadersIt.next();
- // Headers.parseHeader() expects lowercase keys.
- String keyValue = entry.getKey() + ": "
- + entry.getValue()[HEADERS_MAP_INDEX_VALUE];
- CharArrayBuffer buffer = new CharArrayBuffer(keyValue.length());
- buffer.append(keyValue);
- // Parse it into the header container.
- headers.parseHeader(buffer);
- }
- CacheResult cacheResult = CacheManager.createCacheFile(
- gearsUrl,
- response.getStatusCode(),
- headers,
- response.getMimeType(),
- true); // forceCache
-
- if (cacheResult == null) {
- // With the no-cache policy we could end up
- // with a null result
- return null;
- }
-
- // Set encoding if specified.
- String encoding = response.getEncoding();
- if (encoding != null) {
- cacheResult.setEncoding(encoding);
- }
- // Copy the response body to the CacheResult. This handles all
- // combinations of memory vs on-disk on both sides.
- InputStream inputStream = response.getInputStream();
- OutputStream outputStream = cacheResult.getOutputStream();
- boolean copied = copyStream(inputStream, outputStream);
- // Close the input and output streams to relinquish their
- // resources earlier.
- try {
- inputStream.close();
- } catch (IOException ex) {
- log("IOException closing InputStream: " + ex);
- copied = false;
- }
- try {
- outputStream.close();
- } catch (IOException ex) {
- log("IOException closing OutputStream: " + ex);
- copied = false;
- }
- if (!copied) {
- log("copyStream of local result failed");
- return null;
- }
- // Save the entry into the browser's cache.
- CacheManager.saveCacheFile(gearsUrl, cacheResult);
- // Get it back from the cache, this time properly initialized to
- // be used for input.
- cacheResult = CacheManager.getCacheFile(gearsUrl, null);
- if (cacheResult != null) {
- log("Returning surrogate result");
- return cacheResult;
- } else {
- // Not an expected condition, but handle gracefully. Perhaps out
- // of memory or disk?
- Log.e(LOG_TAG, "Lost CacheResult between save and get. Can't serve.\n");
- return null;
- }
+ return new PluginData(response.getInputStream(),
+ response.getContentLength(),
+ response.getResponseHeaders(),
+ response.getStatusCode());
}
/**
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 19ec77d..bd4bba8 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -17,7 +17,6 @@
package android.widget;
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -28,9 +27,11 @@ import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.Editable;
+import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -40,7 +41,9 @@ import android.view.ViewConfiguration;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
-import android.view.WindowManagerImpl;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
import android.view.ContextMenu.ContextMenuInfo;
import com.android.internal.R;
@@ -369,7 +372,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private int mLastTouchMode = TOUCH_MODE_UNKNOWN;
- // TODO: REMOVE WHEN WE'RE DONE WITH PROFILING
private static final boolean PROFILE_SCROLLING = false;
private boolean mScrollProfilingStarted = false;
@@ -423,6 +425,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
private FastScroller mFastScroller;
+ private int mTouchSlop;
+
+ private float mDensityScale;
+
/**
* Interface definition for a callback to be invoked when the list or grid
* has been scrolled.
@@ -558,6 +564,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public boolean isFastScrollEnabled() {
return mFastScrollEnabled;
}
+
+ /**
+ * If fast scroll is visible, then don't draw the vertical scrollbar.
+ * @hide
+ */
+ @Override
+ protected boolean isVerticalScrollBarHidden() {
+ return mFastScroller != null && mFastScroller.isVisible();
+ }
/**
* When smooth scrollbar is enabled, the position and size of the scrollbar thumb
@@ -696,6 +711,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
setWillNotDraw(false);
setAlwaysDrawnWithCacheEnabled(false);
setScrollingCacheEnabled(true);
+
+ mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ mDensityScale = getContext().getResources().getDisplayMetrics().density;
}
private void useDefaultSelector() {
@@ -877,15 +895,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mSyncMode = SYNC_FIRST_POSITION;
}
- // Don't restore the type filter window when there is no keyboard
- int keyboardHidden = getContext().getResources().getConfiguration().keyboardHidden;
- if (keyboardHidden != Configuration.KEYBOARDHIDDEN_YES) {
- String filterText = ss.filter;
- setFilterText(filterText);
- }
+ setFilterText(ss.filter);
+
requestLayout();
}
+ private boolean acceptFilter() {
+ if (!mTextFilterEnabled || !(getAdapter() instanceof Filterable) ||
+ ((Filterable) getAdapter()).getFilter() == null) {
+ return false;
+ }
+ final Context context = mContext;
+ final InputMethodManager inputManager = (InputMethodManager)
+ context.getSystemService(Context.INPUT_METHOD_SERVICE);
+ return !inputManager.isFullscreenMode();
+ }
+
/**
* Sets the initial value for the text filter.
* @param filterText The text to use for the filter.
@@ -893,7 +918,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* @see #setTextFilterEnabled
*/
public void setFilterText(String filterText) {
- if (mTextFilterEnabled && filterText != null && filterText.length() > 0) {
+ // TODO: Should we check for acceptFilter()?
+ if (mTextFilterEnabled && !TextUtils.isEmpty(filterText)) {
createTextFilter(false);
// This is going to call our listener onTextChanged, but we might not
// be ready to bring up a window yet
@@ -913,6 +939,18 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
+ /**
+ * Returns the list's text filter, if available.
+ * @return the list's text filter or null if filtering isn't enabled
+ * @hide pending API Council approval
+ */
+ public CharSequence getTextFilter() {
+ if (mTextFilterEnabled && mTextFilter != null) {
+ return mTextFilter.getText();
+ }
+ return null;
+ }
+
@Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
@@ -944,6 +982,18 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mSelectorRect.setEmpty();
invalidate();
}
+
+ /**
+ * The list is empty and we need to change the layout, so *really* clear everything out.
+ * @hide - for AutoCompleteTextView & SearchDialog only
+ */
+ /* package */ void resetListAndClearViews() {
+ rememberSyncState();
+ removeAllViewsInLayout();
+ mRecycler.clear();
+ mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
+ requestLayout();
+ }
@Override
protected int computeVerticalScrollExtent() {
@@ -1063,6 +1113,24 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mInLayout = false;
}
+ /**
+ * @hide
+ */
+ @Override
+ protected boolean setFrame(int left, int top, int right, int bottom) {
+ final boolean changed = super.setFrame(left, top, right, bottom);
+
+ // Reposition the popup when the frame has changed. This includes
+ // translating the widget, not just changing its dimension. The
+ // filter popup needs to follow the widget.
+ if (mFiltered && changed && getWindowVisibility() == View.VISIBLE && mPopup != null &&
+ mPopup.isShowing()) {
+ positionPopup();
+ }
+
+ return changed;
+ }
+
protected void layoutChildren() {
}
@@ -1366,7 +1434,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final View v = getChildAt(mSelectedPosition - mFirstPosition);
- if (v != null) v.setPressed(true);
+ if (v != null) {
+ if (v.hasFocusable()) return;
+ v.setPressed(true);
+ }
setPressed(true);
final boolean longClickable = isLongClickable();
@@ -1610,6 +1681,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);
handled = super.showContextMenuForChild(AbsListView.this);
}
+ if (handled) {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
return handled;
}
@@ -1758,8 +1832,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// Check if we have moved far enough that it looks more like a
// scroll than a tap
final int distance = Math.abs(deltaY);
- int touchSlop = ViewConfiguration.getTouchSlop();
- if (distance > touchSlop) {
+ if (distance > mTouchSlop) {
createScrollingCache();
mTouchMode = TOUCH_MODE_SCROLL;
mMotionCorrection = deltaY;
@@ -1979,8 +2052,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
velocityTracker.computeCurrentVelocity(1000);
int initialVelocity = (int)velocityTracker.getYVelocity();
- if ((Math.abs(initialVelocity) > ViewConfiguration.getMinimumFlingVelocity()) &&
- (getChildCount() > 0)){
+ if ((Math.abs(initialVelocity) >
+ ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) &&
+ (getChildCount() > 0)) {
if (mFlingRunnable == null) {
mFlingRunnable = new FlingRunnable();
}
@@ -2571,10 +2645,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
clearScrollingCache();
mSpecificTop = selectedTop;
selectedPos = lookForSelectablePosition(selectedPos, down);
- if (selectedPos >= 0) {
+ if (selectedPos >= firstPosition && selectedPos <= getLastVisiblePosition()) {
mLayoutMode = LAYOUT_SPECIFIC;
setSelectionInt(selectedPos);
invokeOnItemScrollListener();
+ } else {
+ selectedPos = INVALID_POSITION;
}
reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
@@ -2711,17 +2787,28 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private void showPopup() {
// Make sure we have a window before showing the popup
if (getWindowVisibility() == View.VISIBLE) {
- int screenHeight = WindowManagerImpl.getDefault().getDefaultDisplay().getHeight();
- final int[] xy = new int[2];
- getLocationOnScreen(xy);
- int bottomGap = screenHeight - xy[1] - getHeight() + 20;
- mPopup.showAtLocation(this, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL,
- xy[0], bottomGap);
+ createTextFilter(true);
+ positionPopup();
// Make sure we get focus if we are showing the popup
checkFocus();
}
}
+ private void positionPopup() {
+ int screenHeight = getResources().getDisplayMetrics().heightPixels;
+ final int[] xy = new int[2];
+ getLocationOnScreen(xy);
+ // TODO: The 20 below should come from the theme and be expressed in dip
+ // TODO: And the gravity should be defined in the theme as well
+ final int bottomGap = screenHeight - xy[1] - getHeight() + (int) (mDensityScale * 20);
+ if (!mPopup.isShowing()) {
+ mPopup.showAtLocation(this, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL,
+ xy[0], bottomGap);
+ } else {
+ mPopup.update(xy[0], bottomGap, -1, -1);
+ }
+ }
+
/**
* What is the distance between the source and destination rectangles given the direction of
* focus navigation between them? The direction basically helps figure out more quickly what is
@@ -2783,8 +2870,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* @return True if the text filter handled the event, false otherwise.
*/
boolean sendToTextFilter(int keyCode, int count, KeyEvent event) {
- if (!mTextFilterEnabled || !(getAdapter() instanceof Filterable) ||
- ((Filterable) getAdapter()).getFilter() == null) {
+ if (!acceptFilter()) {
return false;
}
@@ -2840,6 +2926,30 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
/**
+ * Return an InputConnection for editing of the filter text.
+ */
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+ if (isTextFilterEnabled()) {
+ // XXX we need to have the text filter created, so we can get an
+ // InputConnection to proxy to. Unfortunately this means we pretty
+ // much need to make it as soon as a list view gets focus.
+ createTextFilter(false);
+ return mTextFilter.onCreateInputConnection(outAttrs);
+ }
+ return null;
+ }
+
+ /**
+ * For filtering we proxy an input connection to an internal text editor,
+ * and this allows the proxying to happen.
+ */
+ @Override
+ public boolean checkInputConnectionProxy(View view) {
+ return view == mTextFilter;
+ }
+
+ /**
* Creates the window for the text filter and populates it with an EditText field;
*
* @param animateEntrance true if the window should appear with an animation
@@ -2848,13 +2958,19 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mPopup == null) {
Context c = getContext();
PopupWindow p = new PopupWindow(c);
- LayoutInflater layoutInflater = (LayoutInflater) c
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater layoutInflater = (LayoutInflater)
+ c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mTextFilter = (EditText) layoutInflater.inflate(
com.android.internal.R.layout.typing_filter, null);
+ // For some reason setting this as the "real" input type changes
+ // the text view in some way that it doesn't work, and I don't
+ // want to figure out why this is.
+ mTextFilter.setRawInputType(EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_FILTER);
mTextFilter.addTextChangedListener(this);
p.setFocusable(false);
p.setTouchable(false);
+ p.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
p.setContentView(mTextFilter);
p.setWidth(LayoutParams.WRAP_CONTENT);
p.setHeight(LayoutParams.WRAP_CONTENT);
@@ -2915,7 +3031,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* filtering as the text changes.
*/
public void onTextChanged(CharSequence s, int start, int before, int count) {
- if (mPopup != null) {
+ if (mPopup != null && isTextFilterEnabled()) {
int length = s.length();
boolean showing = mPopup.isShowing();
if (!showing && length > 0) {
@@ -3070,6 +3186,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
int viewType;
+ /**
+ * When this boolean is set, the view has been added to the AbsListView
+ * at least once. It is used to know whether headers/footers have already
+ * been added to the list view and whether they should be treated as
+ * recycled views or not.
+ */
+ boolean recycledHeaderFooter;
+
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
@@ -3203,7 +3327,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (lp != null && lp.viewType != AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
// Note: We do place AdapterView.ITEM_VIEW_TYPE_IGNORE in active views.
// However, we will NOT place them into scrap views.
- activeViews[i] = getChildAt(i);
+ activeViews[i] = child;
}
}
}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 9ebfa86..37d5bfe 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -40,9 +40,15 @@ public abstract class AbsSeekBar extends ProgressBar {
* Whether this is user seekable.
*/
boolean mIsUserSeekable = true;
+
+ /**
+ * On key presses (right or left), the amount to increment/decrement the
+ * progress.
+ */
+ private int mKeyProgressIncrement = 1;
private static final int NO_ALPHA = 0xFF;
- float mDisabledAlpha;
+ private float mDisabledAlpha;
public AbsSeekBar(Context context) {
super(context);
@@ -101,6 +107,39 @@ public abstract class AbsSeekBar extends ProgressBar {
invalidate();
}
+ /**
+ * Sets the amount of progress changed via the arrow keys.
+ *
+ * @param increment The amount to increment or decrement when the user
+ * presses the arrow keys.
+ */
+ public void setKeyProgressIncrement(int increment) {
+ mKeyProgressIncrement = increment < 0 ? -increment : increment;
+ }
+
+ /**
+ * Returns the amount of progress changed via the arrow keys.
+ * <p>
+ * By default, this will be a value that is derived from the max progress.
+ *
+ * @return The amount to increment or decrement when the user presses the
+ * arrow keys. This will be positive.
+ */
+ public int getKeyProgressIncrement() {
+ return mKeyProgressIncrement;
+ }
+
+ @Override
+ public synchronized void setMax(int max) {
+ super.setMax(max);
+
+ if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) {
+ // It will take the user too long to change this via keys, change it
+ // to something more reasonable
+ setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20)));
+ }
+ }
+
@Override
protected boolean verifyDrawable(Drawable who) {
return who == mThumb || super.verifyDrawable(who);
@@ -316,12 +355,12 @@ public abstract class AbsSeekBar extends ProgressBar {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_LEFT:
if (progress <= 0) break;
- setProgress(progress - 1, true);
+ setProgress(progress - mKeyProgressIncrement, true);
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (progress >= getMax()) break;
- setProgress(progress + 1, true);
+ setProgress(progress + mKeyProgressIncrement, true);
return true;
}
diff --git a/core/java/android/widget/Adapter.java b/core/java/android/widget/Adapter.java
index e952dd5..f2b3e2a 100644
--- a/core/java/android/widget/Adapter.java
+++ b/core/java/android/widget/Adapter.java
@@ -116,7 +116,7 @@ public interface Adapter {
* can be converted to the other in {@link #getView}. Note: Integers must be in the
* range 0 to {@link #getViewTypeCount} - 1. {@link #IGNORE_ITEM_VIEW_TYPE} can
* also be returned.
- * @see IGNORE_ITEM_VIEW_TYPE
+ * @see #IGNORE_ITEM_VIEW_TYPE
*/
int getItemViewType(int position);
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index fbb0105..f847bc3 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -28,6 +28,7 @@ import android.os.Handler;
import android.text.format.Time;
import android.util.AttributeSet;
import android.view.View;
+import android.widget.RemoteViews.RemoteView;
import java.util.TimeZone;
@@ -35,6 +36,7 @@ import java.util.TimeZone;
* This widget display an analogic clock with two hands for hours and
* minutes.
*/
+@RemoteView
public class AnalogClock extends View {
private Time mCalendar;
@@ -46,7 +48,6 @@ public class AnalogClock extends View {
private int mDialHeight;
private boolean mAttached;
- private long mLastTime;
private final Handler mHandler = new Handler();
private float mMinutes;
@@ -94,7 +95,6 @@ public class AnalogClock extends View {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- onTimeChanged();
if (!mAttached) {
mAttached = true;
IntentFilter filter = new IntentFilter();
@@ -105,6 +105,15 @@ public class AnalogClock extends View {
getContext().registerReceiver(mIntentReceiver, filter, null, mHandler);
}
+
+ // NOTE: It's safe to do these after registering the receiver since the receiver always runs
+ // in the main thread, therefore the receiver can't run before this method returns.
+
+ // The time zone may have changed while the receiver wasn't registered, so update the Time
+ mCalendar = new Time();
+
+ // Make sure we update to the current time
+ onTimeChanged();
}
@Override
@@ -210,9 +219,7 @@ public class AnalogClock extends View {
}
private void onTimeChanged() {
- long time = System.currentTimeMillis();
- mCalendar.set(time);
- mLastTime = time;
+ mCalendar.setToNow();
int hour = mCalendar.hour;
int minute = mCalendar.minute;
@@ -229,8 +236,6 @@ public class AnalogClock extends View {
if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
String tz = intent.getStringExtra("time-zone");
mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
- } else {
- mCalendar = new Time();
}
onTimeChanged();
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index c65a3ce..c28210d 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -25,6 +25,8 @@ import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Comparator;
+import java.util.Collections;
/**
* A ListAdapter that manages a ListView backed by an array of arbitrary
@@ -227,6 +229,17 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable {
}
/**
+ * Sorts the content of this adapter using the specified comparator.
+ *
+ * @param comparator The comparator used to sort the objects contained
+ * in this adapter.
+ */
+ public void sort(Comparator<? super T> comparator) {
+ Collections.sort(mObjects, comparator);
+ if (mNotifyOnChange) notifyDataSetChanged();
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 7d52901..e613541 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -78,6 +78,8 @@ import com.android.internal.R;
* @attr ref android.R.styleable#AutoCompleteTextView_completionThreshold
* @attr ref android.R.styleable#AutoCompleteTextView_completionHintView
* @attr ref android.R.styleable#AutoCompleteTextView_dropDownSelector
+ * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor
+ * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth
*/
public class AutoCompleteTextView extends EditText implements Filter.FilterListener {
static final boolean DEBUG = false;
@@ -96,6 +98,9 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
private DropDownListView mDropDownList;
private int mDropDownVerticalOffset;
private int mDropDownHorizontalOffset;
+ private int mDropDownAnchorId;
+ private View mDropDownAnchorView; // view is retrieved lazily from id once needed
+ private int mDropDownWidth;
private Drawable mDropDownListHighlight;
@@ -110,8 +115,14 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
private Validator mValidator = null;
+ private boolean mBlockCompletion;
+
private AutoCompleteTextView.ListSelectorHider mHideSelector;
+ // Indicates whether this AutoCompleteTextView is attached to a window or not
+ // The widget is attached to a window when mAttachCount > 0
+ private int mAttachCount;
+
public AutoCompleteTextView(Context context) {
this(context, null);
}
@@ -141,23 +152,29 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
a.getDimension(R.styleable.AutoCompleteTextView_dropDownVerticalOffset, 0.0f);
mDropDownHorizontalOffset = (int)
a.getDimension(R.styleable.AutoCompleteTextView_dropDownHorizontalOffset, 0.0f);
+
+ // Get the anchor's id now, but the view won't be ready, so wait to actually get the
+ // view and store it in mDropDownAnchorView lazily in getDropDownAnchorView later.
+ // Defaults to NO_ID, in which case the getDropDownAnchorView method will simply return
+ // this TextView, as a default anchoring point.
+ mDropDownAnchorId = a.getResourceId(R.styleable.AutoCompleteTextView_dropDownAnchor,
+ View.NO_ID);
+
+ // For dropdown width, the developer can specify a specific width, or FILL_PARENT
+ // (for full screen width) or WRAP_CONTENT (to match the width of the anchored view).
+ mDropDownWidth = a.getLayoutDimension(R.styleable.AutoCompleteTextView_dropDownWidth,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
mHintResource = a.getResourceId(R.styleable.AutoCompleteTextView_completionHintView,
R.layout.simple_dropdown_hint);
- // A little trickiness for backwards compatibility: if the app
- // didn't specify an explicit content type, then we will fill in the
- // auto complete flag for them.
- int contentType = a.getInt(
- R.styleable.AutoCompleteTextView_inputType,
- EditorInfo.TYPE_NULL);
- if (contentType == EditorInfo.TYPE_NULL) {
- contentType = getInputType();
- if ((contentType&EditorInfo.TYPE_MASK_CLASS)
- == EditorInfo.TYPE_CLASS_TEXT) {
- contentType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE;
- setRawInputType(contentType);
- }
+ // Always turn on the auto complete input type flag, since it
+ // makes no sense to use this widget without it.
+ int inputType = getInputType();
+ if ((inputType&EditorInfo.TYPE_MASK_CLASS)
+ == EditorInfo.TYPE_CLASS_TEXT) {
+ inputType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE;
+ setRawInputType(inputType);
}
a.recycle();
@@ -187,6 +204,49 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
public void setCompletionHint(CharSequence hint) {
mHintText = hint;
}
+
+ /**
+ * <p>Returns the current width for the auto-complete drop down list. This can
+ * be a fixed width, or {@link ViewGroup.LayoutParams#FILL_PARENT} to fill the screen, or
+ * {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the width of its anchor view.</p>
+ *
+ * @return the width for the drop down list
+ */
+ public int getDropDownWidth() {
+ return mDropDownWidth;
+ }
+
+ /**
+ * <p>Sets the current width for the auto-complete drop down list. This can
+ * be a fixed width, or {@link ViewGroup.LayoutParams#FILL_PARENT} to fill the screen, or
+ * {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the width of its anchor view.</p>
+ *
+ * @param width the width to use
+ */
+ public void setDropDownWidth(int width) {
+ mDropDownWidth = width;
+ }
+
+ /**
+ * <p>Returns the id for the view that the auto-complete drop down list is anchored to.</p>
+ *
+ * @return the view's id, or {@link View#NO_ID} if none specified
+ */
+ public int getDropDownAnchor() {
+ return mDropDownAnchorId;
+ }
+
+ /**
+ * <p>Sets the view to which the auto-complete drop down list should anchor. The view
+ * corresponding to this id will not be loaded until the next time it is needed to avoid
+ * loading a view which is not yet instantiated.</p>
+ *
+ * @param id the id to anchor the drop down list view to
+ */
+ public void setDropDownAnchor(int id) {
+ mDropDownAnchorId = id;
+ mDropDownAnchorView = null;
+ }
/**
* <p>Returns the number of characters the user must type before the drop
@@ -300,6 +360,15 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
/**
* <p>Changes the list of data used for auto completion. The provided list
* must be a filterable list adapter.</p>
+ *
+ * <p>The caller is still responsible for managing any resources used by the adapter.
+ * Notably, when the AutoCompleteTextView is closed or released, the adapter is not notified.
+ * A common case is the use of {@link android.widget.CursorAdapter}, which
+ * contains a {@link android.database.Cursor} that must be closed. This can be done
+ * automatically (see
+ * {@link android.app.Activity#startManagingCursor(android.database.Cursor)
+ * startManagingCursor()}),
+ * or by manually closing the cursor when the AutoCompleteTextView is dismissed.</p>
*
* @param adapter the adapter holding the auto completion data
*
@@ -368,7 +437,10 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
&& keyCode != KeyEvent.KEYCODE_DPAD_CENTER))) {
int curIndex = mDropDownList.getSelectedItemPosition();
boolean consumed;
- if (keyCode == KeyEvent.KEYCODE_DPAD_UP && curIndex <= 0) {
+ final boolean below = !mPopup.isAboveAnchor();
+ if ((below && keyCode == KeyEvent.KEYCODE_DPAD_UP && curIndex <= 0) ||
+ (!below && keyCode == KeyEvent.KEYCODE_DPAD_DOWN && curIndex >=
+ mDropDownList.getAdapter().getCount() - 1)) {
// When the selection is at the top, we block the key
// event to prevent focus from moving.
mDropDownList.hideSelector();
@@ -389,14 +461,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
// by ensuring it has focus and getting its window out
// of touch mode.
mDropDownList.requestFocusFromTouch();
- if (false) {
- // Update whether the pop-up is in front of or behind
- // the input method, depending on whether the user has
- // moved down in it.
- mPopup.setInputMethodMode(curIndex > 0
- ? PopupWindow.INPUT_METHOD_NOT_NEEDED
- : PopupWindow.INPUT_METHOD_NEEDED);
- }
mPopup.update();
switch (keyCode) {
@@ -409,13 +473,15 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
return true;
}
} else {
- if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+ if (below && keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
// when the selection is at the bottom, we block the
// event to avoid going to the next focusable widget
Adapter adapter = mDropDownList.getAdapter();
if (adapter != null && curIndex == adapter.getCount() - 1) {
return true;
}
+ } else if (!below && keyCode == KeyEvent.KEYCODE_DPAD_UP && curIndex == 0) {
+ return true;
}
}
}
@@ -430,6 +496,10 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
boolean handled = super.onKeyDown(keyCode, event);
mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
+ if (handled && isPopupShowing() && mDropDownList != null) {
+ clearListSelection();
+ }
+
return handled;
}
@@ -462,6 +532,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
}
void doBeforeTextChanged() {
+ if (mBlockCompletion) return;
+
// when text is changed, inserted or deleted, we attempt to show
// the drop down
mOpenBefore = isPopupShowing();
@@ -469,6 +541,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
}
void doAfterTextChanged() {
+ if (mBlockCompletion) return;
+
// if the list was open before the keystroke, but closed afterwards,
// then something in the keystroke processing (an input filter perhaps)
// called performCompletion() and we shouldn't do any more processing.
@@ -556,6 +630,16 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
}
/**
+ * We're changing the adapter and its views so really, really clear everything out
+ * @hide - for SearchDialog only
+ */
+ public void resetListAndClearViews() {
+ if (mDropDownList != null) {
+ mDropDownList.resetListAndClearViews();
+ }
+ }
+
+ /**
* <p>Starts filtering the content of the drop down list. The filtering
* pattern is the content of the edit box. Subclasses should override this
* method to filter with a different pattern, for instance a substring of
@@ -579,9 +663,13 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
performCompletion(null, -1, -1);
}
- @Override public void onCommitCompletion(CompletionInfo completion) {
+ @Override
+ public void onCommitCompletion(CompletionInfo completion) {
if (isPopupShowing()) {
+ mBlockCompletion = true;
replaceText(completion.getText());
+ mBlockCompletion = false;
+
if (mItemClickListener != null) {
final DropDownListView list = mDropDownList;
// Note that we don't have a View here, so we will need to
@@ -604,7 +692,10 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
Log.w(TAG, "performCompletion: no selected item");
return;
}
+
+ mBlockCompletion = true;
replaceText(convertSelectionToString(selectedItem));
+ mBlockCompletion = false;
if (mItemClickListener != null) {
final DropDownListView list = mDropDownList;
@@ -620,6 +711,14 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
dismissDropDown();
}
+
+ /**
+ * Identifies whether the view is currently performing a text completion, so subclasses
+ * can decide whether to respond to text changed events.
+ */
+ public boolean isPerformingCompletion() {
+ return mBlockCompletion;
+ }
/**
* <p>Performs the text completion by replacing the current text by the
@@ -636,6 +735,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
}
public void onFilterComplete(int count) {
+ if (mAttachCount <= 0) return;
+
/*
* This checks enoughToFilter() again because filtering requests
* are asynchronous, so the result may come back after enough text
@@ -671,8 +772,15 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mAttachCount++;
+ }
+
+ @Override
protected void onDetachedFromWindow() {
dismissDropDown();
+ mAttachCount--;
super.onDetachedFromWindow();
}
@@ -694,11 +802,23 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
boolean result = super.setFrame(l, t, r, b);
if (mPopup.isShowing()) {
- mPopup.update(this, getMeasuredWidth() - mPaddingLeft - mPaddingRight, -1);
+ mPopup.update(this, r - l, -1);
}
return result;
}
+
+ /**
+ * <p>Used for lazy instantiation of the anchor view from the id we have. If the value of
+ * the id is NO_ID or we can't find a view for the given id, we return this TextView as
+ * the default anchoring point.</p>
+ */
+ private View getDropDownAnchorView() {
+ if (mDropDownAnchorView == null && mDropDownAnchorId != View.NO_ID) {
+ mDropDownAnchorView = getRootView().findViewById(mDropDownAnchorId);
+ }
+ return mDropDownAnchorView == null ? this : mDropDownAnchorView;
+ }
/**
* <p>Displays the drop down on screen.</p>
@@ -706,16 +826,36 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
public void showDropDown() {
int height = buildDropDown();
if (mPopup.isShowing()) {
- mPopup.update(this, mDropDownHorizontalOffset, mDropDownVerticalOffset,
- getMeasuredWidth() - mPaddingLeft - mPaddingRight, height);
+ int widthSpec;
+ if (mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT) {
+ // The call to PopupWindow's update method below can accept -1 for any
+ // value you do not want to update.
+ widthSpec = -1;
+ } else if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ widthSpec = getDropDownAnchorView().getWidth();
+ } else {
+ widthSpec = mDropDownWidth;
+ }
+ mPopup.update(getDropDownAnchorView(), mDropDownHorizontalOffset,
+ mDropDownVerticalOffset, widthSpec, height);
} else {
- mPopup.setWindowLayoutMode(0, ViewGroup.LayoutParams.WRAP_CONTENT);
- mPopup.setWidth(getMeasuredWidth() - mPaddingLeft - mPaddingRight);
+ if (mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT) {
+ mPopup.setWindowLayoutMode(ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ } else {
+ mPopup.setWindowLayoutMode(0, ViewGroup.LayoutParams.WRAP_CONTENT);
+ if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ mPopup.setWidth(getDropDownAnchorView().getWidth());
+ } else {
+ mPopup.setWidth(mDropDownWidth);
+ }
+ }
mPopup.setHeight(height);
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
mPopup.setOutsideTouchable(true);
mPopup.setTouchInterceptor(new PopupTouchIntercepter());
- mPopup.showAsDropDown(this, mDropDownHorizontalOffset, mDropDownVerticalOffset);
+ mPopup.showAsDropDown(getDropDownAnchorView(),
+ mDropDownHorizontalOffset, mDropDownVerticalOffset);
mDropDownList.setSelection(ListView.INVALID_POSITION);
mDropDownList.hideSelector();
mDropDownList.requestFocus();
@@ -739,7 +879,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
int N = mAdapter.getCount();
if (N > 20) N = 20;
CompletionInfo[] completions = new CompletionInfo[N];
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
Object item = mAdapter.getItem(i);
long id = mAdapter.getItemId(i);
completions[i] = new CompletionInfo(id, i,
@@ -783,7 +923,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
// measure the hint's height to find how much more vertical space
// we need to add to the drop down's height
- int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
+ int widthSpec = MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST);
int heightSpec = MeasureSpec.UNSPECIFIED;
hintView.measure(widthSpec, heightSpec);
@@ -807,8 +947,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
}
// Max height available on the screen for a popup anchored to us
- final int maxHeight = mPopup.getMaxAvailableHeight(this);
- otherHeights += dropDownView.getPaddingTop() + dropDownView.getPaddingBottom();
+ final int maxHeight = mPopup.getMaxAvailableHeight(this, mDropDownVerticalOffset);
+ //otherHeights += dropDownView.getPaddingTop() + dropDownView.getPaddingBottom();
return mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
0, ListView.NO_POSITION, maxHeight - otherHeights, 2) + otherHeights;
@@ -984,6 +1124,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
protected int[] onCreateDrawableState(int extraSpace) {
int[] res = super.onCreateDrawableState(extraSpace);
+ //noinspection ConstantIfStatement
if (false) {
StringBuilder sb = new StringBuilder("Created drawable state: [");
for (int i=0; i<res.length; i++) {
diff --git a/core/java/android/widget/BaseAdapter.java b/core/java/android/widget/BaseAdapter.java
index 1921d73..532fd76 100644
--- a/core/java/android/widget/BaseAdapter.java
+++ b/core/java/android/widget/BaseAdapter.java
@@ -42,6 +42,10 @@ public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
mDataSetObservable.unregisterObserver(observer);
}
+ /**
+ * Notifies the attached View that the underlying data has been changed
+ * and it should refresh itself.
+ */
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index 7086ae2..91add58 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -46,6 +46,18 @@ import java.util.Locale;
public class Chronometer extends TextView {
private static final String TAG = "Chronometer";
+ /**
+ * A callback that notifies when the chronometer has incremented on its own.
+ */
+ public interface OnChronometerTickListener {
+
+ /**
+ * Notification that the chronometer has changed.
+ */
+ void onChronometerTick(Chronometer chronometer);
+
+ }
+
private long mBase;
private boolean mVisible;
private boolean mStarted;
@@ -56,7 +68,11 @@ public class Chronometer extends TextView {
private Locale mFormatterLocale;
private Object[] mFormatterArgs = new Object[1];
private StringBuilder mFormatBuilder;
-
+ private OnChronometerTickListener mOnChronometerTickListener;
+ private StringBuilder mRecycle = new StringBuilder(8);
+
+ private static final int TICK_WHAT = 2;
+
/**
* Initialize this Chronometer object.
* Sets the base to the current time.
@@ -99,8 +115,10 @@ public class Chronometer extends TextView {
*
* @param base Use the {@link SystemClock#elapsedRealtime} time base.
*/
+ @android.view.RemotableViewMethod
public void setBase(long base) {
mBase = base;
+ dispatchChronometerTick();
updateText(SystemClock.elapsedRealtime());
}
@@ -122,6 +140,7 @@ public class Chronometer extends TextView {
*
* @param format the format string.
*/
+ @android.view.RemotableViewMethod
public void setFormat(String format) {
mFormat = format;
if (format != null && mFormatBuilder == null) {
@@ -137,6 +156,23 @@ public class Chronometer extends TextView {
}
/**
+ * Sets the listener to be called when the chronometer changes.
+ *
+ * @param listener The listener.
+ */
+ public void setOnChronometerTickListener(OnChronometerTickListener listener) {
+ mOnChronometerTickListener = listener;
+ }
+
+ /**
+ * @return The listener (may be null) that is listening for chronometer change
+ * events.
+ */
+ public OnChronometerTickListener getOnChronometerTickListener() {
+ return mOnChronometerTickListener;
+ }
+
+ /**
* Start counting up. This does not affect the base as set from {@link #setBase}, just
* the view display.
*
@@ -161,6 +197,15 @@ public class Chronometer extends TextView {
updateRunning();
}
+ /**
+ * The same as calling {@link #start} or {@link #stop}.
+ */
+ @android.view.RemotableViewMethod
+ public void setStarted(boolean started) {
+ mStarted = started;
+ updateRunning();
+ }
+
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
@@ -175,10 +220,10 @@ public class Chronometer extends TextView {
updateRunning();
}
- private void updateText(long now) {
+ private synchronized void updateText(long now) {
long seconds = now - mBase;
seconds /= 1000;
- String text = DateUtils.formatElapsedTime(seconds);
+ String text = DateUtils.formatElapsedTime(mRecycle, seconds);
if (mFormat != null) {
Locale loc = Locale.getDefault();
@@ -206,7 +251,10 @@ public class Chronometer extends TextView {
if (running != mRunning) {
if (running) {
updateText(SystemClock.elapsedRealtime());
- mHandler.sendMessageDelayed(Message.obtain(), 1000);
+ dispatchChronometerTick();
+ mHandler.sendMessageDelayed(Message.obtain(mHandler, TICK_WHAT), 1000);
+ } else {
+ mHandler.removeMessages(TICK_WHAT);
}
mRunning = running;
}
@@ -214,10 +262,17 @@ public class Chronometer extends TextView {
private Handler mHandler = new Handler() {
public void handleMessage(Message m) {
- if (mStarted) {
+ if (mRunning) {
updateText(SystemClock.elapsedRealtime());
- sendMessageDelayed(Message.obtain(), 1000);
+ dispatchChronometerTick();
+ sendMessageDelayed(Message.obtain(this, TICK_WHAT), 1000);
}
}
};
+
+ void dispatchChronometerTick() {
+ if (mOnChronometerTickListener != null) {
+ mOnChronometerTickListener.onChronometerTick(this);
+ }
+ }
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index e56a741..d4482dc 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -251,7 +251,12 @@ public abstract class CompoundButton extends Button implements Checkable {
invalidate();
}
}
-
+
+ @Override
+ protected boolean verifyDrawable(Drawable who) {
+ return super.verifyDrawable(who) || who == mButtonDrawable;
+ }
+
static class SavedState extends BaseSavedState {
boolean checked;
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
index 3d758e7..898e501 100644
--- a/core/java/android/widget/CursorAdapter.java
+++ b/core/java/android/widget/CursorAdapter.java
@@ -348,6 +348,21 @@ public abstract class CursorAdapter extends BaseAdapter implements Filterable,
mFilterQueryProvider = filterQueryProvider;
}
+ /**
+ * Called when the {@link ContentObserver} on the cursor receives a change notification.
+ * The default implementation provides the auto-requery logic, but may be overridden by
+ * sub classes.
+ *
+ * @see ContentObserver#onChange(boolean)
+ * @hide pending API Council approval
+ */
+ protected void onContentChanged() {
+ if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {
+ if (Config.LOGV) Log.v("Cursor", "Auto requerying " + mCursor + " due to update");
+ mDataValid = mCursor.requery();
+ }
+ }
+
private class ChangeObserver extends ContentObserver {
public ChangeObserver() {
super(new Handler());
@@ -360,10 +375,7 @@ public abstract class CursorAdapter extends BaseAdapter implements Filterable,
@Override
public void onChange(boolean selfChange) {
- if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {
- if (Config.LOGV) Log.v("Cursor", "Auto requerying " + mCursor + " due to update");
- mDataValid = mCursor.requery();
- }
+ onContentChanged();
}
}
diff --git a/core/java/android/widget/CursorFilter.java b/core/java/android/widget/CursorFilter.java
index afd5b10..dbded69 100644
--- a/core/java/android/widget/CursorFilter.java
+++ b/core/java/android/widget/CursorFilter.java
@@ -60,11 +60,10 @@ class CursorFilter extends Filter {
}
@Override
- protected void publishResults(CharSequence constraint,
- FilterResults results) {
+ protected void publishResults(CharSequence constraint, FilterResults results) {
Cursor oldCursor = mClient.getCursor();
- if (results.values != oldCursor) {
+ if (results.values != null && results.values != oldCursor) {
mClient.changeCursor((Cursor) results.values);
}
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 67010b2..54f2707 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -47,11 +47,8 @@ public class DatePicker extends FrameLayout {
/* UI Components */
private final NumberPicker mDayPicker;
private final NumberPicker mMonthPicker;
- private final NumberPicker mYearPicker;
-
- private final int mStartYear;
- private final int mEndYear;
-
+ private final NumberPicker mYearPicker;
+
/**
* How we notify users the date has changed.
*/
@@ -87,12 +84,9 @@ public class DatePicker extends FrameLayout {
public DatePicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- LayoutInflater inflater =
- (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(R.layout.date_picker,
- this, // we are the parent
- true);
-
+ LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.date_picker, this, true);
+
mDayPicker = (NumberPicker) findViewById(R.id.day);
mDayPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
mDayPicker.setSpeed(100);
@@ -134,20 +128,17 @@ public class DatePicker extends FrameLayout {
});
// attributes
- TypedArray a = context
- .obtainStyledAttributes(attrs, R.styleable.DatePicker);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker);
- mStartYear = a.getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
- mEndYear = a.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
+ int mStartYear = a.getInt(R.styleable.DatePicker_startYear, DEFAULT_START_YEAR);
+ int mEndYear = a.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
mYearPicker.setRange(mStartYear, mEndYear);
a.recycle();
// initialize to current date
Calendar cal = Calendar.getInstance();
- init(cal.get(Calendar.YEAR),
- cal.get(Calendar.MONTH),
- cal.get(Calendar.DAY_OF_MONTH), null);
+ init(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), null);
// re-order the number pickers to match the current date format
reorderPickers();
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 3de561a..0fc8f49 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -187,6 +187,9 @@ public class ExpandableListView extends ListView {
private Drawable mChildDivider;
private boolean mClipChildDivider;
+ // Bounds of the indicator to be drawn
+ private final Rect mIndicatorRect = new Rect();
+
public ExpandableListView(Context context) {
this(context, null);
}
@@ -247,17 +250,16 @@ public class ExpandableListView extends ListView {
final int myB = mBottom;
- PositionMetadata pos = null;
+ PositionMetadata pos;
View item;
Drawable indicator;
int t, b;
// Start at a value that is neither child nor group
int lastItemType = ~(ExpandableListPosition.CHILD | ExpandableListPosition.GROUP);
-
- // Bounds of the indicator to be drawn
- Rect indicatorRect = new Rect();
-
+
+ final Rect indicatorRect = mIndicatorRect;
+
// The "child" mentioned in the following two lines is this
// View's child, not referring to an expandable list's
// notion of a child (as opposed to a group)
@@ -303,11 +305,11 @@ public class ExpandableListView extends ListView {
// Use item's full height + the divider height
if (mStackFromBottom) {
// See ListView#dispatchDraw
- indicatorRect.top = t - mDividerHeight;
+ indicatorRect.top = t;// - mDividerHeight;
indicatorRect.bottom = b;
} else {
indicatorRect.top = t;
- indicatorRect.bottom = b + mDividerHeight;
+ indicatorRect.bottom = b;// + mDividerHeight;
}
// Get the indicator (with its state set to the item's state)
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index bdcfeef..3368477 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -26,7 +26,6 @@ import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.SystemClock;
-import android.util.TypedValue;
import android.view.MotionEvent;
/**
@@ -34,7 +33,8 @@ import android.view.MotionEvent;
*/
class FastScroller {
-
+ // Minimum number of pages to justify showing a fast scroll thumb
+ private static int MIN_PAGES = 4;
// Scroll thumb not showing
private static final int STATE_NONE = 0;
// Not implemented yet - fade-in transition
@@ -61,6 +61,8 @@ class FastScroller {
private int mVisibleItem;
private Paint mPaint;
private int mListOffset;
+ private int mItemCount = -1;
+ private boolean mLongList;
private Object [] mSections;
private String mSectionText;
@@ -154,6 +156,10 @@ class FastScroller {
setState(STATE_NONE);
}
+ boolean isVisible() {
+ return !(mState == STATE_NONE);
+ }
+
public void draw(Canvas canvas) {
if (mState == STATE_NONE) {
@@ -214,7 +220,17 @@ class FastScroller {
void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
-
+ // Are there enough pages to require fast scroll? Recompute only if total count changes
+ if (mItemCount != totalItemCount && visibleItemCount > 0) {
+ mItemCount = totalItemCount;
+ mLongList = mItemCount / visibleItemCount >= MIN_PAGES;
+ }
+ if (!mLongList) {
+ if (mState != STATE_NONE) {
+ setState(STATE_NONE);
+ }
+ return;
+ }
if (totalItemCount - visibleItemCount > 0 && mState != STATE_DRAGGING ) {
mThumbY = ((mList.getHeight() - mThumbH) * firstVisibleItem)
/ (totalItemCount - visibleItemCount);
@@ -296,12 +312,17 @@ class FastScroller {
// Non-existent letter
while (section > 0) {
section--;
- prevIndex = mSectionIndexer.getPositionForSection(section);
- if (prevIndex != index) {
- prevSection = section;
- sectionIndex = section;
- break;
- }
+ prevIndex = mSectionIndexer.getPositionForSection(section);
+ if (prevIndex != index) {
+ prevSection = section;
+ sectionIndex = section;
+ break;
+ } else if (section == 0) {
+ // When section reaches 0 here, sectionIndex must follow it.
+ // Assuming mSectionIndexer.getPositionForSection(0) == 0.
+ sectionIndex = 0;
+ break;
+ }
}
}
// Find the next index, in case the assumed next index is not
diff --git a/core/java/android/widget/Filter.java b/core/java/android/widget/Filter.java
index 7f1601e..7e55c78 100644
--- a/core/java/android/widget/Filter.java
+++ b/core/java/android/widget/Filter.java
@@ -20,6 +20,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
+import android.util.Log;
/**
* <p>A filter constrains data with a filtering pattern.</p>
@@ -36,14 +37,16 @@ import android.os.Message;
* @see android.widget.Filterable
*/
public abstract class Filter {
+ private static final String LOG_TAG = "Filter";
+
private static final String THREAD_NAME = "Filter";
private static final int FILTER_TOKEN = 0xD0D0F00D;
private static final int FINISH_TOKEN = 0xDEADBEEF;
-
+
private Handler mThreadHandler;
private Handler mResultHandler;
- private String mConstraint;
- private boolean mConstraintIsValid = false;
+
+ private final Object mLock = new Object();
/**
* <p>Creates a new asynchronous filter.</p>
@@ -80,15 +83,7 @@ public abstract class Filter {
* @see #publishResults(CharSequence, android.widget.Filter.FilterResults)
*/
public final void filter(CharSequence constraint, FilterListener listener) {
- synchronized (this) {
- String constraintAsString = constraint != null ? constraint.toString() : null;
- if (mConstraintIsValid && (
- (constraintAsString == null && mConstraint == null) ||
- (constraintAsString != null && constraintAsString.equals(mConstraint)))) {
- // nothing to do
- return;
- }
-
+ synchronized (mLock) {
if (mThreadHandler == null) {
HandlerThread thread = new HandlerThread(THREAD_NAME);
thread.start();
@@ -100,16 +95,13 @@ public abstract class Filter {
RequestArguments args = new RequestArguments();
// make sure we use an immutable copy of the constraint, so that
// it doesn't change while the filter operation is in progress
- args.constraint = constraintAsString;
+ args.constraint = constraint != null ? constraint.toString() : null;
args.listener = listener;
message.obj = args;
mThreadHandler.removeMessages(FILTER_TOKEN);
mThreadHandler.removeMessages(FINISH_TOKEN);
mThreadHandler.sendMessage(message);
-
- mConstraint = constraintAsString;
- mConstraintIsValid = true;
}
}
@@ -221,13 +213,16 @@ public abstract class Filter {
RequestArguments args = (RequestArguments) msg.obj;
try {
args.results = performFiltering(args.constraint);
+ } catch (Exception e) {
+ args.results = new FilterResults();
+ Log.w(LOG_TAG, "An exception occured during performFiltering()!", e);
} finally {
message = mResultHandler.obtainMessage(what);
message.obj = args;
message.sendToTarget();
}
- synchronized (this) {
+ synchronized (mLock) {
if (mThreadHandler != null) {
Message finishMessage = mThreadHandler.obtainMessage(FINISH_TOKEN);
mThreadHandler.sendMessageDelayed(finishMessage, 3000);
@@ -235,7 +230,7 @@ public abstract class Filter {
}
break;
case FINISH_TOKEN:
- synchronized (this) {
+ synchronized (mLock) {
if (mThreadHandler != null) {
mThreadHandler.getLooper().quit();
mThreadHandler = null;
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index b4ed3ba..8aafee2 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -93,6 +93,7 @@ public class FrameLayout extends ViewGroup {
*
* @attr ref android.R.styleable#FrameLayout_foregroundGravity
*/
+ @android.view.RemotableViewMethod
public void setForegroundGravity(int foregroundGravity) {
if (mForegroundGravity != foregroundGravity) {
if ((foregroundGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
@@ -348,6 +349,7 @@ public class FrameLayout extends ViewGroup {
*
* @attr ref android.R.styleable#FrameLayout_measureAllChildren
*/
+ @android.view.RemotableViewMethod
public void setMeasureAllChildren(boolean measureAll) {
mMeasureAllChildren = measureAll;
}
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 7b9735c..e7b303a 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -27,6 +27,7 @@ import android.util.Config;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -180,7 +181,7 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
public Gallery(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mGestureDetector = new GestureDetector(this);
+ mGestureDetector = new GestureDetector(context, this);
mGestureDetector.setIsLongpressEnabled(true);
TypedArray a = context.obtainStyledAttributes(
@@ -994,6 +995,7 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
return;
}
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
long id = getItemIdAtPosition(mDownTouchPosition);
dispatchLongPress(mDownTouchView, mDownTouchPosition, id);
}
@@ -1086,6 +1088,10 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
handled = super.showContextMenuForChild(this);
}
+ if (handled) {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
+
return handled;
}
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 38bfc7c..11fab8f 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -924,32 +924,24 @@ public class GridView extends AbsListView {
final int count = mItemCount;
if (count > 0) {
final View child = obtainView(0);
- final int childViewType = mAdapter.getItemViewType(0);
- AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams();
- if (lp == null) {
- lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
+ AbsListView.LayoutParams p = (AbsListView.LayoutParams)child.getLayoutParams();
+ if (p == null) {
+ p = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 0);
- child.setLayoutParams(lp);
- }
- lp.viewType = childViewType;
-
- final int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
- mListPadding.left + mListPadding.right, lp.width);
-
- int lpHeight = lp.height;
-
- int childHeightSpec;
- if (lpHeight > 0) {
- childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
- } else {
- childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ child.setLayoutParams(p);
}
+ p.viewType = mAdapter.getItemViewType(0);
+ int childHeightSpec = getChildMeasureSpec(
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height);
+ int childWidthSpec = getChildMeasureSpec(
+ MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width);
child.measure(childWidthSpec, childHeightSpec);
+
childHeight = child.getMeasuredHeight();
- if (mRecycler.shouldRecycleViewType(childViewType)) {
+ if (mRecycler.shouldRecycleViewType(p.viewType)) {
mRecycler.addScrapView(child);
}
}
@@ -1337,11 +1329,8 @@ public class GridView extends AbsListView {
*/
@Override
void setSelectionInt(int position) {
- mBlockLayoutRequests = true;
setNextSelectedPositionInt(position);
layoutChildren();
-
- mBlockLayoutRequests = false;
}
@Override
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
new file mode 100644
index 0000000..652e30c
--- /dev/null
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -0,0 +1,1197 @@
+/*
+ * 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 android.widget;
+
+import android.util.AttributeSet;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.KeyEvent;
+import android.view.FocusFinder;
+import android.view.MotionEvent;
+import android.view.ViewParent;
+import android.view.animation.AnimationUtils;
+import android.content.Context;
+import android.content.res.TypedArray;
+
+import java.util.List;
+
+/**
+ * Layout container for a view hierarchy that can be scrolled by the user,
+ * allowing it to be larger than the physical display. A HorizontalScrollView
+ * is a {@link FrameLayout}, meaning you should place one child in it
+ * containing the entire contents to scroll; this child may itself be a layout
+ * manager with a complex hierarchy of objects. A child that is often used
+ * is a {@link LinearLayout} in a horizontal orientation, presenting a horizontal
+ * array of top-level items that the user can scroll through.
+ *
+ * <p>You should never use a HorizontalScrollView with a {@link ListView}, since
+ * ListView takes care of its own scrolling. Most importantly, doing this
+ * defeats all of the important optimizations in ListView for dealing with
+ * large lists, since it effectively forces the ListView to display its entire
+ * list of items to fill up the infinite container supplied by HorizontalScrollView.
+ *
+ * <p>The {@link TextView} class also
+ * takes care of its own scrolling, so does not require a ScrollView, but
+ * using the two together is possible to achieve the effect of a text view
+ * within a larger container.
+ *
+ * <p>HorizontalScrollView only supports horizontal scrolling.
+ */
+public class HorizontalScrollView extends FrameLayout {
+ private static final int ANIMATED_SCROLL_GAP = ScrollView.ANIMATED_SCROLL_GAP;
+
+ private static final float MAX_SCROLL_FACTOR = ScrollView.MAX_SCROLL_FACTOR;
+
+
+ private long mLastScroll;
+
+ private final Rect mTempRect = new Rect();
+ private Scroller mScroller;
+
+ /**
+ * Flag to indicate that we are moving focus ourselves. This is so the
+ * code that watches for focus changes initiated outside this ScrollView
+ * knows that it does not have to do anything.
+ */
+ private boolean mScrollViewMovedFocus;
+
+ /**
+ * Position of the last motion event.
+ */
+ private float mLastMotionX;
+
+ /**
+ * True when the layout has changed but the traversal has not come through yet.
+ * Ideally the view hierarchy would keep track of this for us.
+ */
+ private boolean mIsLayoutDirty = true;
+
+ /**
+ * The child to give focus to in the event that a child has requested focus while the
+ * layout is dirty. This prevents the scroll from being wrong if the child has not been
+ * laid out before requesting focus.
+ */
+ private View mChildToScrollTo = null;
+
+ /**
+ * True if the user is currently dragging this ScrollView around. This is
+ * not the same as 'is being flinged', which can be checked by
+ * mScroller.isFinished() (flinging begins when the user lifts his finger).
+ */
+ private boolean mIsBeingDragged = false;
+
+ /**
+ * Determines speed during touch scrolling
+ */
+ private VelocityTracker mVelocityTracker;
+
+ /**
+ * When set to true, the scroll view measure its child to make it fill the currently
+ * visible area.
+ */
+ private boolean mFillViewport;
+
+ /**
+ * Whether arrow scrolling is animated.
+ */
+ private boolean mSmoothScrollingEnabled = true;
+
+ private int mTouchSlop;
+
+ public HorizontalScrollView(Context context) {
+ this(context, null);
+ }
+
+ public HorizontalScrollView(Context context, AttributeSet attrs) {
+ this(context, attrs, com.android.internal.R.attr.horizontalScrollViewStyle);
+ }
+
+ public HorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initScrollView();
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ android.R.styleable.HorizontalScrollView, defStyle, 0);
+
+ setFillViewport(a.getBoolean(android.R.styleable.HorizontalScrollView_fillViewport, false));
+
+ a.recycle();
+ }
+
+ @Override
+ protected float getLeftFadingEdgeStrength() {
+ if (getChildCount() == 0) {
+ return 0.0f;
+ }
+
+ final int length = getHorizontalFadingEdgeLength();
+ if (mScrollX < length) {
+ return mScrollX / (float) length;
+ }
+
+ return 1.0f;
+ }
+
+ @Override
+ protected float getRightFadingEdgeStrength() {
+ if (getChildCount() == 0) {
+ return 0.0f;
+ }
+
+ final int length = getHorizontalFadingEdgeLength();
+ final int rightEdge = getWidth() - mPaddingRight;
+ final int span = getChildAt(0).getRight() - mScrollX - rightEdge;
+ if (span < length) {
+ return span / (float) length;
+ }
+
+ return 1.0f;
+ }
+
+ /**
+ * @return The maximum amount this scroll view will scroll in response to
+ * an arrow event.
+ */
+ public int getMaxScrollAmount() {
+ return (int) (MAX_SCROLL_FACTOR * (mRight - mLeft));
+ }
+
+
+ private void initScrollView() {
+ mScroller = new Scroller(getContext());
+ setFocusable(true);
+ setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
+ setWillNotDraw(false);
+ mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+ }
+
+ @Override
+ public void addView(View child) {
+ if (getChildCount() > 0) {
+ throw new IllegalStateException("HorizontalScrollView can host only one direct child");
+ }
+
+ super.addView(child);
+ }
+
+ @Override
+ public void addView(View child, int index) {
+ if (getChildCount() > 0) {
+ throw new IllegalStateException("HorizontalScrollView can host only one direct child");
+ }
+
+ super.addView(child, index);
+ }
+
+ @Override
+ public void addView(View child, ViewGroup.LayoutParams params) {
+ if (getChildCount() > 0) {
+ throw new IllegalStateException("HorizontalScrollView can host only one direct child");
+ }
+
+ super.addView(child, params);
+ }
+
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ if (getChildCount() > 0) {
+ throw new IllegalStateException("HorizontalScrollView can host only one direct child");
+ }
+
+ super.addView(child, index, params);
+ }
+
+ /**
+ * @return Returns true this HorizontalScrollView can be scrolled
+ */
+ private boolean canScroll() {
+ View child = getChildAt(0);
+ if (child != null) {
+ int childWidth = child.getWidth();
+ return getWidth() < childWidth + mPaddingLeft + mPaddingRight ;
+ }
+ return false;
+ }
+
+ /**
+ * Indicates whether this ScrollView's content is stretched to fill the viewport.
+ *
+ * @return True if the content fills the viewport, false otherwise.
+ */
+ public boolean isFillViewport() {
+ return mFillViewport;
+ }
+
+ /**
+ * Indicates this ScrollView whether it should stretch its content width to fill
+ * the viewport or not.
+ *
+ * @param fillViewport True to stretch the content's width to the viewport's
+ * boundaries, false otherwise.
+ */
+ public void setFillViewport(boolean fillViewport) {
+ if (fillViewport != mFillViewport) {
+ mFillViewport = fillViewport;
+ requestLayout();
+ }
+ }
+
+ /**
+ * @return Whether arrow scrolling will animate its transition.
+ */
+ public boolean isSmoothScrollingEnabled() {
+ return mSmoothScrollingEnabled;
+ }
+
+ /**
+ * Set whether arrow scrolling will animate its transition.
+ * @param smoothScrollingEnabled whether arrow scrolling will animate its transition
+ */
+ public void setSmoothScrollingEnabled(boolean smoothScrollingEnabled) {
+ mSmoothScrollingEnabled = smoothScrollingEnabled;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ if (!mFillViewport) {
+ return;
+ }
+
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ if (widthMode == MeasureSpec.UNSPECIFIED) {
+ return;
+ }
+
+ final View child = getChildAt(0);
+ int width = getMeasuredWidth();
+ if (child.getMeasuredHeight() < width) {
+ final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+ int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, mPaddingTop
+ + mPaddingBottom, lp.height);
+ width -= mPaddingLeft;
+ width -= mPaddingRight;
+ int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ }
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ // Let the focused view and/or our descendants get the key first
+ boolean handled = super.dispatchKeyEvent(event);
+ if (handled) {
+ return true;
+ }
+ return executeKeyEvent(event);
+ }
+
+ /**
+ * You can call this function yourself to have the scroll view perform
+ * scrolling from a key event, just as if the event had been dispatched to
+ * it by the view hierarchy.
+ *
+ * @param event The key event to execute.
+ * @return Return true if the event was handled, else false.
+ */
+ public boolean executeKeyEvent(KeyEvent event) {
+ mTempRect.setEmpty();
+
+ if (!canScroll()) {
+ if (isFocused()) {
+ View currentFocused = findFocus();
+ if (currentFocused == this) currentFocused = null;
+ View nextFocused = FocusFinder.getInstance().findNextFocus(this,
+ currentFocused, View.FOCUS_RIGHT);
+ return nextFocused != null && nextFocused != this &&
+ nextFocused.requestFocus(View.FOCUS_RIGHT);
+ }
+ return false;
+ }
+
+ boolean handled = false;
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ switch (event.getKeyCode()) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (!event.isAltPressed()) {
+ handled = arrowScroll(View.FOCUS_LEFT);
+ } else {
+ handled = fullScroll(View.FOCUS_LEFT);
+ }
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (!event.isAltPressed()) {
+ handled = arrowScroll(View.FOCUS_RIGHT);
+ } else {
+ handled = fullScroll(View.FOCUS_RIGHT);
+ }
+ break;
+ case KeyEvent.KEYCODE_SPACE:
+ pageScroll(event.isShiftPressed() ? View.FOCUS_LEFT : View.FOCUS_RIGHT);
+ break;
+ }
+ }
+
+ return handled;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ /*
+ * This method JUST determines whether we want to intercept the motion.
+ * If we return true, onMotionEvent will be called and we do the actual
+ * scrolling there.
+ */
+
+ /*
+ * Shortcut the most recurring case: the user is in the dragging
+ * state and he is moving his finger. We want to intercept this
+ * motion.
+ */
+ final int action = ev.getAction();
+ if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
+ return true;
+ }
+
+ if (!canScroll()) {
+ mIsBeingDragged = false;
+ return false;
+ }
+
+ final float x = ev.getX();
+
+ switch (action) {
+ case MotionEvent.ACTION_MOVE:
+ /*
+ * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
+ * whether the user has moved far enough from his original down touch.
+ */
+
+ /*
+ * Locally do absolute value. mLastMotionX is set to the x value
+ * of the down event.
+ */
+ final int xDiff = (int) Math.abs(x - mLastMotionX);
+ if (xDiff > mTouchSlop) {
+ mIsBeingDragged = true;
+ if (mParent != null) mParent.requestDisallowInterceptTouchEvent(true);
+ }
+ break;
+
+ case MotionEvent.ACTION_DOWN:
+ /* Remember location of down touch */
+ mLastMotionX = x;
+
+ /*
+ * If being flinged and user touches the screen, initiate drag;
+ * otherwise don't. mScroller.isFinished should be false when
+ * being flinged.
+ */
+ mIsBeingDragged = !mScroller.isFinished();
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ /* Release the drag */
+ mIsBeingDragged = false;
+ break;
+ }
+
+ /*
+ * The only time we want to intercept motion events is if we are in the
+ * drag mode.
+ */
+ return mIsBeingDragged;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+
+ if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
+ // Don't handle edge touches immediately -- they may actually belong to one of our
+ // descendants.
+ return false;
+ }
+
+ if (!canScroll()) {
+ return false;
+ }
+
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(ev);
+
+ final int action = ev.getAction();
+ final float x = ev.getX();
+
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ /*
+ * If being flinged and user touches, stop the fling. isFinished
+ * will be false if being flinged.
+ */
+ if (!mScroller.isFinished()) {
+ mScroller.abortAnimation();
+ }
+
+ // Remember where the motion event started
+ mLastMotionX = x;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ // Scroll to follow the motion event
+ final int deltaX = (int) (mLastMotionX - x);
+ mLastMotionX = x;
+
+ if (deltaX < 0) {
+ if (mScrollX > 0) {
+ scrollBy(deltaX, 0);
+ }
+ } else if (deltaX > 0) {
+ final int rightEdge = getWidth() - mPaddingRight;
+ final int availableToScroll = getChildAt(0).getRight() - mScrollX - rightEdge;
+ if (availableToScroll > 0) {
+ scrollBy(Math.min(availableToScroll, deltaX), 0);
+ }
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000);
+ int initialVelocity = (int) velocityTracker.getXVelocity();
+
+ if ((Math.abs(initialVelocity) >
+ ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) &&
+ getChildCount() > 0) {
+ fling(-initialVelocity);
+ }
+
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * <p>
+ * Finds the next focusable component that fits in this View's bounds
+ * (excluding fading edges) pretending that this View's left is located at
+ * the parameter left.
+ * </p>
+ *
+ * @param leftFocus look for a candidate is the one at the left of the bounds
+ * if leftFocus is true, or at the right of the bounds if leftFocus
+ * is false
+ * @param left the left offset of the bounds in which a focusable must be
+ * found (the fading edge is assumed to start at this position)
+ * @param preferredFocusable the View that has highest priority and will be
+ * returned if it is within my bounds (null is valid)
+ * @return the next focusable component in the bounds or null if none can be found
+ */
+ private View findFocusableViewInMyBounds(final boolean leftFocus,
+ final int left, View preferredFocusable) {
+ /*
+ * The fading edge's transparent side should be considered for focus
+ * since it's mostly visible, so we divide the actual fading edge length
+ * by 2.
+ */
+ final int fadingEdgeLength = getHorizontalFadingEdgeLength() / 2;
+ final int leftWithoutFadingEdge = left + fadingEdgeLength;
+ final int rightWithoutFadingEdge = left + getWidth() - fadingEdgeLength;
+
+ if ((preferredFocusable != null)
+ && (preferredFocusable.getLeft() < rightWithoutFadingEdge)
+ && (preferredFocusable.getRight() > leftWithoutFadingEdge)) {
+ return preferredFocusable;
+ }
+
+ return findFocusableViewInBounds(leftFocus, leftWithoutFadingEdge,
+ rightWithoutFadingEdge);
+ }
+
+ /**
+ * <p>
+ * Finds the next focusable component that fits in the specified bounds.
+ * </p>
+ *
+ * @param leftFocus look for a candidate is the one at the left of the bounds
+ * if leftFocus is true, or at the right of the bounds if
+ * leftFocus is false
+ * @param left the left offset of the bounds in which a focusable must be
+ * found
+ * @param right the right offset of the bounds in which a focusable must
+ * be found
+ * @return the next focusable component in the bounds or null if none can
+ * be found
+ */
+ private View findFocusableViewInBounds(boolean leftFocus, int left, int right) {
+
+ List<View> focusables = getFocusables(View.FOCUS_FORWARD);
+ View focusCandidate = null;
+
+ /*
+ * A fully contained focusable is one where its left is below the bound's
+ * left, and its right is above the bound's right. A partially
+ * contained focusable is one where some part of it is within the
+ * bounds, but it also has some part that is not within bounds. A fully contained
+ * focusable is preferred to a partially contained focusable.
+ */
+ boolean foundFullyContainedFocusable = false;
+
+ int count = focusables.size();
+ for (int i = 0; i < count; i++) {
+ View view = focusables.get(i);
+ int viewLeft = view.getLeft();
+ int viewRight = view.getRight();
+
+ if (left < viewRight && viewLeft < right) {
+ /*
+ * the focusable is in the target area, it is a candidate for
+ * focusing
+ */
+
+ final boolean viewIsFullyContained = (left < viewLeft) &&
+ (viewRight < right);
+
+ if (focusCandidate == null) {
+ /* No candidate, take this one */
+ focusCandidate = view;
+ foundFullyContainedFocusable = viewIsFullyContained;
+ } else {
+ final boolean viewIsCloserToBoundary =
+ (leftFocus && viewLeft < focusCandidate.getLeft()) ||
+ (!leftFocus && viewRight > focusCandidate.getRight());
+
+ if (foundFullyContainedFocusable) {
+ if (viewIsFullyContained && viewIsCloserToBoundary) {
+ /*
+ * We're dealing with only fully contained views, so
+ * it has to be closer to the boundary to beat our
+ * candidate
+ */
+ focusCandidate = view;
+ }
+ } else {
+ if (viewIsFullyContained) {
+ /* Any fully contained view beats a partially contained view */
+ focusCandidate = view;
+ foundFullyContainedFocusable = true;
+ } else if (viewIsCloserToBoundary) {
+ /*
+ * Partially contained view beats another partially
+ * contained view if it's closer
+ */
+ focusCandidate = view;
+ }
+ }
+ }
+ }
+ }
+
+ return focusCandidate;
+ }
+
+ /**
+ * <p>Handles scrolling in response to a "page up/down" shortcut press. This
+ * method will scroll the view by one page left or right and give the focus
+ * to the leftmost/rightmost component in the new visible area. If no
+ * component is a good candidate for focus, this scrollview reclaims the
+ * focus.</p>
+ *
+ * @param direction the scroll direction: {@link android.view.View#FOCUS_LEFT}
+ * to go one page left or {@link android.view.View#FOCUS_RIGHT}
+ * to go one page right
+ * @return true if the key event is consumed by this method, false otherwise
+ */
+ public boolean pageScroll(int direction) {
+ boolean right = direction == View.FOCUS_RIGHT;
+ int width = getWidth();
+
+ if (right) {
+ mTempRect.left = getScrollX() + width;
+ int count = getChildCount();
+ if (count > 0) {
+ View view = getChildAt(count - 1);
+ if (mTempRect.left + width > view.getRight()) {
+ mTempRect.left = view.getRight() - width;
+ }
+ }
+ } else {
+ mTempRect.left = getScrollX() - width;
+ if (mTempRect.left < 0) {
+ mTempRect.left = 0;
+ }
+ }
+ mTempRect.right = mTempRect.left + width;
+
+ return scrollAndFocus(direction, mTempRect.left, mTempRect.right);
+ }
+
+ /**
+ * <p>Handles scrolling in response to a "home/end" shortcut press. This
+ * method will scroll the view to the left or right and give the focus
+ * to the leftmost/rightmost component in the new visible area. If no
+ * component is a good candidate for focus, this scrollview reclaims the
+ * focus.</p>
+ *
+ * @param direction the scroll direction: {@link android.view.View#FOCUS_LEFT}
+ * to go the left of the view or {@link android.view.View#FOCUS_RIGHT}
+ * to go the right
+ * @return true if the key event is consumed by this method, false otherwise
+ */
+ public boolean fullScroll(int direction) {
+ boolean right = direction == View.FOCUS_RIGHT;
+ int width = getWidth();
+
+ mTempRect.left = 0;
+ mTempRect.right = width;
+
+ if (right) {
+ int count = getChildCount();
+ if (count > 0) {
+ View view = getChildAt(count - 1);
+ mTempRect.right = view.getRight();
+ mTempRect.left = mTempRect.right - width;
+ }
+ }
+
+ return scrollAndFocus(direction, mTempRect.left, mTempRect.right);
+ }
+
+ /**
+ * <p>Scrolls the view to make the area defined by <code>left</code> and
+ * <code>right</code> visible. This method attempts to give the focus
+ * to a component visible in this area. If no component can be focused in
+ * the new visible area, the focus is reclaimed by this scrollview.</p>
+ *
+ * @param direction the scroll direction: {@link android.view.View#FOCUS_LEFT}
+ * to go left {@link android.view.View#FOCUS_RIGHT} to right
+ * @param left the left offset of the new area to be made visible
+ * @param right the right offset of the new area to be made visible
+ * @return true if the key event is consumed by this method, false otherwise
+ */
+ private boolean scrollAndFocus(int direction, int left, int right) {
+ boolean handled = true;
+
+ int width = getWidth();
+ int containerLeft = getScrollX();
+ int containerRight = containerLeft + width;
+ boolean goLeft = direction == View.FOCUS_LEFT;
+
+ View newFocused = findFocusableViewInBounds(goLeft, left, right);
+ if (newFocused == null) {
+ newFocused = this;
+ }
+
+ if (left >= containerLeft && right <= containerRight) {
+ handled = false;
+ } else {
+ int delta = goLeft ? (left - containerLeft) : (right - containerRight);
+ doScrollX(delta);
+ }
+
+ if (newFocused != findFocus() && newFocused.requestFocus(direction)) {
+ mScrollViewMovedFocus = true;
+ mScrollViewMovedFocus = false;
+ }
+
+ return handled;
+ }
+
+ /**
+ * Handle scrolling in response to a left or right arrow click.
+ *
+ * @param direction The direction corresponding to the arrow key that was
+ * pressed
+ * @return True if we consumed the event, false otherwise
+ */
+ public boolean arrowScroll(int direction) {
+
+ View currentFocused = findFocus();
+ if (currentFocused == this) currentFocused = null;
+
+ View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, direction);
+
+ final int maxJump = getMaxScrollAmount();
+
+ if (nextFocused != null && isWithinDeltaOfScreen(nextFocused, maxJump)) {
+ nextFocused.getDrawingRect(mTempRect);
+ offsetDescendantRectToMyCoords(nextFocused, mTempRect);
+ int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
+ doScrollX(scrollDelta);
+ nextFocused.requestFocus(direction);
+ } else {
+ // no new focus
+ int scrollDelta = maxJump;
+
+ if (direction == View.FOCUS_LEFT && getScrollX() < scrollDelta) {
+ scrollDelta = getScrollX();
+ } else if (direction == View.FOCUS_RIGHT) {
+
+ int daRight = getChildAt(getChildCount() - 1).getRight();
+
+ int screenRight = getScrollX() + getWidth();
+
+ if (daRight - screenRight < maxJump) {
+ scrollDelta = daRight - screenRight;
+ }
+ }
+ if (scrollDelta == 0) {
+ return false;
+ }
+ doScrollX(direction == View.FOCUS_RIGHT ? scrollDelta : -scrollDelta);
+ }
+
+ if (currentFocused != null && currentFocused.isFocused()
+ && isOffScreen(currentFocused)) {
+ // previously focused item still has focus and is off screen, give
+ // it up (take it back to ourselves)
+ // (also, need to temporarily force FOCUS_BEFORE_DESCENDANTS so we are
+ // sure to
+ // get it)
+ final int descendantFocusability = getDescendantFocusability(); // save
+ setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+ requestFocus();
+ setDescendantFocusability(descendantFocusability); // restore
+ }
+ return true;
+ }
+
+ /**
+ * @return whether the descendant of this scroll view is scrolled off
+ * screen.
+ */
+ private boolean isOffScreen(View descendant) {
+ return !isWithinDeltaOfScreen(descendant, 0);
+ }
+
+ /**
+ * @return whether the descendant of this scroll view is within delta
+ * pixels of being on the screen.
+ */
+ private boolean isWithinDeltaOfScreen(View descendant, int delta) {
+ descendant.getDrawingRect(mTempRect);
+ offsetDescendantRectToMyCoords(descendant, mTempRect);
+
+ return (mTempRect.right + delta) >= getScrollX()
+ && (mTempRect.left - delta) <= (getScrollX() + getWidth());
+ }
+
+ /**
+ * Smooth scroll by a X delta
+ *
+ * @param delta the number of pixels to scroll by on the X axis
+ */
+ private void doScrollX(int delta) {
+ if (delta != 0) {
+ if (mSmoothScrollingEnabled) {
+ smoothScrollBy(delta, 0);
+ } else {
+ scrollBy(delta, 0);
+ }
+ }
+ }
+
+ /**
+ * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.
+ *
+ * @param dx the number of pixels to scroll by on the X axis
+ * @param dy the number of pixels to scroll by on the Y axis
+ */
+ public final void smoothScrollBy(int dx, int dy) {
+ long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll;
+ if (duration > ANIMATED_SCROLL_GAP) {
+ mScroller.startScroll(mScrollX, mScrollY, dx, dy);
+ invalidate();
+ } else {
+ if (!mScroller.isFinished()) {
+ mScroller.abortAnimation();
+ }
+ scrollBy(dx, dy);
+ }
+ mLastScroll = AnimationUtils.currentAnimationTimeMillis();
+ }
+
+ /**
+ * Like {@link #scrollTo}, but scroll smoothly instead of immediately.
+ *
+ * @param x the position where to scroll on the X axis
+ * @param y the position where to scroll on the Y axis
+ */
+ public final void smoothScrollTo(int x, int y) {
+ smoothScrollBy(x - mScrollX, y - mScrollY);
+ }
+
+ /**
+ * <p>The scroll range of a scroll view is the overall width of all of its
+ * children.</p>
+ */
+ @Override
+ protected int computeHorizontalScrollRange() {
+ int count = getChildCount();
+ return count == 0 ? getWidth() : getChildAt(0).getRight();
+ }
+
+
+ @Override
+ protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) {
+ ViewGroup.LayoutParams lp = child.getLayoutParams();
+
+ int childWidthMeasureSpec;
+ int childHeightMeasureSpec;
+
+ childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop
+ + mPaddingBottom, lp.height);
+
+ childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ }
+
+ @Override
+ protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
+ int parentHeightMeasureSpec, int heightUsed) {
+ final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+
+ final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
+ mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
+ + heightUsed, lp.height);
+ final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED);
+
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ }
+
+ @Override
+ public void computeScroll() {
+ if (mScroller.computeScrollOffset()) {
+ // This is called at drawing time by ViewGroup. We don't want to
+ // re-show the scrollbars at this point, which scrollTo will do,
+ // so we replicate most of scrollTo here.
+ //
+ // It's a little odd to call onScrollChanged from inside the drawing.
+ //
+ // It is, except when you remember that computeScroll() is used to
+ // animate scrolling. So unless we want to defer the onScrollChanged()
+ // until the end of the animated scrolling, we don't really have a
+ // choice here.
+ //
+ // I agree. The alternative, which I think would be worse, is to post
+ // something and tell the subclasses later. This is bad because there
+ // will be a window where mScrollX/Y is different from what the app
+ // thinks it is.
+ //
+ int oldX = mScrollX;
+ int oldY = mScrollY;
+ int x = mScroller.getCurrX();
+ int y = mScroller.getCurrY();
+ if (getChildCount() > 0) {
+ View child = getChildAt(0);
+ mScrollX = clamp(x, getWidth() - mPaddingRight - mPaddingLeft, child.getWidth());
+ mScrollY = clamp(y, getHeight() - mPaddingBottom - mPaddingTop, child.getHeight());
+ } else {
+ mScrollX = x;
+ mScrollY = y;
+ }
+ if (oldX != mScrollX || oldY != mScrollY) {
+ onScrollChanged(mScrollX, mScrollY, oldX, oldY);
+ }
+
+ // Keep on drawing until the animation has finished.
+ postInvalidate();
+ }
+ }
+
+ /**
+ * Scrolls the view to the given child.
+ *
+ * @param child the View to scroll to
+ */
+ private void scrollToChild(View child) {
+ child.getDrawingRect(mTempRect);
+
+ /* Offset from child's local coordinates to ScrollView coordinates */
+ offsetDescendantRectToMyCoords(child, mTempRect);
+
+ int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
+
+ if (scrollDelta != 0) {
+ scrollBy(scrollDelta, 0);
+ }
+ }
+
+ /**
+ * If rect is off screen, scroll just enough to get it (or at least the
+ * first screen size chunk of it) on screen.
+ *
+ * @param rect The rectangle.
+ * @param immediate True to scroll immediately without animation
+ * @return true if scrolling was performed
+ */
+ private boolean scrollToChildRect(Rect rect, boolean immediate) {
+ final int delta = computeScrollDeltaToGetChildRectOnScreen(rect);
+ final boolean scroll = delta != 0;
+ if (scroll) {
+ if (immediate) {
+ scrollBy(delta, 0);
+ } else {
+ smoothScrollBy(delta, 0);
+ }
+ }
+ return scroll;
+ }
+
+ /**
+ * Compute the amount to scroll in the X direction in order to get
+ * a rectangle completely on the screen (or, if taller than the screen,
+ * at least the first screen size chunk of it).
+ *
+ * @param rect The rect.
+ * @return The scroll delta.
+ */
+ protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
+
+ int width = getWidth();
+ int screenLeft = getScrollX();
+ int screenRight = screenLeft + width;
+
+ int fadingEdge = getHorizontalFadingEdgeLength();
+
+ // leave room for left fading edge as long as rect isn't at very left
+ if (rect.left > 0) {
+ screenLeft += fadingEdge;
+ }
+
+ // leave room for right fading edge as long as rect isn't at very right
+ if (rect.right < getChildAt(0).getWidth()) {
+ screenRight -= fadingEdge;
+ }
+
+ int scrollXDelta = 0;
+
+ if (rect.right > screenRight && rect.left > screenLeft) {
+ // need to move right to get it in view: move right just enough so
+ // that the entire rectangle is in view (or at least the first
+ // screen size chunk).
+
+ if (rect.width() > width) {
+ // just enough to get screen size chunk on
+ scrollXDelta += (rect.left - screenLeft);
+ } else {
+ // get entire rect at right of screen
+ scrollXDelta += (rect.right - screenRight);
+ }
+
+ // make sure we aren't scrolling beyond the end of our content
+ int right = getChildAt(getChildCount() - 1).getRight();
+ int distanceToRight = right - screenRight;
+ scrollXDelta = Math.min(scrollXDelta, distanceToRight);
+
+ } else if (rect.left < screenLeft && rect.right < screenRight) {
+ // need to move right to get it in view: move right just enough so that
+ // entire rectangle is in view (or at least the first screen
+ // size chunk of it).
+
+ if (rect.width() > width) {
+ // screen size chunk
+ scrollXDelta -= (screenRight - rect.right);
+ } else {
+ // entire rect at left
+ scrollXDelta -= (screenLeft - rect.left);
+ }
+
+ // make sure we aren't scrolling any further than the left our content
+ scrollXDelta = Math.max(scrollXDelta, -getScrollX());
+ }
+ return scrollXDelta;
+ }
+
+ @Override
+ public void requestChildFocus(View child, View focused) {
+ if (!mScrollViewMovedFocus) {
+ if (!mIsLayoutDirty) {
+ scrollToChild(focused);
+ } else {
+ // The child may not be laid out yet, we can't compute the scroll yet
+ mChildToScrollTo = focused;
+ }
+ }
+ super.requestChildFocus(child, focused);
+ }
+
+
+ /**
+ * When looking for focus in children of a scroll view, need to be a little
+ * more careful not to give focus to something that is scrolled off screen.
+ *
+ * This is more expensive than the default {@link android.view.ViewGroup}
+ * implementation, otherwise this behavior might have been made the default.
+ */
+ @Override
+ protected boolean onRequestFocusInDescendants(int direction,
+ Rect previouslyFocusedRect) {
+
+ // convert from forward / backward notation to up / down / left / right
+ // (ugh).
+ if (direction == View.FOCUS_FORWARD) {
+ direction = View.FOCUS_RIGHT;
+ } else if (direction == View.FOCUS_BACKWARD) {
+ direction = View.FOCUS_LEFT;
+ }
+
+ final View nextFocus = previouslyFocusedRect == null ?
+ FocusFinder.getInstance().findNextFocus(this, null, direction) :
+ FocusFinder.getInstance().findNextFocusFromRect(this,
+ previouslyFocusedRect, direction);
+
+ if (nextFocus == null) {
+ return false;
+ }
+
+ if (isOffScreen(nextFocus)) {
+ return false;
+ }
+
+ return nextFocus.requestFocus(direction, previouslyFocusedRect);
+ }
+
+ @Override
+ public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
+ boolean immediate) {
+ // offset into coordinate space of this scroll view
+ rectangle.offset(child.getLeft() - child.getScrollX(),
+ child.getTop() - child.getScrollY());
+
+ return scrollToChildRect(rectangle, immediate);
+ }
+
+ @Override
+ public void requestLayout() {
+ mIsLayoutDirty = true;
+ super.requestLayout();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ mIsLayoutDirty = false;
+ // Give a child focus if it needs it
+ if (mChildToScrollTo != null && isViewDescendantOf(mChildToScrollTo, this)) {
+ scrollToChild(mChildToScrollTo);
+ }
+ mChildToScrollTo = null;
+
+ // Calling this with the present values causes it to re-clam them
+ scrollTo(mScrollX, mScrollY);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+
+ View currentFocused = findFocus();
+ if (null == currentFocused || this == currentFocused)
+ return;
+
+ final int maxJump = mRight - mLeft;
+
+ if (isWithinDeltaOfScreen(currentFocused, maxJump)) {
+ currentFocused.getDrawingRect(mTempRect);
+ offsetDescendantRectToMyCoords(currentFocused, mTempRect);
+ int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
+ doScrollX(scrollDelta);
+ }
+ }
+
+ /**
+ * Return true if child is an descendant of parent, (or equal to the parent).
+ */
+ private boolean isViewDescendantOf(View child, View parent) {
+ if (child == parent) {
+ return true;
+ }
+
+ final ViewParent theParent = child.getParent();
+ return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
+ }
+
+ /**
+ * Fling the scroll view
+ *
+ * @param velocityX The initial velocity in the X direction. Positive
+ * numbers mean that the finger/curor is moving down the screen,
+ * which means we want to scroll towards the left.
+ */
+ public void fling(int velocityX) {
+ int width = getWidth() - mPaddingRight - mPaddingLeft;
+ int right = getChildAt(0).getWidth();
+
+ mScroller.fling(mScrollX, mScrollY, velocityX, 0, 0, right - width, 0, 0);
+
+ final boolean movingRight = velocityX > 0;
+
+ View newFocused = findFocusableViewInMyBounds(movingRight,
+ mScroller.getFinalX(), findFocus());
+
+ if (newFocused == null) {
+ newFocused = this;
+ }
+
+ if (newFocused != findFocus()
+ && newFocused.requestFocus(movingRight ? View.FOCUS_RIGHT : View.FOCUS_LEFT)) {
+ mScrollViewMovedFocus = true;
+ mScrollViewMovedFocus = false;
+ }
+
+ invalidate();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This version also clamps the scrolling to the bounds of our child.
+ */
+ public void scrollTo(int x, int y) {
+ // we rely on the fact the View.scrollBy calls scrollTo.
+ if (getChildCount() > 0) {
+ View child = getChildAt(0);
+ x = clamp(x, getWidth() - mPaddingRight - mPaddingLeft, child.getWidth());
+ y = clamp(y, getHeight() - mPaddingBottom - mPaddingTop, child.getHeight());
+ if (x != mScrollX || y != mScrollY) {
+ super.scrollTo(x, y);
+ }
+ }
+ }
+
+ private int clamp(int n, int my, int child) {
+ if (my >= child || n < 0) {
+ return 0;
+ }
+ if ((my + n) > child) {
+ return child - my;
+ }
+ return n;
+ }
+}
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index b5d4e2d..480b0b8 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -48,6 +48,7 @@ import android.widget.RemoteViews.RemoteView;
* @attr ref android.R.styleable#ImageView_maxHeight
* @attr ref android.R.styleable#ImageView_tint
* @attr ref android.R.styleable#ImageView_scaleType
+ * @attr ref android.R.styleable#ImageView_cropToPadding
*/
@RemoteView
public class ImageView extends View {
@@ -192,6 +193,7 @@ public class ImageView extends View {
*
* @attr ref android.R.styleable#ImageView_adjustViewBounds
*/
+ @android.view.RemotableViewMethod
public void setAdjustViewBounds(boolean adjustViewBounds) {
mAdjustViewBounds = adjustViewBounds;
if (adjustViewBounds) {
@@ -216,6 +218,7 @@ public class ImageView extends View {
*
* @attr ref android.R.styleable#ImageView_maxWidth
*/
+ @android.view.RemotableViewMethod
public void setMaxWidth(int maxWidth) {
mMaxWidth = maxWidth;
}
@@ -237,6 +240,7 @@ public class ImageView extends View {
*
* @attr ref android.R.styleable#ImageView_maxHeight
*/
+ @android.view.RemotableViewMethod
public void setMaxHeight(int maxHeight) {
mMaxHeight = maxHeight;
}
@@ -255,6 +259,7 @@ public class ImageView extends View {
*
* @attr ref android.R.styleable#ImageView_src
*/
+ @android.view.RemotableViewMethod
public void setImageResource(int resId) {
if (mUri != null || mResource != resId) {
updateDrawable(null);
@@ -271,6 +276,7 @@ public class ImageView extends View {
*
* @param uri The Uri of an image
*/
+ @android.view.RemotableViewMethod
public void setImageURI(Uri uri) {
if (mResource != 0 ||
(mUri != uri &&
@@ -305,6 +311,7 @@ public class ImageView extends View {
*
* @param bm The bitmap to set
*/
+ @android.view.RemotableViewMethod
public void setImageBitmap(Bitmap bm) {
// if this is used frequently, may handle bitmaps explicitly
// to reduce the intermediate drawable object
@@ -326,6 +333,13 @@ public class ImageView extends View {
resizeFromDrawable();
}
+ /**
+ * Sets the image level, when it is constructed from a
+ * {@link android.graphics.drawable.LevelListDrawable}.
+ *
+ * @param level The new level for the image.
+ */
+ @android.view.RemotableViewMethod
public void setImageLevel(int level) {
mLevel = level;
if (mDrawable != null) {
@@ -832,7 +846,7 @@ public class ImageView extends View {
@Override
public int getBaseline() {
- return mBaselineAligned ? getHeight() : -1;
+ return mBaselineAligned ? getMeasuredHeight() : -1;
}
/**
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 36ed8bd..a9822f8 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -136,6 +136,7 @@ public class LinearLayout extends ViewGroup {
*
* @attr ref android.R.styleable#LinearLayout_baselineAligned
*/
+ @android.view.RemotableViewMethod
public void setBaselineAligned(boolean baselineAligned) {
mBaselineAligned = baselineAligned;
}
@@ -208,6 +209,7 @@ public class LinearLayout extends ViewGroup {
*
* @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
*/
+ @android.view.RemotableViewMethod
public void setBaselineAlignedChildIndex(int i) {
if ((i < 0) || (i >= getChildCount())) {
throw new IllegalArgumentException("base aligned child index out "
@@ -265,6 +267,7 @@ public class LinearLayout extends ViewGroup {
* to 0.0f if the weight sum should be computed from the children's
* layout_weight
*/
+ @android.view.RemotableViewMethod
public void setWeightSum(float weightSum) {
mWeightSum = Math.max(0.0f, weightSum);
}
@@ -336,7 +339,7 @@ public class LinearLayout extends ViewGroup {
// heightMode is either UNSPECIFIED OR AT_MOST, and this child
// wanted to stretch to fill available space. Translate that to
// WRAP_CONTENT so that it does not end up with a height of 0
- oldHeight = lp.height;
+ oldHeight = 0;
lp.height = LayoutParams.WRAP_CONTENT;
}
@@ -475,8 +478,6 @@ public class LinearLayout extends ViewGroup {
matchWidthLocally ? margin : measuredWidth);
allFillParent = allFillParent && lp.width == LayoutParams.FILL_PARENT;
- alternativeMaxWidth = Math.max(alternativeMaxWidth,
- matchWidthLocally ? margin : measuredWidth);
mTotalLength += child.getMeasuredHeight() + lp.topMargin +
lp.bottomMargin + getNextLocationOffset(child);
@@ -607,7 +608,7 @@ public class LinearLayout extends ViewGroup {
// widthMode is either UNSPECIFIED OR AT_MOST, and this child
// wanted to stretch to fill available space. Translate that to
// WRAP_CONTENT so that it does not end up with a width of 0
- oldWidth = lp.width;
+ oldWidth = 0;
lp.width = LayoutParams.WRAP_CONTENT;
}
@@ -766,8 +767,6 @@ public class LinearLayout extends ViewGroup {
matchHeightLocally ? margin : childHeight);
allFillParent = allFillParent && lp.height == LayoutParams.FILL_PARENT;
- alternativeMaxHeight = Math.max(alternativeMaxHeight,
- matchHeightLocally ? margin : childHeight);
if (baselineAligned) {
final int childBaseline = child.getBaseline();
@@ -803,8 +802,7 @@ public class LinearLayout extends ViewGroup {
maxHeight = Math.max(maxHeight, ascent + descent);
}
} else {
- alternativeMaxHeight = Math.max(alternativeMaxHeight,
- weightedMaxHeight);
+ alternativeMaxHeight = Math.max(alternativeMaxHeight, weightedMaxHeight);
}
if (!allFillParent && heightMode != MeasureSpec.EXACTLY) {
@@ -1154,6 +1152,7 @@ public class LinearLayout extends ViewGroup {
*
* @attr ref android.R.styleable#LinearLayout_gravity
*/
+ @android.view.RemotableViewMethod
public void setGravity(int gravity) {
if (mGravity != gravity) {
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
@@ -1169,6 +1168,7 @@ public class LinearLayout extends ViewGroup {
}
}
+ @android.view.RemotableViewMethod
public void setHorizontalGravity(int horizontalGravity) {
final int gravity = horizontalGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
if ((mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != gravity) {
@@ -1177,6 +1177,7 @@ public class LinearLayout extends ViewGroup {
}
}
+ @android.view.RemotableViewMethod
public void setVerticalGravity(int verticalGravity) {
final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK;
if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index dfc7bc3..aced533 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -26,7 +26,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
-import android.util.SparseArray;
import android.view.FocusFinder;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -127,13 +126,7 @@ public class ListView extends AbsListView {
private SparseBooleanArray mCheckStates;
// used for temporary calculations.
- private Rect mTempRect = new Rect();
-
- /**
- * Used to save / restore the state of the focused child in {@link #layoutChildren()}
- */
- private SparseArray<Parcelable> mfocusRestoreChildState = new SparseArray<Parcelable>();
-
+ private final Rect mTempRect = new Rect();
// the single allocated result per list view; kinda cheesey but avoids
// allocating these thingies too often.
@@ -1011,34 +1004,13 @@ public class ListView extends AbsListView {
if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED ||
heightMode == MeasureSpec.UNSPECIFIED)) {
final View child = obtainView(0);
- final int childViewType = mAdapter.getItemViewType(0);
-
- AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams();
- if (lp == null) {
- lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT, 0);
- child.setLayoutParams(lp);
- }
- lp.viewType = childViewType;
-
- final int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
- mListPadding.left + mListPadding.right, lp.width);
-
- int lpHeight = lp.height;
-
- int childHeightSpec;
- if (lpHeight > 0) {
- childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
- } else {
- childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- }
- child.measure(childWidthSpec, childHeightSpec);
+ measureScrapChild(child, 0, widthMeasureSpec);
childWidth = child.getMeasuredWidth();
childHeight = child.getMeasuredHeight();
- if (mRecycler.shouldRecycleViewType(childViewType)) {
+ if (recycleOnMeasure()) {
mRecycler.addScrapView(child);
}
}
@@ -1055,13 +1027,41 @@ public class ListView extends AbsListView {
if (heightMode == MeasureSpec.AT_MOST) {
// TODO: after first layout we should maybe start at the first visible position, not 0
- heightSize = measureHeightOfChildren(
- MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY),
- 0, NO_POSITION, heightSize, -1);
+ heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
}
setMeasuredDimension(widthSize, heightSize);
- mWidthMeasureSpec = widthMeasureSpec;
+ mWidthMeasureSpec = widthMeasureSpec;
+ }
+
+ private void measureScrapChild(View child, int position, int widthMeasureSpec) {
+ LayoutParams p = (LayoutParams) child.getLayoutParams();
+ if (p == null) {
+ p = new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT, 0);
+ child.setLayoutParams(p);
+ }
+ p.viewType = mAdapter.getItemViewType(position);
+
+ int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
+ mListPadding.left + mListPadding.right, p.width);
+ int lpHeight = p.height;
+ int childHeightSpec;
+ if (lpHeight > 0) {
+ childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
+ } else {
+ childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ }
+ child.measure(childWidthSpec, childHeightSpec);
+ }
+
+ /**
+ * @return True to recycle the views used to measure this ListView in
+ * UNSPECIFIED/AT_MOST modes, false otherwise.
+ * @hide
+ */
+ protected boolean recycleOnMeasure() {
+ return true;
}
/**
@@ -1090,8 +1090,8 @@ public class ListView extends AbsListView {
* startPosition is 0).
* @return The height of this ListView with the given children.
*/
- final int measureHeightOfChildren(final int widthMeasureSpec, final int startPosition,
- int endPosition, final int maxHeight, int disallowPartialChildPosition) {
+ final int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition,
+ final int maxHeight, int disallowPartialChildPosition) {
final ListAdapter adapter = mAdapter;
if (adapter == null) {
@@ -1110,29 +1110,20 @@ public class ListView extends AbsListView {
// mItemCount - 1 since endPosition parameter is inclusive
endPosition = (endPosition == NO_POSITION) ? adapter.getCount() - 1 : endPosition;
final AbsListView.RecycleBin recycleBin = mRecycler;
+ final boolean recyle = recycleOnMeasure();
+
for (i = startPosition; i <= endPosition; ++i) {
child = obtainView(i);
- final int childViewType = adapter.getItemViewType(i);
- AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams();
- if (lp == null) {
- lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT, 0);
- child.setLayoutParams(lp);
- }
- lp.viewType = childViewType;
+ measureScrapChild(child, i, widthMeasureSpec);
if (i > 0) {
// Count the divider for all but one child
returnedHeight += dividerHeight;
}
- child.measure(widthMeasureSpec, lp.height >= 0
- ? MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY)
- : MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-
// Recycle the view before we possibly return from the method
- if (recycleBin.shouldRecycleViewType(childViewType)) {
+ if (recyle) {
recycleBin.addScrapView(child);
}
@@ -1329,6 +1320,8 @@ public class ListView extends AbsListView {
final boolean blockLayoutRequests = mBlockLayoutRequests;
if (!blockLayoutRequests) {
mBlockLayoutRequests = true;
+ } else {
+ return;
}
try {
@@ -1438,14 +1431,12 @@ public class ListView extends AbsListView {
// we can remember the focused view to restore after relayout if the
// data hasn't changed, or if the focused position is a header or footer
if (!dataChanged || isDirectChildHeaderOrFooter(focusedChild)) {
- focusLayoutRestoreDirectChild = getFocusedChild();
- if (focusLayoutRestoreDirectChild != null) {
-
- // remember its state
- focusLayoutRestoreDirectChild.saveHierarchyState(mfocusRestoreChildState);
-
- // remember the specific view that had focus
- focusLayoutRestoreView = findFocus();
+ focusLayoutRestoreDirectChild = focusedChild;
+ // remember the specific view that had focus
+ focusLayoutRestoreView = findFocus();
+ if (focusLayoutRestoreView != null) {
+ // tell it we are going to mess with it
+ focusLayoutRestoreView.onStartTemporaryDetach();
}
}
requestFocus();
@@ -1528,10 +1519,6 @@ public class ListView extends AbsListView {
sel.setSelected(false);
mSelectorRect.setEmpty();
}
-
- if (sel == focusLayoutRestoreDirectChild) {
- focusLayoutRestoreDirectChild.restoreHierarchyState(mfocusRestoreChildState);
- }
} else {
positionSelector(sel);
}
@@ -1544,10 +1531,16 @@ public class ListView extends AbsListView {
// focus (i.e. something focusable in touch mode)
if (hasFocus() && focusLayoutRestoreView != null) {
focusLayoutRestoreView.requestFocus();
- focusLayoutRestoreDirectChild.restoreHierarchyState(mfocusRestoreChildState);
}
}
+ // tell focus view we are done mucking with it, if it is still in
+ // our view hierarchy.
+ if (focusLayoutRestoreView != null
+ && focusLayoutRestoreView.getWindowToken() != null) {
+ focusLayoutRestoreView.onFinishTemporaryDetach();
+ }
+
mLayoutMode = LAYOUT_NORMAL;
mDataChanged = false;
mNeedSync = false;
@@ -1656,16 +1649,20 @@ public class ListView extends AbsListView {
// Respect layout params that are already in the view. Otherwise make some up...
// noinspection unchecked
- AbsListView.LayoutParams p = (AbsListView.LayoutParams)child.getLayoutParams();
+ AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams();
if (p == null) {
p = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 0);
}
p.viewType = mAdapter.getItemViewType(position);
- if (recycled) {
+ if (recycled || (p.recycledHeaderFooter &&
+ p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {
attachViewToParent(child, flowDown ? -1 : 0, p);
} else {
+ if (p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
+ p.recycledHeaderFooter = true;
+ }
addViewInLayout(child, flowDown ? -1 : 0, p, true);
}
@@ -1675,7 +1672,7 @@ public class ListView extends AbsListView {
if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
if (child instanceof Checkable) {
- ((Checkable)child).setChecked(mCheckStates.get(position));
+ ((Checkable) child).setChecked(mCheckStates.get(position));
}
}
@@ -1718,12 +1715,11 @@ public class ListView extends AbsListView {
}
/**
- * Sets the currently selected item
+ * Sets the currently selected item. If in touch mode, the item will not be selected
+ * but it will still be positioned appropriately. If the specified selection position
+ * is less than 0, then the item at position 0 will be selected.
*
* @param position Index (starting at 0) of the data item to be selected.
- *
- * If in touch mode, the item will not be selected but it will still be positioned
- * appropriately.
*/
@Override
public void setSelection(int position) {
@@ -1773,10 +1769,8 @@ public class ListView extends AbsListView {
*/
@Override
void setSelectionInt(int position) {
- mBlockLayoutRequests = true;
setNextSelectedPositionInt(position);
layoutChildren();
- mBlockLayoutRequests = false;
}
/**
@@ -2180,6 +2174,10 @@ public class ListView extends AbsListView {
&& !isViewAncestorOf(selectedView, this)) {
selectedView = null;
hideSelector();
+
+ // but we don't want to set the ressurect position (that would make subsequent
+ // unhandled key events bring back the item we just scrolled off!)
+ mResurrectToPosition = INVALID_POSITION;
}
if (needToRedraw) {
@@ -2646,6 +2644,7 @@ public class ListView extends AbsListView {
final int listBottom = getHeight() - mListPadding.bottom;
final int listTop = mListPadding.top;
+ final AbsListView.RecycleBin recycleBin = mRecycler;
if (amount < 0) {
// shifted items up
@@ -2673,8 +2672,13 @@ public class ListView extends AbsListView {
// top views may be panned off screen
View first = getChildAt(0);
while (first.getBottom() < listTop) {
- removeViewInLayout(first);
- mRecycler.addScrapView(first);
+ AbsListView.LayoutParams layoutParams = (LayoutParams) first.getLayoutParams();
+ if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {
+ removeViewInLayout(first);
+ recycleBin.addScrapView(first);
+ } else {
+ detachViewFromParent(first);
+ }
first = getChildAt(0);
mFirstPosition++;
}
@@ -2699,8 +2703,13 @@ public class ListView extends AbsListView {
// bottom view may be panned off screen
while (last.getTop() > listBottom) {
- removeViewInLayout(last);
- mRecycler.addScrapView(last);
+ AbsListView.LayoutParams layoutParams = (LayoutParams) last.getLayoutParams();
+ if (recycleBin.shouldRecycleViewType(layoutParams.viewType)) {
+ removeViewInLayout(last);
+ recycleBin.addScrapView(last);
+ } else {
+ detachViewFromParent(last);
+ }
last = getChildAt(--lastIndex);
}
}
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index f2cec92..227fb95 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -451,6 +451,7 @@ public class MediaController extends FrameLayout {
public void onProgressChanged(SeekBar bar, int progress, boolean fromtouch) {
if (fromtouch) {
mDragging = true;
+ duration = mPlayer.getDuration();
long newposition = (duration * progress) / 1000L;
mPlayer.seekTo( (int) newposition);
if (mCurrentTime != null)
diff --git a/core/java/android/widget/MultiAutoCompleteTextView.java b/core/java/android/widget/MultiAutoCompleteTextView.java
index 59a9310..05abc26 100644
--- a/core/java/android/widget/MultiAutoCompleteTextView.java
+++ b/core/java/android/widget/MultiAutoCompleteTextView.java
@@ -126,7 +126,7 @@ public class MultiAutoCompleteTextView extends AutoCompleteTextView {
Editable text = getText();
int end = getSelectionEnd();
- if (end < 0) {
+ if (end < 0 || mTokenizer == null) {
return false;
}
@@ -147,7 +147,7 @@ public class MultiAutoCompleteTextView extends AutoCompleteTextView {
public void performValidation() {
Validator v = getValidator();
- if (v == null) {
+ if (v == null || mTokenizer == null) {
return;
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 50248c1..a4f729f 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -24,15 +24,20 @@ import android.view.View;
import android.view.WindowManager;
import android.view.Gravity;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.view.View.OnTouchListener;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
import android.os.IBinder;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import java.lang.ref.WeakReference;
+
/**
* <p>A popup window that can be used to display an arbitrary view. The popup
* windows is a floating container that appears on top of the current
@@ -98,6 +103,8 @@ public class PopupWindow {
private Rect mTempRect = new Rect();
private Drawable mBackground;
+ private Drawable mAboveAnchorBackgroundDrawable;
+ private Drawable mBelowAnchorBackgroundDrawable;
private boolean mAboveAnchor;
@@ -109,7 +116,23 @@ public class PopupWindow {
private static final int[] ABOVE_ANCHOR_STATE_SET = new int[] {
com.android.internal.R.attr.state_above_anchor
};
-
+
+ private WeakReference<View> mAnchor;
+ private OnScrollChangedListener mOnScrollChangedListener =
+ new OnScrollChangedListener() {
+ public void onScrollChanged() {
+ View anchor = mAnchor.get();
+ if (anchor != null && mPopupView != null) {
+ WindowManager.LayoutParams p = (WindowManager.LayoutParams)
+ mPopupView.getLayoutParams();
+
+ mAboveAnchor = findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff);
+ update(p.x, p.y, -1, -1, true);
+ }
+ }
+ };
+ private int mAnchorXoff, mAnchorYoff;
+
/**
* <p>Create a new empty, non focusable popup window of dimension (0,0).</p>
*
@@ -144,6 +167,43 @@ public class PopupWindow {
mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground);
+ // If this is a StateListDrawable, try to find and store the drawable to be
+ // used when the drop-down is placed above its anchor view, and the one to be
+ // used when the drop-down is placed below its anchor view. We extract
+ // the drawables ourselves to work around a problem with using refreshDrawableState
+ // that it will take into account the padding of all drawables specified in a
+ // StateListDrawable, thus adding superfluous padding to drop-down views.
+ //
+ // We assume a StateListDrawable will have a drawable for ABOVE_ANCHOR_STATE_SET and
+ // at least one other drawable, intended for the 'below-anchor state'.
+ if (mBackground instanceof StateListDrawable) {
+ StateListDrawable background = (StateListDrawable) mBackground;
+
+ // Find the above-anchor view - this one's easy, it should be labeled as such.
+ int aboveAnchorStateIndex = background.getStateDrawableIndex(ABOVE_ANCHOR_STATE_SET);
+
+ // Now, for the below-anchor view, look for any other drawable specified in the
+ // StateListDrawable which is not for the above-anchor state and use that.
+ int count = background.getStateCount();
+ int belowAnchorStateIndex = -1;
+ for (int i = 0; i < count; i++) {
+ if (i != aboveAnchorStateIndex) {
+ belowAnchorStateIndex = i;
+ break;
+ }
+ }
+
+ // Store the drawables we found, if we found them. Otherwise, set them both
+ // to null so that we'll just use refreshDrawableState.
+ if (aboveAnchorStateIndex != -1 && belowAnchorStateIndex != -1) {
+ mAboveAnchorBackgroundDrawable = background.getStateDrawable(aboveAnchorStateIndex);
+ mBelowAnchorBackgroundDrawable = background.getStateDrawable(belowAnchorStateIndex);
+ } else {
+ mBelowAnchorBackgroundDrawable = null;
+ mAboveAnchorBackgroundDrawable = null;
+ }
+ }
+
a.recycle();
}
@@ -579,6 +639,8 @@ public class PopupWindow {
return;
}
+ unregisterForScrollChanged();
+
mIsShowing = true;
mIsDropdown = false;
@@ -617,6 +679,8 @@ public class PopupWindow {
* the popup in its entirety, this method tries to find a parent scroll
* view to scroll. If no parent scroll view can be scrolled, the bottom-left
* corner of the popup is pinned at the top left corner of the anchor view.</p>
+ * <p>If the view later scrolls to move <code>anchor</code> to a different
+ * location, the popup will be moved correspondingly.</p>
*
* @param anchor the view on which to pin the popup window
*
@@ -627,22 +691,54 @@ public class PopupWindow {
return;
}
+ registerForScrollChanged(anchor, xoff, yoff);
+
mIsShowing = true;
mIsDropdown = true;
WindowManager.LayoutParams p = createPopupLayout(anchor.getWindowToken());
preparePopup(p);
+ mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff);
+
if (mBackground != null) {
- mPopupView.refreshDrawableState();
+ // If the background drawable provided was a StateListDrawable with above-anchor
+ // and below-anchor states, use those. Otherwise rely on refreshDrawableState to
+ // do the job.
+ if (mAboveAnchorBackgroundDrawable != null) {
+ if (mAboveAnchor) {
+ mPopupView.setBackgroundDrawable(mAboveAnchorBackgroundDrawable);
+ } else {
+ mPopupView.setBackgroundDrawable(mBelowAnchorBackgroundDrawable);
+ }
+ } else {
+ mPopupView.refreshDrawableState();
+ }
}
- mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff);
+
if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;
+
p.windowAnimations = computeAnimationResource();
+
invokePopup(p);
}
/**
+ * Indicates whether the popup is showing above (the y coordinate of the popup's bottom
+ * is less than the y coordinate of the anchor) or below the anchor view (the y coordinate
+ * of the popup is greater than y coordinate of the anchor's bottom).
+ *
+ * The value returned
+ * by this method is meaningful only after {@link #showAsDropDown(android.view.View)}
+ * or {@link #showAsDropDown(android.view.View, int, int)} was invoked.
+ *
+ * @return True if this popup is showing above the anchor view, false otherwise.
+ */
+ public boolean isAboveAnchor() {
+ return mAboveAnchor;
+ }
+
+ /**
* <p>Prepare the popup by embedding in into a new ViewGroup if the
* background drawable is not null. If embedding is required, the layout
* parameters' height is mnodified to take into account the background's
@@ -652,28 +748,22 @@ public class PopupWindow {
*/
private void preparePopup(WindowManager.LayoutParams p) {
if (mBackground != null) {
+ final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
+ int height = ViewGroup.LayoutParams.FILL_PARENT;
+ if (layoutParams != null &&
+ layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ }
+
// when a background is available, we embed the content view
// within another view that owns the background drawable
PopupViewContainer popupViewContainer = new PopupViewContainer(mContext);
PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.FILL_PARENT
+ ViewGroup.LayoutParams.FILL_PARENT, height
);
popupViewContainer.setBackgroundDrawable(mBackground);
popupViewContainer.addView(mContentView, listParams);
- if (p.height >= 0) {
- // accomodate the popup's height to take into account the
- // background's padding
- p.height += popupViewContainer.getPaddingTop() +
- popupViewContainer.getPaddingBottom();
- }
- if (p.width >= 0) {
- // accomodate the popup's width to take into account the
- // background's padding
- p.width += popupViewContainer.getPaddingLeft() +
- popupViewContainer.getPaddingRight();
- }
mPopupView = popupViewContainer;
} else {
mPopupView = mContentView;
@@ -720,7 +810,8 @@ public class PopupWindow {
p.flags = computeFlags(p.flags);
p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
p.token = token;
-
+ p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
+
return p;
}
@@ -746,7 +837,7 @@ public class PopupWindow {
if (!mTouchable) {
curFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
}
- if (mTouchable) {
+ if (mOutsideTouchable) {
curFlags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
}
if (!mClippingEnabled) {
@@ -781,7 +872,9 @@ public class PopupWindow {
*
* @return true if the popup is translated upwards to fit on screen
*/
- private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p, int xoff, int yoff) {
+ private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
+ int xoff, int yoff) {
+
anchor.getLocationInWindow(mDrawingLocation);
p.x = mDrawingLocation[0] + xoff;
p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff;
@@ -795,8 +888,7 @@ public class PopupWindow {
anchor.getWindowVisibleDisplayFrame(displayFrame);
final View root = anchor.getRootView();
- if (mScreenLocation[1] + anchor.getMeasuredHeight() + yoff + mPopupHeight > displayFrame.bottom
- || p.x + mPopupWidth - root.getWidth() > 0) {
+ if (p.y + mPopupHeight > displayFrame.bottom || p.x + mPopupWidth - root.getWidth() > 0) {
// if the drop down disappears at the bottom of the screen. we try to
// scroll a parent scrollview or move the drop down back up on top of
// the edit box
@@ -815,11 +907,11 @@ public class PopupWindow {
// determine whether there is more space above or below the anchor
anchor.getLocationOnScreen(mScreenLocation);
- onTop = (displayFrame.bottom - mScreenLocation[1] - anchor.getMeasuredHeight() - yoff)
- < (mScreenLocation[1] - yoff - displayFrame.top);
+ onTop = (displayFrame.bottom - mScreenLocation[1] - anchor.getMeasuredHeight() - yoff) <
+ (mScreenLocation[1] - yoff - displayFrame.top);
if (onTop) {
p.gravity = Gravity.LEFT | Gravity.BOTTOM;
- p.y = root.getHeight() - mDrawingLocation[1] - yoff;
+ p.y = root.getHeight() - mDrawingLocation[1] + yoff;
} else {
p.y = mDrawingLocation[1] + anchor.getMeasuredHeight() + yoff;
}
@@ -841,15 +933,30 @@ public class PopupWindow {
* shown.
*/
public int getMaxAvailableHeight(View anchor) {
+ return getMaxAvailableHeight(anchor, 0);
+ }
+
+ /**
+ * Returns the maximum height that is available for the popup to be
+ * completely shown. It is recommended that this height be the maximum for
+ * the popup's height, otherwise it is possible that the popup will be
+ * clipped.
+ *
+ * @param anchor The view on which the popup window must be anchored.
+ * @param yOffset y offset from the view's bottom edge
+ * @return The maximum available height for the popup to be completely
+ * shown.
+ */
+ public int getMaxAvailableHeight(View anchor, int yOffset) {
final Rect displayFrame = new Rect();
anchor.getWindowVisibleDisplayFrame(displayFrame);
final int[] anchorPos = mDrawingLocation;
anchor.getLocationOnScreen(anchorPos);
- final int distanceToBottom = displayFrame.bottom
- - (anchorPos[1] + anchor.getHeight());
- final int distanceToTop = anchorPos[1] - displayFrame.top;
+ final int distanceToBottom = displayFrame.bottom -
+ (anchorPos[1] + anchor.getHeight()) - yOffset;
+ final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
// anchorPos[1] is distance from anchor to top of screen
int returnedHeight = Math.max(distanceToBottom, distanceToTop);
@@ -870,6 +977,8 @@ public class PopupWindow {
*/
public void dismiss() {
if (isShowing() && mPopupView != null) {
+ unregisterForScrollChanged();
+
mWindowManager.removeView(mPopupView);
if (mPopupView != mContentView && mPopupView instanceof ViewGroup) {
((ViewGroup) mPopupView).removeView(mContentView);
@@ -938,11 +1047,32 @@ public class PopupWindow {
* @param height the new height, can be -1 to ignore
*/
public void update(int x, int y, int width, int height) {
+ update(x, y, width, height, false);
+ }
+
+ /**
+ * <p>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()}.</p>
+ *
+ * @param x the new x location
+ * @param y the new y location
+ * @param width the new width, can be -1 to ignore
+ * @param height the new height, can be -1 to ignore
+ * @param force reposition the window even if the specified position
+ * already seems to correspond to the LayoutParams
+ *
+ * @hide pending API council approval
+ */
+ public void update(int x, int y, int width, int height, boolean force) {
if (width != -1) {
+ mLastWidth = width;
setWidth(width);
}
if (height != -1) {
+ mLastHeight = height;
setHeight(height);
}
@@ -953,7 +1083,7 @@ public class PopupWindow {
WindowManager.LayoutParams p = (WindowManager.LayoutParams)
mPopupView.getLayoutParams();
- boolean update = false;
+ boolean update = force;
final int finalWidth = mWidthMode < 0 ? mWidthMode : mLastWidth;
if (width != -1 && p.width != finalWidth) {
@@ -990,22 +1120,6 @@ public class PopupWindow {
}
if (update) {
- if (mPopupView != mContentView) {
- final View popupViewContainer = mPopupView;
- if (p.height >= 0) {
- // accomodate the popup's height to take into account the
- // background's padding
- p.height += popupViewContainer.getPaddingTop() +
- popupViewContainer.getPaddingBottom();
- }
- if (p.width >= 0) {
- // accomodate the popup's width to take into account the
- // background's padding
- p.width += popupViewContainer.getPaddingLeft() +
- popupViewContainer.getPaddingRight();
- }
- }
-
mWindowManager.updateViewLayout(mPopupView, p);
}
}
@@ -1029,6 +1143,8 @@ public class PopupWindow {
* 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()}.</p>
+ * <p>If the view later scrolls to move <code>anchor</code> to a different
+ * location, the popup will be moved correspondingly.</p>
*
* @param anchor the popup's anchor view
* @param xoff x offset from the view's left edge
@@ -1041,6 +1157,12 @@ public class PopupWindow {
return;
}
+ WeakReference<View> oldAnchor = mAnchor;
+ if (oldAnchor == null || oldAnchor.get() != anchor ||
+ mAnchorXoff != xoff || mAnchorYoff != yoff) {
+ registerForScrollChanged(anchor, xoff, yoff);
+ }
+
WindowManager.LayoutParams p = (WindowManager.LayoutParams)
mPopupView.getLayoutParams();
@@ -1055,10 +1177,10 @@ public class PopupWindow {
mPopupHeight = height;
}
- findDropDownPosition(anchor, p, xoff, yoff);
+ mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff);
update(p.x, p.y, width, height);
}
-
+
/**
* Listener that is called when this popup window is dismissed.
*/
@@ -1068,7 +1190,33 @@ public class PopupWindow {
*/
public void onDismiss();
}
-
+
+ private void unregisterForScrollChanged() {
+ WeakReference<View> anchorRef = mAnchor;
+ View anchor = null;
+ if (anchorRef != null) {
+ anchor = anchorRef.get();
+ }
+ if (anchor != null) {
+ ViewTreeObserver vto = anchor.getViewTreeObserver();
+ vto.removeOnScrollChangedListener(mOnScrollChangedListener);
+ }
+ mAnchor = null;
+ }
+
+ private void registerForScrollChanged(View anchor, int xoff, int yoff) {
+ unregisterForScrollChanged();
+
+ mAnchor = new WeakReference<View>(anchor);
+ ViewTreeObserver vto = anchor.getViewTreeObserver();
+ if (vto != null) {
+ vto.addOnScrollChangedListener(mOnScrollChangedListener);
+ }
+
+ mAnchorXoff = xoff;
+ mAnchorYoff = yoff;
+ }
+
private class PopupViewContainer extends FrameLayout {
public PopupViewContainer(Context context) {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 2e04b5d..441414a 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -344,6 +344,7 @@ public class ProgressBar extends View {
*
* @param indeterminate true to enable the indeterminate mode
*/
+ @android.view.RemotableViewMethod
public synchronized void setIndeterminate(boolean indeterminate) {
if ((!mOnlyIndeterminate || !mIndeterminate) && indeterminate != mIndeterminate) {
mIndeterminate = indeterminate;
@@ -525,10 +526,12 @@ public class ProgressBar extends View {
* @see #getProgress()
* @see #incrementProgressBy(int)
*/
+ @android.view.RemotableViewMethod
public synchronized void setProgress(int progress) {
setProgress(progress, false);
}
+ @android.view.RemotableViewMethod
synchronized void setProgress(int progress, boolean fromUser) {
if (mIndeterminate) {
return;
@@ -560,6 +563,7 @@ public class ProgressBar extends View {
* @see #getSecondaryProgress()
* @see #incrementSecondaryProgressBy(int)
*/
+ @android.view.RemotableViewMethod
public synchronized void setSecondaryProgress(int secondaryProgress) {
if (mIndeterminate) {
return;
@@ -633,6 +637,7 @@ public class ProgressBar extends View {
* @see #setProgress(int)
* @see #setSecondaryProgress(int)
*/
+ @android.view.RemotableViewMethod
public synchronized void setMax(int max) {
if (max < 0) {
max = 0;
@@ -758,10 +763,10 @@ public class ProgressBar extends View {
@Override
public void invalidateDrawable(Drawable dr) {
if (!mInDrawing) {
- if (dr == mProgressDrawable || dr == mIndeterminateDrawable) {
+ if (verifyDrawable(dr)) {
final Rect dirty = dr.getBounds();
final int scrollX = mScrollX + mPaddingLeft;
- final int scrollY = mScrollY + mPaddingRight;
+ final int scrollY = mScrollY + mPaddingTop;
invalidate(dirty.left + scrollX, dirty.top + scrollY,
dirty.right + scrollX, dirty.bottom + scrollY);
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index ed8df22..393346a 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -122,6 +122,23 @@ public class RadioGroup extends LinearLayout {
}
}
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ if (child instanceof RadioButton) {
+ final RadioButton button = (RadioButton) child;
+ if (button.isChecked()) {
+ mProtectFromCheckedChange = true;
+ if (mCheckedId != -1) {
+ setCheckedStateForView(mCheckedId, false);
+ }
+ mProtectFromCheckedChange = false;
+ setCheckedId(button.getId());
+ }
+ }
+
+ super.addView(child, index, params);
+ }
+
/**
* <p>Sets the selection to the radio button whose identifier is passed in
* parameter. Using -1 as the selection identifier clears the selection;
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 91d5805..52c421c 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -22,6 +22,7 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.Gravity;
+import android.view.ViewDebug;
import android.widget.RemoteViews.RemoteView;
import android.graphics.Rect;
import com.android.internal.R;
@@ -152,7 +153,7 @@ public class RelativeLayout extends ViewGroup {
private void initFromAttributes(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RelativeLayout);
- mIgnoreGravity = a.getResourceId(R.styleable.RelativeLayout_ignoreGravity, 0);
+ mIgnoreGravity = a.getResourceId(R.styleable.RelativeLayout_ignoreGravity, View.NO_ID);
mGravity = a.getInt(R.styleable.RelativeLayout_gravity, mGravity);
a.recycle();
}
@@ -168,6 +169,7 @@ public class RelativeLayout extends ViewGroup {
*
* @attr ref android.R.styleable#RelativeLayout_ignoreGravity
*/
+ @android.view.RemotableViewMethod
public void setIgnoreGravity(int viewId) {
mIgnoreGravity = viewId;
}
@@ -183,6 +185,7 @@ public class RelativeLayout extends ViewGroup {
*
* @attr ref android.R.styleable#RelativeLayout_gravity
*/
+ @android.view.RemotableViewMethod
public void setGravity(int gravity) {
if (mGravity != gravity) {
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
@@ -198,6 +201,7 @@ public class RelativeLayout extends ViewGroup {
}
}
+ @android.view.RemotableViewMethod
public void setHorizontalGravity(int horizontalGravity) {
final int gravity = horizontalGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
if ((mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != gravity) {
@@ -206,6 +210,7 @@ public class RelativeLayout extends ViewGroup {
}
}
+ @android.view.RemotableViewMethod
public void setVerticalGravity(int verticalGravity) {
final int gravity = verticalGravity & Gravity.VERTICAL_GRAVITY_MASK;
if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != gravity) {
@@ -263,7 +268,7 @@ public class RelativeLayout extends ViewGroup {
int right = Integer.MIN_VALUE;
int bottom = Integer.MIN_VALUE;
- if ((horizontalGravity || verticalGravity) && mIgnoreGravity != 0) {
+ if ((horizontalGravity || verticalGravity) && mIgnoreGravity != View.NO_ID) {
ignore = findViewById(mIgnoreGravity);
}
@@ -799,13 +804,33 @@ public class RelativeLayout extends ViewGroup {
* @attr ref android.R.styleable#RelativeLayout_Layout_layout_centerVertical
*/
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
+ @ViewDebug.ExportedProperty(resolveId = true, indexMapping = {
+ @ViewDebug.IntToString(from = ABOVE, to = "above"),
+ @ViewDebug.IntToString(from = ALIGN_BASELINE, to = "alignBaseline"),
+ @ViewDebug.IntToString(from = ALIGN_BOTTOM, to = "alignBottom"),
+ @ViewDebug.IntToString(from = ALIGN_LEFT, to = "alignLeft"),
+ @ViewDebug.IntToString(from = ALIGN_PARENT_BOTTOM, to = "alignParentBottom"),
+ @ViewDebug.IntToString(from = ALIGN_PARENT_LEFT, to = "alignParentLeft"),
+ @ViewDebug.IntToString(from = ALIGN_PARENT_RIGHT, to = "alignParentRight"),
+ @ViewDebug.IntToString(from = ALIGN_PARENT_TOP, to = "alignParentTop"),
+ @ViewDebug.IntToString(from = ALIGN_RIGHT, to = "alignRight"),
+ @ViewDebug.IntToString(from = ALIGN_TOP, to = "alignTop"),
+ @ViewDebug.IntToString(from = BELOW, to = "below"),
+ @ViewDebug.IntToString(from = CENTER_HORIZONTAL, to = "centerHorizontal"),
+ @ViewDebug.IntToString(from = CENTER_IN_PARENT, to = "center"),
+ @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") })
private int[] mRules = new int[VERB_COUNT];
+
private int mLeft, mTop, mRight, mBottom;
/**
* When true, uses the parent as the anchor if the anchor doesn't exist or if
* the anchor's visibility is GONE.
*/
+ @ViewDebug.ExportedProperty
public boolean alignWithParent;
public LayoutParams(Context c, AttributeSet attrs) {
diff --git a/core/java/android/gadget/GadgetInfo.aidl b/core/java/android/widget/RemoteViews.aidl
index 7231545..ec86410 100644
--- a/core/java/android/gadget/GadgetInfo.aidl
+++ b/core/java/android/widget/RemoteViews.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.gadget;
+package android.widget;
-parcelable GadgetInfo;
+parcelable RemoteViews;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 5721095..e000d2e 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -30,15 +31,21 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.RemotableViewMethod;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater.Filter;
import android.view.View.OnClickListener;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import java.lang.Class;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -77,19 +84,22 @@ public class RemoteViews implements Parcelable, Filter {
/**
- * This annotation indicates that a subclass of View is alllowed to be used with the
- * {@link android.widget.RemoteViews} mechanism.
+ * This annotation indicates that a subclass of View is alllowed to be used
+ * with the {@link android.widget.RemoteViews} mechanism.
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface RemoteView {
}
-
+
/**
* Exception to send when something goes wrong executing an action
*
*/
public static class ActionException extends RuntimeException {
+ public ActionException(Exception ex) {
+ super(ex);
+ }
public ActionException(String message) {
super(message);
}
@@ -107,320 +117,349 @@ public class RemoteViews implements Parcelable, Filter {
return 0;
}
};
-
- /**
- * Equivalent to calling View.setVisibility
- */
- private class SetViewVisibility extends Action {
- public SetViewVisibility(int id, int vis) {
- viewId = id;
- visibility = vis;
- }
-
- public SetViewVisibility(Parcel parcel) {
- viewId = parcel.readInt();
- visibility = parcel.readInt();
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(TAG);
- dest.writeInt(viewId);
- dest.writeInt(visibility);
- }
-
- @Override
- public void apply(View root) {
- View target = root.findViewById(viewId);
- if (target != null) {
- target.setVisibility(visibility);
- }
- }
-
- private int viewId;
- private int visibility;
- public final static int TAG = 0;
- }
-
+
/**
- * Equivalent to calling TextView.setText
+ * Equivalent to calling
+ * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
+ * to launch the provided {@link PendingIntent}.
*/
- private class SetTextViewText extends Action {
- public SetTextViewText(int id, CharSequence t) {
- viewId = id;
- text = t;
+ private class SetOnClickPendingIntent extends Action {
+ public SetOnClickPendingIntent(int id, PendingIntent pendingIntent) {
+ this.viewId = id;
+ this.pendingIntent = pendingIntent;
}
- public SetTextViewText(Parcel parcel) {
+ public SetOnClickPendingIntent(Parcel parcel) {
viewId = parcel.readInt();
- text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(TAG);
dest.writeInt(viewId);
- TextUtils.writeToParcel(text, dest, flags);
+ pendingIntent.writeToParcel(dest, 0 /* no flags */);
}
@Override
public void apply(View root) {
- TextView target = (TextView) root.findViewById(viewId);
- if (target != null) {
- target.setText(text);
+ final View target = root.findViewById(viewId);
+ if (target != null && pendingIntent != null) {
+ OnClickListener listener = new OnClickListener() {
+ public void onClick(View v) {
+ try {
+ // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
+ pendingIntent.send();
+ } catch (CanceledException e) {
+ throw new ActionException(e.toString());
+ }
+ }
+ };
+ target.setOnClickListener(listener);
}
}
int viewId;
- CharSequence text;
+ PendingIntent pendingIntent;
+
public final static int TAG = 1;
}
/**
- * Equivalent to calling ImageView.setResource
+ * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
+ * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
+ * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given view.
+ * <p>
+ * These operations will be performed on the {@link Drawable} returned by the
+ * target {@link View#getBackground()} by default. If targetBackground is false,
+ * we assume the target is an {@link ImageView} and try applying the operations
+ * to {@link ImageView#getDrawable()}.
+ * <p>
+ * You can omit specific calls by marking their values with null or -1.
*/
- private class SetImageViewResource extends Action {
- public SetImageViewResource(int id, int src) {
- viewId = id;
- srcId = src;
+ private class SetDrawableParameters extends Action {
+ public SetDrawableParameters(int id, boolean targetBackground, int alpha,
+ int colorFilter, PorterDuff.Mode mode, int level) {
+ this.viewId = id;
+ this.targetBackground = targetBackground;
+ this.alpha = alpha;
+ this.colorFilter = colorFilter;
+ this.filterMode = mode;
+ this.level = level;
}
- public SetImageViewResource(Parcel parcel) {
+ public SetDrawableParameters(Parcel parcel) {
viewId = parcel.readInt();
- srcId = parcel.readInt();
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(TAG);
- dest.writeInt(viewId);
- dest.writeInt(srcId);
- }
-
- @Override
- public void apply(View root) {
- ImageView target = (ImageView) root.findViewById(viewId);
- Drawable d = mContext.getResources().getDrawable(srcId);
- if (target != null) {
- target.setImageDrawable(d);
+ targetBackground = parcel.readInt() != 0;
+ alpha = parcel.readInt();
+ colorFilter = parcel.readInt();
+ boolean hasMode = parcel.readInt() != 0;
+ if (hasMode) {
+ filterMode = PorterDuff.Mode.valueOf(parcel.readString());
+ } else {
+ filterMode = null;
}
- }
-
- int viewId;
- int srcId;
- public final static int TAG = 2;
- }
-
- /**
- * Equivalent to calling ImageView.setImageURI
- */
- private class SetImageViewUri extends Action {
- public SetImageViewUri(int id, Uri u) {
- viewId = id;
- uri = u;
- }
-
- public SetImageViewUri(Parcel parcel) {
- viewId = parcel.readInt();
- uri = Uri.CREATOR.createFromParcel(parcel);
+ level = parcel.readInt();
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(TAG);
dest.writeInt(viewId);
- Uri.writeToParcel(dest, uri);
+ dest.writeInt(targetBackground ? 1 : 0);
+ dest.writeInt(alpha);
+ dest.writeInt(colorFilter);
+ if (filterMode != null) {
+ dest.writeInt(1);
+ dest.writeString(filterMode.toString());
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeInt(level);
}
@Override
public void apply(View root) {
- ImageView target = (ImageView) root.findViewById(viewId);
- if (target != null) {
- target.setImageURI(uri);
+ final View target = root.findViewById(viewId);
+ if (target == null) {
+ return;
+ }
+
+ // Pick the correct drawable to modify for this view
+ Drawable targetDrawable = null;
+ if (targetBackground) {
+ targetDrawable = target.getBackground();
+ } else if (target instanceof ImageView) {
+ ImageView imageView = (ImageView) target;
+ targetDrawable = imageView.getDrawable();
+ }
+
+ // Perform modifications only if values are set correctly
+ if (alpha != -1) {
+ targetDrawable.setAlpha(alpha);
+ }
+ if (colorFilter != -1 && filterMode != null) {
+ targetDrawable.setColorFilter(colorFilter, filterMode);
+ }
+ if (level != -1) {
+ targetDrawable.setLevel(level);
}
}
int viewId;
- Uri uri;
+ boolean targetBackground;
+ int alpha;
+ int colorFilter;
+ PorterDuff.Mode filterMode;
+ int level;
+
public final static int TAG = 3;
}
-
+
/**
- * Equivalent to calling ImageView.setImageBitmap
+ * Base class for the reflection actions.
*/
- private class SetImageViewBitmap extends Action {
- public SetImageViewBitmap(int id, Bitmap src) {
- viewId = id;
- bitmap = src;
- }
+ private class ReflectionAction extends Action {
+ static final int TAG = 2;
+
+ static final int BOOLEAN = 1;
+ static final int BYTE = 2;
+ static final int SHORT = 3;
+ static final int INT = 4;
+ static final int LONG = 5;
+ static final int FLOAT = 6;
+ static final int DOUBLE = 7;
+ static final int CHAR = 8;
+ static final int STRING = 9;
+ static final int CHAR_SEQUENCE = 10;
+ static final int URI = 11;
+ static final int BITMAP = 12;
- public SetImageViewBitmap(Parcel parcel) {
- viewId = parcel.readInt();
- bitmap = Bitmap.CREATOR.createFromParcel(parcel);
+ int viewId;
+ String methodName;
+ int type;
+ Object value;
+
+ ReflectionAction(int viewId, String methodName, int type, Object value) {
+ this.viewId = viewId;
+ this.methodName = methodName;
+ this.type = type;
+ this.value = value;
+ }
+
+ ReflectionAction(Parcel in) {
+ this.viewId = in.readInt();
+ this.methodName = in.readString();
+ this.type = in.readInt();
+ if (false) {
+ Log.d("RemoteViews", "read viewId=0x" + Integer.toHexString(this.viewId)
+ + " methodName=" + this.methodName + " type=" + this.type);
+ }
+ switch (this.type) {
+ case BOOLEAN:
+ this.value = in.readInt() != 0;
+ break;
+ case BYTE:
+ this.value = in.readByte();
+ break;
+ case SHORT:
+ this.value = (short)in.readInt();
+ break;
+ case INT:
+ this.value = in.readInt();
+ break;
+ case LONG:
+ this.value = in.readLong();
+ break;
+ case FLOAT:
+ this.value = in.readFloat();
+ break;
+ case DOUBLE:
+ this.value = in.readDouble();
+ break;
+ case CHAR:
+ this.value = (char)in.readInt();
+ break;
+ case STRING:
+ this.value = in.readString();
+ break;
+ case CHAR_SEQUENCE:
+ this.value = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ break;
+ case URI:
+ this.value = Uri.CREATOR.createFromParcel(in);
+ break;
+ case BITMAP:
+ this.value = Bitmap.CREATOR.createFromParcel(in);
+ break;
+ default:
+ break;
+ }
}
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(TAG);
- dest.writeInt(viewId);
- if (bitmap != null) {
- bitmap.writeToParcel(dest, flags);
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(TAG);
+ out.writeInt(this.viewId);
+ out.writeString(this.methodName);
+ out.writeInt(this.type);
+ if (false) {
+ Log.d("RemoteViews", "write viewId=0x" + Integer.toHexString(this.viewId)
+ + " methodName=" + this.methodName + " type=" + this.type);
+ }
+ switch (this.type) {
+ case BOOLEAN:
+ out.writeInt(((Boolean)this.value).booleanValue() ? 1 : 0);
+ break;
+ case BYTE:
+ out.writeByte(((Byte)this.value).byteValue());
+ break;
+ case SHORT:
+ out.writeInt(((Short)this.value).shortValue());
+ break;
+ case INT:
+ out.writeInt(((Integer)this.value).intValue());
+ break;
+ case LONG:
+ out.writeLong(((Long)this.value).longValue());
+ break;
+ case FLOAT:
+ out.writeFloat(((Float)this.value).floatValue());
+ break;
+ case DOUBLE:
+ out.writeDouble(((Double)this.value).doubleValue());
+ break;
+ case CHAR:
+ out.writeInt((int)((Character)this.value).charValue());
+ break;
+ case STRING:
+ out.writeString((String)this.value);
+ break;
+ case CHAR_SEQUENCE:
+ TextUtils.writeToParcel((CharSequence)this.value, out, flags);
+ break;
+ case URI:
+ ((Uri)this.value).writeToParcel(out, flags);
+ break;
+ case BITMAP:
+ ((Bitmap)this.value).writeToParcel(out, flags);
+ break;
+ default:
+ break;
}
}
- @Override
- public void apply(View root) {
- if (bitmap != null) {
- ImageView target = (ImageView) root.findViewById(viewId);
- Drawable d = new BitmapDrawable(bitmap);
- if (target != null) {
- target.setImageDrawable(d);
- }
+ private Class getParameterType() {
+ switch (this.type) {
+ case BOOLEAN:
+ return boolean.class;
+ case BYTE:
+ return byte.class;
+ case SHORT:
+ return short.class;
+ case INT:
+ return int.class;
+ case LONG:
+ return long.class;
+ case FLOAT:
+ return float.class;
+ case DOUBLE:
+ return double.class;
+ case CHAR:
+ return char.class;
+ case STRING:
+ return String.class;
+ case CHAR_SEQUENCE:
+ return CharSequence.class;
+ case URI:
+ return Uri.class;
+ case BITMAP:
+ return Bitmap.class;
+ default:
+ return null;
}
}
- int viewId;
- Bitmap bitmap;
- public final static int TAG = 4;
- }
-
- /**
- * Equivalent to calling Chronometer.setBase, Chronometer.setFormat,
- * and Chronometer.start/stop.
- */
- private class SetChronometer extends Action {
- public SetChronometer(int id, long base, String format, boolean running) {
- this.viewId = id;
- this.base = base;
- this.format = format;
- this.running = running;
- }
-
- public SetChronometer(Parcel parcel) {
- viewId = parcel.readInt();
- base = parcel.readLong();
- format = parcel.readString();
- running = parcel.readInt() != 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(TAG);
- dest.writeInt(viewId);
- dest.writeLong(base);
- dest.writeString(format);
- dest.writeInt(running ? 1 : 0);
- }
-
@Override
public void apply(View root) {
- Chronometer target = (Chronometer) root.findViewById(viewId);
- if (target != null) {
- target.setBase(base);
- target.setFormat(format);
- if (running) {
- target.start();
- } else {
- target.stop();
- }
+ final View view = root.findViewById(viewId);
+ if (view == null) {
+ throw new ActionException("can't find view: 0x" + Integer.toHexString(viewId));
}
- }
-
- int viewId;
- boolean running;
- long base;
- String format;
- public final static int TAG = 5;
- }
-
- /**
- * Equivalent to calling ProgressBar.setMax, ProgressBar.setProgress and
- * ProgressBar.setIndeterminate
- */
- private class SetProgressBar extends Action {
- public SetProgressBar(int id, int max, int progress, boolean indeterminate) {
- this.viewId = id;
- this.progress = progress;
- this.max = max;
- this.indeterminate = indeterminate;
- }
-
- public SetProgressBar(Parcel parcel) {
- viewId = parcel.readInt();
- progress = parcel.readInt();
- max = parcel.readInt();
- indeterminate = parcel.readInt() != 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(TAG);
- dest.writeInt(viewId);
- dest.writeInt(progress);
- dest.writeInt(max);
- dest.writeInt(indeterminate ? 1 : 0);
- }
-
- @Override
- public void apply(View root) {
- ProgressBar target = (ProgressBar) root.findViewById(viewId);
- if (target != null) {
- target.setIndeterminate(indeterminate);
- if (!indeterminate) {
- target.setMax(max);
- target.setProgress(progress);
- }
+ Class param = getParameterType();
+ if (param == null) {
+ throw new ActionException("bad type: " + this.type);
}
- }
-
- int viewId;
- boolean indeterminate;
- int progress;
- int max;
- public final static int TAG = 6;
- }
-
- /**
- * Equivalent to calling
- * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
- * to launch the provided {@link PendingIntent}.
- */
- private class SetOnClickPendingIntent extends Action {
- public SetOnClickPendingIntent(int id, PendingIntent pendingIntent) {
- this.viewId = id;
- this.pendingIntent = pendingIntent;
- }
-
- public SetOnClickPendingIntent(Parcel parcel) {
- viewId = parcel.readInt();
- pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(TAG);
- dest.writeInt(viewId);
- pendingIntent.writeToParcel(dest, 0 /* no flags */);
- }
-
- @Override
- public void apply(View root) {
- final View target = root.findViewById(viewId);
- if (target != null && pendingIntent != null) {
- OnClickListener listener = new OnClickListener() {
- public void onClick(View v) {
- try {
- // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
- pendingIntent.send();
- } catch (CanceledException e) {
- throw new ActionException(e.toString());
- }
- }
- };
- target.setOnClickListener(listener);
+ Class klass = view.getClass();
+ Method method = null;
+ try {
+ method = klass.getMethod(this.methodName, getParameterType());
+ }
+ catch (NoSuchMethodException ex) {
+ throw new ActionException("view: " + klass.getName() + " doesn't have method: "
+ + this.methodName + "(" + param.getName() + ")");
+ }
+
+ if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
+ throw new ActionException("view: " + klass.getName()
+ + " can't use method with RemoteViews: "
+ + this.methodName + "(" + param.getName() + ")");
}
- }
-
- int viewId;
- PendingIntent pendingIntent;
- public final static int TAG = 7;
+ try {
+ if (false) {
+ Log.d("RemoteViews", "view: " + klass.getName() + " calling method: "
+ + this.methodName + "(" + param.getName() + ") with "
+ + (this.value == null ? "null" : this.value.getClass().getName()));
+ }
+ method.invoke(view, this.value);
+ }
+ catch (Exception ex) {
+ throw new ActionException(ex);
+ }
+ }
}
+
/**
* Create a new RemoteViews object that will display the views contained
* in the specified layout file.
@@ -447,32 +486,17 @@ public class RemoteViews implements Parcelable, Filter {
for (int i=0; i<count; i++) {
int tag = parcel.readInt();
switch (tag) {
- case SetViewVisibility.TAG:
- mActions.add(new SetViewVisibility(parcel));
- break;
- case SetTextViewText.TAG:
- mActions.add(new SetTextViewText(parcel));
- break;
- case SetImageViewResource.TAG:
- mActions.add(new SetImageViewResource(parcel));
- break;
- case SetImageViewUri.TAG:
- mActions.add(new SetImageViewUri(parcel));
- break;
- case SetImageViewBitmap.TAG:
- mActions.add(new SetImageViewBitmap(parcel));
- break;
- case SetChronometer.TAG:
- mActions.add(new SetChronometer(parcel));
- break;
- case SetProgressBar.TAG:
- mActions.add(new SetProgressBar(parcel));
- break;
case SetOnClickPendingIntent.TAG:
mActions.add(new SetOnClickPendingIntent(parcel));
break;
+ case SetDrawableParameters.TAG:
+ mActions.add(new SetDrawableParameters(parcel));
+ break;
+ case ReflectionAction.TAG:
+ mActions.add(new ReflectionAction(parcel));
+ break;
default:
- throw new ActionException("Tag " + tag + "not found");
+ throw new ActionException("Tag " + tag + " not found");
}
}
}
@@ -505,7 +529,7 @@ public class RemoteViews implements Parcelable, Filter {
* @param visibility The new visibility for the view
*/
public void setViewVisibility(int viewId, int visibility) {
- addAction(new SetViewVisibility(viewId, visibility));
+ setInt(viewId, "setVisibility", visibility);
}
/**
@@ -515,7 +539,7 @@ public class RemoteViews implements Parcelable, Filter {
* @param text The new text for the view
*/
public void setTextViewText(int viewId, CharSequence text) {
- addAction(new SetTextViewText(viewId, text));
+ setCharSequence(viewId, "setText", text);
}
/**
@@ -525,7 +549,7 @@ public class RemoteViews implements Parcelable, Filter {
* @param srcId The new resource id for the drawable
*/
public void setImageViewResource(int viewId, int srcId) {
- addAction(new SetImageViewResource(viewId, srcId));
+ setInt(viewId, "setImageResource", srcId);
}
/**
@@ -535,7 +559,7 @@ public class RemoteViews implements Parcelable, Filter {
* @param uri The Uri for the image
*/
public void setImageViewUri(int viewId, Uri uri) {
- addAction(new SetImageViewUri(viewId, uri));
+ setUri(viewId, "setImageURI", uri);
}
/**
@@ -545,7 +569,7 @@ public class RemoteViews implements Parcelable, Filter {
* @param bitmap The new Bitmap for the drawable
*/
public void setImageViewBitmap(int viewId, Bitmap bitmap) {
- addAction(new SetImageViewBitmap(viewId, bitmap));
+ setBitmap(viewId, "setImageBitmap", bitmap);
}
/**
@@ -560,16 +584,20 @@ public class RemoteViews implements Parcelable, Filter {
* {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.
* @param format The Chronometer format string, or null to
* simply display the timer value.
- * @param running True if you want the clock to be running, false if not.
+ * @param started True if you want the clock to be started, false if not.
*/
- public void setChronometer(int viewId, long base, String format, boolean running) {
- addAction(new SetChronometer(viewId, base, format, running));
+ public void setChronometer(int viewId, long base, String format, boolean started) {
+ setLong(viewId, "setBase", base);
+ setString(viewId, "setFormat", format);
+ setBoolean(viewId, "setStarted", started);
}
/**
* Equivalent to calling {@link ProgressBar#setMax ProgressBar.setMax},
* {@link ProgressBar#setProgress ProgressBar.setProgress}, and
* {@link ProgressBar#setIndeterminate ProgressBar.setIndeterminate}
+ *
+ * If indeterminate is true, then the values for max and progress are ignored.
*
* @param viewId The id of the view whose text should change
* @param max The 100% value for the progress bar
@@ -579,7 +607,11 @@ public class RemoteViews implements Parcelable, Filter {
*/
public void setProgressBar(int viewId, int max, int progress,
boolean indeterminate) {
- addAction(new SetProgressBar(viewId, max, progress, indeterminate));
+ setBoolean(viewId, "setIndeterminate", indeterminate);
+ if (!indeterminate) {
+ setInt(viewId, "setMax", max);
+ setInt(viewId, "setProgress", progress);
+ }
}
/**
@@ -595,6 +627,97 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * @hide
+ * Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
+ * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
+ * and/or {@link Drawable#setLevel(int)} on the {@link Drawable} of a given
+ * view.
+ * <p>
+ * You can omit specific calls by marking their values with null or -1.
+ *
+ * @param viewId The id of the view that contains the target
+ * {@link Drawable}
+ * @param targetBackground If true, apply these parameters to the
+ * {@link Drawable} returned by
+ * {@link android.view.View#getBackground()}. Otherwise, assume
+ * the target view is an {@link ImageView} and apply them to
+ * {@link ImageView#getDrawable()}.
+ * @param alpha Specify an alpha value for the drawable, or -1 to leave
+ * unchanged.
+ * @param colorFilter Specify a color for a
+ * {@link android.graphics.ColorFilter} for this drawable, or -1
+ * to leave unchanged.
+ * @param mode Specify a PorterDuff mode for this drawable, or null to leave
+ * unchanged.
+ * @param level Specify the level for the drawable, or -1 to leave
+ * unchanged.
+ */
+ public void setDrawableParameters(int viewId, boolean targetBackground, int alpha,
+ int colorFilter, PorterDuff.Mode mode, int level) {
+ addAction(new SetDrawableParameters(viewId, targetBackground, alpha,
+ colorFilter, mode, level));
+ }
+
+ /**
+ * Equivalent to calling {@link android.widget.TextView#setTextColor(int)}.
+ *
+ * @param viewId The id of the view whose text should change
+ * @param color Sets the text color for all the states (normal, selected,
+ * focused) to be this color.
+ */
+ public void setTextColor(int viewId, int color) {
+ setInt(viewId, "setTextColor", color);
+ }
+
+ public void setBoolean(int viewId, String methodName, boolean value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BOOLEAN, value));
+ }
+
+ public void setByte(int viewId, String methodName, byte value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BYTE, value));
+ }
+
+ public void setShort(int viewId, String methodName, short value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.SHORT, value));
+ }
+
+ public void setInt(int viewId, String methodName, int value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.INT, value));
+ }
+
+ public void setLong(int viewId, String methodName, long value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.LONG, value));
+ }
+
+ public void setFloat(int viewId, String methodName, float value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.FLOAT, value));
+ }
+
+ public void setDouble(int viewId, String methodName, double value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.DOUBLE, value));
+ }
+
+ public void setChar(int viewId, String methodName, char value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR, value));
+ }
+
+ public void setString(int viewId, String methodName, String value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.STRING, value));
+ }
+
+ public void setCharSequence(int viewId, String methodName, CharSequence value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.CHAR_SEQUENCE, value));
+ }
+
+ public void setUri(int viewId, String methodName, Uri value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.URI, value));
+ }
+
+ public void setBitmap(int viewId, String methodName, Bitmap value) {
+ addAction(new ReflectionAction(viewId, methodName, ReflectionAction.BITMAP, value));
+ }
+
+ /**
* Inflates the view hierarchy represented by this object and applies
* all of the actions.
*
diff --git a/core/java/android/widget/ResourceCursorAdapter.java b/core/java/android/widget/ResourceCursorAdapter.java
index 9052ae3..a5dbd98 100644
--- a/core/java/android/widget/ResourceCursorAdapter.java
+++ b/core/java/android/widget/ResourceCursorAdapter.java
@@ -46,10 +46,30 @@ public abstract class ResourceCursorAdapter extends CursorAdapter {
public ResourceCursorAdapter(Context context, int layout, Cursor c) {
super(context, c);
mLayout = mDropDownLayout = layout;
- mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/**
+ * Constructor.
+ *
+ * @param context The context where the ListView associated with this
+ * SimpleListItemFactory is running
+ * @param layout resource identifier of a layout file that defines the views
+ * for this list item. Unless you override them later, this will
+ * define both the item views and the drop down views.
+ * @param c The cursor from which to get the data.
+ * @param autoRequery If true the adapter will call requery() on the
+ * cursor whenever it changes so the most recent
+ * data is always displayed.
+ * @hide Pending API Council approval
+ */
+ public ResourceCursorAdapter(Context context, int layout, Cursor c, boolean autoRequery) {
+ super(context, c, autoRequery);
+ mLayout = mDropDownLayout = layout;
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ /**
* Inflates view(s) from the specified XML file.
*
* @see android.widget.CursorAdapter#newView(android.content.Context,
diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java
index 17f9128..3b113ae 100644
--- a/core/java/android/widget/ScrollBarDrawable.java
+++ b/core/java/android/widget/ScrollBarDrawable.java
@@ -152,10 +152,12 @@ public class ScrollBarDrawable extends Drawable {
} else {
track = mHorizontalTrack;
}
- if (mChanged) {
- track.setBounds(bounds);
+ if (track != null) {
+ if (mChanged) {
+ track.setBounds(bounds);
+ }
+ track.draw(canvas);
}
- track.draw(canvas);
}
protected void drawThumb(Canvas canvas, Rect bounds, int offset, int length, boolean vertical) {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 20166cf..c9b3751 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -44,13 +44,7 @@ import java.util.List;
* manager with a complex hierarchy of objects. A child that is often used
* is a {@link LinearLayout} in a vertical orientation, presenting a vertical
* array of top-level items that the user can scroll through.
- *
- * <p>You should never use a ScrollView with a {@link ListView}, since
- * ListView takes care of its own scrolling. Most importantly, doing this
- * defeats all of the important optimizations in ListView for dealing with
- * large lists, since it effectively forces the ListView to display its entire
- * list of items to fill up the infinite container supplied by ScrollView.
- *
+ *
* <p>The {@link TextView} class also
* takes care of its own scrolling, so does not require a ScrollView, but
* using the two together is possible to achieve the effect of a text view
@@ -62,13 +56,9 @@ public class ScrollView extends FrameLayout {
static final String TAG = "ScrollView";
static final boolean localLOGV = false || Config.LOGV;
- private static final int ANIMATED_SCROLL_GAP = 250;
+ static final int ANIMATED_SCROLL_GAP = 250;
- /**
- * When arrow scrolling, ListView will never scroll more than this factor
- * times the height of the list.
- */
- private static final float MAX_SCROLL_FACTOR = 0.5f;
+ static final float MAX_SCROLL_FACTOR = 0.5f;
private long mLastScroll;
@@ -124,6 +114,8 @@ public class ScrollView extends FrameLayout {
*/
private boolean mSmoothScrollingEnabled = true;
+ private int mTouchSlop;
+
public ScrollView(Context context) {
this(context, null);
}
@@ -165,8 +157,8 @@ public class ScrollView extends FrameLayout {
}
final int length = getVerticalFadingEdgeLength();
- final int bottom = getChildAt(0).getBottom();
- final int span = bottom - mScrollY - getHeight();
+ final int bottomEdge = getHeight() - mPaddingBottom;
+ final int span = getChildAt(0).getBottom() - mScrollY - bottomEdge;
if (span < length) {
return span / (float) length;
}
@@ -188,6 +180,7 @@ public class ScrollView extends FrameLayout {
setFocusable(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setWillNotDraw(false);
+ mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
@Override
@@ -401,7 +394,7 @@ public class ScrollView extends FrameLayout {
* of the down event.
*/
final int yDiff = (int) Math.abs(y - mLastMotionY);
- if (yDiff > ViewConfiguration.getTouchSlop()) {
+ if (yDiff > mTouchSlop) {
mIsBeingDragged = true;
}
break;
@@ -488,8 +481,9 @@ public class ScrollView extends FrameLayout {
velocityTracker.computeCurrentVelocity(1000);
int initialVelocity = (int) velocityTracker.getYVelocity();
- if ((Math.abs(initialVelocity) > ViewConfiguration.getMinimumFlingVelocity()) &&
- (getChildCount() > 0)) {
+ if ((Math.abs(initialVelocity) >
+ ViewConfiguration.get(mContext).getScaledMinimumFlingVelocity()) &&
+ getChildCount() > 0) {
fling(-initialVelocity);
}
@@ -812,7 +806,7 @@ public class ScrollView extends FrameLayout {
/**
* Smooth scroll by a Y delta
*
- * @param delta the number of pixels to scroll by on the X axis
+ * @param delta the number of pixels to scroll by on the Y axis
*/
private void doScrollY(int delta) {
if (delta != 0) {
@@ -923,8 +917,8 @@ public class ScrollView extends FrameLayout {
int y = mScroller.getCurrY();
if (getChildCount() > 0) {
View child = getChildAt(0);
- mScrollX = clamp(x, this.getWidth(), child.getWidth());
- mScrollY = clamp(y, this.getHeight(), child.getHeight());
+ mScrollX = clamp(x, getWidth() - mPaddingRight - mPaddingLeft, child.getWidth());
+ mScrollY = clamp(y, getHeight() - mPaddingBottom - mPaddingTop, child.getHeight());
if (localLOGV) Log.v(TAG, "mScrollY=" + mScrollY + " y=" + y
+ " height=" + this.getHeight()
+ " child height=" + child.getHeight());
@@ -1167,8 +1161,8 @@ public class ScrollView extends FrameLayout {
* which means we want to scroll towards the top.
*/
public void fling(int velocityY) {
- int height = getHeight();
- int bottom = getChildAt(getChildCount() - 1).getBottom();
+ int height = getHeight() - mPaddingBottom - mPaddingTop;
+ int bottom = getChildAt(0).getHeight();
mScroller.fling(mScrollX, mScrollY, 0, velocityY, 0, 0, 0, bottom - height);
@@ -1198,8 +1192,8 @@ public class ScrollView extends FrameLayout {
// we rely on the fact the View.scrollBy calls scrollTo.
if (getChildCount() > 0) {
View child = getChildAt(0);
- x = clamp(x, this.getWidth(), child.getWidth());
- y = clamp(y, this.getHeight(), child.getHeight());
+ x = clamp(x, getWidth() - mPaddingRight - mPaddingLeft, child.getWidth());
+ y = clamp(y, getHeight() - mPaddingBottom - mPaddingTop, child.getHeight());
if (x != mScrollX || y != mScrollY) {
super.scrollTo(x, y);
}
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index fbe5e57..febc956 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -132,6 +132,26 @@ public class Scroller {
}
/**
+ * Returns the start X offset in the scroll.
+ *
+ * @return The start X offset as an absolute distance from the origin.
+ * @hide pending API council
+ */
+ public final int getStartX() {
+ return mStartX;
+ }
+
+ /**
+ * Returns the start Y offset in the scroll.
+ *
+ * @return The start Y offset as an absolute distance from the origin.
+ * @hide pending API council
+ */
+ public final int getStartY() {
+ return mStartY;
+ }
+
+ /**
* Returns where the scroll will end. Valid only for "fling" scrolls.
*
* @return The final X offset as an absolute distance from the origin.
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index 261da9f..093c24e 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -36,12 +36,16 @@ import java.util.Map;
* Binding data to views occurs in two phases. First, if a
* {@link android.widget.SimpleAdapter.ViewBinder} is available,
* {@link ViewBinder#setViewValue(android.view.View, Object, String)}
- * is invoked. If the returned value is true, binding has occured. If the
- * returned value is false and the view to bind is a TextView,
- * {@link #setViewText(TextView, String)} is invoked. If the returned value
- * is false and the view to bind is an ImageView,
- * {@link #setViewImage(ImageView, int)} or {@link #setViewImage(ImageView, String)} is
- * invoked. If no appropriate binding can be found, an {@link IllegalStateException} is thrown.
+ * is invoked. If the returned value is true, binding has occurred.
+ * If the returned value is false, the following views are then tried in order:
+ * <ul>
+ * <li> A view that implements Checkable (e.g. CheckBox). The expected bind value is a boolean.
+ * <li> TextView. The expected bind value is a string and {@link #setViewText(TextView, String)}
+ * is invoked.
+ * <li> ImageView. The expected bind value is a resource id or a string and
+ * {@link #setViewImage(ImageView, int)} or {@link #setViewImage(ImageView, String)} is invoked.
+ * </ul>
+ * If no appropriate binding can be found, an {@link IllegalStateException} is thrown.
*/
public class SimpleAdapter extends BaseAdapter implements Filterable {
private int[] mTo;
@@ -176,7 +180,16 @@ public class SimpleAdapter extends BaseAdapter implements Filterable {
}
if (!bound) {
- if (v instanceof TextView) {
+ if (v instanceof Checkable) {
+ if (data instanceof Boolean) {
+ ((Checkable) v).setChecked((Boolean) data);
+ } else {
+ throw new IllegalStateException(v.getClass().getName() +
+ " should be bound to a Boolean, not a " + data.getClass());
+ }
+ } else if (v instanceof TextView) {
+ // Note: keep the instanceof TextView check at the bottom of these
+ // ifs since a lot of views are TextViews (e.g. CheckBoxes).
setViewText((TextView) v, text);
} else if (v instanceof ImageView) {
if (data instanceof Integer) {
diff --git a/core/java/com/android/internal/widget/SlidingDrawer.java b/core/java/android/widget/SlidingDrawer.java
index a4045d5..e0f1bb4 100644
--- a/core/java/com/android/internal/widget/SlidingDrawer.java
+++ b/core/java/android/widget/SlidingDrawer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.widget;
+package android.widget;
import android.view.ViewGroup;
import android.view.View;
@@ -30,7 +30,7 @@ import android.graphics.Bitmap;
import android.os.SystemClock;
import android.os.Handler;
import android.os.Message;
-import com.android.internal.R;
+import android.R;
/**
* SlidingDrawer hides content out of the screen and allows the user to drag a handle
@@ -48,7 +48,7 @@ import com.android.internal.R;
* content:
*
* <pre class="prettyprint">
- * &lt;com.android.internal.widget.SlidingDrawer
+ * &lt;SlidingDrawer
* android:id="@+id/drawer"
* android:layout_width="fill_parent"
* android:layout_height="fill_parent"
@@ -66,16 +66,16 @@ import com.android.internal.R;
* android:layout_width="fill_parent"
* android:layout_height="fill_parent" /&gt;
*
- * &lt;/com.android.internal.widget.SlidingDrawer&gt;
+ * &lt;/SlidingDrawer&gt;
* </pre>
*
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_content
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_handle
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_topOffset
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_bottomOffset
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_orientation
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_allowSingleTap
- * @attr ref com.android.internal.R.styleable#SlidingDrawer_animateOnClick
+ * @attr ref android.R.styleable#SlidingDrawer_content
+ * @attr ref android.R.styleable#SlidingDrawer_handle
+ * @attr ref android.R.styleable#SlidingDrawer_topOffset
+ * @attr ref android.R.styleable#SlidingDrawer_bottomOffset
+ * @attr ref android.R.styleable#SlidingDrawer_orientation
+ * @attr ref android.R.styleable#SlidingDrawer_allowSingleTap
+ * @attr ref android.R.styleable#SlidingDrawer_animateOnClick
*/
public class SlidingDrawer extends ViewGroup {
public static final int ORIENTATION_HORIZONTAL = 0;
@@ -128,6 +128,13 @@ public class SlidingDrawer extends ViewGroup {
private boolean mAllowSingleTap;
private boolean mAnimateOnClick;
+ private final int mTapThreshold;
+ private final int mMaximumTapVelocity;
+ private final int mMaximumMinorVelocity;
+ private final int mMaximumMajorVelocity;
+ private final int mMaximumAcceleration;
+ private final int mVelocityUnits;
+
/**
* Callback invoked when the drawer is opened.
*/
@@ -206,6 +213,14 @@ public class SlidingDrawer extends ViewGroup {
mHandleId = handleId;
mContentId = contentId;
+ final float density = getResources().getDisplayMetrics().density;
+ mTapThreshold = (int) (TAP_THRESHOLD * density + 0.5f);
+ mMaximumTapVelocity = (int) (MAXIMUM_TAP_VELOCITY * density + 0.5f);
+ mMaximumMinorVelocity = (int) (MAXIMUM_MINOR_VELOCITY * density + 0.5f);
+ mMaximumMajorVelocity = (int) (MAXIMUM_MAJOR_VELOCITY * density + 0.5f);
+ mMaximumAcceleration = (int) (MAXIMUM_ACCELERATION * density + 0.5f);
+ mVelocityUnits = (int) (VELOCITY_UNITS * density + 0.5f);
+
a.recycle();
setAlwaysDrawnWithCacheEnabled(false);
@@ -343,15 +358,17 @@ public class SlidingDrawer extends ViewGroup {
}
if (action == MotionEvent.ACTION_DOWN) {
- if (mOnDrawerScrollListener != null) {
- mOnDrawerScrollListener.onScrollStarted();
- }
mTracking = true;
handle.setPressed(true);
// Must be called before prepareTracking()
prepareContent();
+ // Must be called after prepareContent()
+ if (mOnDrawerScrollListener != null) {
+ mOnDrawerScrollListener.onScrollStarted();
+ }
+
if (mVertical) {
final int top = mHandle.getTop();
mTouchDelta = (int) y - top;
@@ -383,7 +400,7 @@ public class SlidingDrawer extends ViewGroup {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
final VelocityTracker velocityTracker = mVelocityTracker;
- velocityTracker.computeCurrentVelocity(VELOCITY_UNITS);
+ velocityTracker.computeCurrentVelocity(mVelocityUnits);
float yVelocity = velocityTracker.getYVelocity();
float xVelocity = velocityTracker.getXVelocity();
@@ -395,16 +412,16 @@ public class SlidingDrawer extends ViewGroup {
if (xVelocity < 0) {
xVelocity = -xVelocity;
}
- if (xVelocity > MAXIMUM_MINOR_VELOCITY) {
- xVelocity = MAXIMUM_MINOR_VELOCITY;
+ if (xVelocity > mMaximumMinorVelocity) {
+ xVelocity = mMaximumMinorVelocity;
}
} else {
negative = xVelocity < 0;
if (yVelocity < 0) {
yVelocity = -yVelocity;
}
- if (yVelocity > MAXIMUM_MINOR_VELOCITY) {
- yVelocity = MAXIMUM_MINOR_VELOCITY;
+ if (yVelocity > mMaximumMinorVelocity) {
+ yVelocity = mMaximumMinorVelocity;
}
}
@@ -416,13 +433,13 @@ public class SlidingDrawer extends ViewGroup {
final int top = mHandle.getTop();
final int left = mHandle.getLeft();
- if (Math.abs(velocity) < MAXIMUM_TAP_VELOCITY) {
- if (vertical ? (mExpanded && top < TAP_THRESHOLD + mTopOffset) ||
+ if (Math.abs(velocity) < mMaximumTapVelocity) {
+ if (vertical ? (mExpanded && top < mTapThreshold + mTopOffset) ||
(!mExpanded && top > mBottomOffset + mBottom - mTop -
- mHandleHeight - TAP_THRESHOLD) :
- (mExpanded && left < TAP_THRESHOLD + mTopOffset) ||
+ mHandleHeight - mTapThreshold) :
+ (mExpanded && left < mTapThreshold + mTopOffset) ||
(!mExpanded && left > mBottomOffset + mRight - mLeft -
- mHandleWidth - TAP_THRESHOLD)) {
+ mHandleWidth - mTapThreshold)) {
if (mAllowSingleTap) {
playSoundEffect(SoundEffectConstants.CLICK);
@@ -432,6 +449,8 @@ public class SlidingDrawer extends ViewGroup {
} else {
animateOpen(vertical ? top : left);
}
+ } else {
+ performFling(vertical ? top : left, velocity, false);
}
} else {
@@ -450,12 +469,12 @@ public class SlidingDrawer extends ViewGroup {
private void animateClose(int position) {
prepareTracking(position);
- performFling(position, 2000.0f, true);
+ performFling(position, mMaximumAcceleration, true);
}
private void animateOpen(int position) {
prepareTracking(position);
- performFling(position, -2000.0f, true);
+ performFling(position, -mMaximumAcceleration, true);
}
private void performFling(int position, float velocity, boolean always) {
@@ -463,35 +482,35 @@ public class SlidingDrawer extends ViewGroup {
mAnimatedVelocity = velocity;
if (mExpanded) {
- if (always || (velocity > MAXIMUM_MAJOR_VELOCITY ||
+ if (always || (velocity > mMaximumMajorVelocity ||
(position > mTopOffset + (mVertical ? mHandleHeight : mHandleWidth) &&
- velocity > -MAXIMUM_MAJOR_VELOCITY))) {
+ velocity > -mMaximumMajorVelocity))) {
// We are expanded, but they didn't move sufficiently to cause
// us to retract. Animate back to the expanded position.
- mAnimatedAcceleration = MAXIMUM_ACCELERATION;
+ mAnimatedAcceleration = mMaximumAcceleration;
if (velocity < 0) {
mAnimatedVelocity = 0;
}
} else {
// We are expanded and are now going to animate away.
- mAnimatedAcceleration = -MAXIMUM_ACCELERATION;
+ mAnimatedAcceleration = -mMaximumAcceleration;
if (velocity > 0) {
mAnimatedVelocity = 0;
}
}
} else {
- if (!always && (velocity > MAXIMUM_MAJOR_VELOCITY ||
+ if (!always && (velocity > mMaximumMajorVelocity ||
(position > (mVertical ? getHeight() : getWidth()) / 2 &&
- velocity > -MAXIMUM_MAJOR_VELOCITY))) {
+ velocity > -mMaximumMajorVelocity))) {
// We are collapsed, and they moved enough to allow us to expand.
- mAnimatedAcceleration = MAXIMUM_ACCELERATION;
+ mAnimatedAcceleration = mMaximumAcceleration;
if (velocity < 0) {
mAnimatedVelocity = 0;
}
} else {
// We are collapsed, but they didn't move sufficiently to cause
// us to retract. Animate back to the collapsed position.
- mAnimatedAcceleration = -MAXIMUM_ACCELERATION;
+ mAnimatedAcceleration = -mMaximumAcceleration;
if (velocity > 0) {
mAnimatedVelocity = 0;
}
@@ -512,8 +531,8 @@ public class SlidingDrawer extends ViewGroup {
mVelocityTracker = VelocityTracker.obtain();
boolean opening = !mExpanded;
if (opening) {
- mAnimatedAcceleration = MAXIMUM_ACCELERATION;
- mAnimatedVelocity = 200;
+ mAnimatedAcceleration = mMaximumAcceleration;
+ mAnimatedVelocity = mMaximumMajorVelocity;
mAnimationPosition = mBottomOffset +
(mVertical ? getHeight() - mHandleHeight : getWidth() - mHandleWidth);
moveHandle((int) mAnimationPosition);
@@ -747,11 +766,11 @@ public class SlidingDrawer extends ViewGroup {
* @see #toggle()
*/
public void animateClose() {
+ prepareContent();
final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;
if (scrollListener != null) {
scrollListener.onScrollStarted();
}
- prepareContent();
animateClose(mVertical ? mHandle.getTop() : mHandle.getLeft());
if (scrollListener != null) {
scrollListener.onScrollEnded();
@@ -768,11 +787,11 @@ public class SlidingDrawer extends ViewGroup {
* @see #toggle()
*/
public void animateOpen() {
+ prepareContent();
final OnDrawerScrollListener scrollListener = mOnDrawerScrollListener;
if (scrollListener != null) {
scrollListener.onScrollStarted();
}
- prepareContent();
animateOpen(mVertical ? mHandle.getTop() : mHandle.getLeft());
if (scrollListener != null) {
scrollListener.onScrollEnded();
@@ -782,6 +801,7 @@ public class SlidingDrawer extends ViewGroup {
private void closeDrawer() {
moveHandle(COLLAPSED_FULL_CLOSED);
mContent.setVisibility(View.GONE);
+ mContent.destroyDrawingCache();
if (!mExpanded) {
return;
@@ -796,8 +816,6 @@ public class SlidingDrawer extends ViewGroup {
private void openDrawer() {
moveHandle(EXPANDED_FULL_OPEN);
mContent.setVisibility(View.VISIBLE);
- // TODO: Should we uncomment to preserve memory, but increase memory churn?
- // mContent.destroyDrawingCache();
if (mExpanded) {
return;
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index da4a077..dc2c70d 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -405,7 +405,7 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
* Specify a label and icon as the tab indicator.
*/
public TabSpec setIndicator(CharSequence label, Drawable icon) {
- mIndicatorStrategy = new LabelAndIconIndicatorStategy(label, icon);
+ mIndicatorStrategy = new LabelAndIconIndicatorStrategy(label, icon);
return this;
}
@@ -497,12 +497,12 @@ mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
/**
* How we create a tab indicator that has a label and an icon
*/
- private class LabelAndIconIndicatorStategy implements IndicatorStrategy {
+ private class LabelAndIconIndicatorStrategy implements IndicatorStrategy {
private final CharSequence mLabel;
private final Drawable mIcon;
- private LabelAndIconIndicatorStategy(CharSequence label, Drawable icon) {
+ private LabelAndIconIndicatorStrategy(CharSequence label, Drawable icon) {
mLabel = label;
mIcon = icon;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index aa70663..7b62b50 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,7 @@
package android.widget;
import android.content.Context;
+import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -32,6 +33,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.ResultReceiver;
import android.os.SystemClock;
import android.os.Message;
import android.text.BoringLayout;
@@ -41,7 +43,9 @@ import android.text.GetChars;
import android.text.GraphicsOperations;
import android.text.ClipboardManager;
import android.text.InputFilter;
+import android.text.InputType;
import android.text.Layout;
+import android.text.ParcelableSpan;
import android.text.Selection;
import android.text.SpanWatcher;
import android.text.Spannable;
@@ -69,7 +73,6 @@ import android.text.method.TransformationMethod;
import android.text.style.ParagraphStyle;
import android.text.style.URLSpan;
import android.text.style.UpdateAppearance;
-import android.text.style.UpdateLayout;
import android.text.util.Linkify;
import android.util.AttributeSet;
import android.util.Log;
@@ -83,9 +86,11 @@ import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
+import android.view.ViewRoot;
import android.view.ViewTreeObserver;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.AnimationUtils;
+import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -168,6 +173,9 @@ import org.xmlpull.v1.XmlPullParserException;
*/
@RemoteView
public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
+ static final String TAG = "TextView";
+ static final boolean DEBUG_EXTRACT = false;
+
private static int PRIORITY = 100;
private ColorStateList mTextColor;
@@ -177,6 +185,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private int mCurHintTextColor;
private boolean mFreezesText;
private boolean mFrozenWithFocus;
+ private boolean mTemporaryDetach;
+
+ private boolean mEatTouchRelease = false;
+ private boolean mScrolled = false;
private Editable.Factory mEditableFactory = Editable.Factory.getInstance();
private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
@@ -207,16 +219,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight;
int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight;
int mDrawablePadding;
- };
+ }
private Drawables mDrawables;
private CharSequence mError;
private boolean mErrorWasChanged;
private PopupWindow 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).
+ * It causes the error to be shown later, when onAttachedToWindow()
+ * is called.
+ */
+ private boolean mShowErrorAfterAttach;
private CharWrapper mCharWrapper = null;
private boolean mSelectionMoved = false;
+ private boolean mTouchFocusSelected = false;
private Marquee mMarquee;
private boolean mRestartMarquee;
@@ -224,8 +244,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private int mMarqueeRepeatLimit = 3;
class InputContentType {
- String privateContentType;
+ int imeOptions = EditorInfo.IME_NULL;
+ String privateImeOptions;
+ CharSequence imeActionLabel;
+ int imeActionId;
Bundle extras;
+ OnEditorActionListener onEditorActionListener;
+ boolean enterDown;
}
InputContentType mInputContentType;
@@ -235,7 +260,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
float[] mTmpOffset = new float[2];
ExtractedTextRequest mExtracting;
final ExtractedText mTmpExtracted = new ExtractedText();
- boolean mBatchEditing;
+ int mBatchEditNesting;
+ boolean mCursorChanged;
+ boolean mSelectionModeChanged;
+ boolean mContentChanged;
+ int mChangedStart, mChangedEnd, mChangedDelta;
}
InputMethodState mInputMethodState;
@@ -250,6 +279,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
p.measureText("H");
}
+ /**
+ * Interface definition for a callback to be invoked when an action is
+ * performed on the editor.
+ */
+ public interface OnEditorActionListener {
+ /**
+ * Called when an action is being performed.
+ *
+ * @param v The view that was clicked.
+ * @param actionId Identifier of the action. This will be either the
+ * identifier you supplied, or {@link EditorInfo#IME_NULL
+ * EditorInfo.IME_NULL} if being called due to the enter key
+ * being pressed.
+ * @param event If triggered by an enter key, this is the event;
+ * otherwise, this is null.
+ * @return Return true if you have consumed the action, else false.
+ */
+ boolean onEditorAction(TextView v, int actionId, KeyEvent event);
+ }
+
public TextView(Context context) {
this(context, null);
}
@@ -358,7 +407,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
int shadowcolor = 0;
float dx = 0, dy = 0, r = 0;
boolean password = false;
- int contentType = EditorInfo.TYPE_NULL;
+ int inputType = EditorInfo.TYPE_NULL;
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
@@ -592,11 +641,34 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
break;
case com.android.internal.R.styleable.TextView_inputType:
- contentType = a.getInt(attr, mInputType);
+ inputType = a.getInt(attr, mInputType);
break;
- case com.android.internal.R.styleable.TextView_editorPrivateContentType:
- setPrivateContentType(a.getString(attr));
+ case com.android.internal.R.styleable.TextView_imeOptions:
+ if (mInputContentType == null) {
+ mInputContentType = new InputContentType();
+ }
+ mInputContentType.imeOptions = a.getInt(attr,
+ mInputContentType.imeOptions);
+ break;
+
+ case com.android.internal.R.styleable.TextView_imeActionLabel:
+ if (mInputContentType == null) {
+ mInputContentType = new InputContentType();
+ }
+ mInputContentType.imeActionLabel = a.getText(attr);
+ break;
+
+ case com.android.internal.R.styleable.TextView_imeActionId:
+ if (mInputContentType == null) {
+ mInputContentType = new InputContentType();
+ }
+ mInputContentType.imeActionId = a.getInt(attr,
+ mInputContentType.imeActionId);
+ break;
+
+ case com.android.internal.R.styleable.TextView_privateImeOptions:
+ setPrivateImeOptions(a.getString(attr));
break;
case com.android.internal.R.styleable.TextView_editorExtras:
@@ -614,7 +686,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
BufferType bufferType = BufferType.EDITABLE;
- if ((contentType&(EditorInfo.TYPE_MASK_CLASS
+ if ((inputType&(EditorInfo.TYPE_MASK_CLASS
|EditorInfo.TYPE_MASK_VARIATION))
== (EditorInfo.TYPE_CLASS_TEXT
|EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)) {
@@ -638,57 +710,57 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
throw new RuntimeException(ex);
}
try {
- mInputType = contentType != EditorInfo.TYPE_NULL
- ? contentType
+ mInputType = inputType != EditorInfo.TYPE_NULL
+ ? inputType
: mInput.getInputType();
} catch (IncompatibleClassChangeError e) {
mInputType = EditorInfo.TYPE_CLASS_TEXT;
}
} else if (digits != null) {
mInput = DigitsKeyListener.getInstance(digits.toString());
- mInputType = contentType;
- } else if (contentType != EditorInfo.TYPE_NULL) {
- setInputType(contentType, true);
- singleLine = (contentType&(EditorInfo.TYPE_MASK_CLASS
+ mInputType = inputType;
+ } else if (inputType != EditorInfo.TYPE_NULL) {
+ setInputType(inputType, true);
+ singleLine = (inputType&(EditorInfo.TYPE_MASK_CLASS
| EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)) !=
(EditorInfo.TYPE_CLASS_TEXT
| EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE);
} else if (phone) {
mInput = DialerKeyListener.getInstance();
- contentType = EditorInfo.TYPE_CLASS_PHONE;
+ inputType = EditorInfo.TYPE_CLASS_PHONE;
} else if (numeric != 0) {
mInput = DigitsKeyListener.getInstance((numeric & SIGNED) != 0,
(numeric & DECIMAL) != 0);
- contentType = EditorInfo.TYPE_CLASS_NUMBER;
+ inputType = EditorInfo.TYPE_CLASS_NUMBER;
if ((numeric & SIGNED) != 0) {
- contentType |= EditorInfo.TYPE_NUMBER_FLAG_SIGNED;
+ inputType |= EditorInfo.TYPE_NUMBER_FLAG_SIGNED;
}
if ((numeric & DECIMAL) != 0) {
- contentType |= EditorInfo.TYPE_NUMBER_FLAG_DECIMAL;
+ inputType |= EditorInfo.TYPE_NUMBER_FLAG_DECIMAL;
}
- mInputType = contentType;
+ mInputType = inputType;
} else if (autotext || autocap != -1) {
TextKeyListener.Capitalize cap;
- contentType = EditorInfo.TYPE_CLASS_TEXT;
+ inputType = EditorInfo.TYPE_CLASS_TEXT;
if (!singleLine) {
- contentType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
+ inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
}
switch (autocap) {
case 1:
cap = TextKeyListener.Capitalize.SENTENCES;
- contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES;
+ inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES;
break;
case 2:
cap = TextKeyListener.Capitalize.WORDS;
- contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
+ inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
break;
case 3:
cap = TextKeyListener.Capitalize.CHARACTERS;
- contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS;
+ inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS;
break;
default:
@@ -697,7 +769,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
mInput = TextKeyListener.getInstance(autotext, cap);
- mInputType = contentType;
+ mInputType = inputType;
} else if (editable) {
mInput = TextKeyListener.getInstance();
mInputType = EditorInfo.TYPE_CLASS_TEXT;
@@ -769,6 +841,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (password) {
setTransformationMethod(PasswordTransformationMethod.getInstance());
typefaceIndex = MONOSPACE;
+ } else if ((mInputType&(EditorInfo.TYPE_MASK_CLASS
+ |EditorInfo.TYPE_MASK_VARIATION))
+ == (EditorInfo.TYPE_CLASS_TEXT
+ |EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)) {
+ typefaceIndex = MONOSPACE;
}
setTypefaceByIndex(typefaceIndex, styleIndex);
@@ -1057,6 +1134,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @attr ref android.R.styleable#TextView_singleLine
*/
public final void setTransformationMethod(TransformationMethod method) {
+ if (method == mTransformation) {
+ // Avoid the setText() below if the transformation is
+ // the same.
+ return;
+ }
if (mTransformation != null) {
if (mText instanceof Spannable) {
((Spannable) mText).removeSpan(mTransformation);
@@ -1330,7 +1412,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) {
final Resources resources = getContext().getResources();
- setCompoundDrawables(left != 0 ? resources.getDrawable(left) : null,
+ setCompoundDrawablesWithIntrinsicBounds(left != 0 ? resources.getDrawable(left) : null,
top != 0 ? resources.getDrawable(top) : null,
right != 0 ? resources.getDrawable(right) : null,
bottom != 0 ? resources.getDrawable(bottom) : null);
@@ -1412,10 +1494,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void setPadding(int left, int top, int right, int bottom) {
- if (left != getPaddingLeft() ||
- right != getPaddingRight() ||
- top != getPaddingTop() ||
- bottom != getPaddingBottom()) {
+ if (left != mPaddingLeft ||
+ right != mPaddingRight ||
+ top != mPaddingTop ||
+ bottom != mPaddingBottom) {
nullLayouts();
}
@@ -1504,6 +1586,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_textSize
*/
+ @android.view.RemotableViewMethod
public void setTextSize(float size) {
setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
}
@@ -1555,6 +1638,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_textScaleX
*/
+ @android.view.RemotableViewMethod
public void setTextScaleX(float size) {
if (size != mTextPaint.getTextScaleX()) {
mTextPaint.setTextScaleX(size);
@@ -1603,6 +1687,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_textColor
*/
+ @android.view.RemotableViewMethod
public void setTextColor(int color) {
mTextColor = ColorStateList.valueOf(color);
updateTextColors();
@@ -1645,6 +1730,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_textColorHighlight
*/
+ @android.view.RemotableViewMethod
public void setHighlightColor(int color) {
if (mHighlightColor != color) {
mHighlightColor = color;
@@ -1686,6 +1772,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_autoLink
*/
+ @android.view.RemotableViewMethod
public final void setAutoLinkMask(int mask) {
mAutoLinkMask = mask;
}
@@ -1698,6 +1785,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_linksClickable
*/
+ @android.view.RemotableViewMethod
public final void setLinksClickable(boolean whether) {
mLinksClickable = whether;
}
@@ -1734,6 +1822,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_textColorHint
*/
+ @android.view.RemotableViewMethod
public final void setHintTextColor(int color) {
mHintTextColor = ColorStateList.valueOf(color);
updateTextColors();
@@ -1772,6 +1861,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_textColorLink
*/
+ @android.view.RemotableViewMethod
public final void setLinkTextColor(int color) {
mLinkTextColor = ColorStateList.valueOf(color);
updateTextColors();
@@ -1859,6 +1949,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* reflows the text if they are different from the old flags.
* @see Paint#setFlags
*/
+ @android.view.RemotableViewMethod
public void setPaintFlags(int flags) {
if (mTextPaint.getFlags() != flags) {
mTextPaint.setFlags(flags);
@@ -1892,6 +1983,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_minLines
*/
+ @android.view.RemotableViewMethod
public void setMinLines(int minlines) {
mMinimum = minlines;
mMinMode = LINES;
@@ -1905,6 +1997,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_minHeight
*/
+ @android.view.RemotableViewMethod
public void setMinHeight(int minHeight) {
mMinimum = minHeight;
mMinMode = PIXELS;
@@ -1918,6 +2011,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_maxLines
*/
+ @android.view.RemotableViewMethod
public void setMaxLines(int maxlines) {
mMaximum = maxlines;
mMaxMode = LINES;
@@ -1931,6 +2025,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_maxHeight
*/
+ @android.view.RemotableViewMethod
public void setMaxHeight(int maxHeight) {
mMaximum = maxHeight;
mMaxMode = PIXELS;
@@ -1944,6 +2039,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_lines
*/
+ @android.view.RemotableViewMethod
public void setLines(int lines) {
mMaximum = mMinimum = lines;
mMaxMode = mMinMode = LINES;
@@ -1959,6 +2055,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_height
*/
+ @android.view.RemotableViewMethod
public void setHeight(int pixels) {
mMaximum = mMinimum = pixels;
mMaxMode = mMinMode = PIXELS;
@@ -1972,6 +2069,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_minEms
*/
+ @android.view.RemotableViewMethod
public void setMinEms(int minems) {
mMinWidth = minems;
mMinWidthMode = EMS;
@@ -1985,6 +2083,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_minWidth
*/
+ @android.view.RemotableViewMethod
public void setMinWidth(int minpixels) {
mMinWidth = minpixels;
mMinWidthMode = PIXELS;
@@ -1998,6 +2097,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_maxEms
*/
+ @android.view.RemotableViewMethod
public void setMaxEms(int maxems) {
mMaxWidth = maxems;
mMaxWidthMode = EMS;
@@ -2011,6 +2111,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_maxWidth
*/
+ @android.view.RemotableViewMethod
public void setMaxWidth(int maxpixels) {
mMaxWidth = maxpixels;
mMaxWidthMode = PIXELS;
@@ -2024,6 +2125,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_ems
*/
+ @android.view.RemotableViewMethod
public void setEms(int ems) {
mMaxWidth = mMinWidth = ems;
mMaxWidthMode = mMinWidthMode = EMS;
@@ -2039,6 +2141,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_width
*/
+ @android.view.RemotableViewMethod
public void setWidth(int pixels) {
mMaxWidth = mMinWidth = pixels;
mMaxWidthMode = mMinWidthMode = PIXELS;
@@ -2150,6 +2253,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
int selEnd;
CharSequence text;
boolean frozenWithFocus;
+ CharSequence error;
SavedState(Parcelable superState) {
super(superState);
@@ -2162,6 +2266,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
out.writeInt(selEnd);
out.writeInt(frozenWithFocus ? 1 : 0);
TextUtils.writeToParcel(text, out, flags);
+
+ if (error == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(1);
+ TextUtils.writeToParcel(error, out, flags);
+ }
}
@Override
@@ -2192,6 +2303,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
selEnd = in.readInt();
frozenWithFocus = (in.readInt() != 0);
text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+
+ if (in.readInt() != 0) {
+ error = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ }
}
}
@@ -2244,6 +2359,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
ss.frozenWithFocus = true;
}
+ ss.error = mError;
+
return ss;
}
@@ -2289,6 +2406,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
}
+
+ if (ss.error != null) {
+ setError(ss.error);
+ }
}
/**
@@ -2304,6 +2425,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_freezesText
*/
+ @android.view.RemotableViewMethod
public void setFreezesText(boolean freezesText) {
mFreezesText = freezesText;
}
@@ -2342,12 +2464,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* Sets the string value of the TextView. TextView <em>does not</em> accept
* HTML-like formatting, which you can do with text strings in XML resource files.
* To style your strings, attach android.text.style.* objects to a
- * {@link android.text.SpannableString SpannableString}, or see
- * <a href="{@docRoot}reference/available-resources.html#stringresources">
- * String Resources</a> for an example of setting formatted text in the XML resource file.
+ * {@link android.text.SpannableString SpannableString}, or see the
+ * <a href="{@docRoot}guide/topics/resources/available-resources.html#stringresources">
+ * Available Resource Types</a> documentation for an example of setting
+ * formatted text in the XML resource file.
*
* @attr ref android.R.styleable#TextView_text
*/
+ @android.view.RemotableViewMethod
public final void setText(CharSequence text) {
setText(text, mBufferType);
}
@@ -2360,6 +2484,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @see #setText(CharSequence)
*/
+ @android.view.RemotableViewMethod
public final void setTextKeepState(CharSequence text) {
setTextKeepState(text, mBufferType);
}
@@ -2630,6 +2755,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ @android.view.RemotableViewMethod
public final void setText(int resid) {
setText(getContext().getResources().getText(resid));
}
@@ -2648,6 +2774,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_hint
*/
+ @android.view.RemotableViewMethod
public final void setHint(CharSequence hint) {
mHint = TextUtils.stringOrSpannedString(hint);
@@ -2668,6 +2795,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_hint
*/
+ @android.view.RemotableViewMethod
public final void setHint(int resid) {
setHint(getContext().getResources().getText(resid));
}
@@ -2698,20 +2826,40 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
public void setInputType(int type) {
setInputType(type, false);
- if ((type&(EditorInfo.TYPE_MASK_CLASS
- |EditorInfo.TYPE_MASK_VARIATION))
+ final int variation = type&(EditorInfo.TYPE_MASK_CLASS
+ |EditorInfo.TYPE_MASK_VARIATION);
+ final boolean isPassword = variation
== (EditorInfo.TYPE_CLASS_TEXT
- |EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)) {
+ |EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+ boolean forceUpdate = false;
+ if (isPassword) {
setTransformationMethod(PasswordTransformationMethod.getInstance());
setTypefaceByIndex(MONOSPACE, 0);
+ } else if (mTransformation == PasswordTransformationMethod.getInstance()) {
+ // We need to clean up if we were previously in password mode.
+ if (variation != (EditorInfo.TYPE_CLASS_TEXT
+ |EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD)) {
+ setTypefaceByIndex(-1, -1);
+ }
+ forceUpdate = true;
+ } else if (variation == (EditorInfo.TYPE_CLASS_TEXT
+ |EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD)) {
+ setTypefaceByIndex(MONOSPACE, 0);
}
+
boolean multiLine = (type&(EditorInfo.TYPE_MASK_CLASS
| EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)) ==
(EditorInfo.TYPE_CLASS_TEXT
| EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE);
- if (mSingleLine == multiLine) {
- setSingleLine(!multiLine);
- }
+
+ // We need to update the single line mode if it has changed or we
+ // were previously in password mode.
+ if (mSingleLine == multiLine || forceUpdate) {
+ // Change single line mode, but only change the transformation if
+ // we are not in password mode.
+ applySingleLine(!multiLine, !isPassword);
+ }
+
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) imm.restartInput(this);
}
@@ -2719,7 +2867,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* Directly change the content type integer of the text view, without
* modifying any other state.
- * @see #setContentType
+ * @see #setInputType(int)
* @see android.text.InputType
* @attr ref android.R.styleable#TextView_inputType
*/
@@ -2783,28 +2931,175 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * Change the editor type integer associated with the text view, which
+ * will be reported to an IME with {@link EditorInfo#imeOptions} when it
+ * has focus.
+ * @see #getImeOptions
+ * @see android.view.inputmethod.EditorInfo
+ * @attr ref android.R.styleable#TextView_imeOptions
+ */
+ public void setImeOptions(int imeOptions) {
+ if (mInputContentType == null) {
+ mInputContentType = new InputContentType();
+ }
+ mInputContentType.imeOptions = imeOptions;
+ }
+
+ /**
+ * Get the type of the IME editor.
+ *
+ * @see #setImeOptions(int)
+ * @see android.view.inputmethod.EditorInfo
+ */
+ public int getImeOptions() {
+ return mInputContentType != null
+ ? mInputContentType.imeOptions : EditorInfo.IME_NULL;
+ }
+
+ /**
+ * Change the custom IME action associated with the text view, which
+ * will be reported to an IME with {@link EditorInfo#actionLabel}
+ * and {@link EditorInfo#actionId} when it has focus.
+ * @see #getImeActionLabel
+ * @see #getImeActionId
+ * @see android.view.inputmethod.EditorInfo
+ * @attr ref android.R.styleable#TextView_imeActionLabel
+ * @attr ref android.R.styleable#TextView_imeActionId
+ */
+ public void setImeActionLabel(CharSequence label, int actionId) {
+ if (mInputContentType == null) {
+ mInputContentType = new InputContentType();
+ }
+ mInputContentType.imeActionLabel = label;
+ mInputContentType.imeActionId = actionId;
+ }
+
+ /**
+ * Get the IME action label previous set with {@link #setImeActionLabel}.
+ *
+ * @see #setImeActionLabel
+ * @see android.view.inputmethod.EditorInfo
+ */
+ public CharSequence getImeActionLabel() {
+ return mInputContentType != null
+ ? mInputContentType.imeActionLabel : null;
+ }
+
+ /**
+ * Get the IME action ID previous set with {@link #setImeActionLabel}.
+ *
+ * @see #setImeActionLabel
+ * @see android.view.inputmethod.EditorInfo
+ */
+ public int getImeActionId() {
+ return mInputContentType != null
+ ? mInputContentType.imeActionId : 0;
+ }
+
+ /**
+ * Set a special listener to be called when an action is performed
+ * on the text view. This will be called when the enter key is pressed,
+ * or when an action supplied to the IME is selected by the user. Setting
+ * this means that the normal hard key event will not insert a newline
+ * into the text view, even if it is multi-line; holding down the ALT
+ * modifier will, however, allow the user to insert a newline character.
+ */
+ public void setOnEditorActionListener(OnEditorActionListener l) {
+ if (mInputContentType == null) {
+ mInputContentType = new InputContentType();
+ }
+ mInputContentType.onEditorActionListener = l;
+ }
+
+ /**
+ * Called when an attached input method calls
+ * {@link InputConnection#performEditorAction(int)
+ * InputConnection.performEditorAction()}
+ * for this text view. The default implementation will call your action
+ * listener supplied to {@link #setOnEditorActionListener}, or perform
+ * a standard operation for {@link EditorInfo#IME_ACTION_NEXT
+ * EditorInfo.IME_ACTION_NEXT} or {@link EditorInfo#IME_ACTION_DONE
+ * EditorInfo.IME_ACTION_DONE}.
+ *
+ * <p>For backwards compatibility, if no IME options have been set and the
+ * text view would not normally advance focus on enter, then
+ * the NEXT and DONE actions received here will be turned into an enter
+ * key down/up pair to go through the normal key handling.
+ *
+ * @param actionCode The code of the action being performed.
+ *
+ * @see #setOnEditorActionListener
+ */
+ public void onEditorAction(int actionCode) {
+ final InputContentType ict = mInputContentType;
+ if (ict != null) {
+ if (ict.onEditorActionListener != null) {
+ if (ict.onEditorActionListener.onEditorAction(this,
+ actionCode, null)) {
+ 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
+ // app may be expecting.
+ if (actionCode == EditorInfo.IME_ACTION_NEXT) {
+ View v = focusSearch(FOCUS_DOWN);
+ if (v != null) {
+ if (!v.requestFocus(FOCUS_DOWN)) {
+ throw new IllegalStateException("focus search returned a view " +
+ "that wasn't able to take focus!");
+ }
+ }
+ return;
+
+ } else if (actionCode == EditorInfo.IME_ACTION_DONE) {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ imm.hideSoftInputFromWindow(getWindowToken(), 0);
+ }
+ return;
+ }
+ }
+
+ 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)));
+ }
+
+ /**
* Set the private content type of the text, which is the
- * {@link EditorInfo#privateContentType TextBoxAttribute.privateContentType}
+ * {@link EditorInfo#privateImeOptions EditorInfo.privateImeOptions}
* field that will be filled in when creating an input connection.
*
- * @see #getPrivateContentType()
- * @see EditorInfo#privateContentType
- * @attr ref android.R.styleable#TextView_editorPrivateContentType
+ * @see #getPrivateImeOptions()
+ * @see EditorInfo#privateImeOptions
+ * @attr ref android.R.styleable#TextView_privateImeOptions
*/
- public void setPrivateContentType(String type) {
+ public void setPrivateImeOptions(String type) {
if (mInputContentType == null) mInputContentType = new InputContentType();
- mInputContentType.privateContentType = type;
+ mInputContentType.privateImeOptions = type;
}
/**
* Get the private type of the content.
*
- * @see #setPrivateContentType(String)
- * @see EditorInfo#privateContentType
+ * @see #setPrivateImeOptions(String)
+ * @see EditorInfo#privateImeOptions
*/
- public String getPrivateContentType() {
+ public String getPrivateImeOptions() {
return mInputContentType != null
- ? mInputContentType.privateContentType : null;
+ ? mInputContentType.privateImeOptions : null;
}
/**
@@ -2814,7 +3109,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* given integer is the resource ID of an XML resource holding an
* {@link android.R.styleable#InputExtras &lt;input-extras&gt;} XML tree.
*
- * @see #getInputExtras()
+ * @see #getInputExtras(boolean)
* @see EditorInfo#extras
* @attr ref android.R.styleable#TextView_editorExtras
*/
@@ -2832,7 +3127,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @param create If true, the extras will be created if they don't already
* exist. Otherwise, null will be returned if none have been created.
- * @see #setInputExtras(int)
+ * @see #setInputExtras(int)View
* @see EditorInfo#extras
* @attr ref android.R.styleable#TextView_editorExtras
*/
@@ -2865,6 +3160,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* <code>error</code> is <code>null</code>, the error message and icon
* will be cleared.
*/
+ @android.view.RemotableViewMethod
public void setError(CharSequence error) {
if (error == null) {
setError(null, null);
@@ -2916,13 +3212,39 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
private void showError() {
+ if (getWindowToken() == null) {
+ mShowErrorAfterAttach = true;
+ return;
+ }
+
if (mPopup == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
- TextView err = (TextView) inflater.inflate(com.android.internal.R.layout.textview_hint,
+ final TextView err = (TextView) inflater.inflate(com.android.internal.R.layout.textview_hint,
null);
- mPopup = new PopupWindow(err, 200, 50);
+ 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.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.
+ mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
}
TextView tv = (TextView) mPopup.getContentView();
@@ -2979,6 +3301,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mPopup.dismiss();
}
}
+
+ mShowErrorAfterAttach = false;
}
private void chooseSize(PopupWindow pop, CharSequence text, TextView tv) {
@@ -3269,6 +3593,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ mTemporaryDetach = false;
+
+ if (mShowErrorAfterAttach) {
+ showError();
+ mShowErrorAfterAttach = false;
+ }
+ }
+
+ @Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
@@ -3311,6 +3647,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
@Override
+ protected boolean verifyDrawable(Drawable who) {
+ final boolean verified = super.verifyDrawable(who);
+ if (!verified && mDrawables != null) {
+ return who == mDrawables.mDrawableLeft || who == mDrawables.mDrawableTop ||
+ who == mDrawables.mDrawableRight || who == mDrawables.mDrawableBottom;
+ }
+ return verified;
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
// Draw the background for this view
super.onDraw(canvas);
@@ -3505,38 +3851,48 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
*/
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (highlight != null && mInputMethodState != null
- && !mInputMethodState.mBatchEditing && imm != null) {
- if (imm.isActive(this)) {
- int candStart = -1;
- int candEnd = -1;
- if (mText instanceof Spannable) {
- Spannable sp = (Spannable)mText;
- candStart = EditableInputConnection.getComposingSpanStart(sp);
- candEnd = EditableInputConnection.getComposingSpanEnd(sp);
+ final InputMethodState ims = mInputMethodState;
+ if (ims != null && ims.mBatchEditNesting == 0) {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ if (imm.isActive(this)) {
+ boolean reported = false;
+ if (ims.mContentChanged || ims.mSelectionModeChanged) {
+ // We are in extract mode and the content has changed
+ // in some way... just report complete new text to the
+ // input method.
+ reported = reportExtractedText();
+ }
+ if (!reported && highlight != null) {
+ int candStart = -1;
+ int candEnd = -1;
+ if (mText instanceof Spannable) {
+ Spannable sp = (Spannable)mText;
+ candStart = EditableInputConnection.getComposingSpanStart(sp);
+ candEnd = EditableInputConnection.getComposingSpanEnd(sp);
+ }
+ imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
+ }
+ }
+
+ if (imm.isWatchingCursor(this) && highlight != null) {
+ highlight.computeBounds(ims.mTmpRectF, true);
+ ims.mTmpOffset[0] = ims.mTmpOffset[1] = 0;
+
+ canvas.getMatrix().mapPoints(ims.mTmpOffset);
+ ims.mTmpRectF.offset(ims.mTmpOffset[0], ims.mTmpOffset[1]);
+
+ ims.mTmpRectF.offset(0, voffsetCursor - voffsetText);
+
+ ims.mCursorRectInWindow.set((int)(ims.mTmpRectF.left + 0.5),
+ (int)(ims.mTmpRectF.top + 0.5),
+ (int)(ims.mTmpRectF.right + 0.5),
+ (int)(ims.mTmpRectF.bottom + 0.5));
+
+ imm.updateCursor(this,
+ ims.mCursorRectInWindow.left, ims.mCursorRectInWindow.top,
+ ims.mCursorRectInWindow.right, ims.mCursorRectInWindow.bottom);
}
- imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
- }
-
- if (imm.isWatchingCursor(this)) {
- final InputMethodState ims = mInputMethodState;
- highlight.computeBounds(ims.mTmpRectF, true);
- ims.mTmpOffset[0] = ims.mTmpOffset[1] = 0;
-
- canvas.getMatrix().mapPoints(ims.mTmpOffset);
- ims.mTmpRectF.offset(ims.mTmpOffset[0], ims.mTmpOffset[1]);
-
- ims.mTmpRectF.offset(0, voffsetCursor - voffsetText);
-
- ims.mCursorRectInWindow.set((int)(ims.mTmpRectF.left + 0.5),
- (int)(ims.mTmpRectF.top + 0.5),
- (int)(ims.mTmpRectF.right + 0.5),
- (int)(ims.mTmpRectF.bottom + 0.5));
-
- imm.updateCursor(this,
- ims.mCursorRectInWindow.left, ims.mCursorRectInWindow.top,
- ims.mCursorRectInWindow.right, ims.mCursorRectInWindow.bottom);
}
}
@@ -3634,7 +3990,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- int which = doKeyDown(keyCode, event);
+ int which = doKeyDown(keyCode, event, null);
if (which == 0) {
// Go through default dispatching.
return super.onKeyDown(keyCode, event);
@@ -3647,12 +4003,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
- int which = doKeyDown(keyCode, down);
+ int which = doKeyDown(keyCode, down, event);
if (which == 0) {
// Go through default dispatching.
return super.onKeyMultiple(keyCode, repeatCount, event);
}
+ if (which == -1) {
+ // Consumed the whole thing.
+ return true;
+ }
+ repeatCount--;
+
// We are going to dispatch the remaining events to either the input
// or movement method. To do this, we will just send a repeated stream
// of down and up events until we have done the complete repeatCount.
@@ -3680,15 +4042,67 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return true;
}
- private int doKeyDown(int keyCode, KeyEvent event) {
+ /**
+ * Returns true if pressing ENTER in this field advances focus instead
+ * of inserting the character. This is true mostly in single-line fields,
+ * but also in mail addresses and subjects which will display on multiple
+ * lines but where it doesn't make sense to insert newlines.
+ */
+ private boolean shouldAdvanceFocusOnEnter() {
+ if (mInput == null) {
+ return false;
+ }
+
+ if (mSingleLine) {
+ return true;
+ }
+
+ if ((mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) {
+ int variation = mInputType & EditorInfo.TYPE_MASK_VARIATION;
+
+ if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS ||
+ variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT) {
+ return true;
+ }
+ }
+
+ 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;
}
switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
- if (mSingleLine && mInput != null) {
+ if (!isInterestingEnter(event)) {
+ // Ignore enter key we aren't interested in.
+ 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...
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ if (shouldAdvanceFocusOnEnter()) {
return 0;
}
}
@@ -3702,20 +4116,63 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
mErrorWasChanged = false;
- if (mInput.onKeyDown(this, (Editable) mText, keyCode, event)) {
- if (mError != null && !mErrorWasChanged) {
- setError(null, null);
+ boolean doDown = true;
+ if (otherEvent != null) {
+ try {
+ beginBatchEdit();
+ boolean handled = mInput.onKeyOther(this, (Editable) mText,
+ otherEvent);
+ if (mError != null && !mErrorWasChanged) {
+ setError(null, null);
+ }
+ doDown = false;
+ if (handled) {
+ return -1;
+ }
+ } catch (AbstractMethodError e) {
+ // onKeyOther was added after 1.0, so if it isn't
+ // implemented we need to try to dispatch as a regular down.
+ } finally {
+ endBatchEdit();
+ }
+ }
+
+ if (doDown) {
+ beginBatchEdit();
+ if (mInput.onKeyDown(this, (Editable) mText, keyCode, event)) {
+ endBatchEdit();
+ if (mError != null && !mErrorWasChanged) {
+ setError(null, null);
+ }
+ return 1;
}
- return 1;
+ endBatchEdit();
}
}
// bug 650865: sometimes we get a key event before a layout.
// don't try to move around if we don't know the layout.
- if (mMovement != null && mLayout != null)
- if (mMovement.onKeyDown(this, (Spannable)mText, keyCode, event))
- return 2;
+ if (mMovement != null && mLayout != null) {
+ boolean doDown = true;
+ if (otherEvent != null) {
+ try {
+ boolean handled = mMovement.onKeyOther(this, (Spannable) mText,
+ otherEvent);
+ doDown = false;
+ if (handled) {
+ return -1;
+ }
+ } catch (AbstractMethodError e) {
+ // onKeyOther was added after 1.0, so if it isn't
+ // implemented we need to try to dispatch as a regular down.
+ }
+ }
+ if (doDown) {
+ if (mMovement.onKeyDown(this, (Spannable)mText, keyCode, event))
+ return 2;
+ }
+ }
return 0;
}
@@ -3728,8 +4185,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
+ /*
+ * If there is a click listener, just call through to
+ * super, which will invoke it.
+ *
+ * If there isn't a click listener, try to show the soft
+ * input method. (It will also
+ * call performClick(), but that won't do anything in
+ * this case.)
+ */
+ if (mOnClickListener == null) {
+ if (mMovement != null && mText instanceof Editable
+ && mLayout != null && onCheckIsTextEditor()) {
+ InputMethodManager imm = (InputMethodManager)
+ getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(this, 0);
+ }
+ }
+ return super.onKeyUp(keyCode, event);
+
case KeyEvent.KEYCODE_ENTER:
- if (mSingleLine && mInput != null) {
+ if (mInputContentType != null
+ && mInputContentType.onEditorActionListener != null
+ && mInputContentType.enterDown) {
+ mInputContentType.enterDown = false;
+ if (mInputContentType.onEditorActionListener.onEditorAction(
+ this, EditorInfo.IME_NULL, event)) {
+ return true;
+ }
+ }
+
+ if (shouldAdvanceFocusOnEnter()) {
/*
* If there is a click listener, just call through to
* super, which will invoke it.
@@ -3756,6 +4242,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
super.onKeyUp(keyCode, event);
return true;
+ } else if ((event.getFlags()
+ & KeyEvent.FLAG_SOFT_KEYBOARD) != 0) {
+ // No target for next focus, but make sure the IME
+ // if this came from it.
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ imm.hideSoftInputFromWindow(getWindowToken(), 0);
+ }
}
}
@@ -3784,11 +4278,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mInputMethodState = new InputMethodState();
}
outAttrs.inputType = mInputType;
- outAttrs.hintText = mHint;
if (mInputContentType != null) {
- outAttrs.privateContentType = mInputContentType.privateContentType;
+ outAttrs.imeOptions = mInputContentType.imeOptions;
+ outAttrs.privateImeOptions = mInputContentType.privateImeOptions;
+ outAttrs.actionLabel = mInputContentType.imeActionLabel;
+ outAttrs.actionId = mInputContentType.imeActionId;
outAttrs.extras = mInputContentType.extras;
+ } else {
+ outAttrs.imeOptions = EditorInfo.IME_NULL;
+ }
+ if ((outAttrs.imeOptions&EditorInfo.IME_MASK_ACTION)
+ == EditorInfo.IME_ACTION_UNSPECIFIED) {
+ if (focusSearch(FOCUS_DOWN) != null) {
+ // An action has not been set, but the enter key will move to
+ // the next focus, so set the action to that.
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
+ } else {
+ // An action has not been set, and there is no focus to move
+ // to, so let's just supply a "done" action.
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_DONE;
+ }
+ if (!shouldAdvanceFocusOnEnter()) {
+ outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION;
+ }
}
+ outAttrs.hintText = mHint;
if (mText instanceof Editable) {
InputConnection ic = new EditableInputConnection(this);
outAttrs.initialSelStart = Selection.getSelectionStart(mText);
@@ -3803,14 +4317,69 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* If this TextView contains editable content, extract a portion of it
* based on the information in <var>request</var> in to <var>outText</var>.
- * @return Returns true if the text is editable and was successfully
- * extracted, else false.
+ * @return Returns true if the text was successfully extracted, else false.
*/
public boolean extractText(ExtractedTextRequest request,
ExtractedText outText) {
- Editable content = getEditableText();
+ return extractTextInternal(request, EXTRACT_UNKNOWN, EXTRACT_UNKNOWN,
+ EXTRACT_UNKNOWN, outText);
+ }
+
+ static final int EXTRACT_NOTHING = -2;
+ static final int EXTRACT_UNKNOWN = -1;
+
+ boolean extractTextInternal(ExtractedTextRequest request,
+ int partialStartOffset, int partialEndOffset, int delta,
+ ExtractedText outText) {
+ final CharSequence content = mText;
if (content != null) {
- outText.text = content.subSequence(0, content.length());
+ if (partialStartOffset != EXTRACT_NOTHING) {
+ final int N = content.length();
+ if (partialStartOffset < 0) {
+ outText.partialStartOffset = outText.partialEndOffset = -1;
+ partialStartOffset = 0;
+ partialEndOffset = N;
+ } else {
+ // Adjust offsets to ensure we contain full spans.
+ if (content instanceof Spanned) {
+ Spanned spanned = (Spanned)content;
+ Object[] spans = spanned.getSpans(partialStartOffset,
+ partialEndOffset, ParcelableSpan.class);
+ int i = spans.length;
+ while (i > 0) {
+ i--;
+ int j = spanned.getSpanStart(spans[i]);
+ if (j < partialStartOffset) partialStartOffset = j;
+ j = spanned.getSpanEnd(spans[i]);
+ if (j > partialEndOffset) partialEndOffset = j;
+ }
+ }
+ outText.partialStartOffset = partialStartOffset;
+ outText.partialEndOffset = partialEndOffset;
+ // Now use the delta to determine the actual amount of text
+ // we need.
+ partialEndOffset += delta;
+ if (partialEndOffset > N) {
+ partialEndOffset = N;
+ } else if (partialEndOffset < 0) {
+ partialEndOffset = 0;
+ }
+ }
+ if ((request.flags&InputConnection.GET_TEXT_WITH_STYLES) != 0) {
+ outText.text = content.subSequence(partialStartOffset,
+ partialEndOffset);
+ } else {
+ outText.text = TextUtils.substring(content, partialStartOffset,
+ partialEndOffset);
+ }
+ }
+ outText.flags = 0;
+ if (MetaKeyKeyListener.getMetaState(mText, MetaKeyKeyListener.META_SELECTING) != 0) {
+ outText.flags |= ExtractedText.FLAG_SELECTING;
+ }
+ if (mSingleLine) {
+ outText.flags |= ExtractedText.FLAG_SINGLE_LINE;
+ }
outText.startOffset = 0;
outText.selectionStart = Selection.getSelectionStart(content);
outText.selectionEnd = Selection.getSelectionEnd(content);
@@ -3819,19 +4388,50 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return false;
}
- void reportExtractedText() {
- if (mInputMethodState != null) {
+ boolean reportExtractedText() {
+ final InputMethodState ims = mInputMethodState;
+ final boolean contentChanged = ims.mContentChanged;
+ if (ims != null && (contentChanged || ims.mSelectionModeChanged)) {
+ ims.mContentChanged = false;
+ ims.mSelectionModeChanged = false;
final ExtractedTextRequest req = mInputMethodState.mExtracting;
if (req != null) {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
- if (extractText(req, mInputMethodState.mTmpExtracted)) {
+ if (DEBUG_EXTRACT) Log.v(TAG, "Retrieving extracted start="
+ + ims.mChangedStart + " end=" + ims.mChangedEnd
+ + " delta=" + ims.mChangedDelta);
+ if (ims.mChangedStart < 0 && !contentChanged) {
+ ims.mChangedStart = EXTRACT_NOTHING;
+ }
+ if (extractTextInternal(req, ims.mChangedStart, ims.mChangedEnd,
+ ims.mChangedDelta, ims.mTmpExtracted)) {
+ if (DEBUG_EXTRACT) Log.v(TAG, "Reporting extracted start="
+ + ims.mTmpExtracted.partialStartOffset
+ + " end=" + ims.mTmpExtracted.partialEndOffset
+ + ": " + ims.mTmpExtracted.text);
imm.updateExtractedText(this, req.token,
mInputMethodState.mTmpExtracted);
+ return true;
}
}
}
}
+ return false;
+ }
+
+ /**
+ * This is used to remove all style-impacting spans from text before new
+ * extracted text is being replaced into it, so that we don't have any
+ * lingering spans applied during the replace.
+ */
+ static void removeParcelableSpans(Spannable spannable, int start, int end) {
+ Object[] spans = spannable.getSpans(start, end, ParcelableSpan.class);
+ int i = spans.length;
+ while (i > 0) {
+ i--;
+ spannable.removeSpan(spans[i]);
+ }
}
/**
@@ -3839,9 +4439,44 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* returned by {@link #extractText(ExtractedTextRequest, ExtractedText)}.
*/
public void setExtractedText(ExtractedText text) {
- setText(text.text, TextView.BufferType.EDITABLE);
- Selection.setSelection((Spannable)getText(),
- text.selectionStart, text.selectionEnd);
+ Editable content = getEditableText();
+ if (text.text != null) {
+ if (content == null) {
+ setText(text.text, TextView.BufferType.EDITABLE);
+ } else if (text.partialStartOffset < 0) {
+ removeParcelableSpans(content, 0, content.length());
+ content.replace(0, content.length(), text.text);
+ } else {
+ final int N = content.length();
+ int start = text.partialStartOffset;
+ if (start > N) start = N;
+ int end = text.partialEndOffset;
+ if (end > N) end = N;
+ removeParcelableSpans(content, start, end);
+ content.replace(start, end, text.text);
+ }
+ }
+
+ // Now set the selection position... make sure it is in range, to
+ // avoid crashes. If this is a partial update, it is possible that
+ // the underlying text may have changed, causing us problems here.
+ // Also we just don't want to trust clients to do the right thing.
+ Spannable sp = (Spannable)getText();
+ final int N = sp.length();
+ int start = text.selectionStart;
+ if (start < 0) start = 0;
+ else if (start > N) start = N;
+ int end = text.selectionEnd;
+ if (end < 0) end = 0;
+ else if (end > N) end = N;
+ Selection.setSelection(sp, start, end);
+
+ // Finally, update the selection mode.
+ if ((text.flags&ExtractedText.FLAG_SELECTING) != 0) {
+ MetaKeyKeyListener.startSelecting(this, sp);
+ } else {
+ MetaKeyKeyListener.stopSelecting(this, sp);
+ }
}
/**
@@ -3866,36 +4501,91 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public void onCommitCompletion(CompletionInfo text) {
}
+ public void beginBatchEdit() {
+ final InputMethodState ims = mInputMethodState;
+ if (ims != null) {
+ int nesting = ++ims.mBatchEditNesting;
+ if (nesting == 1) {
+ ims.mCursorChanged = false;
+ ims.mChangedDelta = 0;
+ if (ims.mContentChanged) {
+ // We already have a pending change from somewhere else,
+ // so turn this into a full update.
+ ims.mChangedStart = 0;
+ ims.mChangedEnd = mText.length();
+ } else {
+ ims.mChangedStart = EXTRACT_UNKNOWN;
+ ims.mChangedEnd = EXTRACT_UNKNOWN;
+ ims.mContentChanged = false;
+ }
+ onBeginBatchEdit();
+ }
+ }
+ }
+
+ public void endBatchEdit() {
+ final InputMethodState ims = mInputMethodState;
+ if (ims != null) {
+ int nesting = --ims.mBatchEditNesting;
+ if (nesting == 0) {
+ finishBatchEdit(ims);
+ }
+ }
+ }
+
+ void ensureEndedBatchEdit() {
+ final InputMethodState ims = mInputMethodState;
+ if (ims != null && ims.mBatchEditNesting != 0) {
+ ims.mBatchEditNesting = 0;
+ finishBatchEdit(ims);
+ }
+ }
+
+ void finishBatchEdit(final InputMethodState ims) {
+ onEndBatchEdit();
+
+ if (ims.mContentChanged || ims.mSelectionModeChanged) {
+ updateAfterEdit();
+ reportExtractedText();
+ } else if (ims.mCursorChanged) {
+ // Cheezy way to get us to report the current cursor location.
+ invalidateCursor();
+ }
+ }
+
+ void updateAfterEdit() {
+ invalidate();
+ int curs = Selection.getSelectionStart(mText);
+
+ if (curs >= 0 || (mGravity & Gravity.VERTICAL_GRAVITY_MASK) ==
+ Gravity.BOTTOM) {
+ registerForPreDraw();
+ }
+
+ if (curs >= 0) {
+ mHighlightPathBogus = true;
+
+ if (isFocused()) {
+ mShowCursor = SystemClock.uptimeMillis();
+ makeBlink();
+ }
+ }
+
+ checkForResize();
+ }
+
/**
* Called by the framework in response to a request to begin a batch
- * of edit operations from the current input method, as a result of
- * it calling {@link InputConnection#beginBatchEdit
- * InputConnection.beginBatchEdit()}. The default implementation sets
- * up the TextView's internal state to take care of this; if overriding
- * you should call through to the super class.
+ * of edit operations through a call to link {@link #beginBatchEdit()}.
*/
public void onBeginBatchEdit() {
- if (mInputMethodState != null) {
- // XXX we should be smarter here, such as not doing invalidates
- // until all edits are done.
- mInputMethodState.mBatchEditing = true;
- }
}
/**
* Called by the framework in response to a request to end a batch
- * of edit operations from the current input method, as a result of
- * it calling {@link InputConnection#endBatchEdit
- * InputConnection.endBatchEdit()}. The default implementation sets
- * up the TextView's internal state to take care of this; if overriding
- * you should call through to the super class.
+ * of edit operations through a call to link {@link #endBatchEdit}.
*/
public void onEndBatchEdit() {
- if (mInputMethodState != null) {
- mInputMethodState.mBatchEditing = false;
- // Cheezy way to get us to report the current cursor location.
- invalidateCursor();
- }
}
/**
@@ -4542,9 +5232,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Returns true if anything changed.
+ * Move the point, specified by the offset, into the view if it is needed.
+ * This has to be called after layout. Returns true if anything changed.
*/
- private boolean bringPointIntoView(int offset) {
+ public boolean bringPointIntoView(int offset) {
boolean changed = false;
int line = mLayout.getLineForOffset(offset);
@@ -4793,8 +5484,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_singleLine
*/
+ @android.view.RemotableViewMethod
public void setSingleLine(boolean singleLine) {
- mSingleLine = singleLine;
if ((mInputType&EditorInfo.TYPE_MASK_CLASS)
== EditorInfo.TYPE_CLASS_TEXT) {
if (singleLine) {
@@ -4803,19 +5494,27 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mInputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE;
}
}
+ applySingleLine(singleLine, true);
+ }
+ private void applySingleLine(boolean singleLine, boolean applyTransformation) {
+ mSingleLine = singleLine;
if (singleLine) {
setLines(1);
setHorizontallyScrolling(true);
- setTransformationMethod(SingleLineTransformationMethod.
- getInstance());
+ if (applyTransformation) {
+ setTransformationMethod(SingleLineTransformationMethod.
+ getInstance());
+ }
} else {
setMaxLines(Integer.MAX_VALUE);
setHorizontallyScrolling(false);
- setTransformationMethod(null);
+ if (applyTransformation) {
+ setTransformationMethod(null);
+ }
}
}
-
+
/**
* Causes words in the text that are longer than the view is wide
* to be ellipsized instead of broken in the middle. You may also
@@ -4860,6 +5559,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_selectAllOnFocus
*/
+ @android.view.RemotableViewMethod
public void setSelectAllOnFocus(boolean selectAllOnFocus) {
mSelectAllOnFocus = selectAllOnFocus;
@@ -4873,6 +5573,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_cursorVisible
*/
+ @android.view.RemotableViewMethod
public void setCursorVisible(boolean visible) {
mCursorVisible = visible;
invalidate();
@@ -4938,6 +5639,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
float mScroll;
Marquee(TextView v) {
+ final float density = v.getContext().getResources().getDisplayMetrics().density;
+ mScrollUnit = (MARQUEE_PIXELS_PER_SECOND * density) / (float) MARQUEE_RESOLUTION;
mView = new WeakReference<TextView>(v);
}
@@ -5006,7 +5709,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (textView != null && textView.mLayout != null) {
mStatus = MARQUEE_STARTING;
mScroll = 0.0f;
- mScrollUnit = MARQUEE_PIXELS_PER_SECOND / (float) MARQUEE_RESOLUTION;
mMaxScroll = textView.mLayout.getLineWidth(0) - (textView.getWidth() -
textView.getCompoundPaddingLeft() - textView.getCompoundPaddingRight());
textView.invalidate();
@@ -5046,6 +5748,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * This method is called when the selection has changed, in case any
+ * subclasses would like to know.
+ *
+ * @param selStart The new selection start location.
+ * @param selEnd The new selection end location.
+ */
+ protected void onSelectionChanged(int selStart, int selEnd) {
+ }
+
+ /**
* Adds a TextWatcher to the list of those whose methods are called
* whenever this TextView's text changes.
* <p>
@@ -5123,26 +5835,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
void handleTextChanged(CharSequence buffer, int start,
int before, int after) {
- invalidate();
-
- int curs = Selection.getSelectionStart(buffer);
-
- if (curs >= 0 || (mGravity & Gravity.VERTICAL_GRAVITY_MASK) ==
- Gravity.BOTTOM) {
- registerForPreDraw();
- }
-
- if (curs >= 0) {
- mHighlightPathBogus = true;
-
- if (isFocused()) {
- mShowCursor = SystemClock.uptimeMillis();
- makeBlink();
+ final InputMethodState ims = mInputMethodState;
+ if (ims == null || ims.mBatchEditNesting == 0) {
+ updateAfterEdit();
+ }
+ if (ims != null) {
+ ims.mContentChanged = true;
+ if (ims.mChangedStart < 0) {
+ ims.mChangedStart = start;
+ ims.mChangedEnd = start+before;
+ } else {
+ if (ims.mChangedStart > start) ims.mChangedStart = start;
+ if (ims.mChangedEnd < (start+before)) ims.mChangedEnd = start+before;
}
+ ims.mChangedDelta += after-before;
}
-
- checkForResize();
-
+
sendOnTextChanged(buffer, start, before, after);
onTextChanged(buffer, start, before, after);
}
@@ -5151,19 +5859,27 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* Not private so it can be called from an inner class without going
* through a thunk.
*/
- void spanChange(Spanned buf, Object what, int o, int n) {
+ void spanChange(Spanned buf, Object what, int oldStart, int newStart,
+ int oldEnd, int newEnd) {
// XXX Make the start and end move together if this ends up
// spending too much time invalidating.
+ boolean selChanged = false;
+ int newSelStart=-1, newSelEnd=-1;
+
+ final InputMethodState ims = mInputMethodState;
+
if (what == Selection.SELECTION_END) {
mHighlightPathBogus = true;
+ selChanged = true;
+ newSelEnd = newStart;
if (!isFocused()) {
mSelectionMoved = true;
}
- if (o >= 0 || n >= 0) {
- invalidateCursor(Selection.getSelectionStart(buf), o, n);
+ if (oldStart >= 0 || newStart >= 0) {
+ invalidateCursor(Selection.getSelectionStart(buf), oldStart, newStart);
registerForPreDraw();
if (isFocused()) {
@@ -5175,28 +5891,84 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (what == Selection.SELECTION_START) {
mHighlightPathBogus = true;
+ selChanged = true;
+ newSelStart = newStart;
if (!isFocused()) {
mSelectionMoved = true;
}
- if (o >= 0 || n >= 0) {
- invalidateCursor(Selection.getSelectionEnd(buf), o, n);
+ if (oldStart >= 0 || newStart >= 0) {
+ int end = Selection.getSelectionEnd(buf);
+ invalidateCursor(end, oldStart, newStart);
}
}
+ if (selChanged) {
+ if ((buf.getSpanFlags(what)&Spanned.SPAN_INTERMEDIATE) == 0) {
+ if (newSelStart < 0) {
+ newSelStart = Selection.getSelectionStart(buf);
+ }
+ if (newSelEnd < 0) {
+ newSelEnd = Selection.getSelectionEnd(buf);
+ }
+ onSelectionChanged(newSelStart, newSelEnd);
+ }
+ }
+
if (what instanceof UpdateAppearance ||
what instanceof ParagraphStyle) {
- invalidate();
- mHighlightPathBogus = true;
- checkForResize();
+ if (ims == null || ims.mBatchEditNesting == 0) {
+ invalidate();
+ mHighlightPathBogus = true;
+ checkForResize();
+ } else {
+ ims.mContentChanged = true;
+ }
}
if (MetaKeyKeyListener.isMetaTracker(buf, what)) {
mHighlightPathBogus = true;
+ if (ims != null && MetaKeyKeyListener.isSelectingMetaTracker(buf, what)) {
+ ims.mSelectionModeChanged = true;
+ }
if (Selection.getSelectionStart(buf) >= 0) {
- invalidateCursor();
+ if (ims == null || ims.mBatchEditNesting == 0) {
+ invalidateCursor();
+ } else {
+ ims.mCursorChanged = true;
+ }
+ }
+ }
+
+ if (what instanceof ParcelableSpan) {
+ // If this is a span that can be sent to a remote process,
+ // the current extract editor would be interested in it.
+ if (ims != null && ims.mExtracting != null) {
+ if (ims.mBatchEditNesting != 0) {
+ if (oldStart >= 0) {
+ if (ims.mChangedStart > oldStart) {
+ ims.mChangedStart = oldStart;
+ }
+ if (ims.mChangedStart > oldEnd) {
+ ims.mChangedStart = oldEnd;
+ }
+ }
+ if (newStart >= 0) {
+ if (ims.mChangedStart > newStart) {
+ ims.mChangedStart = newStart;
+ }
+ if (ims.mChangedStart > newEnd) {
+ ims.mChangedStart = newEnd;
+ }
+ }
+ } else {
+ if (DEBUG_EXTRACT) Log.v(TAG, "Span change outside of batch: "
+ + oldStart + "-" + oldEnd + ","
+ + newStart + "-" + newEnd + what);
+ ims.mContentChanged = true;
+ }
}
}
}
@@ -5205,36 +5977,45 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
implements TextWatcher, SpanWatcher {
public void beforeTextChanged(CharSequence buffer, int start,
int before, int after) {
+ if (DEBUG_EXTRACT) Log.v(TAG, "beforeTextChanged start=" + start
+ + " before=" + before + " after=" + after + ": " + buffer);
TextView.this.sendBeforeTextChanged(buffer, start, before, after);
}
public void onTextChanged(CharSequence buffer, int start,
int before, int after) {
+ if (DEBUG_EXTRACT) Log.v(TAG, "onTextChanged start=" + start
+ + " before=" + before + " after=" + after + ": " + buffer);
TextView.this.handleTextChanged(buffer, start, before, after);
}
public void afterTextChanged(Editable buffer) {
+ if (DEBUG_EXTRACT) Log.v(TAG, "afterTextChanged: " + buffer);
TextView.this.sendAfterTextChanged(buffer);
if (MetaKeyKeyListener.getMetaState(buffer,
MetaKeyKeyListener.META_SELECTING) != 0) {
MetaKeyKeyListener.stopSelecting(TextView.this, buffer);
}
-
- TextView.this.reportExtractedText();
}
public void onSpanChanged(Spannable buf,
Object what, int s, int e, int st, int en) {
- TextView.this.spanChange(buf, what, s, st);
+ if (DEBUG_EXTRACT) Log.v(TAG, "onSpanChanged s=" + s + " e=" + e
+ + " st=" + st + " en=" + en + " what=" + what + ": " + buf);
+ TextView.this.spanChange(buf, what, s, st, e, en);
}
public void onSpanAdded(Spannable buf, Object what, int s, int e) {
- TextView.this.spanChange(buf, what, -1, s);
+ if (DEBUG_EXTRACT) Log.v(TAG, "onSpanAdded s=" + s + " e=" + e
+ + " what=" + what + ": " + buf);
+ TextView.this.spanChange(buf, what, -1, s, -1, e);
}
public void onSpanRemoved(Spannable buf, Object what, int s, int e) {
- TextView.this.spanChange(buf, what, s, -1);
+ if (DEBUG_EXTRACT) Log.v(TAG, "onSpanRemoved s=" + s + " e=" + e
+ + " what=" + what + ": " + buf);
+ TextView.this.spanChange(buf, what, s, -1, e, -1);
}
}
@@ -5255,9 +6036,27 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
@Override
+ public void onStartTemporaryDetach() {
+ mTemporaryDetach = true;
+ }
+
+ @Override
+ public void onFinishTemporaryDetach() {
+ mTemporaryDetach = false;
+ }
+
+ @Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+ if (mTemporaryDetach) {
+ // If we are temporarily in the detach state, then do nothing.
+ super.onFocusChanged(focused, direction, previouslyFocusedRect);
+ return;
+ }
+
mShowCursor = SystemClock.uptimeMillis();
+ ensureEndedBatchEdit();
+
if (focused) {
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
@@ -5286,6 +6085,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Selection.setSelection((Spannable) mText, selStart, selEnd);
}
+ mTouchFocusSelected = true;
}
mFrozenWithFocus = false;
@@ -5338,11 +6138,25 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
// Don't leave us in the middle of a batch edit.
onEndBatchEdit();
+ if (mInputContentType != null) {
+ mInputContentType.enterDown = false;
+ }
}
startStopMarquee(hasWindowFocus);
}
+ /**
+ * Use {@link BaseInputConnection#removeComposingSpans
+ * BaseInputConnection.removeComposingSpans()} to remove any IME composing
+ * state from this text view.
+ */
+ public void clearComposingText() {
+ if (mText instanceof Spannable) {
+ BaseInputConnection.removeComposingSpans((Spannable)mText);
+ }
+ }
+
@Override
public void setSelected(boolean selected) {
boolean wasSelected = isSelected();
@@ -5358,8 +6172,30 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ class CommitSelectionReceiver extends ResultReceiver {
+ int mNewStart;
+ int mNewEnd;
+
+ CommitSelectionReceiver() {
+ super(getHandler());
+ }
+
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode != InputMethodManager.RESULT_SHOWN) {
+ Selection.setSelection((Spannable)mText, mNewStart, mNewEnd);
+ }
+ }
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
+ final int action = event.getAction();
+ if (action == MotionEvent.ACTION_DOWN) {
+ // Reset this state; it will be re-set if super.onTouchEvent
+ // causes focus to move to the view.
+ mTouchFocusSelected = false;
+ }
+
final boolean superResult = super.onTouchEvent(event);
/*
@@ -5367,24 +6203,57 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* move the selection away from whatever the menu action was
* trying to affect.
*/
- if (mEatTouchRelease && event.getAction() == MotionEvent.ACTION_UP) {
+ if (mEatTouchRelease && action == MotionEvent.ACTION_UP) {
mEatTouchRelease = false;
return superResult;
}
- if (mMovement != null && mText instanceof Spannable &&
- mLayout != null) {
- boolean moved = mMovement.onTouchEvent(this, (Spannable) mText, event);
+ if ((mMovement != null || onCheckIsTextEditor()) && mText instanceof Spannable && mLayout != null) {
+
+ if (action == MotionEvent.ACTION_DOWN) {
+ mScrolled = false;
+ }
+
+ boolean handled = false;
+
+ int oldSelStart = Selection.getSelectionStart(mText);
+ int oldSelEnd = Selection.getSelectionEnd(mText);
+
+ if (mMovement != null) {
+ handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
+ }
if (mText instanceof Editable && onCheckIsTextEditor()) {
- if (event.getAction() == MotionEvent.ACTION_UP && isFocused()) {
+ if (action == MotionEvent.ACTION_UP && isFocused() && !mScrolled) {
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(this, 0);
+
+ // This is going to be gross... if tapping on the text view
+ // causes the IME to be displayed, we don't want the selection
+ // to change. But the selection has already changed, and
+ // we won't know right away whether the IME is getting
+ // displayed, so...
+
+ int newSelStart = Selection.getSelectionStart(mText);
+ int newSelEnd = Selection.getSelectionEnd(mText);
+ CommitSelectionReceiver csr = null;
+ if (newSelStart != oldSelStart || newSelEnd != oldSelEnd) {
+ csr = new CommitSelectionReceiver();
+ csr.mNewStart = newSelStart;
+ csr.mNewEnd = newSelEnd;
+ }
+
+ if (imm.showSoftInput(this, 0, csr) && csr != null) {
+ // The IME might get shown -- revert to the old
+ // selection, and change to the new when we finally
+ // find out of it is okay.
+ Selection.setSelection((Spannable)mText, oldSelStart, oldSelEnd);
+ handled = true;
+ }
}
}
- if (moved) {
+ if (handled) {
return true;
}
}
@@ -5392,6 +6261,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return superResult;
}
+ /**
+ * Returns true, only while processing a touch gesture, if the initial
+ * touch down event caused focus to move to the text view and as a result
+ * its selection changed. Only valid while processing the touch gesture
+ * of interest.
+ */
+ public boolean didTouchFocusSelect() {
+ return mTouchFocusSelected;
+ }
+
+ @Override
+ public void cancelLongPress() {
+ super.cancelLongPress();
+ mScrolled = true;
+ }
+
@Override
public boolean onTrackballEvent(MotionEvent event) {
if (mMovement != null && mText instanceof Spannable &&
@@ -5408,8 +6293,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mScroller = s;
}
- private static class Blink extends Handler
- implements Runnable {
+ private static class Blink extends Handler implements Runnable {
private WeakReference<TextView> mView;
private boolean mCancelled;
@@ -5514,6 +6398,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return super.computeVerticalScrollRange();
}
+ @Override
+ protected int computeVerticalScrollExtent() {
+ return getHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom();
+ }
+
public enum BufferType {
NORMAL, SPANNABLE, EDITABLE,
}
@@ -5568,28 +6457,28 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
switch (keyCode) {
case KeyEvent.KEYCODE_A:
if (canSelectAll()) {
- return onMenu(ID_SELECT_ALL);
+ return onTextContextMenuItem(ID_SELECT_ALL);
}
break;
case KeyEvent.KEYCODE_X:
if (canCut()) {
- return onMenu(ID_CUT);
+ return onTextContextMenuItem(ID_CUT);
}
break;
case KeyEvent.KEYCODE_C:
if (canCopy()) {
- return onMenu(ID_COPY);
+ return onTextContextMenuItem(ID_COPY);
}
break;
case KeyEvent.KEYCODE_V:
if (canPaste()) {
- return onMenu(ID_PASTE);
+ return onTextContextMenuItem(ID_PASTE);
}
break;
@@ -5655,6 +6544,79 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return false;
}
+ /**
+ * Returns a word to add to the dictionary from the context menu,
+ * or null if there is no cursor or no word at the cursor.
+ */
+ private String getWordForDictionary() {
+ /*
+ * Quick return if the input type is one where adding words
+ * to the dictionary doesn't make any sense.
+ */
+ int klass = mInputType & InputType.TYPE_MASK_CLASS;
+ if (klass == InputType.TYPE_CLASS_NUMBER ||
+ klass == InputType.TYPE_CLASS_PHONE ||
+ klass == InputType.TYPE_CLASS_DATETIME) {
+ return null;
+ }
+
+ int variation = mInputType & InputType.TYPE_MASK_VARIATION;
+ if (variation == InputType.TYPE_TEXT_VARIATION_URI ||
+ variation == InputType.TYPE_TEXT_VARIATION_PASSWORD ||
+ variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD ||
+ variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS ||
+ variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
+ return null;
+ }
+
+ int end = getSelectionEnd();
+
+ if (end < 0) {
+ return null;
+ }
+
+ int start = end;
+ int len = mText.length();
+
+ for (; start > 0; start--) {
+ char c = mTransformed.charAt(start - 1);
+ int type = Character.getType(c);
+
+ if (c != '\'' &&
+ type != Character.UPPERCASE_LETTER &&
+ type != Character.LOWERCASE_LETTER &&
+ type != Character.TITLECASE_LETTER &&
+ type != Character.MODIFIER_LETTER &&
+ type != Character.DECIMAL_DIGIT_NUMBER) {
+ break;
+ }
+ }
+
+ for (; end < len; end++) {
+ char c = mTransformed.charAt(end);
+ int type = Character.getType(c);
+
+ if (c != '\'' &&
+ type != Character.UPPERCASE_LETTER &&
+ type != Character.LOWERCASE_LETTER &&
+ type != Character.TITLECASE_LETTER &&
+ type != Character.MODIFIER_LETTER &&
+ type != Character.DECIMAL_DIGIT_NUMBER) {
+ break;
+ }
+ }
+
+ if (start == end) {
+ return null;
+ }
+
+ if (end - start > 48) {
+ return null;
+ }
+
+ return TextUtils.substring(mTransformed, start, end);
+ }
+
@Override
protected void onCreateContextMenu(ContextMenu menu) {
super.onCreateContextMenu(menu);
@@ -5696,7 +6658,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setOnMenuItemClickListener(handler);
added = true;
} else {
- menu.add(0, ID_SELECT_TEXT, 0,
+ menu.add(0, ID_START_SELECTING_TEXT, 0,
com.android.internal.R.string.selectText).
setOnMenuItemClickListener(handler);
added = true;
@@ -5755,11 +6717,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null && imm.isActive(this)) {
- menu.add(1, ID_SWITCH_IME, 0, com.android.internal.R.string.inputMethod).
+ if (isInputMethodTarget()) {
+ menu.add(1, ID_SWITCH_INPUT_METHOD, 0, com.android.internal.R.string.inputMethod).
+ setOnMenuItemClickListener(handler);
+ added = true;
+ }
+
+ String word = getWordForDictionary();
+ if (word != null) {
+ menu.add(1, ID_ADD_TO_DICTIONARY, 0,
+ getContext().getString(com.android.internal.R.string.addToDictionary, word)).
setOnMenuItemClickListener(handler);
added = true;
+
}
if (added) {
@@ -5767,22 +6737,40 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- private static final int ID_SELECT_ALL = com.android.internal.R.id.selectAll;
- private static final int ID_SELECT_TEXT = com.android.internal.R.id.selectText;
- private static final int ID_STOP_SELECTING_TEXT = com.android.internal.R.id.stopSelectingText;
- private static final int ID_CUT = com.android.internal.R.id.cut;
- private static final int ID_COPY = com.android.internal.R.id.copy;
- private static final int ID_PASTE = com.android.internal.R.id.paste;
- private static final int ID_COPY_URL = com.android.internal.R.id.copyUrl;
- private static final int ID_SWITCH_IME = com.android.internal.R.id.inputMethod;
+ /**
+ * Returns whether this text view is a current input method target. The
+ * default implementation just checks with {@link InputMethodManager}.
+ */
+ public boolean isInputMethodTarget() {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ return imm != null && imm.isActive(this);
+ }
+
+ private static final int ID_SELECT_ALL = android.R.id.selectAll;
+ private static final int ID_START_SELECTING_TEXT = android.R.id.startSelectingText;
+ private static final int ID_STOP_SELECTING_TEXT = android.R.id.stopSelectingText;
+ private static final int ID_CUT = android.R.id.cut;
+ private static final int ID_COPY = android.R.id.copy;
+ private static final int ID_PASTE = android.R.id.paste;
+ private static final int ID_COPY_URL = android.R.id.copyUrl;
+ private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod;
+ private static final int ID_ADD_TO_DICTIONARY = android.R.id.addToDictionary;
private class MenuHandler implements MenuItem.OnMenuItemClickListener {
public boolean onMenuItemClick(MenuItem item) {
- return onMenu(item.getItemId());
+ return onTextContextMenuItem(item.getItemId());
}
}
- private boolean onMenu(int id) {
+ /**
+ * Called when a context menu option for the text view is selected. Currently
+ * this will be one of: {@link android.R.id#selectAll},
+ * {@link android.R.id#startSelectingText}, {@link android.R.id#stopSelectingText},
+ * {@link android.R.id#cut}, {@link android.R.id#copy},
+ * {@link android.R.id#paste}, {@link android.R.id#copyUrl},
+ * or {@link android.R.id#switchInputMethod}.
+ */
+ public boolean onTextContextMenuItem(int id) {
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
@@ -5807,10 +6795,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
switch (id) {
case ID_SELECT_ALL:
Selection.setSelection((Spannable) mText, 0,
- mText.length());
+ mText.length());
return true;
- case ID_SELECT_TEXT:
+ case ID_START_SELECTING_TEXT:
MetaKeyKeyListener.startSelecting(this, (Spannable) mText);
return true;
@@ -5865,12 +6853,23 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return true;
- case ID_SWITCH_IME:
+ case ID_SWITCH_INPUT_METHOD:
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
imm.showInputMethodPicker();
}
return true;
+
+ case ID_ADD_TO_DICTIONARY:
+ String word = getWordForDictionary();
+
+ if (word != null) {
+ Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT");
+ i.putExtra("word", word);
+ getContext().startActivity(i);
+ }
+
+ return true;
}
return false;
@@ -5885,8 +6884,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return false;
}
- private boolean mEatTouchRelease = false;
-
@ViewDebug.ExportedProperty
private CharSequence mText;
private CharSequence mTransformed;
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 1227afd..4c5df2f 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -46,8 +46,10 @@ import java.io.IOException;
* such as scaling and tinting.
*/
public class VideoView extends SurfaceView implements MediaPlayerControl {
+ private String TAG = "VideoView";
// settable by the client
private Uri mUri;
+ private int mDuration;
// All the stuff we need for playing and showing a video
private SurfaceHolder mSurfaceHolder = null;
@@ -184,6 +186,8 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mIsPrepared = false;
+ Log.v(TAG, "reset duration to -1 in openVideo");
+ mDuration = -1;
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
@@ -195,10 +199,10 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaPlayer.prepareAsync();
attachMediaController();
} catch (IOException ex) {
- Log.w("VideoView", "Unable to open content: " + mUri, ex);
+ Log.w(TAG, "Unable to open content: " + mUri, ex);
return;
} catch (IllegalArgumentException ex) {
- Log.w("VideoView", "Unable to open content: " + mUri, ex);
+ Log.w(TAG, "Unable to open content: " + mUri, ex);
return;
}
}
@@ -298,15 +302,15 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
private MediaPlayer.OnErrorListener mErrorListener =
new MediaPlayer.OnErrorListener() {
- public boolean onError(MediaPlayer mp, int a, int b) {
- Log.d("VideoView", "Error: " + a + "," + b);
+ public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
+ Log.d(TAG, "Error: " + framework_err + "," + impl_err);
if (mMediaController != null) {
mMediaController.hide();
}
/* If an error handler has been supplied, use it and finish. */
if (mOnErrorListener != null) {
- if (mOnErrorListener.onError(mMediaPlayer, a, b)) {
+ if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
return true;
}
}
@@ -318,9 +322,17 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
*/
if (getWindowToken() != null) {
Resources r = mContext.getResources();
+ int messageId;
+
+ if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
+ messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback;
+ } else {
+ messageId = com.android.internal.R.string.VideoView_error_text_unknown;
+ }
+
new AlertDialog.Builder(mContext)
.setTitle(com.android.internal.R.string.VideoView_error_title)
- .setMessage(com.android.internal.R.string.VideoView_error_text_unknown)
+ .setMessage(messageId)
.setPositiveButton(com.android.internal.R.string.VideoView_error_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
@@ -497,9 +509,14 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
public int getDuration() {
if (mMediaPlayer != null && mIsPrepared) {
- return mMediaPlayer.getDuration();
+ if (mDuration > 0) {
+ return mDuration;
+ }
+ mDuration = mMediaPlayer.getDuration();
+ return mDuration;
}
- return -1;
+ mDuration = -1;
+ return mDuration;
}
public int getCurrentPosition() {
diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java
index acc9c46..fa8935e 100644
--- a/core/java/android/widget/ViewAnimator.java
+++ b/core/java/android/widget/ViewAnimator.java
@@ -28,6 +28,9 @@ import android.view.animation.AnimationUtils;
/**
* Base class for a {@link FrameLayout} container that will perform animations
* when switching between its views.
+ *
+ * @attr ref android.R.styleable#ViewAnimator_inAnimation
+ * @attr ref android.R.styleable#ViewAnimator_outAnimation
*/
public class ViewAnimator extends FrameLayout {
@@ -144,6 +147,56 @@ public class ViewAnimator extends FrameLayout {
}
}
+ @Override
+ public void removeAllViews() {
+ super.removeAllViews();
+ mWhichChild = 0;
+ mFirstTime = true;
+ }
+
+ @Override
+ public void removeView(View view) {
+ final int index = indexOfChild(view);
+ if (index >= 0) {
+ removeViewAt(index);
+ }
+ }
+
+ @Override
+ public void removeViewAt(int index) {
+ super.removeViewAt(index);
+ final int childCount = getChildCount();
+ if (childCount == 0) {
+ mWhichChild = 0;
+ mFirstTime = true;
+ } else if (mWhichChild >= childCount) {
+ // Displayed is above child count, so float down to top of stack
+ setDisplayedChild(childCount - 1);
+ } else if (mWhichChild == index) {
+ // Displayed was removed, so show the new child living in its place
+ setDisplayedChild(mWhichChild);
+ }
+ }
+
+ public void removeViewInLayout(View view) {
+ removeView(view);
+ }
+
+ public void removeViews(int start, int count) {
+ super.removeViews(start, count);
+ if (getChildCount() == 0) {
+ mWhichChild = 0;
+ mFirstTime = true;
+ } else if (mWhichChild >= start && mWhichChild < start + count) {
+ // Try showing new displayed child, wrapping if needed
+ setDisplayedChild(mWhichChild);
+ }
+ }
+
+ public void removeViewsInLayout(int start, int count) {
+ removeViews(start, count);
+ }
+
/**
* Returns the View corresponding to the currently displayed child.
*
diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java
index a3c15d9..8a7946b 100644
--- a/core/java/android/widget/ViewFlipper.java
+++ b/core/java/android/widget/ViewFlipper.java
@@ -22,11 +22,14 @@ import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
+import android.widget.RemoteViews.RemoteView;
/**
* Simple {@link ViewAnimator} that will animate between two or more views
* that have been added to it. Only one child is shown at a time. If
* requested, can automatically flip between each child at a regular interval.
+ *
+ * @attr ref android.R.styleable#ViewFlipper_flipInterval
*/
public class ViewFlipper extends ViewAnimator {
private int mFlipInterval = 3000;
@@ -52,6 +55,7 @@ public class ViewFlipper extends ViewAnimator {
* @param milliseconds
* time in milliseconds
*/
+ @android.view.RemotableViewMethod
public void setFlipInterval(int milliseconds) {
mFlipInterval = milliseconds;
}
diff --git a/core/java/android/widget/ZoomButton.java b/core/java/android/widget/ZoomButton.java
index 5df8c8a..0df919d 100644
--- a/core/java/android/widget/ZoomButton.java
+++ b/core/java/android/widget/ZoomButton.java
@@ -20,6 +20,7 @@ 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;
@@ -54,9 +55,10 @@ 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(new SimpleOnGestureListener() {
+ mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() {
@Override
public void onLongPress(MotionEvent e) {
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
onLongClick(ZoomButton.this);
}
});
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
new file mode 100644
index 0000000..4daa419
--- /dev/null
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -0,0 +1,848 @@
+/*
+ * 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 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;
+import android.view.MotionEvent;
+import android.view.View;
+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;
+
+/*
+ * 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.
+ * - 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.
+ * <p>
+ * 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
+ * {@link #setZoomInEnabled(boolean)} and {@link #setZoomOutEnabled(boolean)}.
+ * <p>
+ * 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 {
+
+ private static final String TAG = "ZoomButtonsController";
+
+ private static final int ZOOM_CONTROLS_TIMEOUT =
+ (int) ViewConfiguration.getZoomControlsTimeout();
+
+ private static final int ZOOM_CONTROLS_TOUCH_PADDING = 20;
+ private int mTouchPaddingScaledSq;
+
+ private Context mContext;
+ private WindowManager mWindowManager;
+
+ /**
+ * The view that is being zoomed by this zoom controller.
+ */
+ private View mOwnerView;
+
+ /**
+ * The location of the owner view on the screen. This is recalculated
+ * each time the zoom controller is shown.
+ */
+ private int[] mOwnerViewRawLocation = new int[2];
+
+ /**
+ * The container that is added as a window.
+ */
+ private FrameLayout mContainer;
+ private LayoutParams mContainerLayoutParams;
+ private int[] mContainerRawLocation = new int[2];
+
+ private ZoomControls mControls;
+
+ /**
+ * The view (or null) that should receive touch events. This will get set if
+ * the touch down hits the container. It will be reset on the touch up.
+ */
+ private View mTouchTargetView;
+ /**
+ * 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.
+ */
+ 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
+ * it's laid out. Therefore, we must post this logic onto the UI thread so
+ * it will be exceuted AFTER the layout. This is the logic.
+ */
+ private Runnable mPostedVisibleInitializer;
+
+ private IntentFilter mConfigurationChangedFilter =
+ new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
+
+ /**
+ * Needed to reposition the zoom controls after configuration changes.
+ */
+ private BroadcastReceiver mConfigurationChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!mIsVisible) return;
+
+ mHandler.removeMessages(MSG_POST_CONFIGURATION_CHANGED);
+ mHandler.sendEmptyMessage(MSG_POST_CONFIGURATION_CHANGED);
+ }
+ };
+
+ /**
+ * 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. */
+ private static final int MSG_DISMISS_ZOOM_CONTROLS = 3;
+ /**
+ * If setVisible(true) is called and the owner view's window token is null,
+ * we delay the setVisible(true) call until it is not null.
+ */
+ private static final int MSG_POST_SET_VISIBLE = 4;
+
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_POST_CONFIGURATION_CHANGED:
+ onPostConfigurationChanged();
+ break;
+
+ case MSG_DISMISS_ZOOM_CONTROLS:
+ setVisible(false);
+ break;
+
+ case MSG_POST_SET_VISIBLE:
+ if (mOwnerView.getWindowToken() == null) {
+ // Doh, it is still null, just ignore the set visible call
+ Log.e(TAG,
+ "Cannot make the zoom controller visible if the owner view is " +
+ "not attached to a window.");
+ } else {
+ setVisible(true);
+ }
+ break;
+ }
+
+ }
+ };
+
+ /**
+ * 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.
+ */
+ public ZoomButtonsController(View ownerView) {
+ mContext = ownerView.getContext();
+ mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ mOwnerView = ownerView;
+
+ 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) {
+ mControls.setIsZoomInEnabled(enabled);
+ }
+
+ /**
+ * Whether to enable the zoom out control.
+ *
+ * @param enabled Whether to enable the zoom out control.
+ */
+ public void setZoomOutEnabled(boolean enabled) {
+ mControls.setIsZoomOutEnabled(enabled);
+ }
+
+ /**
+ * 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) {
+ mControls.setZoomSpeed(speed);
+ }
+
+ private FrameLayout createContainer() {
+ LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ // Controls are positioned BOTTOM | CENTER with respect to the owner view.
+ lp.gravity = Gravity.TOP | Gravity.LEFT;
+ lp.flags = LayoutParams.FLAG_NOT_TOUCHABLE |
+ LayoutParams.FLAG_NOT_FOCUSABLE |
+ LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+ lp.height = LayoutParams.WRAP_CONTENT;
+ lp.width = LayoutParams.FILL_PARENT;
+ lp.type = LayoutParams.TYPE_APPLICATION_PANEL;
+ lp.format = PixelFormat.TRANSPARENT;
+ lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons;
+ mContainerLayoutParams = lp;
+
+ FrameLayout container = new Container(mContext);
+ container.setLayoutParams(lp);
+ container.setMeasureAllChildren(true);
+
+ LayoutInflater inflater = (LayoutInflater) mContext
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(com.android.internal.R.layout.zoom_container, container);
+
+ mControls = (ZoomControls) container.findViewById(com.android.internal.R.id.zoomControls);
+ mControls.setOnZoomInClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
+ if (mCallback != null) mCallback.onZoom(true);
+ }
+ });
+ mControls.setOnZoomOutClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
+ if (mCallback != null) mCallback.onZoom(false);
+ }
+ });
+
+ return container;
+ }
+
+ /**
+ * 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) {
+ mCallback = listener;
+ }
+
+ /**
+ * 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) {
+ int oldFlags = mContainerLayoutParams.flags;
+ if (focusable) {
+ mContainerLayoutParams.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
+ } else {
+ mContainerLayoutParams.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
+ }
+
+ if ((mContainerLayoutParams.flags != oldFlags) && mIsVisible) {
+ mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams);
+ }
+ }
+
+ /**
+ * Whether the zoom controls are visible to the user.
+ *
+ * @return Whether the zoom controls are visible to the user.
+ */
+ public boolean isVisible() {
+ return mIsVisible;
+ }
+
+ /**
+ * 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) {
+
+ if (visible) {
+ if (mOwnerView.getWindowToken() == null) {
+ /*
+ * We need a window token to show ourselves, maybe the owner's
+ * window hasn't been created yet but it will have been by the
+ * time the looper is idle, so post the setVisible(true) call.
+ */
+ if (!mHandler.hasMessages(MSG_POST_SET_VISIBLE)) {
+ mHandler.sendEmptyMessage(MSG_POST_SET_VISIBLE);
+ }
+ return;
+ }
+
+ dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
+ }
+
+ if (mIsVisible == visible) {
+ return;
+ }
+ mIsVisible = visible;
+
+ if (visible) {
+ if (mContainerLayoutParams.token == null) {
+ mContainerLayoutParams.token = mOwnerView.getWindowToken();
+ }
+
+ mWindowManager.addView(mContainer, mContainerLayoutParams);
+
+ if (mPostedVisibleInitializer == null) {
+ mPostedVisibleInitializer = new Runnable() {
+ public void run() {
+ refreshPositioningVariables();
+
+ if (mCallback != null) {
+ mCallback.onVisibilityChanged(true);
+ }
+ }
+ };
+ }
+
+ mHandler.post(mPostedVisibleInitializer);
+
+ // Handle configuration changes when visible
+ mContext.registerReceiver(mConfigurationChangedReceiver, mConfigurationChangedFilter);
+
+ // Steal touches events from the owner
+ mOwnerView.setOnTouchListener(this);
+ mReleaseTouchListenerOnUp = false;
+
+ } else {
+ // Don't want to steal any more touches
+ if (mTouchTargetView != null) {
+ // We are still stealing the touch events for this touch
+ // sequence, so release the touch listener later
+ mReleaseTouchListenerOnUp = true;
+ } else {
+ mOwnerView.setOnTouchListener(null);
+ }
+
+ // No longer care about configuration changes
+ mContext.unregisterReceiver(mConfigurationChangedReceiver);
+
+ mWindowManager.removeView(mContainer);
+ mHandler.removeCallbacks(mPostedVisibleInitializer);
+
+ if (mCallback != null) {
+ mCallback.onVisibilityChanged(false);
+ }
+ }
+
+ }
+
+ /**
+ * Gets the container that is the parent of the zoom controls.
+ * <p>
+ * 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.
+ */
+ public ViewGroup getContainer() {
+ return mContainer;
+ }
+
+ private void dismissControlsDelayed(int delay) {
+ mHandler.removeMessages(MSG_DISMISS_ZOOM_CONTROLS);
+ mHandler.sendEmptyMessageDelayed(MSG_DISMISS_ZOOM_CONTROLS, delay);
+ }
+
+ /**
+ * 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;
+ }
+
+ return true;
+ }
+
+ private void refreshPositioningVariables() {
+ // Position the zoom controls on the bottom of the owner view.
+ int ownerHeight = mOwnerView.getHeight();
+ int ownerWidth = mOwnerView.getWidth();
+ // The gap between the top of the owner and the top of the container
+ int containerOwnerYOffset = ownerHeight - mContainer.getHeight();
+
+ // Calculate the owner view's bounds
+ mOwnerView.getLocationOnScreen(mOwnerViewRawLocation);
+ mContainerRawLocation[0] = mOwnerViewRawLocation[0];
+ mContainerRawLocation[1] = mOwnerViewRawLocation[1] + containerOwnerYOffset;
+
+ int[] ownerViewWindowLoc = mTempIntArray;
+ mOwnerView.getLocationInWindow(ownerViewWindowLoc);
+
+ // lp.x and lp.y should be relative to the owner's window top-left
+ mContainerLayoutParams.x = ownerViewWindowLoc[0];
+ mContainerLayoutParams.width = ownerWidth;
+ mContainerLayoutParams.y = ownerViewWindowLoc[1] + containerOwnerYOffset;
+ 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;
+ }
+ }
+
+ private boolean isInterestingKey(int keyCode) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_BACK:
+ return true;
+ default:
+ 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;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @hide The ZoomButtonsController implements the OnTouchListener, but this
+ * does not need to be shown in its public API.
+ */
+ 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) {
+ mOwnerView.setOnTouchListener(null);
+ setTouchTargetView(null);
+ mReleaseTouchListenerOnUp = false;
+ }
+
+ // Eat this event
+ return true;
+ }
+
+ dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
+
+ View targetView = mTouchTargetView;
+
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ targetView = findViewForTouch((int) event.getRawX(), (int) event.getRawY());
+ setTouchTargetView(targetView);
+ break;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ setTouchTargetView(null);
+ break;
+ }
+
+ if (targetView != null) {
+ // The upperleft corner of the target view in raw coordinates
+ int targetViewRawX = mContainerRawLocation[0] + mTouchTargetWindowLocation[0];
+ int targetViewRawY = mContainerRawLocation[1] + mTouchTargetWindowLocation[1];
+
+ MotionEvent containerEvent = MotionEvent.obtain(event);
+ // Convert the motion event into the target view's coordinates (from
+ // owner view's coordinates)
+ containerEvent.offsetLocation(mOwnerViewRawLocation[0] - targetViewRawX,
+ mOwnerViewRawLocation[1] - targetViewRawY);
+ /* Disallow negative coordinates (which can occur due to
+ * ZOOM_CONTROLS_TOUCH_PADDING) */
+ if (containerEvent.getX() < 0) {
+ containerEvent.offsetLocation(-containerEvent.getX(), 0);
+ }
+ if (containerEvent.getY() < 0) {
+ containerEvent.offsetLocation(0, -containerEvent.getY());
+ }
+ boolean retValue = targetView.dispatchTouchEvent(containerEvent);
+ containerEvent.recycle();
+ return retValue || consumeEvent;
+
+ } else {
+ return consumeEvent;
+ }
+ }
+
+ private void setTouchTargetView(View view) {
+ mTouchTargetView = view;
+ if (view != null) {
+ view.getLocationInWindow(mTouchTargetWindowLocation);
+ }
+ }
+
+ /**
+ * Returns the View that should receive a touch at the given coordinates.
+ *
+ * @param rawX The raw X.
+ * @param rawY The raw Y.
+ * @return The view that should receive the touches, or null if there is not one.
+ */
+ private View findViewForTouch(int rawX, int rawY) {
+ // Reverse order so the child drawn on top gets first dibs.
+ int containerCoordsX = rawX - mContainerRawLocation[0];
+ int containerCoordsY = rawY - mContainerRawLocation[1];
+ Rect frame = mTempRect;
+
+ 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) {
+ continue;
+ }
+
+ child.getHitRect(frame);
+ if (frame.contains(containerCoordsX, containerCoordsY)) {
+ return child;
+ }
+
+ int 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 distanceSq = distanceX * distanceX + distanceY * distanceY;
+
+ if ((distanceSq < mTouchPaddingScaledSq) &&
+ (distanceSq < closestChildDistanceSq)) {
+ closestChild = child;
+ closestChildDistanceSq = distanceSq;
+ }
+ }
+
+ return closestChild;
+ }
+
+ private void onPostConfigurationChanged() {
+ dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
+ 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.
+ * <p>
+ * 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);
+ }
+
+ /*
+ * Need to override this to intercept the key events. Otherwise, we
+ * would attach a key listener to the container but its superclass
+ * ViewGroup gives it to the focused View instead of calling the key
+ * listener, and so we wouldn't get the events.
+ */
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ return onContainerKey(event) ? true : super.dispatchKeyEvent(event);
+ }
+ }
+
+ /**
+ * 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 1fd662c..84d8f0e 100644
--- a/core/java/android/widget/ZoomControls.java
+++ b/core/java/android/widget/ZoomControls.java
@@ -29,8 +29,12 @@ 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.
- */
+ * provides callbacks to register for events. */
+// TODO: pending API council
+// * <p>
+// * 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/ExternalMediaFormatActivity.java b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
new file mode 100644
index 0000000..000f6c4
--- /dev/null
+++ b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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.internal.app;
+
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IMountService;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.Environment;
+import android.widget.Toast;
+import android.util.Log;
+
+/**
+ * This activity is shown to the user to confirm formatting of external media.
+ * It uses the alert dialog style. It will be launched from a notification, or from settings
+ */
+public class ExternalMediaFormatActivity extends AlertActivity implements DialogInterface.OnClickListener {
+
+ private static final int POSITIVE_BUTTON = AlertDialog.BUTTON1;
+
+ /** Used to detect when the media state changes, in case we need to call finish() */
+ private BroadcastReceiver mStorageReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.d("ExternalMediaFormatActivity", "got action " + action);
+
+ if (action == Intent.ACTION_MEDIA_REMOVED ||
+ action == Intent.ACTION_MEDIA_CHECKING ||
+ action == Intent.ACTION_MEDIA_MOUNTED ||
+ action == Intent.ACTION_MEDIA_SHARED) {
+ finish();
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Log.d("ExternalMediaFormatActivity", "onCreate!");
+ // Set up the "dialog"
+ final AlertController.AlertParams p = mAlertParams;
+ p.mIconId = com.android.internal.R.drawable.stat_sys_warning;
+ p.mTitle = getString(com.android.internal.R.string.extmedia_format_title);
+ p.mMessage = getString(com.android.internal.R.string.extmedia_format_message);
+ p.mPositiveButtonText = getString(com.android.internal.R.string.extmedia_format_button_format);
+ p.mPositiveButtonListener = this;
+ p.mNegativeButtonText = getString(com.android.internal.R.string.cancel);
+ p.mNegativeButtonListener = this;
+ setupAlert();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_MEDIA_REMOVED);
+ filter.addAction(Intent.ACTION_MEDIA_CHECKING);
+ filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
+ filter.addAction(Intent.ACTION_MEDIA_SHARED);
+ registerReceiver(mStorageReceiver, filter);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ unregisterReceiver(mStorageReceiver);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onClick(DialogInterface dialog, int which) {
+
+ if (which == POSITIVE_BUTTON) {
+ IMountService mountService = IMountService.Stub.asInterface(ServiceManager
+ .getService("mount"));
+ if (mountService != null) {
+ try {
+ mountService.formatMedia(Environment.getExternalStorageDirectory().toString());
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ // No matter what, finish the activity
+ finish();
+ }
+}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 434850c..edda1d9 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -19,11 +19,17 @@ package com.android.internal.app;
import com.android.internal.os.BatteryStatsImpl;
interface IBatteryStats {
- BatteryStatsImpl getStatistics();
+ byte[] getStatistics();
void noteStartWakelock(int uid, String name, int type);
void noteStopWakelock(int uid, String name, int type);
void noteStartSensor(int uid, int sensor);
void noteStopSensor(int uid, int sensor);
+ void noteStartGps(int uid);
+ void noteStopGps(int uid);
+ void noteScreenOn();
+ void noteScreenOff();
+ void notePhoneOn();
+ void notePhoneOff();
void setOnBattery(boolean onBattery);
long getAwakeTimeBattery();
long getAwakeTimePlugged();
diff --git a/tests/GadgetHost/src/com/android/gadgethost/TestGadgetProvider.java b/core/java/com/android/internal/app/IUsageStats.aidl
index 8f9641b..6b053d5 100644..100755
--- a/tests/GadgetHost/src/com/android/gadgethost/TestGadgetProvider.java
+++ b/core/java/com/android/internal/app/IUsageStats.aidl
@@ -14,19 +14,14 @@
* limitations under the License.
*/
-package com.android.gadgethost;
+package com.android.internal.app;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
+import android.content.ComponentName;
+import com.android.internal.os.PkgUsageStats;
-public class TestGadgetProvider extends BroadcastReceiver {
-
- static final String TAG = "TestGadgetProvider";
-
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "intent=" + intent);
- }
+interface IUsageStats {
+ void noteResumeComponent(in ComponentName componentName);
+ void notePauseComponent(in ComponentName componentName);
+ PkgUsageStats getPkgUsageStats(in ComponentName componentName);
+ PkgUsageStats[] getAllPkgUsageStats();
}
-
diff --git a/core/java/com/android/internal/app/UsbStorageStopActivity.java b/core/java/com/android/internal/app/UsbStorageStopActivity.java
new file mode 100644
index 0000000..557a523
--- /dev/null
+++ b/core/java/com/android/internal/app/UsbStorageStopActivity.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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.internal.app;
+
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IMountService;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.widget.Toast;
+
+/**
+ * This activity is shown to the user for him/her to disable USB mass storage.
+ * It uses the alert dialog style. It will be launched from a notification.
+ */
+public class UsbStorageStopActivity extends AlertActivity implements DialogInterface.OnClickListener {
+
+ private static final int POSITIVE_BUTTON = AlertDialog.BUTTON1;
+
+ /** Used to detect when the USB cable is unplugged, so we can call finish() */
+ private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction() == Intent.ACTION_BATTERY_CHANGED) {
+ handleBatteryChanged(intent);
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Set up the "dialog"
+ final AlertController.AlertParams p = mAlertParams;
+ p.mIconId = com.android.internal.R.drawable.ic_dialog_alert;
+ p.mTitle = getString(com.android.internal.R.string.usb_storage_stop_title);
+ p.mMessage = getString(com.android.internal.R.string.usb_storage_stop_message);
+ p.mPositiveButtonText = getString(com.android.internal.R.string.usb_storage_stop_button_mount);
+ p.mPositiveButtonListener = this;
+ p.mNegativeButtonText = getString(com.android.internal.R.string.usb_storage_stop_button_unmount);
+ p.mNegativeButtonListener = this;
+ setupAlert();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ unregisterReceiver(mBatteryReceiver);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onClick(DialogInterface dialog, int which) {
+
+ if (which == POSITIVE_BUTTON) {
+ stopUsbStorage();
+ }
+
+ // No matter what, finish the activity
+ finish();
+ }
+
+ private void stopUsbStorage() {
+ IMountService mountService = IMountService.Stub.asInterface(ServiceManager
+ .getService("mount"));
+ if (mountService == null) {
+ showStoppingError();
+ return;
+ }
+
+ try {
+ mountService.setMassStorageEnabled(false);
+ } catch (RemoteException e) {
+ showStoppingError();
+ return;
+ }
+ }
+
+ private void handleBatteryChanged(Intent intent) {
+ int pluggedType = intent.getIntExtra("plugged", 0);
+ if (pluggedType == 0) {
+ // It was disconnected from the plug, so finish
+ finish();
+ }
+ }
+
+ private void showStoppingError() {
+ Toast.makeText(this, com.android.internal.R.string.usb_storage_stop_error_message,
+ Toast.LENGTH_LONG).show();
+ }
+
+}
diff --git a/core/java/com/android/internal/gadget/IGadgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl
index 6f9af04..2ed4773 100644
--- a/core/java/com/android/internal/gadget/IGadgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetHost.aidl
@@ -14,16 +14,15 @@
* limitations under the License.
*/
-package com.android.internal.gadget;
+package com.android.internal.appwidget;
import android.content.ComponentName;
-import android.gadget.GadgetInfo;
+import android.appwidget.AppWidgetProviderInfo;
+import android.widget.RemoteViews;
/** {@hide} */
-interface IGadgetService {
- int allocateGadgetId(String hostPackage);
- void deleteGadgetId(int gadgetId);
- void bindGadgetId(int gadgetId, in ComponentName provider);
- GadgetInfo getGadgetInfo(int gadgetId);
- List<GadgetInfo> getInstalledProviders();
+oneway interface IAppWidgetHost {
+ void updateAppWidget(int appWidgetId, in RemoteViews views);
+ void providerChanged(int appWidgetId, in AppWidgetProviderInfo info);
}
+
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
new file mode 100644
index 0000000..496aa1a
--- /dev/null
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -0,0 +1,50 @@
+/*
+ * 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.internal.appwidget;
+
+import android.content.ComponentName;
+import android.appwidget.AppWidgetProviderInfo;
+import com.android.internal.appwidget.IAppWidgetHost;
+import android.widget.RemoteViews;
+
+/** {@hide} */
+interface IAppWidgetService {
+
+ //
+ // for AppWidgetHost
+ //
+ int[] startListening(IAppWidgetHost host, String packageName, int hostId,
+ out List<RemoteViews> updatedViews);
+ void stopListening(int hostId);
+ int allocateAppWidgetId(String packageName, int hostId);
+ void deleteAppWidgetId(int appWidgetId);
+ void deleteHost(int hostId);
+ void deleteAllHosts();
+ RemoteViews getAppWidgetViews(int appWidgetId);
+
+ //
+ // for AppWidgetManager
+ //
+ void updateAppWidgetIds(in int[] appWidgetIds, in RemoteViews views);
+ void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views);
+ List<AppWidgetProviderInfo> getInstalledProviders();
+ AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId);
+ void bindAppWidgetId(int appWidgetId, in ComponentName provider);
+ int[] getAppWidgetIds(in ComponentName provider);
+
+}
+
diff --git a/core/java/com/android/internal/gadget/package.html b/core/java/com/android/internal/appwidget/package.html
index db6f78b..db6f78b 100644
--- a/core/java/com/android/internal/gadget/package.html
+++ b/core/java/com/android/internal/appwidget/package.html
diff --git a/core/java/com/android/internal/logging/AndroidConfig.java b/core/java/com/android/internal/logging/AndroidConfig.java
index d8be889..f8002c6 100644
--- a/core/java/com/android/internal/logging/AndroidConfig.java
+++ b/core/java/com/android/internal/logging/AndroidConfig.java
@@ -34,11 +34,14 @@ public class AndroidConfig {
super();
try {
- Logger.global.addHandler(new AndroidHandler());
- Logger.global.setLevel(Level.ALL);
+ Logger rootLogger = Logger.getLogger("");
+ rootLogger.addHandler(new AndroidHandler());
+ rootLogger.setLevel(Level.INFO);
+
+ // Turn down logging in Apache libraries.
+ Logger.getLogger("org.apache").setLevel(Level.WARNING);
} catch (Exception ex) {
ex.printStackTrace();
}
- }
-
+ }
}
diff --git a/core/java/com/android/internal/logging/AndroidHandler.java b/core/java/com/android/internal/logging/AndroidHandler.java
index a6a4c64..d9fcf60 100644
--- a/core/java/com/android/internal/logging/AndroidHandler.java
+++ b/core/java/com/android/internal/logging/AndroidHandler.java
@@ -18,14 +18,14 @@ package com.android.internal.logging;
import android.util.Log;
-import java.util.logging.Formatter;
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.SimpleFormatter;
+import java.util.logging.*;
+import java.util.Date;
+import java.text.MessageFormat;
+import java.io.PrintWriter;
+import java.io.StringWriter;
/**
- * Implements a {@link java.util.Logger} handler that writes to the Android log. The
+ * Implements a {@link java.util.logging.Logger} handler that writes to the Android log. The
* implementation is rather straightforward. The name of the logger serves as
* the log tag. Only the log levels need to be converted appropriately. For
* this purpose, the following mapping is being used:
@@ -81,8 +81,24 @@ public class AndroidHandler extends Handler {
/**
* Holds the formatter for all Android log handlers.
*/
- private static final Formatter THE_FORMATTER = new SimpleFormatter();
-
+ private static final Formatter THE_FORMATTER = new Formatter() {
+ @Override
+ public String format(LogRecord r) {
+ Throwable thrown = r.getThrown();
+ if (thrown != null) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ sw.write(r.getMessage());
+ sw.write("\n");
+ thrown.printStackTrace(pw);
+ pw.flush();
+ return sw.toString();
+ } else {
+ return r.getMessage();
+ }
+ }
+ };
+
/**
* Constructs a new instance of the Android log handler.
*/
@@ -106,27 +122,40 @@ public class AndroidHandler extends Handler {
int level = getAndroidLevel(record.getLevel());
String tag = record.getLoggerName();
+ if (tag == null) {
+ // Anonymous logger.
+ tag = "null";
+ } else {
+ // Tags must be <= 23 characters.
+ int length = tag.length();
+ if (length > 23) {
+ // Most loggers use the full class name. Try dropping the
+ // package.
+ int lastPeriod = tag.lastIndexOf(".");
+ if (length - lastPeriod - 1 <= 23) {
+ tag = tag.substring(lastPeriod + 1);
+ } else {
+ // Use last 23 chars.
+ tag = tag.substring(tag.length() - 23);
+ }
+ }
+ }
+
if (!Log.isLoggable(tag, level)) {
return;
}
-
- String msg;
- try {
- msg = getFormatter().format(record);
- } catch (RuntimeException e) {
- Log.e("AndroidHandler", "Error formatting log record", e);
- msg = record.getMessage();
- }
- Log.println(level, tag, msg);
+
+ String message = getFormatter().format(record);
+ Log.println(level, tag, message);
} catch (RuntimeException e) {
- Log.e("AndroidHandler", "Error publishing log record", e);
+ Log.e("AndroidHandler", "Error logging message.", e);
}
}
/**
- * Converts a {@link java.util.Logger} logging level into an Android one.
+ * Converts a {@link java.util.logging.Logger} logging level into an Android one.
*
- * @param level The {@link java.util.Logger} logging level.
+ * @param level The {@link java.util.logging.Logger} logging level.
*
* @return The resulting Android logging level.
*/
diff --git a/core/java/com/android/internal/net/DbSSLSessionCache.java b/core/java/com/android/internal/net/DbSSLSessionCache.java
new file mode 100644
index 0000000..842d40b
--- /dev/null
+++ b/core/java/com/android/internal/net/DbSSLSessionCache.java
@@ -0,0 +1,289 @@
+// Copyright 2009 The Android Open Source Project
+
+package com.android.internal.net;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.net.ssl.SSLSession;
+
+/**
+ * Hook into harmony SSL cache to persist the SSL sessions.
+ *
+ * Current implementation is suitable for saving a small number of hosts -
+ * like google services. It can be extended with expiration and more features
+ * to support more hosts.
+ *
+ * {@hide}
+ */
+public class DbSSLSessionCache implements SSLClientSessionCache {
+ private static final String TAG = "DbSSLSessionCache";
+
+ /**
+ * Table where sessions are stored.
+ */
+ public static final String SSL_CACHE_TABLE = "ssl_sessions";
+
+ private static final String SSL_CACHE_ID = "_id";
+
+ /**
+ * Key is host:port - port is not optional.
+ */
+ private static final String SSL_CACHE_HOSTPORT = "hostport";
+
+ /**
+ * Base64-encoded DER value of the session.
+ */
+ private static final String SSL_CACHE_SESSION = "session";
+
+ /**
+ * Time when the record was added - should be close to the time
+ * of the initial session negotiation.
+ */
+ private static final String SSL_CACHE_TIME_SEC = "time_sec";
+
+ public static final String DATABASE_NAME = "ssl_sessions.db";
+
+ public static final int DATABASE_VERSION = 2;
+
+ /** public for testing
+ */
+ public static final int SSL_CACHE_ID_COL = 0;
+ public static final int SSL_CACHE_HOSTPORT_COL = 1;
+ public static final int SSL_CACHE_SESSION_COL = 2;
+ public static final int SSL_CACHE_TIME_SEC_COL = 3;
+
+ public static final int MAX_CACHE_SIZE = 256;
+
+ private final Map<String, byte[]> mExternalCache =
+ new HashMap<String, byte[]>();
+
+
+ private DatabaseHelper mDatabaseHelper;
+
+ private boolean mNeedsCacheLoad = true;
+
+ public static final String[] PROJECTION = new String[] {
+ SSL_CACHE_ID,
+ SSL_CACHE_HOSTPORT,
+ SSL_CACHE_SESSION,
+ SSL_CACHE_TIME_SEC
+ };
+
+ private static final Map<String,DbSSLSessionCache> sInstances =
+ new HashMap<String,DbSSLSessionCache>();
+
+ /**
+ * Returns a singleton instance of the DbSSLSessionCache that should be used for this
+ * context's package.
+ *
+ * @param context The context that should be used for getting/creating the singleton instance.
+ * @return The singleton instance for the context's package.
+ */
+ public static synchronized DbSSLSessionCache getInstanceForPackage(Context context) {
+ String packageName = context.getPackageName();
+ if (sInstances.containsKey(packageName)) {
+ return sInstances.get(packageName);
+ }
+ DbSSLSessionCache cache = new DbSSLSessionCache(context);
+ sInstances.put(packageName, cache);
+ return cache;
+ }
+
+ /**
+ * Create a SslSessionCache instance, using the specified context to
+ * initialize the database.
+ *
+ * This constructor will use the default database - created for the application
+ * context.
+ *
+ * @param activityContext
+ */
+ private DbSSLSessionCache(Context activityContext) {
+ Context appContext = activityContext.getApplicationContext();
+ mDatabaseHelper = new DatabaseHelper(appContext);
+ }
+
+ /**
+ * Create a SslSessionCache that uses a specific database.
+ *
+ *
+ * @param database
+ */
+ public DbSSLSessionCache(DatabaseHelper database) {
+ this.mDatabaseHelper = database;
+ }
+
+ public void putSessionData(SSLSession session, byte[] der) {
+ if (mDatabaseHelper == null) {
+ return;
+ }
+ synchronized (this.getClass()) {
+ SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+ if (mExternalCache.size() == MAX_CACHE_SIZE) {
+ // remove oldest.
+ // TODO: check if the new one is in cached already ( i.e. update ).
+ Cursor byTime = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE,
+ PROJECTION, null, null, null, null, SSL_CACHE_TIME_SEC);
+ if (byTime.moveToFirst()) {
+ // TODO: can I do byTime.deleteRow() ?
+ String hostPort = byTime.getString(SSL_CACHE_HOSTPORT_COL);
+ db.delete(SSL_CACHE_TABLE,
+ SSL_CACHE_HOSTPORT + "= ?" , new String[] { hostPort });
+ mExternalCache.remove(hostPort);
+ } else {
+ Log.w(TAG, "No rows found");
+ // something is wrong, clear it
+ clear();
+ }
+ }
+ // Serialize native session to standard DER encoding
+ long t0 = System.currentTimeMillis();
+
+ String b64 = new String(Base64.encodeBase64(der));
+ String key = session.getPeerHost() + ":" + session.getPeerPort();
+
+ ContentValues values = new ContentValues();
+ values.put(SSL_CACHE_HOSTPORT, key);
+ values.put(SSL_CACHE_SESSION, b64);
+ values.put(SSL_CACHE_TIME_SEC, System.currentTimeMillis() / 1000);
+
+ mExternalCache.put(key, der);
+
+ try {
+ db.insert(SSL_CACHE_TABLE, null /*nullColumnHack */ , values);
+ } catch(SQLException ex) {
+ // Ignore - nothing we can do to recover, and caller shouldn't
+ // be affected.
+ Log.w(TAG, "Ignoring SQL exception when caching session", ex);
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ long t1 = System.currentTimeMillis();
+ Log.d(TAG, "New SSL session " + session.getPeerHost() +
+ " DER len: " + der.length + " " + (t1 - t0));
+ }
+ }
+
+ }
+
+ public byte[] getSessionData(String host, int port) {
+ // Current (simple) implementation does a single lookup to DB, then saves
+ // all entries to the cache.
+
+ // This works for google services - i.e. small number of certs.
+ // If we extend this to all processes - we should hold a separate cache
+ // or do lookups to DB each time.
+ if (mDatabaseHelper == null) {
+ return null;
+ }
+ synchronized(this.getClass()) {
+ if (mNeedsCacheLoad) {
+ // Don't try to load again, if something is wrong on the first
+ // request it'll likely be wrong each time.
+ mNeedsCacheLoad = false;
+ long t0 = System.currentTimeMillis();
+
+ Cursor cur = null;
+ try {
+ cur = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE,
+ PROJECTION, null, null, null, null, null);
+ if (cur.moveToFirst()) {
+ do {
+ String hostPort = cur.getString(SSL_CACHE_HOSTPORT_COL);
+ String value = cur.getString(SSL_CACHE_SESSION_COL);
+
+ if (hostPort == null || value == null) {
+ continue;
+ }
+ // TODO: blob support ?
+ byte[] der = Base64.decodeBase64(value.getBytes());
+ mExternalCache.put(hostPort, der);
+ } while (cur.moveToNext());
+
+ }
+ } catch (SQLException ex) {
+ Log.d(TAG, "Error loading SSL cached entries ", ex);
+ } finally {
+ if (cur != null) {
+ cur.close();
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ long t1 = System.currentTimeMillis();
+ Log.d(TAG, "LOADED CACHED SSL " + (t1 - t0) + " ms");
+ }
+ }
+ }
+
+ String key = host + ":" + port;
+
+ return mExternalCache.get(key);
+ }
+ }
+
+ /**
+ * Reset the database and internal state.
+ * Used for testing or to free space.
+ */
+ public void clear() {
+ synchronized(this) {
+ try {
+ mExternalCache.clear();
+ mNeedsCacheLoad = true;
+ mDatabaseHelper.getWritableDatabase().delete(SSL_CACHE_TABLE,
+ null, null);
+ } catch (SQLException ex) {
+ Log.d(TAG, "Error removing SSL cached entries ", ex);
+ // ignore - nothing we can do about it
+ }
+ }
+ }
+
+ public byte[] getSessionData(byte[] id) {
+ // We support client side only - the cache will do nothing for
+ // server-side sessions.
+ return null;
+ }
+
+ /** Visible for testing.
+ */
+ public static class DatabaseHelper extends SQLiteOpenHelper {
+
+ public DatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null /* factory */, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + SSL_CACHE_TABLE + " (" +
+ SSL_CACHE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+ SSL_CACHE_HOSTPORT + " TEXT UNIQUE ON CONFLICT REPLACE," +
+ SSL_CACHE_SESSION + " TEXT," +
+ SSL_CACHE_TIME_SEC + " INTEGER" +
+ ");");
+
+ // No index - we load on startup, index would slow down inserts.
+ // If we want to scale this to lots of rows - we could use
+ // index, but then we'll hit DB a bit too often ( including
+ // negative hits )
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL("DROP TABLE IF EXISTS " + SSL_CACHE_TABLE );
+ onCreate(db);
+ }
+
+ }
+
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8912960..7eea8b7 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -17,18 +17,19 @@
package com.android.internal.os;
import android.os.BatteryStats;
+import android.os.NetStat;
import android.os.Parcel;
import android.os.ParcelFormatException;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.Log;
+import android.util.Printer;
import android.util.SparseArray;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -38,13 +39,15 @@ import java.util.Map;
* battery life. All times are represented in microseconds except where indicated
* otherwise.
*/
-public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
+public final class BatteryStatsImpl extends BatteryStats {
+ private static final String TAG = "BatteryStatsImpl";
+ private static final boolean DEBUG = false;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 13;
+ private static final int VERSION = 25;
private final File mFile;
private final File mBackupFile;
@@ -62,8 +65,13 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
final ArrayList<Timer> mPartialTimers = new ArrayList<Timer>();
final ArrayList<Timer> mFullTimers = new ArrayList<Timer>();
final ArrayList<Timer> mWindowTimers = new ArrayList<Timer>();
- final ArrayList<Timer> mSensorTimers = new ArrayList<Timer>();
+ final SparseArray<ArrayList<Timer>> mSensorTimers
+ = new SparseArray<ArrayList<Timer>>();
+ // These are the objects that will want to do something when the device
+ // is unplugged from power.
+ final ArrayList<Unpluggable> mUnpluggables = new ArrayList<Unpluggable>();
+
int mStartCount;
long mBatteryUptime;
@@ -77,17 +85,27 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
long mRealtime;
long mRealtimeStart;
long mLastRealtime;
-
+
+ boolean mScreenOn;
+ Timer mScreenOnTimer;
+
+ boolean mPhoneOn;
+ Timer mPhoneOnTimer;
+
/**
* These provide time bases that discount the time the device is plugged
* in to power.
*/
boolean mOnBattery;
+ boolean mOnBatteryInternal;
long mTrackBatteryPastUptime;
long mTrackBatteryUptimeStart;
long mTrackBatteryPastRealtime;
long mTrackBatteryRealtimeStart;
-
+
+ long mUnpluggedBatteryUptime;
+ long mUnpluggedBatteryRealtime;
+
long mLastWriteTime = 0; // Milliseconds
// For debugging
@@ -95,101 +113,162 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mFile = mBackupFile = null;
}
+ public static interface Unpluggable {
+ void unplug(long batteryUptime, long batteryRealtime);
+ void plug(long batteryUptime, long batteryRealtime);
+ }
+
/**
* State for keeping track of timing information.
*/
- public static final class Timer extends BatteryStats.Timer {
- ArrayList<Timer> mTimerPool;
+ public static final class Timer extends BatteryStats.Timer implements Unpluggable {
+ final int mType;
+ final ArrayList<Timer> mTimerPool;
- int mType;
int mNesting;
int mCount;
int mLoadedCount;
int mLastCount;
+ int mUnpluggedCount;
- // Times are in microseconds for better accuracy when dividing by the lock count
+ // Times are in microseconds for better accuracy when dividing by the
+ // lock count, and are in "battery realtime" units.
- long mTotalTime; // Add mUnpluggedTotalTime to get true value
- long mLoadedTotalTime;
- long mLastTotalTime;
- long mStartTime;
- long mUpdateTime;
+ /**
+ * The total time we have accumulated since the start of the original
+ * boot, to the last time something interesting happened in the
+ * current run.
+ */
+ long mTotalTime;
+
+ /**
+ * The total time we loaded for the previous runs. Subtract this from
+ * mTotalTime to find the time for the current run of the system.
+ */
+ long mLoadedTime;
+
+ /**
+ * The run time of the last run of the system, as loaded from the
+ * saved data.
+ */
+ long mLastTime;
/**
- * The value of mTotalTime when unplug() was last called, initially 0.
+ * The value of mTotalTime when unplug() was last called. Subtract
+ * this from mTotalTime to find the time since the last unplug from
+ * power.
*/
- long mTotalTimeAtLastUnplug;
+ long mUnpluggedTime;
- /** Constructor used for unmarshalling only. */
- Timer() {}
+ /**
+ * The last time at which we updated the timer. If mNesting is > 0,
+ * subtract this from the current battery time to find the amount of
+ * time we have been running since we last computed an update.
+ */
+ long mUpdateTime;
+
+ /**
+ * The total time at which the timer was acquired, to determine if
+ * was actually held for an interesting duration.
+ */
+ long mAcquireTime;
+
+ Timer(int type, ArrayList<Timer> timerPool,
+ ArrayList<Unpluggable> unpluggables, Parcel in) {
+ mType = type;
+ mTimerPool = timerPool;
+ mCount = in.readInt();
+ mLoadedCount = in.readInt();
+ mLastCount = in.readInt();
+ mUnpluggedCount = in.readInt();
+ mTotalTime = in.readLong();
+ mLoadedTime = in.readLong();
+ mLastTime = in.readLong();
+ mUpdateTime = in.readLong();
+ mUnpluggedTime = in.readLong();
+ unpluggables.add(this);
+ }
- Timer(int type, ArrayList<Timer> timerPool) {
+ Timer(int type, ArrayList<Timer> timerPool,
+ ArrayList<Unpluggable> unpluggables) {
mType = type;
mTimerPool = timerPool;
+ unpluggables.add(this);
}
- public void writeToParcel(Parcel out) {
- out.writeInt(mType);
- out.writeInt(mNesting);
+ public void writeToParcel(Parcel out, long batteryRealtime) {
out.writeInt(mCount);
out.writeInt(mLoadedCount);
out.writeInt(mLastCount);
- out.writeLong(mTotalTime);
- out.writeLong(mLoadedTotalTime);
- out.writeLong(mLastTotalTime);
- out.writeLong(mStartTime);
+ out.writeInt(mUnpluggedCount);
+ out.writeLong(computeRunTimeLocked(batteryRealtime));
+ out.writeLong(mLoadedTime);
+ out.writeLong(mLastTime);
out.writeLong(mUpdateTime);
- out.writeLong(mTotalTimeAtLastUnplug);
+ out.writeLong(mUnpluggedTime);
}
- public void readFromParcel(Parcel in) {
- mType = in.readInt();
- mNesting = in.readInt();
- mCount = in.readInt();
- mLoadedCount = in.readInt();
- mLastCount = in.readInt();
- mTotalTime = in.readLong();
- mLoadedTotalTime = in.readLong();
- mLastTotalTime = in.readLong();
- mStartTime = in.readLong();
- mUpdateTime = in.readLong();
- mTotalTimeAtLastUnplug = in.readLong();
- }
-
- private void unplug() {
- mTotalTimeAtLastUnplug += mTotalTime;
- mTotalTime = 0;
+ public void unplug(long batteryUptime, long batteryRealtime) {
+ if (DEBUG && mType < 0) {
+ Log.v(TAG, "unplug #" + mType + ": realtime=" + batteryRealtime
+ + " old mUnpluggedTime=" + mUnpluggedTime
+ + " old mUnpluggedCount=" + mUnpluggedCount);
+ }
+ mUnpluggedTime = computeRunTimeLocked(batteryRealtime);
+ mUnpluggedCount = mCount;
+ if (DEBUG && mType < 0) {
+ Log.v(TAG, "unplug #" + mType
+ + ": new mUnpluggedTime=" + mUnpluggedTime
+ + " new mUnpluggedCount=" + mUnpluggedCount);
+ }
}
+ public void plug(long batteryUptime, long batteryRealtime) {
+ if (mNesting > 0) {
+ if (DEBUG && mType < 0) {
+ Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime
+ + " old mTotalTime=" + mTotalTime
+ + " old mUpdateTime=" + mUpdateTime);
+ }
+ mTotalTime = computeRunTimeLocked(batteryRealtime);
+ mUpdateTime = batteryRealtime;
+ if (DEBUG && mType < 0) {
+ Log.v(TAG, "plug #" + mType
+ + ": new mTotalTime=" + mTotalTime
+ + " old mUpdateTime=" + mUpdateTime);
+ }
+ }
+ }
+
/**
* Writes a possibly null Timer to a Parcel.
*
* @param out the Parcel to be written to.
* @param timer a Timer, or null.
*/
- public static void writeTimerToParcel(Parcel out, Timer timer) {
+ public static void writeTimerToParcel(Parcel out, Timer timer,
+ long batteryRealtime) {
if (timer == null) {
out.writeInt(0); // indicates null
return;
}
out.writeInt(1); // indicates non-null
- timer.writeToParcel(out);
+ timer.writeToParcel(out, batteryRealtime);
}
@Override
- public long getTotalTime(long now, int which) {
+ public long getTotalTime(long batteryRealtime, int which) {
long val;
if (which == STATS_LAST) {
- val = mLastTotalTime;
+ val = mLastTime;
} else {
- val = computeRunTimeLocked(now);
- if (which != STATS_UNPLUGGED) {
- val += mTotalTimeAtLastUnplug;
- }
- if ((which == STATS_CURRENT) || (which == STATS_UNPLUGGED)) {
- val -= mLoadedTotalTime;
+ val = computeRunTimeLocked(batteryRealtime);
+ if (which == STATS_UNPLUGGED) {
+ val -= mUnpluggedTime;
+ } else if (which != STATS_TOTAL) {
+ val -= mLoadedTime;
}
}
@@ -203,7 +282,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
val = mLastCount;
} else {
val = mCount;
- if ((which == STATS_CURRENT) || (which == STATS_UNPLUGGED)) {
+ if (which == STATS_UNPLUGGED) {
+ val -= mUnpluggedCount;
+ } else if (which != STATS_TOTAL) {
val -= mLoadedCount;
}
}
@@ -211,16 +292,37 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
return val;
}
+ public void logState() {
+ Log.i("foo", "mNesting=" + mNesting + " mCount=" + mCount
+ + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
+ + " mUnpluggedCount=" + mUnpluggedCount);
+ Log.i("foo", "mTotalTime=" + mTotalTime
+ + " mLoadedTime=" + mLoadedTime);
+ Log.i("foo", "mLastTime=" + mLastTime
+ + " mUnpluggedTime=" + mUnpluggedTime);
+ Log.i("foo", "mUpdateTime=" + mUpdateTime
+ + " mAcquireTime=" + mAcquireTime);
+ }
+
void startRunningLocked(BatteryStatsImpl stats) {
if (mNesting++ == 0) {
- mStartTime = mUpdateTime =
- stats.getBatteryUptimeLocked(SystemClock.elapsedRealtime() * 1000);
- // Accumulate time to all other active counters with the current value of mCount
- refreshTimersLocked(stats);
- // Add this timer to the active pool
- mTimerPool.add(this);
+ mUpdateTime = stats.getBatteryRealtimeLocked(
+ SystemClock.elapsedRealtime() * 1000);
+ if (mTimerPool != null) {
+ // Accumulate time to all currently active timers before adding
+ // this new one to the pool.
+ refreshTimersLocked(stats, mTimerPool);
+ // Add this timer to the active pool
+ mTimerPool.add(this);
+ }
// Increment the count
mCount++;
+ mAcquireTime = mTotalTime;
+ if (DEBUG && mType < 0) {
+ Log.v(TAG, "start #" + mType + ": mUpdateTime=" + mUpdateTime
+ + " mTotalTime=" + mTotalTime + " mCount=" + mCount
+ + " mAcquireTime=" + mAcquireTime);
+ }
}
}
@@ -230,83 +332,158 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
return;
}
if (--mNesting == 0) {
- // Accumulate time to all active counters with the current value of mCount
- refreshTimersLocked(stats);
- // Remove this timer from the active pool
- mTimerPool.remove(this);
- // Decrement the count
- mCount--;
+ if (mTimerPool != null) {
+ // Accumulate time to all active counters, scaled by the total
+ // active in the pool, before taking this one out of the pool.
+ refreshTimersLocked(stats, mTimerPool);
+ // Remove this timer from the active pool
+ mTimerPool.remove(this);
+ } else {
+ final long realtime = SystemClock.elapsedRealtime() * 1000;
+ final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
+ mNesting = 1;
+ mTotalTime = computeRunTimeLocked(batteryRealtime);
+ mNesting = 0;
+ }
+
+ if (DEBUG && mType < 0) {
+ Log.v(TAG, "stop #" + mType + ": mUpdateTime=" + mUpdateTime
+ + " mTotalTime=" + mTotalTime + " mCount=" + mCount
+ + " mAcquireTime=" + mAcquireTime);
+ }
+
+ if (mTotalTime == mAcquireTime) {
+ // If there was no change in the time, then discard this
+ // count. A somewhat cheezy strategy, but hey.
+ mCount--;
+ }
}
}
// Update the total time for all other running Timers with the same type as this Timer
// due to a change in timer count
- private void refreshTimersLocked(BatteryStatsImpl stats) {
- for (Timer t : mTimerPool) {
- t.updateTimeLocked(stats);
- }
- }
-
- /**
- * Update totalTime and reset updateTime
- * @param stats
- */
- private void updateTimeLocked(BatteryStatsImpl stats) {
- long realtime = SystemClock.elapsedRealtime() * 1000;
- long heldTime = stats.getBatteryUptimeLocked(realtime) - mUpdateTime;
- if (heldTime > 0) {
- mTotalTime += (heldTime * 1000) / mCount;
+ private static void refreshTimersLocked(final BatteryStatsImpl stats,
+ final ArrayList<Timer> pool) {
+ final long realtime = SystemClock.elapsedRealtime() * 1000;
+ final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
+ final int N = pool.size();
+ for (int i=N-1; i>= 0; i--) {
+ final Timer t = pool.get(i);
+ long heldTime = batteryRealtime - t.mUpdateTime;
+ if (heldTime > 0) {
+ t.mTotalTime += heldTime / N;
+ }
+ t.mUpdateTime = batteryRealtime;
}
- mUpdateTime = stats.getBatteryUptimeLocked(realtime);
}
- private long computeRunTimeLocked(long curBatteryUptime) {
- return mTotalTime +
- (mNesting > 0 ? ((curBatteryUptime * 1000) - mUpdateTime) / mCount : 0);
+ private long computeRunTimeLocked(long curBatteryRealtime) {
+ return mTotalTime + (mNesting > 0
+ ? (curBatteryRealtime - mUpdateTime)
+ / (mTimerPool != null ? mTimerPool.size() : 1)
+ : 0);
}
- void writeSummaryFromParcelLocked(Parcel out, long curBatteryUptime) {
- long runTime = computeRunTimeLocked(curBatteryUptime);
+ void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
+ long runTime = computeRunTimeLocked(batteryRealtime);
// Divide by 1000 for backwards compatibility
out.writeLong((runTime + 500) / 1000);
- out.writeLong(((runTime - mLoadedTotalTime) + 500) / 1000);
+ out.writeLong(((runTime - mLoadedTime) + 500) / 1000);
out.writeInt(mCount);
out.writeInt(mCount - mLoadedCount);
}
void readSummaryFromParcelLocked(Parcel in) {
// Multiply by 1000 for backwards compatibility
- mTotalTime = mLoadedTotalTime = in.readLong() * 1000;
- mLastTotalTime = in.readLong();
+ mTotalTime = mLoadedTime = in.readLong() * 1000;
+ mLastTime = in.readLong() * 1000;
+ mUnpluggedTime = mTotalTime;
mCount = mLoadedCount = in.readInt();
mLastCount = in.readInt();
+ mUnpluggedCount = mCount;
mNesting = 0;
}
}
- public void unplugTimers() {
- ArrayList<Timer> timers;
-
- timers = mPartialTimers;
- for (int i = timers.size() - 1; i >= 0; i--) {
- timers.get(i).unplug();
+ public void doUnplug(long batteryUptime, long batteryRealtime) {
+ for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
+ Uid u = mUidStats.valueAt(iu);
+ u.mStartedTcpBytesReceived = NetStat.getUidRxBytes(u.mUid);
+ u.mStartedTcpBytesSent = NetStat.getUidTxBytes(u.mUid);
+ u.mTcpBytesReceivedAtLastUnplug = u.mCurrentTcpBytesReceived;
+ u.mTcpBytesSentAtLastUnplug = u.mCurrentTcpBytesSent;
}
- timers = mFullTimers;
- for (int i = timers.size() - 1; i >= 0; i--) {
- timers.get(i).unplug();
+ for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
+ mUnpluggables.get(i).unplug(batteryUptime, batteryRealtime);
}
- timers = mWindowTimers;
- for (int i = timers.size() - 1; i >= 0; i--) {
- timers.get(i).unplug();
+ }
+
+ public void doPlug(long batteryUptime, long batteryRealtime) {
+ for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
+ Uid u = mUidStats.valueAt(iu);
+ if (u.mStartedTcpBytesReceived >= 0) {
+ u.mCurrentTcpBytesReceived = u.computeCurrentTcpBytesReceived();
+ u.mStartedTcpBytesReceived = -1;
+ }
+ if (u.mStartedTcpBytesSent >= 0) {
+ u.mCurrentTcpBytesSent = u.computeCurrentTcpBytesSent();
+ u.mStartedTcpBytesSent = -1;
+ }
}
- timers = mSensorTimers;
- for (int i = timers.size() - 1; i >= 0; i--) {
- timers.get(i).unplug();
+ for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
+ mUnpluggables.get(i).plug(batteryUptime, batteryRealtime);
}
}
- @Override
- public SparseArray<? extends BatteryStats.Uid> getUidStats() {
+ public void noteStartGps(int uid) {
+ mUidStats.get(uid).noteStartGps();
+ }
+
+ public void noteStopGps(int uid) {
+ mUidStats.get(uid).noteStopGps();
+ }
+
+ public void noteScreenOnLocked() {
+ if (!mScreenOn) {
+ mScreenOn = true;
+ mScreenOnTimer.startRunningLocked(this);
+ }
+ }
+
+ public void noteScreenOffLocked() {
+ if (mScreenOn) {
+ mScreenOn = false;
+ mScreenOnTimer.stopRunningLocked(this);
+ }
+ }
+
+ public void notePhoneOnLocked() {
+ if (!mPhoneOn) {
+ mPhoneOn = true;
+ mPhoneOnTimer.startRunningLocked(this);
+ }
+ }
+
+ public void notePhoneOffLocked() {
+ if (mPhoneOn) {
+ mPhoneOn = false;
+ mPhoneOnTimer.stopRunningLocked(this);
+ }
+ }
+
+ @Override public long getScreenOnTime(long batteryRealtime, int which) {
+ return mScreenOnTimer.getTotalTime(batteryRealtime, which);
+ }
+
+ @Override public long getPhoneOnTime(long batteryRealtime, int which) {
+ return mPhoneOnTimer.getTotalTime(batteryRealtime, which);
+ }
+
+ @Override public boolean getIsOnBattery() {
+ return mOnBattery;
+ }
+
+ @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
return mUidStats;
}
@@ -314,7 +491,20 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
* The statistics associated with a particular uid.
*/
public final class Uid extends BatteryStats.Uid {
-
+
+ final int mUid;
+ long mLoadedTcpBytesReceived;
+ long mLoadedTcpBytesSent;
+ long mCurrentTcpBytesReceived;
+ long mCurrentTcpBytesSent;
+ long mTcpBytesReceivedAtLastUnplug;
+ long mTcpBytesSentAtLastUnplug;
+
+ // These are not saved/restored when parcelling, since we want
+ // to return from the parcel with a snapshot of the state.
+ long mStartedTcpBytesReceived = -1;
+ long mStartedTcpBytesSent = -1;
+
/**
* The statistics we have collected for this uid's wake locks.
*/
@@ -334,6 +524,10 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
* The statistics we have collected for this uid's processes.
*/
final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
+
+ public Uid(int uid) {
+ mUid = uid;
+ }
@Override
public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
@@ -354,20 +548,62 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
return mPackageStats;
}
-
- void writeToParcelLocked(Parcel out) {
+
+ public int getUid() {
+ return mUid;
+ }
+
+ public long getTcpBytesReceived(int which) {
+ if (which == STATS_LAST) {
+ return mLoadedTcpBytesReceived;
+ } else {
+ long current = computeCurrentTcpBytesReceived();
+ if (which == STATS_UNPLUGGED) {
+ current -= mTcpBytesReceivedAtLastUnplug;
+ } else if (which == STATS_TOTAL) {
+ current += mLoadedTcpBytesReceived;
+ }
+ return current;
+ }
+ }
+
+ public long computeCurrentTcpBytesReceived() {
+ return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
+ ? (NetStat.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0);
+ }
+
+ public long getTcpBytesSent(int which) {
+ if (which == STATS_LAST) {
+ return mLoadedTcpBytesSent;
+ } else {
+ long current = computeCurrentTcpBytesSent();
+ if (which == STATS_UNPLUGGED) {
+ current -= mTcpBytesSentAtLastUnplug;
+ } else if (which == STATS_TOTAL) {
+ current += mLoadedTcpBytesSent;
+ }
+ return current;
+ }
+ }
+
+ public long computeCurrentTcpBytesSent() {
+ return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
+ ? (NetStat.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
+ }
+
+ void writeToParcelLocked(Parcel out, long batteryRealtime) {
out.writeInt(mWakelockStats.size());
for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
out.writeString(wakelockEntry.getKey());
Uid.Wakelock wakelock = wakelockEntry.getValue();
- wakelock.writeToParcelLocked(out);
+ wakelock.writeToParcelLocked(out, batteryRealtime);
}
out.writeInt(mSensorStats.size());
for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
out.writeInt(sensorEntry.getKey());
Uid.Sensor sensor = sensorEntry.getValue();
- sensor.writeToParcelLocked(out);
+ sensor.writeToParcelLocked(out, batteryRealtime);
}
out.writeInt(mProcessStats.size());
@@ -383,15 +619,22 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
Uid.Pkg pkg = pkgEntry.getValue();
pkg.writeToParcelLocked(out);
}
+
+ out.writeLong(mLoadedTcpBytesReceived);
+ out.writeLong(mLoadedTcpBytesSent);
+ out.writeLong(computeCurrentTcpBytesReceived());
+ out.writeLong(computeCurrentTcpBytesSent());
+ out.writeLong(mTcpBytesReceivedAtLastUnplug);
+ out.writeLong(mTcpBytesSentAtLastUnplug);
}
- void readFromParcelLocked(Parcel in) {
+ void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
int numWakelocks = in.readInt();
mWakelockStats.clear();
for (int j = 0; j < numWakelocks; j++) {
String wakelockName = in.readString();
Uid.Wakelock wakelock = new Wakelock();
- wakelock.readFromParcelLocked(in);
+ wakelock.readFromParcelLocked(unpluggables, in);
mWakelockStats.put(wakelockName, wakelock);
}
@@ -399,8 +642,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mSensorStats.clear();
for (int k = 0; k < numSensors; k++) {
int sensorNumber = in.readInt();
- Uid.Sensor sensor = new Sensor();
- sensor.readFromParcelLocked(in);
+ Uid.Sensor sensor = new Sensor(sensorNumber);
+ sensor.readFromParcelLocked(mUnpluggables, in);
mSensorStats.put(sensorNumber, sensor);
}
@@ -421,6 +664,13 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
pkg.readFromParcelLocked(in);
mPackageStats.put(packageName, pkg);
}
+
+ mLoadedTcpBytesReceived = in.readLong();
+ mLoadedTcpBytesSent = in.readLong();
+ mCurrentTcpBytesReceived = in.readLong();
+ mCurrentTcpBytesSent = in.readLong();
+ mTcpBytesReceivedAtLastUnplug = in.readLong();
+ mTcpBytesSentAtLastUnplug = in.readLong();
}
/**
@@ -430,17 +680,17 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
/**
* How long (in ms) this uid has been keeping the device partially awake.
*/
- Timer wakeTimePartial;
+ Timer mTimerPartial;
/**
* How long (in ms) this uid has been keeping the device fully awake.
*/
- Timer wakeTimeFull;
+ Timer mTimerFull;
/**
* How long (in ms) this uid has had a window keeping the device awake.
*/
- Timer wakeTimeWindow;
+ Timer mTimerWindow;
/**
* Reads a possibly null Timer from a Parcel. The timer is associated with the
@@ -449,93 +699,85 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
* @param in the Parcel to be read from.
* return a new Timer, or null.
*/
- private Timer readTimerFromParcel(Parcel in) {
+ private Timer readTimerFromParcel(int type, ArrayList<Timer> pool,
+ ArrayList<Unpluggable> unpluggables, Parcel in) {
if (in.readInt() == 0) {
return null;
}
- Timer timer = new Timer();
- timer.readFromParcel(in);
- // Set the timer pool for the timer according to its type
- switch (timer.mType) {
- case WAKE_TYPE_PARTIAL:
- timer.mTimerPool = mPartialTimers;
- break;
- case WAKE_TYPE_FULL:
- timer.mTimerPool = mFullTimers;
- break;
- case WAKE_TYPE_WINDOW:
- timer.mTimerPool = mWindowTimers;
- break;
- }
- // If the timer is active, add it to the pool
- if (timer.mNesting > 0) {
- timer.mTimerPool.add(timer);
- }
- return timer;
+ return new Timer(type, pool, unpluggables, in);
}
- void readFromParcelLocked(Parcel in) {
- wakeTimePartial = readTimerFromParcel(in);
- wakeTimeFull = readTimerFromParcel(in);
- wakeTimeWindow = readTimerFromParcel(in);
+ void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
+ mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
+ mPartialTimers, unpluggables, in);
+ mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
+ mFullTimers, unpluggables, in);
+ mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
+ mWindowTimers, unpluggables, in);
}
- void writeToParcelLocked(Parcel out) {
- Timer.writeTimerToParcel(out, wakeTimePartial);
- Timer.writeTimerToParcel(out, wakeTimeFull);
- Timer.writeTimerToParcel(out, wakeTimeWindow);
+ void writeToParcelLocked(Parcel out, long batteryRealtime) {
+ Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
+ Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
+ Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
}
@Override
public Timer getWakeTime(int type) {
switch (type) {
- case WAKE_TYPE_FULL: return wakeTimeFull;
- case WAKE_TYPE_PARTIAL: return wakeTimePartial;
- case WAKE_TYPE_WINDOW: return wakeTimeWindow;
+ case WAKE_TYPE_FULL: return mTimerFull;
+ case WAKE_TYPE_PARTIAL: return mTimerPartial;
+ case WAKE_TYPE_WINDOW: return mTimerWindow;
default: throw new IllegalArgumentException("type = " + type);
}
}
}
public final class Sensor extends BatteryStats.Uid.Sensor {
- Timer sensorTime;
+ final int mHandle;
+ Timer mTimer;
+
+ public Sensor(int handle) {
+ mHandle = handle;
+ }
- private Timer readTimerFromParcel(Parcel in) {
+ private Timer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
+ Parcel in) {
if (in.readInt() == 0) {
return null;
}
- Timer timer = new Timer();
- timer.readFromParcel(in);
- // Set the timer pool for the timer
- timer.mTimerPool = mSensorTimers;
-
- // If the timer is active, add it to the pool
- if (timer.mNesting > 0) {
- timer.mTimerPool.add(timer);
+ ArrayList<Timer> pool = mSensorTimers.get(mHandle);
+ if (pool == null) {
+ pool = new ArrayList<Timer>();
+ mSensorTimers.put(mHandle, pool);
}
- return timer;
+ return new Timer(0, pool, unpluggables, in);
}
- void readFromParcelLocked(Parcel in) {
- sensorTime = readTimerFromParcel(in);
+ void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
+ mTimer = readTimerFromParcel(unpluggables, in);
}
- void writeToParcelLocked(Parcel out) {
- Timer.writeTimerToParcel(out, sensorTime);
+ void writeToParcelLocked(Parcel out, long batteryRealtime) {
+ Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
}
@Override
public Timer getSensorTime() {
- return sensorTime;
+ return mTimer;
+ }
+
+ public int getHandle() {
+ return mHandle;
}
}
/**
* The statistics associated with a particular process.
*/
- public final class Proc extends BatteryStats.Uid.Proc {
+ public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
/**
* Total time (in 1/100 sec) spent executing in user code.
*/
@@ -581,6 +823,34 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
*/
int mLastStarts;
+ /**
+ * The amount of user time when last unplugged.
+ */
+ long mUnpluggedUserTime;
+
+ /**
+ * The amount of system time when last unplugged.
+ */
+ long mUnpluggedSystemTime;
+
+ /**
+ * The number of times the process has started before unplugged.
+ */
+ int mUnpluggedStarts;
+
+ Proc() {
+ mUnpluggables.add(this);
+ }
+
+ public void unplug(long batteryUptime, long batteryRealtime) {
+ mUnpluggedUserTime = mUserTime;
+ mUnpluggedSystemTime = mSystemTime;
+ mUnpluggedStarts = mStarts;
+ }
+
+ public void plug(long batteryUptime, long batteryRealtime) {
+ }
+
void writeToParcelLocked(Parcel out) {
out.writeLong(mUserTime);
out.writeLong(mSystemTime);
@@ -591,6 +861,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
out.writeLong(mLastUserTime);
out.writeLong(mLastSystemTime);
out.writeInt(mLastStarts);
+ out.writeLong(mUnpluggedUserTime);
+ out.writeLong(mUnpluggedSystemTime);
+ out.writeInt(mUnpluggedStarts);
}
void readFromParcelLocked(Parcel in) {
@@ -603,6 +876,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mLastUserTime = in.readLong();
mLastSystemTime = in.readLong();
mLastStarts = in.readInt();
+ mUnpluggedUserTime = in.readLong();
+ mUnpluggedSystemTime = in.readLong();
+ mUnpluggedStarts = in.readInt();
}
public BatteryStatsImpl getBatteryStats() {
@@ -627,6 +903,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
val = mUserTime;
if (which == STATS_CURRENT) {
val -= mLoadedUserTime;
+ } else if (which == STATS_UNPLUGGED) {
+ val -= mUnpluggedUserTime;
}
}
return val;
@@ -641,6 +919,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
val = mSystemTime;
if (which == STATS_CURRENT) {
val -= mLoadedSystemTime;
+ } else if (which == STATS_UNPLUGGED) {
+ val -= mUnpluggedSystemTime;
}
}
return val;
@@ -655,6 +935,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
val = mStarts;
if (which == STATS_CURRENT) {
val -= mLoadedStarts;
+ } else if (which == STATS_UNPLUGGED) {
+ val -= mUnpluggedStarts;
}
}
return val;
@@ -664,7 +946,7 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
/**
* The statistics associated with a particular package.
*/
- public final class Pkg extends BatteryStats.Uid.Pkg {
+ public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
/**
* Number of times this package has done something that could wake up the
* device from sleep.
@@ -684,14 +966,32 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
int mLastWakeups;
/**
+ * Number of things that could wake up the device as of the
+ * last run.
+ */
+ int mUnpluggedWakeups;
+
+ /**
* The statics we have collected for this package's services.
*/
final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
+ Pkg() {
+ mUnpluggables.add(this);
+ }
+
+ public void unplug(long batteryUptime, long batteryRealtime) {
+ mUnpluggedWakeups = mWakeups;
+ }
+
+ public void plug(long batteryUptime, long batteryRealtime) {
+ }
+
void readFromParcelLocked(Parcel in) {
mWakeups = in.readInt();
mLoadedWakeups = in.readInt();
mLastWakeups = in.readInt();
+ mUnpluggedWakeups = in.readInt();
int numServs = in.readInt();
mServiceStats.clear();
@@ -708,6 +1008,7 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
out.writeInt(mWakeups);
out.writeInt(mLoadedWakeups);
out.writeInt(mLastWakeups);
+ out.writeInt(mUnpluggedWakeups);
out.writeInt(mServiceStats.size());
for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
@@ -732,6 +1033,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
val = mWakeups;
if (which == STATS_CURRENT) {
val -= mLoadedWakeups;
+ } else if (which == STATS_UNPLUGGED) {
+ val -= mUnpluggedWakeups;
}
}
@@ -741,9 +1044,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
/**
* The statistics associated with a particular service.
*/
- public final class Serv extends BatteryStats.Uid.Pkg.Serv {
+ public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
/**
- * Total time (ms) the service has been left started.
+ * Total time (ms in battery uptime) the service has been left started.
*/
long mStartTime;
@@ -764,13 +1067,13 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
int mStarts;
/**
- * Total time (ms) the service has been left launched.
+ * Total time (ms in battery uptime) the service has been left launched.
*/
long mLaunchedTime;
/**
* If service has been launched and not yet exited, this is
- * when it was launched.
+ * when it was launched (ms in battery uptime).
*/
long mLaunchedSince;
@@ -785,7 +1088,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
int mLaunches;
/**
- * The amount of time spent started loaded from a previous save.
+ * The amount of time spent started loaded from a previous save
+ * (ms in battery uptime).
*/
long mLoadedStartTime;
@@ -800,7 +1104,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
int mLoadedLaunches;
/**
- * The amount of time spent started as of the last run.
+ * The amount of time spent started as of the last run (ms
+ * in battery uptime).
*/
long mLastStartTime;
@@ -814,6 +1119,35 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
*/
int mLastLaunches;
+ /**
+ * The amount of time spent started when last unplugged (ms
+ * in battery uptime).
+ */
+ long mUnpluggedStartTime;
+
+ /**
+ * The number of starts when last unplugged.
+ */
+ int mUnpluggedStarts;
+
+ /**
+ * The number of launches when last unplugged.
+ */
+ int mUnpluggedLaunches;
+
+ Serv() {
+ mUnpluggables.add(this);
+ }
+
+ public void unplug(long batteryUptime, long batteryRealtime) {
+ mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
+ mUnpluggedStarts = mStarts;
+ mUnpluggedLaunches = mLaunches;
+ }
+
+ public void plug(long batteryUptime, long batteryRealtime) {
+ }
+
void readFromParcelLocked(Parcel in) {
mStartTime = in.readLong();
mRunningSince = in.readLong();
@@ -829,6 +1163,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mLastStartTime = in.readLong();
mLastStarts = in.readInt();
mLastLaunches = in.readInt();
+ mUnpluggedStartTime = in.readLong();
+ mUnpluggedStarts = in.readInt();
+ mUnpluggedLaunches = in.readInt();
}
void writeToParcelLocked(Parcel out) {
@@ -846,6 +1183,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
out.writeLong(mLastStartTime);
out.writeInt(mLastStarts);
out.writeInt(mLastLaunches);
+ out.writeLong(mUnpluggedStartTime);
+ out.writeInt(mUnpluggedStarts);
+ out.writeInt(mUnpluggedLaunches);
}
long getLaunchTimeToNowLocked(long batteryUptime) {
@@ -912,6 +1252,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
val = mLaunches;
if (which == STATS_CURRENT) {
val -= mLoadedLaunches;
+ } else if (which == STATS_UNPLUGGED) {
+ val -= mUnpluggedLaunches;
}
}
@@ -927,6 +1269,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
val = getStartTimeToNowLocked(now);
if (which == STATS_CURRENT) {
val -= mLoadedStartTime;
+ } else if (which == STATS_UNPLUGGED) {
+ val -= mUnpluggedStartTime;
}
}
@@ -942,6 +1286,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
val = mStarts;
if (which == STATS_CURRENT) {
val -= mLoadedStarts;
+ } else if (which == STATS_UNPLUGGED) {
+ val -= mUnpluggedStarts;
}
}
@@ -1014,24 +1360,24 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
Timer t = null;
switch (type) {
case WAKE_TYPE_PARTIAL:
- t = wl.wakeTimePartial;
+ t = wl.mTimerPartial;
if (t == null) {
- t = new Timer(WAKE_TYPE_PARTIAL, mPartialTimers);
- wl.wakeTimePartial = t;
+ t = new Timer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables);
+ wl.mTimerPartial = t;
}
return t;
case WAKE_TYPE_FULL:
- t = wl.wakeTimeFull;
+ t = wl.mTimerFull;
if (t == null) {
- t = new Timer(WAKE_TYPE_FULL, mFullTimers);
- wl.wakeTimeFull = t;
+ t = new Timer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables);
+ wl.mTimerFull = t;
}
return t;
case WAKE_TYPE_WINDOW:
- t = wl.wakeTimeWindow;
+ t = wl.mTimerWindow;
if (t == null) {
- t = new Timer(WAKE_TYPE_WINDOW, mWindowTimers);
- wl.wakeTimeWindow = t;
+ t = new Timer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables);
+ wl.mTimerWindow = t;
}
return t;
default:
@@ -1040,20 +1386,25 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
}
public Timer getSensorTimerLocked(int sensor, boolean create) {
- Integer sId = Integer.valueOf(sensor);
- Sensor se = mSensorStats.get(sId);
+ Sensor se = mSensorStats.get(sensor);
if (se == null) {
if (!create) {
return null;
}
- se = new Sensor();
- mSensorStats.put(sId, se);
+ se = new Sensor(sensor);
+ mSensorStats.put(sensor, se);
+ }
+ Timer t = se.mTimer;
+ if (t != null) {
+ return t;
}
- Timer t = se.sensorTime;
- if (t == null) {
- t = new Timer(0, mSensorTimers);
- se.sensorTime = t;
+ ArrayList<Timer> timers = mSensorTimers.get(sensor);
+ if (timers == null) {
+ timers = new ArrayList<Timer>();
+ mSensorTimers.put(sensor, timers);
}
+ t = new Timer(BatteryStats.SENSOR, timers, mUnpluggables);
+ se.mTimer = t;
return t;
}
@@ -1085,6 +1436,20 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
t.stopRunningLocked(BatteryStatsImpl.this);
}
}
+
+ public void noteStartGps() {
+ Timer t = getSensorTimerLocked(Sensor.GPS, true);
+ if (t != null) {
+ t.startRunningLocked(BatteryStatsImpl.this);
+ }
+ }
+
+ public void noteStopGps() {
+ Timer t = getSensorTimerLocked(Sensor.GPS, false);
+ if (t != null) {
+ t.stopRunningLocked(BatteryStatsImpl.this);
+ }
+ }
public BatteryStatsImpl getBatteryStats() {
return BatteryStatsImpl.this;
@@ -1095,11 +1460,15 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mFile = new File(filename);
mBackupFile = new File(filename + ".bak");
mStartCount++;
- mOnBattery = true;
+ mScreenOnTimer = new Timer(-1, null, mUnpluggables);
+ mPhoneOnTimer = new Timer(-2, null, mUnpluggables);
+ mOnBattery = mOnBatteryInternal = false;
mTrackBatteryPastUptime = 0;
mTrackBatteryPastRealtime = 0;
mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
+ mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
+ mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
}
public BatteryStatsImpl(Parcel p) {
@@ -1119,18 +1488,22 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
public void setOnBattery(boolean onBattery) {
synchronized(this) {
if (mOnBattery != onBattery) {
+ mOnBattery = mOnBatteryInternal = onBattery;
+
long uptime = SystemClock.uptimeMillis() * 1000;
long mSecRealtime = SystemClock.elapsedRealtime();
long realtime = mSecRealtime * 1000;
if (onBattery) {
mTrackBatteryUptimeStart = uptime;
mTrackBatteryRealtimeStart = realtime;
- unplugTimers();
+ mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
+ mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
+ doUnplug(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
} else {
mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
+ doPlug(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
}
- mOnBattery = onBattery;
if ((mLastWriteTime + (60 * 1000)) < mSecRealtime) {
if (mFile != null) {
writeLocked();
@@ -1151,10 +1524,10 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
@Override
public long computeUptime(long curTime, int which) {
switch (which) {
- case STATS_TOTAL: return mUptime + (curTime-mUptimeStart);
- case STATS_LAST: return mLastUptime;
- case STATS_CURRENT: return (curTime-mUptimeStart);
- case STATS_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
+ case STATS_TOTAL: return mUptime + (curTime-mUptimeStart);
+ case STATS_LAST: return mLastUptime;
+ case STATS_CURRENT: return (curTime-mUptimeStart);
+ case STATS_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
}
return 0;
}
@@ -1162,10 +1535,10 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
@Override
public long computeRealtime(long curTime, int which) {
switch (which) {
- case STATS_TOTAL: return mRealtime + (curTime-mRealtimeStart);
- case STATS_LAST: return mLastRealtime;
- case STATS_CURRENT: return (curTime-mRealtimeStart);
- case STATS_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
+ case STATS_TOTAL: return mRealtime + (curTime-mRealtimeStart);
+ case STATS_LAST: return mLastRealtime;
+ case STATS_CURRENT: return (curTime-mRealtimeStart);
+ case STATS_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
}
return 0;
}
@@ -1173,13 +1546,14 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
@Override
public long computeBatteryUptime(long curTime, int which) {
switch (which) {
- case STATS_TOTAL:
- return mBatteryUptime + getBatteryUptime(curTime);
- case STATS_LAST:
- return mBatteryLastUptime;
- case STATS_CURRENT:
- case STATS_UNPLUGGED:
- return getBatteryUptime(curTime);
+ case STATS_TOTAL:
+ return mBatteryUptime + getBatteryUptime(curTime);
+ case STATS_LAST:
+ return mBatteryLastUptime;
+ case STATS_CURRENT:
+ return getBatteryUptime(curTime);
+ case STATS_UNPLUGGED:
+ return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
}
return 0;
}
@@ -1187,20 +1561,21 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
@Override
public long computeBatteryRealtime(long curTime, int which) {
switch (which) {
- case STATS_TOTAL:
- return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
- case STATS_LAST:
- return mBatteryLastRealtime;
- case STATS_CURRENT:
- case STATS_UNPLUGGED:
- return getBatteryRealtimeLocked(curTime);
+ case STATS_TOTAL:
+ return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
+ case STATS_LAST:
+ return mBatteryLastRealtime;
+ case STATS_CURRENT:
+ return getBatteryRealtimeLocked(curTime);
+ case STATS_UNPLUGGED:
+ return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
}
return 0;
}
long getBatteryUptimeLocked(long curTime) {
long time = mTrackBatteryPastUptime;
- if (mOnBattery) {
+ if (mOnBatteryInternal) {
time += curTime - mTrackBatteryUptimeStart;
}
return time;
@@ -1217,7 +1592,7 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
long getBatteryRealtimeLocked(long curTime) {
long time = mTrackBatteryPastRealtime;
- if (mOnBattery) {
+ if (mOnBatteryInternal) {
time += curTime - mTrackBatteryRealtimeStart;
}
return time;
@@ -1234,7 +1609,7 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
public Uid getUidStatsLocked(int uid) {
Uid u = mUidStats.get(uid);
if (u == null) {
- u = new Uid();
+ u = new Uid(uid);
mUidStats.put(uid, u);
}
return u;
@@ -1246,7 +1621,7 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
public void removeUidStatsLocked(int uid) {
mUidStats.remove(uid);
}
-
+
/**
* Retrieve the statistics object for a particular process, creating
* if needed.
@@ -1373,8 +1748,8 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
private void readSummaryFromParcel(Parcel in) {
final int version = in.readInt();
if (version != VERSION) {
- Log.e("BatteryStats", "readFromParcel: version got " + version
- + ", expected " + VERSION);
+ Log.w("BatteryStats", "readFromParcel: version got " + version
+ + ", expected " + VERSION + "; erasing old stats");
return;
}
@@ -1388,15 +1763,20 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mRealtime = in.readLong();
mLastRealtime = in.readLong();
mStartCount++;
+
+ mScreenOn = false;
+ mScreenOnTimer.readSummaryFromParcelLocked(in);
+ mPhoneOn = false;
+ mPhoneOnTimer.readSummaryFromParcelLocked(in);
final int NU = in.readInt();
- for (int iu=0; iu<NU; iu++) {
+ for (int iu = 0; iu < NU; iu++) {
int uid = in.readInt();
- Uid u = new Uid();
+ Uid u = new Uid(uid);
mUidStats.put(uid, u);
int NW = in.readInt();
- for (int iw=0; iw<NW; iw++) {
+ for (int iw = 0; iw < NW; iw++) {
String wlName = in.readString();
if (in.readInt() != 0) {
u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
@@ -1409,18 +1789,17 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
}
}
- if (version >= 12) {
- int NSE = in.readInt();
- for (int is=0; is<NSE; is++) {
- int seNumber = in.readInt();
- if (in.readInt() != 0) {
- u.getSensorTimerLocked(seNumber, true).readSummaryFromParcelLocked(in);
- }
+ int NP = in.readInt();
+ for (int is = 0; is < NP; is++) {
+ int seNumber = in.readInt();
+ if (in.readInt() != 0) {
+ u.getSensorTimerLocked(seNumber, true)
+ .readSummaryFromParcelLocked(in);
}
}
- int NP = in.readInt();
- for (int ip=0; ip<NP; ip++) {
+ NP = in.readInt();
+ for (int ip = 0; ip < NP; ip++) {
String procName = in.readString();
Uid.Proc p = u.getProcessStatsLocked(procName);
p.mUserTime = p.mLoadedUserTime = in.readLong();
@@ -1432,13 +1811,13 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
}
NP = in.readInt();
- for (int ip=0; ip<NP; ip++) {
+ for (int ip = 0; ip < NP; ip++) {
String pkgName = in.readString();
Uid.Pkg p = u.getPackageStatsLocked(pkgName);
p.mWakeups = p.mLoadedWakeups = in.readInt();
p.mLastWakeups = in.readInt();
final int NS = in.readInt();
- for (int is=0; is<NS; is++) {
+ for (int is = 0; is < NS; is++) {
String servName = in.readString();
Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
s.mStartTime = s.mLoadedStartTime = in.readLong();
@@ -1449,6 +1828,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
s.mLastLaunches = in.readInt();
}
}
+
+ u.mLoadedTcpBytesReceived = in.readLong();
+ u.mLoadedTcpBytesSent = in.readLong();
}
}
@@ -1459,9 +1841,10 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
* @param out the Parcel to be written to.
*/
public void writeSummaryToParcel(Parcel out) {
- final long NOW = getBatteryUptimeLocked();
final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
+ final long NOW = getBatteryUptimeLocked(NOW_SYS);
+ final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS);
out.writeInt(VERSION);
@@ -1474,10 +1857,13 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT));
out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL));
out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT));
+
+ mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+ mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
final int NU = mUidStats.size();
out.writeInt(NU);
- for (int iu=0; iu<NU; iu++) {
+ for (int iu = 0; iu < NU; iu++) {
out.writeInt(mUidStats.keyAt(iu));
Uid u = mUidStats.valueAt(iu);
@@ -1485,24 +1871,24 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
out.writeInt(NW);
if (NW > 0) {
for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
- : u.mWakelockStats.entrySet()) {
+ : u.mWakelockStats.entrySet()) {
out.writeString(ent.getKey());
Uid.Wakelock wl = ent.getValue();
- if (wl.wakeTimeFull != null) {
+ if (wl.mTimerFull != null) {
out.writeInt(1);
- wl.wakeTimeFull.writeSummaryFromParcelLocked(out, NOW);
+ wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
- if (wl.wakeTimePartial != null) {
+ if (wl.mTimerPartial != null) {
out.writeInt(1);
- wl.wakeTimePartial.writeSummaryFromParcelLocked(out, NOW);
+ wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
- if (wl.wakeTimeWindow != null) {
+ if (wl.mTimerWindow != null) {
out.writeInt(1);
- wl.wakeTimeWindow.writeSummaryFromParcelLocked(out, NOW);
+ wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
@@ -1513,12 +1899,12 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
out.writeInt(NSE);
if (NSE > 0) {
for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
- : u.mSensorStats.entrySet()) {
+ : u.mSensorStats.entrySet()) {
out.writeInt(ent.getKey());
Uid.Sensor se = ent.getValue();
- if (se.sensorTime != null) {
+ if (se.mTimer != null) {
out.writeInt(1);
- se.sensorTime.writeSummaryFromParcelLocked(out, NOW);
+ se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL);
} else {
out.writeInt(0);
}
@@ -1568,6 +1954,9 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
}
}
}
+
+ out.writeLong(u.getTcpBytesReceived(STATS_TOTAL));
+ out.writeLong(u.getTcpBytesSent(STATS_TOTAL));
}
}
@@ -1586,6 +1975,10 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mBatteryLastUptime = in.readLong();
mBatteryRealtime = in.readLong();
mBatteryLastRealtime = in.readLong();
+ mScreenOn = false;
+ mScreenOnTimer = new Timer(-1, null, mUnpluggables, in);
+ mPhoneOn = false;
+ mPhoneOnTimer = new Timer(-2, null, mUnpluggables, in);
mUptime = in.readLong();
mUptimeStart = in.readLong();
mLastUptime = in.readLong();
@@ -1593,10 +1986,13 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
mRealtimeStart = in.readLong();
mLastRealtime = in.readLong();
mOnBattery = in.readInt() != 0;
+ mOnBatteryInternal = false; // we are no longer really running.
mTrackBatteryPastUptime = in.readLong();
mTrackBatteryUptimeStart = in.readLong();
mTrackBatteryPastRealtime = in.readLong();
mTrackBatteryRealtimeStart = in.readLong();
+ mUnpluggedBatteryUptime = in.readLong();
+ mUnpluggedBatteryRealtime = in.readLong();
mLastWriteTime = in.readLong();
mPartialTimers.clear();
@@ -1606,10 +2002,10 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
int numUids = in.readInt();
mUidStats.clear();
for (int i = 0; i < numUids; i++) {
- int key = in.readInt();
- Uid uid = new Uid();
- uid.readFromParcelLocked(in);
- mUidStats.append(key, uid);
+ int uid = in.readInt();
+ Uid u = new Uid(uid);
+ u.readFromParcelLocked(mUnpluggables, in);
+ mUidStats.append(uid, u);
}
}
@@ -1619,12 +2015,19 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
@SuppressWarnings("unused")
void writeToParcelLocked(Parcel out, int flags) {
+ final long uSecUptime = SystemClock.uptimeMillis() * 1000;
+ final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
+ final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
+ final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
+
out.writeInt(MAGIC);
out.writeInt(mStartCount);
out.writeLong(mBatteryUptime);
out.writeLong(mBatteryLastUptime);
out.writeLong(mBatteryRealtime);
out.writeLong(mBatteryLastRealtime);
+ mScreenOnTimer.writeToParcel(out, batteryRealtime);
+ mPhoneOnTimer.writeToParcel(out, batteryRealtime);
out.writeLong(mUptime);
out.writeLong(mUptimeStart);
out.writeLong(mLastUptime);
@@ -1632,10 +2035,12 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
out.writeLong(mRealtimeStart);
out.writeLong(mLastRealtime);
out.writeInt(mOnBattery ? 1 : 0);
- out.writeLong(mTrackBatteryPastUptime);
+ out.writeLong(batteryUptime);
out.writeLong(mTrackBatteryUptimeStart);
- out.writeLong(mTrackBatteryPastRealtime);
+ out.writeLong(batteryRealtime);
out.writeLong(mTrackBatteryRealtimeStart);
+ out.writeLong(mUnpluggedBatteryUptime);
+ out.writeLong(mUnpluggedBatteryRealtime);
out.writeLong(mLastWriteTime);
int size = mUidStats.size();
@@ -1644,7 +2049,7 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
out.writeInt(mUidStats.keyAt(i));
Uid uid = mUidStats.valueAt(i);
- uid.writeToParcelLocked(out);
+ uid.writeToParcelLocked(out, batteryRealtime);
}
}
@@ -1658,4 +2063,14 @@ public final class BatteryStatsImpl extends BatteryStats implements Parcelable {
return new BatteryStatsImpl[size];
}
};
+
+ public void dumpLocked(Printer pw) {
+ if (DEBUG) {
+ Log.i(TAG, "*** Screen timer:");
+ mScreenOnTimer.logState();
+ Log.i(TAG, "*** Phone timer:");
+ mPhoneOnTimer.logState();
+ }
+ super.dumpLocked(pw);
+ }
}
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 1ec74a1..932555d 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -21,7 +21,8 @@ public class HandlerCaller {
public Object arg1;
public Object arg2;
- Object arg3;
+ public Object arg3;
+ public Object arg4;
public int argi1;
public int argi2;
public int argi3;
@@ -119,6 +120,10 @@ public class HandlerCaller {
return mH.obtainMessage(what, arg1, 0);
}
+ public Message obtainMessageII(int what, int arg1, int arg2) {
+ return mH.obtainMessage(what, arg1, arg2);
+ }
+
public Message obtainMessageIO(int what, int arg1, Object arg2) {
return mH.obtainMessage(what, arg1, 0, arg2);
}
@@ -149,6 +154,16 @@ public class HandlerCaller {
return mH.obtainMessage(what, 0, 0, args);
}
+ public Message obtainMessageOOOO(int what, Object arg1, Object arg2,
+ Object arg3, Object arg4) {
+ SomeArgs args = obtainArgs();
+ args.arg1 = arg1;
+ args.arg2 = arg2;
+ args.arg3 = arg3;
+ args.arg4 = arg4;
+ return mH.obtainMessage(what, 0, 0, args);
+ }
+
public Message obtainMessageIIII(int what, int arg1, int arg2,
int arg3, int arg4) {
SomeArgs args = obtainArgs();
diff --git a/core/java/com/android/internal/os/HandlerThread.java b/core/java/com/android/internal/os/HandlerThread.java
deleted file mode 100644
index 1de6bfd..0000000
--- a/core/java/com/android/internal/os/HandlerThread.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2006 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.internal.os;
-
-import android.os.Handler;
-import android.os.HandlerInterface;
-import android.os.Looper;
-
-/**
- * Handy class for starting a new thread containing a Handler
- * @hide
- * @deprecated
- */
-public class HandlerThread extends Thread
-{
- Runnable mSetup;
- HandlerInterface mhi;
- Handler mh;
- Throwable mtr;
- final Object mMonitor = new Object();
-
- public
- HandlerThread(HandlerInterface h, Runnable setup, String name)
- {
- super(name);
-
- mhi = h;
- mSetup = setup;
-
- synchronized (mMonitor) {
- start();
- while (mh == null && mtr == null) {
- try {
- mMonitor.wait();
- } catch (InterruptedException ex) {
- }
- }
- }
-
- if (mtr != null) {
- throw new RuntimeException("exception while starting", mtr);
- }
- }
-
- @Override
- public void
- run()
- {
- synchronized(mMonitor) {
- try {
- Looper.prepare();
- mh = new HandlerHelper (mhi);
-
- if (mSetup != null) {
- mSetup.run();
- mSetup = null;
- }
- } catch (RuntimeException exc) {
- mtr = exc;
- }
-
- mMonitor.notify();
- }
-
- if (mtr == null) {
- Looper.loop();
- }
- }
-
- public Handler
- getHandler()
- {
- return mh;
- }
-
-}
-
diff --git a/core/java/com/android/internal/os/IResultReceiver.aidl b/core/java/com/android/internal/os/IResultReceiver.aidl
new file mode 100644
index 0000000..2b70f95
--- /dev/null
+++ b/core/java/com/android/internal/os/IResultReceiver.aidl
@@ -0,0 +1,25 @@
+/* //device/java/android/android/app/IActivityPendingResult.aidl
+**
+** Copyright 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.internal.os;
+
+import android.os.Bundle;
+
+/** @hide */
+oneway interface IResultReceiver {
+ void send(int resultCode, in Bundle resultData);
+}
diff --git a/core/res/res/drawable/radiobutton_background.xml b/core/java/com/android/internal/os/PkgUsageStats.aidl
index 948a141..8305271 100644..100755
--- a/core/res/res/drawable/radiobutton_background.xml
+++ b/core/java/com/android/internal/os/PkgUsageStats.aidl
@@ -1,6 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/radiobutton_background.xml
+/* //device/java/android/android/content/Intent.aidl
**
** Copyright 2007, The Android Open Source Project
**
@@ -16,8 +14,7 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/radiobutton_label_background" />
-</selector>
+package com.android.internal.os;
+
+parcelable PkgUsageStats;
diff --git a/core/java/com/android/internal/os/PkgUsageStats.java b/core/java/com/android/internal/os/PkgUsageStats.java
new file mode 100755
index 0000000..e847878
--- /dev/null
+++ b/core/java/com/android/internal/os/PkgUsageStats.java
@@ -0,0 +1,60 @@
+package com.android.internal.os;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * implementation of PkgUsageStats associated with an
+ * application package.
+ * @hide
+ */
+public class PkgUsageStats implements Parcelable {
+ public String packageName;
+ public int launchCount;
+ public long usageTime;
+
+ public static final Parcelable.Creator<PkgUsageStats> CREATOR
+ = new Parcelable.Creator<PkgUsageStats>() {
+ public PkgUsageStats createFromParcel(Parcel in) {
+ return new PkgUsageStats(in);
+ }
+
+ public PkgUsageStats[] newArray(int size) {
+ return new PkgUsageStats[size];
+ }
+ };
+
+ public String toString() {
+ return "PkgUsageStats{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + packageName + "}";
+ }
+
+ public PkgUsageStats(String pkgName, int count, long time) {
+ packageName = pkgName;
+ launchCount = count;
+ usageTime = time;
+ }
+
+ public PkgUsageStats(Parcel source) {
+ packageName = source.readString();
+ launchCount = source.readInt();
+ usageTime = source.readLong();
+ }
+
+ public PkgUsageStats(PkgUsageStats pStats) {
+ packageName = pStats.packageName;
+ launchCount = pStats.launchCount;
+ usageTime = pStats.usageTime;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int parcelableFlags){
+ dest.writeString(packageName);
+ dest.writeInt(launchCount);
+ dest.writeLong(usageTime);
+ }
+}
diff --git a/core/java/com/android/internal/os/RecoverySystem.java b/core/java/com/android/internal/os/RecoverySystem.java
new file mode 100644
index 0000000..c938610
--- /dev/null
+++ b/core/java/com/android/internal/os/RecoverySystem.java
@@ -0,0 +1,128 @@
+/*
+ * 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.internal.os;
+
+import android.os.FileUtils;
+import android.os.Power;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Utility class for interacting with the Android recovery partition.
+ * The recovery partition is a small standalone system which can perform
+ * operations that are difficult while the main system is running, like
+ * upgrading system software or reformatting the data partition.
+ * Note that most of these operations must be run as root.
+ *
+ * @hide
+ */
+public class RecoverySystem {
+ private static final String TAG = "RecoverySystem"; // for logging
+
+ // Used to communicate with recovery. See commands/recovery/recovery.c.
+ private static File RECOVERY_DIR = new File("/cache/recovery");
+ private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
+ private static File LOG_FILE = new File(RECOVERY_DIR, "log");
+
+ // Length limits for reading files.
+ private static int LOG_FILE_MAX_LENGTH = 8 * 1024;
+
+ /**
+ * Reboot into the recovery system to install a system update.
+ * @param update package to install (must be in /cache or /data).
+ * @throws IOException if something goes wrong.
+ */
+ public static void rebootAndUpdate(File update) throws IOException {
+ String path = update.getCanonicalPath();
+ if (path.startsWith("/cache/")) {
+ path = "CACHE:" + path.substring(7);
+ } else if (path.startsWith("/data/")) {
+ path = "DATA:" + path.substring(6);
+ } else {
+ throw new IllegalArgumentException(
+ "Must start with /cache or /data: " + path);
+ }
+ bootCommand("--update_package=" + path);
+ }
+
+ /**
+ * Reboot into the recovery system to wipe the /data partition.
+ * @param extras to add to the RECOVERY_COMPLETED intent after rebooting.
+ * @throws IOException if something goes wrong.
+ */
+ public static void rebootAndWipe() throws IOException {
+ bootCommand("--wipe_data");
+ }
+
+ /**
+ * Reboot into the recovery system with the supplied argument.
+ * @param arg to pass to the recovery utility.
+ * @throws IOException if something goes wrong.
+ */
+ private static void bootCommand(String arg) throws IOException {
+ RECOVERY_DIR.mkdirs(); // In case we need it
+ COMMAND_FILE.delete(); // In case it's not writable
+ LOG_FILE.delete();
+
+ FileWriter command = new FileWriter(COMMAND_FILE);
+ try {
+ command.write(arg);
+ command.write("\n");
+ } finally {
+ command.close();
+ }
+
+ // Having written the command file, go ahead and reboot
+ Power.reboot("recovery");
+ throw new IOException("Reboot failed (no permissions?)");
+ }
+
+ /**
+ * Called after booting to process and remove recovery-related files.
+ * @return the log file from recovery, or null if none was found.
+ */
+ public static String handleAftermath() {
+ // Record the tail of the LOG_FILE
+ String log = null;
+ try {
+ log = FileUtils.readTextFile(LOG_FILE, -LOG_FILE_MAX_LENGTH, "...\n");
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "No recovery log file");
+ } catch (IOException e) {
+ Log.e(TAG, "Error reading recovery log", e);
+ }
+
+ // Delete everything in RECOVERY_DIR
+ String[] names = RECOVERY_DIR.list();
+ for (int i = 0; names != null && i < names.length; i++) {
+ File f = new File(RECOVERY_DIR, names[i]);
+ if (!f.delete()) {
+ Log.e(TAG, "Can't delete: " + f);
+ } else {
+ Log.i(TAG, "Deleted: " + f);
+ }
+ }
+
+ return log;
+ }
+}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index f21b62f..ac8b589 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -19,6 +19,7 @@ package com.android.internal.os;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.net.LocalServerSocket;
import android.os.Debug;
@@ -335,32 +336,18 @@ public class ZygoteInit {
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
Log.i(TAG, "Preloading resources...");
+
long startTime = SystemClock.uptimeMillis();
TypedArray ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_drawables);
- int N = ar.length();
- for (int i=0; i<N; i++) {
- if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
- if (Config.LOGV) {
- Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
- }
- runtime.gcSoftReferences();
- runtime.runFinalizationSync();
- Debug.resetGlobalAllocSize();
- }
- int id = ar.getResourceId(i, 0);
- if (Config.LOGV) {
- Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
- }
- if (id != 0) {
- Drawable dr = mResources.getDrawable(id);
- if ((dr.getChangingConfigurations()&~ActivityInfo.CONFIG_FONT_SCALE) != 0) {
- Log.w(TAG, "Preloaded drawable resource #0x"
- + Integer.toHexString(id)
- + " that varies with configuration!!");
- }
- }
- }
+ int N = preloadDrawables(runtime, ar);
+ Log.i(TAG, "...preloaded " + N + " resources in "
+ + (SystemClock.uptimeMillis()-startTime) + "ms.");
+
+ startTime = SystemClock.uptimeMillis();
+ ar = mResources.obtainTypedArray(
+ com.android.internal.R.array.preloaded_color_state_lists);
+ N = preloadColorStateLists(runtime, ar);
Log.i(TAG, "...preloaded " + N + " resources in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
}
@@ -372,6 +359,56 @@ public class ZygoteInit {
}
}
+ private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
+ int N = ar.length();
+ for (int i=0; i<N; i++) {
+ if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
+ if (Config.LOGV) {
+ Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
+ }
+ runtime.gcSoftReferences();
+ runtime.runFinalizationSync();
+ Debug.resetGlobalAllocSize();
+ }
+ int id = ar.getResourceId(i, 0);
+ if (Config.LOGV) {
+ Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
+ }
+ if (id != 0) {
+ mResources.getColorStateList(id);
+ }
+ }
+ return N;
+ }
+
+
+ private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
+ int N = ar.length();
+ for (int i=0; i<N; i++) {
+ if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
+ if (Config.LOGV) {
+ Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
+ }
+ runtime.gcSoftReferences();
+ runtime.runFinalizationSync();
+ Debug.resetGlobalAllocSize();
+ }
+ int id = ar.getResourceId(i, 0);
+ if (Config.LOGV) {
+ Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
+ }
+ if (id != 0) {
+ Drawable dr = mResources.getDrawable(id);
+ if ((dr.getChangingConfigurations()&~ActivityInfo.CONFIG_FONT_SCALE) != 0) {
+ Log.w(TAG, "Preloaded drawable resource #0x"
+ + Integer.toHexString(id)
+ + " (" + ar.getString(i) + ") that varies with configuration!!");
+ }
+ }
+ }
+ return N;
+ }
+
/**
* Runs several special GCs to try to clean up a few generations of
* softly- and final-reachable objects, along with any other garbage.
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 011e944..106392d 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -1,7 +1,5 @@
package com.android.internal.view;
-import com.android.internal.view.IInputContext;
-
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -13,6 +11,8 @@ import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
+import java.lang.ref.WeakReference;
+
public class IInputConnectionWrapper extends IInputContext.Stub {
static final String TAG = "IInputConnectionWrapper";
@@ -22,18 +22,20 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
private static final int DO_GET_EXTRACTED_TEXT = 40;
private static final int DO_COMMIT_TEXT = 50;
private static final int DO_COMMIT_COMPLETION = 55;
+ private static final int DO_SET_SELECTION = 57;
+ private static final int DO_PERFORM_EDITOR_ACTION = 58;
+ private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59;
private static final int DO_SET_COMPOSING_TEXT = 60;
private static final int DO_FINISH_COMPOSING_TEXT = 65;
private static final int DO_SEND_KEY_EVENT = 70;
private static final int DO_DELETE_SURROUNDING_TEXT = 80;
private static final int DO_BEGIN_BATCH_EDIT = 90;
private static final int DO_END_BATCH_EDIT = 95;
- private static final int DO_HIDE_STATUS_ICON = 100;
- private static final int DO_SHOW_STATUS_ICON = 110;
+ private static final int DO_REPORT_FULLSCREEN_MODE = 100;
private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
private static final int DO_CLEAR_META_KEY_STATES = 130;
- private InputConnection mInputConnection;
+ private WeakReference<InputConnection> mInputConnection;
private Looper mMainLooper;
private Handler mH;
@@ -57,17 +59,21 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
}
public IInputConnectionWrapper(Looper mainLooper, InputConnection conn) {
- mInputConnection = conn;
+ mInputConnection = new WeakReference<InputConnection>(conn);
mMainLooper = mainLooper;
mH = new MyHandler(mMainLooper);
}
- public void getTextAfterCursor(int length, int seq, IInputContextCallback callback) {
- dispatchMessage(obtainMessageISC(DO_GET_TEXT_AFTER_CURSOR, length, seq, callback));
+ public boolean isActive() {
+ return true;
+ }
+
+ public void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback) {
+ dispatchMessage(obtainMessageIISC(DO_GET_TEXT_AFTER_CURSOR, length, flags, seq, callback));
}
- public void getTextBeforeCursor(int length, int seq, IInputContextCallback callback) {
- dispatchMessage(obtainMessageISC(DO_GET_TEXT_BEFORE_CURSOR, length, seq, callback));
+ public void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback) {
+ dispatchMessage(obtainMessageIISC(DO_GET_TEXT_BEFORE_CURSOR, length, flags, seq, callback));
}
public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
@@ -88,6 +94,18 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
dispatchMessage(obtainMessageO(DO_COMMIT_COMPLETION, text));
}
+ public void setSelection(int start, int end) {
+ dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end));
+ }
+
+ public void performEditorAction(int id) {
+ dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0));
+ }
+
+ public void performContextMenuAction(int id) {
+ dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
+ }
+
public void setComposingText(CharSequence text, int newCursorPosition) {
dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
}
@@ -117,12 +135,8 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
dispatchMessage(obtainMessage(DO_END_BATCH_EDIT));
}
- public void hideStatusIcon() {
- dispatchMessage(obtainMessage(DO_HIDE_STATUS_ICON));
- }
-
- public void showStatusIcon(String packageName, int resId) {
- dispatchMessage(obtainMessageIO(DO_SHOW_STATUS_ICON, resId, packageName));
+ public void reportFullscreenMode(boolean enabled) {
+ dispatchMessage(obtainMessageII(DO_REPORT_FULLSCREEN_MODE, enabled ? 1 : 0, 0));
}
public void performPrivateCommand(String action, Bundle data) {
@@ -147,8 +161,14 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
case DO_GET_TEXT_AFTER_CURSOR: {
SomeArgs args = (SomeArgs)msg.obj;
try {
- args.callback.setTextAfterCursor(mInputConnection.getTextAfterCursor(msg.arg1),
- args.seq);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
+ args.callback.setTextAfterCursor(null, args.seq);
+ return;
+ }
+ args.callback.setTextAfterCursor(ic.getTextAfterCursor(
+ msg.arg1, msg.arg2), args.seq);
} catch (RemoteException e) {
Log.w(TAG, "Got RemoteException calling setTextAfterCursor", e);
}
@@ -157,8 +177,14 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
case DO_GET_TEXT_BEFORE_CURSOR: {
SomeArgs args = (SomeArgs)msg.obj;
try {
- args.callback.setTextBeforeCursor(mInputConnection.getTextBeforeCursor(msg.arg1),
- args.seq);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
+ args.callback.setTextBeforeCursor(null, args.seq);
+ return;
+ }
+ args.callback.setTextBeforeCursor(ic.getTextBeforeCursor(
+ msg.arg1, msg.arg2), args.seq);
} catch (RemoteException e) {
Log.w(TAG, "Got RemoteException calling setTextBeforeCursor", e);
}
@@ -167,7 +193,13 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
case DO_GET_CURSOR_CAPS_MODE: {
SomeArgs args = (SomeArgs)msg.obj;
try {
- args.callback.setCursorCapsMode(mInputConnection.getCursorCapsMode(msg.arg1),
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
+ args.callback.setCursorCapsMode(0, args.seq);
+ return;
+ }
+ args.callback.setCursorCapsMode(ic.getCursorCapsMode(msg.arg1),
args.seq);
} catch (RemoteException e) {
Log.w(TAG, "Got RemoteException calling setCursorCapsMode", e);
@@ -177,7 +209,13 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
case DO_GET_EXTRACTED_TEXT: {
SomeArgs args = (SomeArgs)msg.obj;
try {
- args.callback.setExtractedText(mInputConnection.getExtractedText(
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getExtractedText on inactive InputConnection");
+ args.callback.setExtractedText(null, args.seq);
+ return;
+ }
+ args.callback.setExtractedText(ic.getExtractedText(
(ExtractedTextRequest)args.arg1, msg.arg1), args.seq);
} catch (RemoteException e) {
Log.w(TAG, "Got RemoteException calling setExtractedText", e);
@@ -185,52 +223,134 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
return;
}
case DO_COMMIT_TEXT: {
- mInputConnection.commitText((CharSequence)msg.obj, msg.arg1);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitText on inactive InputConnection");
+ return;
+ }
+ ic.commitText((CharSequence)msg.obj, msg.arg1);
+ return;
+ }
+ case DO_SET_SELECTION: {
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "setSelection on inactive InputConnection");
+ return;
+ }
+ ic.setSelection(msg.arg1, msg.arg2);
+ return;
+ }
+ case DO_PERFORM_EDITOR_ACTION: {
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "performEditorAction on inactive InputConnection");
+ return;
+ }
+ ic.performEditorAction(msg.arg1);
+ return;
+ }
+ case DO_PERFORM_CONTEXT_MENU_ACTION: {
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "performContextMenuAction on inactive InputConnection");
+ return;
+ }
+ ic.performContextMenuAction(msg.arg1);
return;
}
case DO_COMMIT_COMPLETION: {
- mInputConnection.commitCompletion((CompletionInfo)msg.obj);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitCompletion on inactive InputConnection");
+ return;
+ }
+ ic.commitCompletion((CompletionInfo)msg.obj);
return;
}
case DO_SET_COMPOSING_TEXT: {
- mInputConnection.setComposingText((CharSequence)msg.obj, msg.arg1);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "setComposingText on inactive InputConnection");
+ return;
+ }
+ ic.setComposingText((CharSequence)msg.obj, msg.arg1);
return;
}
case DO_FINISH_COMPOSING_TEXT: {
- mInputConnection.finishComposingText();
+ InputConnection ic = mInputConnection.get();
+ // Note we do NOT check isActive() here, because this is safe
+ // for an IME to call at any time, and we need to allow it
+ // through to clean up our state after the IME has switched to
+ // another client.
+ if (ic == null) {
+ Log.w(TAG, "finishComposingText on inactive InputConnection");
+ return;
+ }
+ ic.finishComposingText();
return;
}
case DO_SEND_KEY_EVENT: {
- mInputConnection.sendKeyEvent((KeyEvent)msg.obj);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "sendKeyEvent on inactive InputConnection");
+ return;
+ }
+ ic.sendKeyEvent((KeyEvent)msg.obj);
return;
}
case DO_CLEAR_META_KEY_STATES: {
- mInputConnection.clearMetaKeyStates(msg.arg1);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
+ return;
+ }
+ ic.clearMetaKeyStates(msg.arg1);
return;
}
case DO_DELETE_SURROUNDING_TEXT: {
- mInputConnection.deleteSurroundingText(msg.arg1, msg.arg2);
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
+ return;
+ }
+ ic.deleteSurroundingText(msg.arg1, msg.arg2);
return;
}
case DO_BEGIN_BATCH_EDIT: {
- mInputConnection.beginBatchEdit();
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "beginBatchEdit on inactive InputConnection");
+ return;
+ }
+ ic.beginBatchEdit();
return;
}
case DO_END_BATCH_EDIT: {
- mInputConnection.beginBatchEdit();
- return;
- }
- case DO_HIDE_STATUS_ICON: {
- mInputConnection.hideStatusIcon();
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "endBatchEdit on inactive InputConnection");
+ return;
+ }
+ ic.endBatchEdit();
return;
}
- case DO_SHOW_STATUS_ICON: {
- mInputConnection.showStatusIcon((String)msg.obj, msg.arg1);
+ case DO_REPORT_FULLSCREEN_MODE: {
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "showStatusIcon on inactive InputConnection");
+ return;
+ }
+ ic.reportFullscreenMode(msg.arg1 == 1);
return;
}
case DO_PERFORM_PRIVATE_COMMAND: {
+ InputConnection ic = mInputConnection.get();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "performPrivateCommand on inactive InputConnection");
+ return;
+ }
SomeArgs args = (SomeArgs)msg.obj;
- mInputConnection.performPrivateCommand((String)args.arg1,
+ ic.performPrivateCommand((String)args.arg1,
(Bundle)args.arg2);
return;
}
@@ -257,6 +377,13 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
return mH.obtainMessage(what, arg1, 0, args);
}
+ Message obtainMessageIISC(int what, int arg1, int arg2, int seq, IInputContextCallback callback) {
+ SomeArgs args = new SomeArgs();
+ args.callback = callback;
+ args.seq = seq;
+ return mH.obtainMessage(what, arg1, arg2, args);
+ }
+
Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq,
IInputContextCallback callback) {
SomeArgs args = new SomeArgs();
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index b048ce2..02cb9e4 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -29,9 +29,9 @@ import com.android.internal.view.IInputContextCallback;
* {@hide}
*/
oneway interface IInputContext {
- void getTextBeforeCursor(int length, int seq, IInputContextCallback callback);
+ void getTextBeforeCursor(int length, int flags, int seq, IInputContextCallback callback);
- void getTextAfterCursor(int length, int seq, IInputContextCallback callback);
+ void getTextAfterCursor(int length, int flags, int seq, IInputContextCallback callback);
void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback);
@@ -48,17 +48,21 @@ import com.android.internal.view.IInputContextCallback;
void commitCompletion(in CompletionInfo completion);
+ void setSelection(int start, int end);
+
+ void performEditorAction(int actionCode);
+
+ void performContextMenuAction(int id);
+
void beginBatchEdit();
void endBatchEdit();
+ void reportFullscreenMode(boolean enabled);
+
void sendKeyEvent(in KeyEvent event);
void clearMetaKeyStates(int states);
void performPrivateCommand(String action, in Bundle data);
-
- void showStatusIcon(String packageName, int resId);
-
- void hideStatusIcon();
}
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index f650713..8ff18ed 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -18,6 +18,7 @@ package com.android.internal.view;
import android.graphics.Rect;
import android.os.IBinder;
+import android.os.ResultReceiver;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
@@ -38,9 +39,9 @@ oneway interface IInputMethod {
void unbindInput();
- void startInput(in EditorInfo attribute);
+ void startInput(in IInputContext inputContext, in EditorInfo attribute);
- void restartInput(in EditorInfo attribute);
+ void restartInput(in IInputContext inputContext, in EditorInfo attribute);
void createSession(IInputMethodCallback callback);
@@ -48,7 +49,7 @@ oneway interface IInputMethod {
void revokeSession(IInputMethodSession session);
- void showSoftInput(boolean explicit);
+ void showSoftInput(int flags, in ResultReceiver resultReceiver);
- void hideSoftInput();
+ void hideSoftInput(int flags, in ResultReceiver resultReceiver);
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 2a15bdb..adec0a7 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -16,6 +16,7 @@
package com.android.internal.view;
+import android.os.ResultReceiver;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.EditorInfo;
import com.android.internal.view.InputBindResult;
@@ -35,18 +36,22 @@ interface IInputMethodManager {
void removeClient(in IInputMethodClient client);
InputBindResult startInput(in IInputMethodClient client,
- in EditorInfo attribute, boolean initial, boolean needResult);
+ IInputContext inputContext, in EditorInfo attribute,
+ boolean initial, boolean needResult);
void finishInput(in IInputMethodClient client);
- void showSoftInput(in IInputMethodClient client, int flags);
- void hideSoftInput(in IInputMethodClient client, int flags);
- void windowGainedFocus(in IInputMethodClient client,
+ boolean showSoftInput(in IInputMethodClient client, int flags,
+ in ResultReceiver resultReceiver);
+ boolean hideSoftInput(in IInputMethodClient client, int flags,
+ in ResultReceiver resultReceiver);
+ void windowGainedFocus(in IInputMethodClient client, in IBinder windowToken,
boolean viewHasFocus, boolean isTextEditor,
int softInputMode, boolean first, int windowFlags);
void showInputMethodPickerFromClient(in IInputMethodClient client);
void setInputMethod(in IBinder token, String id);
void hideMySoftInput(in IBinder token, int flags);
- void updateStatusIcon(int iconId, String iconPackage);
+ void showMySoftInput(in IBinder token, int flags);
+ void updateStatusIcon(in IBinder token, String packageName, int iconId);
boolean setInputMethodEnabled(String id, boolean enabled);
}
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index 8a44976..a05ff14 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -46,4 +46,6 @@ oneway interface IInputMethodSession {
void dispatchTrackballEvent(int seq, in MotionEvent event, IInputMethodCallback callback);
void appPrivateCommand(String action, in Bundle data);
+
+ void toggleSoftInput(int showFlags, int hideFlags);
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index a9ba5f6..b92cb45 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -151,11 +151,11 @@ public class InputConnectionWrapper implements InputConnection {
mIInputContext = inputContext;
}
- public CharSequence getTextAfterCursor(int length) {
+ public CharSequence getTextAfterCursor(int length, int flags) {
CharSequence value = null;
try {
InputContextCallback callback = InputContextCallback.getInstance();
- mIInputContext.getTextAfterCursor(length, callback.mSeq, callback);
+ mIInputContext.getTextAfterCursor(length, flags, callback.mSeq, callback);
synchronized (callback) {
callback.waitForResultLocked();
if (callback.mHaveValue) {
@@ -169,11 +169,11 @@ public class InputConnectionWrapper implements InputConnection {
return value;
}
- public CharSequence getTextBeforeCursor(int length) {
+ public CharSequence getTextBeforeCursor(int length, int flags) {
CharSequence value = null;
try {
InputContextCallback callback = InputContextCallback.getInstance();
- mIInputContext.getTextBeforeCursor(length, callback.mSeq, callback);
+ mIInputContext.getTextBeforeCursor(length, flags, callback.mSeq, callback);
synchronized (callback) {
callback.waitForResultLocked();
if (callback.mHaveValue) {
@@ -241,6 +241,33 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ public boolean setSelection(int start, int end) {
+ try {
+ mIInputContext.setSelection(start, end);
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ public boolean performEditorAction(int actionCode) {
+ try {
+ mIInputContext.performEditorAction(actionCode);
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ public boolean performContextMenuAction(int id) {
+ try {
+ mIInputContext.performContextMenuAction(id);
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
public boolean setComposingText(CharSequence text, int newCursorPosition) {
try {
mIInputContext.setComposingText(text, newCursorPosition);
@@ -304,18 +331,9 @@ public class InputConnectionWrapper implements InputConnection {
}
}
- public boolean hideStatusIcon() {
- try {
- mIInputContext.showStatusIcon(null, 0);
- return true;
- } catch (RemoteException e) {
- return false;
- }
- }
-
- public boolean showStatusIcon(String packageName, int resId) {
+ public boolean reportFullscreenMode(boolean enabled) {
try {
- mIInputContext.showStatusIcon(packageName, resId);
+ mIInputContext.reportFullscreenMode(enabled);
return true;
} catch (RemoteException e) {
return false;
diff --git a/core/java/com/android/internal/view/menu/ExpandedMenuView.java b/core/java/com/android/internal/view/menu/ExpandedMenuView.java
index c16c165..9e4b4ce 100644
--- a/core/java/com/android/internal/view/menu/ExpandedMenuView.java
+++ b/core/java/com/android/internal/view/menu/ExpandedMenuView.java
@@ -80,6 +80,11 @@ public final class ExpandedMenuView extends ListView implements ItemInvoker, Men
setChildrenDrawingCacheEnabled(false);
}
+ @Override
+ protected boolean recycleOnMeasure() {
+ return false;
+ }
+
public boolean invokeItem(MenuItemImpl item) {
return mMenu.performItemAction(item, 0);
}
diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java
index 558a4c3..9e1f2ae 100644
--- a/core/java/com/android/internal/view/menu/IconMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java
@@ -142,9 +142,6 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie
}
void setCaptionMode(boolean shortcut) {
-
- mShortcutCaptionMode = shortcut && (mItemData.shouldShowShortcut());
-
/*
* If there is no item model, don't do any of the below (for example,
* the 'More' item doesn't have a model)
@@ -153,6 +150,8 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie
return;
}
+ mShortcutCaptionMode = shortcut && (mItemData.shouldShowShortcut());
+
CharSequence text = mItemData.getTitleForItemView(this);
if (mShortcutCaptionMode) {
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index 32513cd..e155875 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -220,7 +220,7 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
mRadioButton =
(RadioButton) inflater.inflate(com.android.internal.R.layout.list_menu_item_radio,
this, false);
- addView(mRadioButton, 0);
+ addView(mRadioButton);
}
private void insertCheckBox() {
@@ -228,7 +228,7 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
mCheckBox =
(CheckBox) inflater.inflate(com.android.internal.R.layout.list_menu_item_checkbox,
this, false);
- addView(mCheckBox, 0);
+ addView(mCheckBox);
}
public boolean prefersCondensedTitle() {
diff --git a/core/java/com/android/internal/widget/EditStyledText.java b/core/java/com/android/internal/widget/EditStyledText.java
new file mode 100644
index 0000000..8a4675a
--- /dev/null
+++ b/core/java/com/android/internal/widget/EditStyledText.java
@@ -0,0 +1,931 @@
+/*
+ * 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.internal.widget;
+
+import android.app.AlertDialog.Builder;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.Html;
+import android.text.Spannable;
+import android.text.style.AbsoluteSizeSpan;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.ImageSpan;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.widget.EditText;
+
+/**
+ * EditStyledText extends EditText for managing the flow and status to edit
+ * the styled text. This manages the states and flows of editing, supports
+ * inserting image, import/export HTML.
+ */
+public class EditStyledText extends EditText {
+
+ private static final String LOG_TAG = "EditStyledText";
+ private static final boolean DBG = true;
+
+ /**
+ * The modes of editing actions.
+ */
+ /** The mode that no editing action is done. */
+ public static final int MODE_NOTHING = 0;
+ /** The mode of copy. */
+ public static final int MODE_COPY = 1;
+ /** The mode of paste. */
+ public static final int MODE_PASTE = 2;
+ /** The mode of changing size. */
+ public static final int MODE_SIZE = 3;
+ /** The mode of changing color. */
+ public static final int MODE_COLOR = 4;
+ /** The mode of selection. */
+ public static final int MODE_SELECT = 5;
+
+ /**
+ * The state of selection.
+ */
+ /** The state that selection isn't started. */
+ public static final int STATE_SELECT_OFF = 0;
+ /** The state that selection is started. */
+ public static final int STATE_SELECT_ON = 1;
+ /** The state that selection is done, but not fixed. */
+ public static final int STATE_SELECTED = 2;
+ /** The state that selection is done and not fixed. */
+ public static final int STATE_SELECT_FIX = 3;
+
+ /**
+ * The help message strings.
+ */
+ public static final int HINT_MSG_NULL = 0;
+ public static final int HINT_MSG_COPY_BUF_BLANK = 1;
+ public static final int HINT_MSG_SELECT_START = 2;
+ public static final int HINT_MSG_SELECT_END = 3;
+ public static final int HINT_MSG_PUSH_COMPETE = 4;
+
+ /**
+ * EditStyledTextInterface provides functions for notifying messages to
+ * calling class.
+ */
+ public interface EditStyledTextNotifier {
+ public void notifyHintMsg(int msgId);
+ }
+
+ private EditStyledTextNotifier mESTInterface;
+
+ /**
+ * EditStyledTextEditorManager manages the flow and status of each
+ * function for editing styled text.
+ */
+ private EditorManager mManager;
+ private StyledTextConverter mConverter;
+ private StyledTextToast mToast;
+
+ /**
+ * EditStyledText extends EditText for managing flow of each editing
+ * action.
+ */
+ public EditStyledText(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ public EditStyledText(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public EditStyledText(Context context) {
+ super(context);
+ init();
+ }
+
+ /**
+ * Set Notifier.
+ */
+ public void setNotifier(EditStyledTextNotifier estInterface) {
+ mESTInterface = estInterface;
+ }
+
+ /**
+ * Set Builder for AlertDialog.
+ *
+ * @param builder
+ * Builder for opening Alert Dialog.
+ */
+ public void setBuilder(Builder builder) {
+ mToast.setBuilder(builder);
+ }
+
+ /**
+ * Set Parameters for ColorAlertDialog.
+ *
+ * @param colortitle
+ * Title for Alert Dialog.
+ * @param colornames
+ * List of name of selecting color.
+ * @param colorints
+ * List of int of color.
+ */
+ public void setColorAlertParams(CharSequence colortitle,
+ CharSequence[] colornames, CharSequence[] colorints) {
+ mToast.setColorAlertParams(colortitle, colornames, colorints);
+ }
+
+ /**
+ * Set Parameters for SizeAlertDialog.
+ *
+ * @param sizetitle
+ * Title for Alert Dialog.
+ * @param sizenames
+ * List of name of selecting size.
+ * @param sizedisplayints
+ * List of int of size displayed in TextView.
+ * @param sizesendints
+ * List of int of size exported to HTML.
+ */
+ public void setSizeAlertParams(CharSequence sizetitle,
+ CharSequence[] sizenames, CharSequence[] sizedisplayints,
+ CharSequence[] sizesendints) {
+ mToast.setSizeAlertParams(sizetitle, sizenames, sizedisplayints,
+ sizesendints);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ final boolean superResult = super.onTouchEvent(event);
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onTouchEvent");
+ }
+ mManager.onTouchScreen();
+ }
+ return superResult;
+ }
+
+ /**
+ * Start editing. This function have to be called before other editing
+ * actions.
+ */
+ public void onStartEdit() {
+ mManager.onStartEdit();
+ }
+
+ /**
+ * End editing.
+ */
+ public void onEndEdit() {
+ mManager.onEndEdit();
+ }
+
+ /**
+ * Start "Copy" action.
+ */
+ public void onStartCopy() {
+ mManager.onStartCopy();
+ }
+
+ /**
+ * Start "Paste" action.
+ */
+ public void onStartPaste() {
+ mManager.onStartPaste();
+ }
+
+ /**
+ * Start changing "Size" action.
+ */
+ public void onStartSize() {
+ mManager.onStartSize();
+ }
+
+ /**
+ * Start changing "Color" action.
+ */
+ public void onStartColor() {
+ mManager.onStartColor();
+ }
+
+ /**
+ * Start "Select" action.
+ */
+ public void onStartSelect() {
+ mManager.onStartSelect();
+ }
+
+ /**
+ * Start "SelectAll" action.
+ */
+ public void onStartSelectAll() {
+ mManager.onStartSelectAll();
+ }
+
+ /**
+ * InsertImage to TextView by using URI
+ *
+ * @param uri
+ * URI of the iamge inserted to TextView.
+ */
+ public void onInsertImage(Uri uri) {
+ mManager.onInsertImage(uri);
+ }
+
+ /**
+ * InsertImage to TextView by using resource ID
+ *
+ * @param resId
+ * Resource ID of the iamge inserted to TextView.
+ */
+ public void onInsertImage(int resId) {
+ mManager.onInsertImage(resId);
+ }
+
+ /**
+ * Fix Selected Item.
+ */
+ public void fixSelectedItem() {
+ mManager.onFixSelectItem();
+ }
+
+ /**
+ * Set Size of the Item.
+ *
+ * @param size
+ * The size of the Item.
+ */
+ public void setItemSize(int size) {
+ mManager.setItemSize(size);
+ }
+
+ /**
+ * Set Color of the Item.
+ *
+ * @param color
+ * The color of the Item.
+ */
+ public void setItemColor(int color) {
+ mManager.setItemColor(color);
+ }
+
+ public void onShowColorAlert() {
+ mToast.onShowColorAlertDialog();
+ }
+
+ public void onShowSizeAlert() {
+ mToast.onShowSizeAlertDialog();
+ }
+
+ /**
+ * Check editing is started.
+ *
+ * @return Whether editing is started or not.
+ */
+ public boolean isEditting() {
+ return mManager.isEditting();
+ }
+
+ /**
+ * Get the mode of the action.
+ *
+ * @return The mode of the action.
+ */
+ public int getEditMode() {
+ return mManager.getEditMode();
+ }
+
+ /**
+ * Get the state of the selection.
+ *
+ * @return The state of the selection.
+ */
+ public int getSelectState() {
+ return mManager.getSelectState();
+ }
+
+ public String getBody() {
+ return mConverter.getConvertedBody();
+ }
+
+ /**
+ * Initialize members.
+ */
+ private void init() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- init");
+ requestFocus();
+ }
+ mManager = new EditorManager(this);
+ mConverter = new StyledTextConverter(this);
+ mToast = new StyledTextToast(this);
+ }
+
+ /**
+ * Notify hint messages what action is expected to calling class.
+ *
+ * @param msgId
+ * Id of the hint message.
+ */
+ private void setHintMessage(int msgId) {
+ if (mESTInterface != null) {
+ mESTInterface.notifyHintMsg(msgId);
+ }
+ }
+
+ @Override
+ public Bundle getInputExtras(boolean create) {
+ Bundle bundle = super.getInputExtras(create);
+ if (bundle != null) {
+ bundle.putBoolean("allowEmoji", true);
+ }
+ return bundle;
+ }
+
+ /**
+ * Object which manages the flow and status of editing actions.
+ */
+ private class EditorManager {
+ private boolean mEditFlag = false;
+ private int mMode = 0;
+ private int mState = 0;
+ private int mCurStart = 0;
+ private int mCurEnd = 0;
+ private EditStyledText mEST;
+ private Editable mTextSelectBuffer;
+ private CharSequence mTextCopyBufer;
+
+ EditorManager(EditStyledText est) {
+ mEST = est;
+ }
+
+ public void onStartEdit() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onEdit");
+ }
+ handleResetEdit();
+ }
+
+ public void onEndEdit() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onClickCancel");
+ }
+ handleCancel();
+ }
+
+ public void onStartCopy() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onClickCopy");
+ }
+ handleCopy();
+ }
+
+ public void onStartPaste() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onClickPaste");
+ }
+ handlePaste();
+ }
+
+ public void onStartSize() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onClickSize");
+ }
+ handleSize();
+ }
+
+ public void setItemSize(int size) {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onClickSizeItem");
+ }
+ if (mState == STATE_SELECTED || mState == STATE_SELECT_FIX) {
+ changeSizeSelectedText(size);
+ handleResetEdit();
+ }
+ }
+
+ public void setItemColor(int color) {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onClickColorItem");
+ }
+ if (mState == STATE_SELECTED || mState == STATE_SELECT_FIX) {
+ changeColorSelectedText(color);
+ handleResetEdit();
+ }
+ }
+
+ public void onStartColor() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onClickColor");
+ }
+ handleColor();
+ }
+
+ public void onStartSelect() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onClickSelect");
+ }
+ mMode = MODE_SELECT;
+ if (mState == STATE_SELECT_OFF) {
+ handleSelect();
+ } else {
+ offSelect();
+ handleSelect();
+ }
+ }
+
+ public void onStartSelectAll() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onClickSelectAll");
+ }
+ handleSelectAll();
+ }
+
+ public void onTouchScreen() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onClickView");
+ }
+ if (mState == STATE_SELECT_ON || mState == STATE_SELECTED) {
+ handleSelect();
+ }
+ }
+
+ public void onFixSelectItem() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onClickComplete");
+ }
+ handleComplete();
+ }
+
+ public void onInsertImage(Uri uri) {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onInsertImage by URI: " + uri.getPath()
+ + "," + uri.toString());
+ }
+
+ mEST.getText().append("a");
+ mEST.getText().setSpan(new ImageSpan(mEST.getContext(), uri),
+ mEST.getText().length() - 1, mEST.getText().length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+
+ public void onInsertImage(int resID) {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onInsertImage by resID");
+ }
+ mEST.getText().append("b");
+ mEST.getText().setSpan(new ImageSpan(mEST.getContext(), resID),
+ mEST.getText().length() - 1, mEST.getText().length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+
+ public boolean isEditting() {
+ return mEditFlag;
+ }
+
+ public int getEditMode() {
+ return mMode;
+ }
+
+ public int getSelectState() {
+ return mState;
+ }
+
+ private void handleCancel() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- handleCancel");
+ }
+ mMode = MODE_NOTHING;
+ mState = STATE_SELECT_OFF;
+ mEditFlag = false;
+ offSelect();
+ }
+
+ private void handleComplete() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- handleComplete");
+ }
+ if (!mEditFlag) {
+ return;
+ }
+ if (mState == STATE_SELECTED) {
+ mState = STATE_SELECT_FIX;
+ }
+ switch (mMode) {
+ case MODE_COPY:
+ handleCopy();
+ break;
+ case MODE_COLOR:
+ handleColor();
+ break;
+ case MODE_SIZE:
+ handleSize();
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void handleCopy() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- handleCopy: " + mMode + "," + mState);
+ }
+ if (!mEditFlag) {
+ return;
+ }
+ if (mMode == MODE_NOTHING || mMode == MODE_SELECT) {
+ mMode = MODE_COPY;
+ if (mState == STATE_SELECTED) {
+ mState = STATE_SELECT_FIX;
+ storeSelectedText();
+ } else {
+ handleSelect();
+ }
+ } else if (mMode != MODE_COPY) {
+ handleCancel();
+ mMode = MODE_COPY;
+ handleCopy();
+ } else if (mState == STATE_SELECT_FIX) {
+ mEST.setHintMessage(HINT_MSG_NULL);
+ storeSelectedText();
+ handleResetEdit();
+ }
+ }
+
+ private void handlePaste() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- handlePaste");
+ }
+ if (!mEditFlag) {
+ return;
+ }
+ if (mTextSelectBuffer != null && mTextCopyBufer.length() > 0) {
+ mTextSelectBuffer.insert(mEST.getSelectionStart(),
+ mTextCopyBufer);
+ } else {
+ mEST.setHintMessage(HINT_MSG_COPY_BUF_BLANK);
+ }
+ }
+
+ private void handleSize() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- handleSize: " + mMode + "," + mState);
+ }
+ if (!mEditFlag) {
+ Log.e(LOG_TAG, "--- Editing is not started for handlesize.");
+ return;
+ }
+ if (mMode == MODE_NOTHING || mMode == MODE_SELECT) {
+ mMode = MODE_SIZE;
+ if (mState == STATE_SELECTED) {
+ mState = STATE_SELECT_FIX;
+ handleSize();
+ } else {
+ handleSelect();
+ }
+ } else if (mMode != MODE_SIZE) {
+ handleCancel();
+ mMode = MODE_SIZE;
+ handleSize();
+ } else {
+ if (mState == STATE_SELECT_FIX) {
+ mEST.setHintMessage(HINT_MSG_NULL);
+ mEST.onShowSizeAlert();
+ } else {
+ Log.d(LOG_TAG, "--- handlesize: do nothing");
+ }
+ }
+ }
+
+ private void handleColor() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- handleSize: " + mMode + "," + mState);
+ }
+ if (!mEditFlag) {
+ Log.e(LOG_TAG, "--- Editing is not started for handlecolor.");
+ return;
+ }
+ if (mMode == MODE_NOTHING || mMode == MODE_SELECT) {
+ mMode = MODE_COLOR;
+ if (mState == STATE_SELECTED) {
+ mState = STATE_SELECT_FIX;
+ handleColor();
+ } else {
+ handleSelect();
+ }
+ } else if (mMode != MODE_COLOR) {
+ handleCancel();
+ mMode = MODE_COLOR;
+ handleSize();
+ } else {
+ if (mState == STATE_SELECT_FIX) {
+ mEST.setHintMessage(HINT_MSG_NULL);
+ mEST.onShowColorAlert();
+ } else {
+ Log.d(LOG_TAG, "--- handlecolor: do nothing");
+ }
+ }
+ }
+
+ private void handleSelect() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- handleSelect:" + mEditFlag + "," + mState);
+ }
+ if (!mEditFlag) {
+ return;
+ }
+ if (mState == STATE_SELECT_OFF) {
+ if (isTextSelected()) {
+ Log.e(LOG_TAG, "Selection is off, but selected");
+ }
+ setSelectStartPos();
+ mEST.setHintMessage(HINT_MSG_SELECT_END);
+ } else if (mState == STATE_SELECT_ON) {
+ if (isTextSelected()) {
+ Log.e(LOG_TAG, "Selection now start, but selected");
+ }
+ setSelectEndPos();
+ mEST.setHintMessage(HINT_MSG_PUSH_COMPETE);
+ doNextHandle();
+ } else if (mState == STATE_SELECTED) {
+ if (!isTextSelected()) {
+ Log.e(LOG_TAG, "Selection is done, but not selected");
+ }
+ setSelectEndPos();
+ doNextHandle();
+ }
+ }
+
+ private void handleSelectAll() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- handleSelectAll");
+ }
+ if (!mEditFlag) {
+ return;
+ }
+ mEST.selectAll();
+ }
+
+ private void doNextHandle() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- doNextHandle: " + mMode + "," + mState);
+ }
+ switch (mMode) {
+ case MODE_COPY:
+ handleCopy();
+ break;
+ case MODE_PASTE:
+ handlePaste();
+ break;
+ case MODE_SIZE:
+ handleSize();
+ break;
+ case MODE_COLOR:
+ handleColor();
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void handleResetEdit() {
+ if (DBG) {
+ Log.d(LOG_TAG, "Reset Editor");
+ }
+ handleCancel();
+ mEditFlag = true;
+ mEST.setHintMessage(HINT_MSG_SELECT_START);
+ }
+
+ // Methods of selection
+ private void onSelect() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onSelect:" + mCurStart + "," + mCurEnd);
+ }
+ if (mCurStart >= 0 && mCurStart <= mEST.getText().length()
+ && mCurEnd >= 0 && mCurEnd <= mEST.getText().length()) {
+ mEST.setSelection(mCurStart, mCurEnd);
+ mState = STATE_SELECTED;
+ } else {
+ Log.e(LOG_TAG,
+ "Select is on, but cursor positions are illigal.:"
+ + mEST.getText().length() + "," + mCurStart
+ + "," + mCurEnd);
+ }
+ }
+
+ private void offSelect() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- offSelect");
+ }
+ int currpos = mEST.getSelectionStart();
+ mEST.setSelection(currpos, currpos);
+ mState = STATE_SELECT_OFF;
+ }
+
+ private void setSelectStartPos() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- setSelectStartPos");
+ }
+ mCurStart = mEST.getSelectionStart();
+ mState = STATE_SELECT_ON;
+ }
+
+ private void setSelectEndPos() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- setSelectEndPos:"
+ + mEST.getSelectionStart());
+ }
+ int curpos = mEST.getSelectionStart();
+ if (curpos < mCurStart) {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- setSelectEndPos: swap is done.");
+ }
+ mCurEnd = mCurStart;
+ mCurStart = curpos;
+ } else {
+ mCurEnd = curpos;
+ }
+ onSelect();
+ }
+
+ private boolean isTextSelected() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- isTextSelected:" + mCurStart + ","
+ + mCurEnd);
+ }
+ return (mCurStart != mCurEnd)
+ && (mState == STATE_SELECTED ||
+ mState == STATE_SELECT_FIX);
+ }
+
+ private void storeSelectedText() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- storeSelectedText");
+ }
+ mTextSelectBuffer = mEST.getText();
+ mTextCopyBufer = mTextSelectBuffer.subSequence(mCurStart, mCurEnd);
+ }
+
+ private void changeSizeSelectedText(int size) {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- changeSizeSelectedText:" + size + ","
+ + mCurStart + "," + mCurEnd);
+ }
+ mEST.getText().setSpan(new AbsoluteSizeSpan(size), mCurStart,
+ mCurEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+
+ private void changeColorSelectedText(int color) {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- changeCollorSelectedText:" + color + ","
+ + mCurStart + "," + mCurEnd);
+ }
+ mEST.getText().setSpan(new ForegroundColorSpan(color), mCurStart,
+ mCurEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ private class StyledTextConverter {
+ private EditStyledText mEST;
+
+ public StyledTextConverter(EditStyledText est) {
+ mEST = est;
+ }
+
+ public String getConvertedBody() {
+ String htmlBody = Html.toHtml(mEST.getText());
+ return htmlBody;
+ }
+ }
+
+ private class StyledTextToast {
+ Builder mBuilder;
+ CharSequence mColorTitle;
+ CharSequence mSizeTitle;
+ CharSequence[] mColorNames;
+ CharSequence[] mColorInts;
+ CharSequence[] mSizeNames;
+ CharSequence[] mSizeDisplayInts;
+ CharSequence[] mSizeSendInts;
+ EditStyledText mEST;
+
+ public StyledTextToast(EditStyledText est) {
+ mEST = est;
+ }
+
+ public void setBuilder(Builder builder) {
+ mBuilder = builder;
+ }
+
+ public void setColorAlertParams(CharSequence colortitle,
+ CharSequence[] colornames, CharSequence[] colorints) {
+ mColorTitle = colortitle;
+ mColorNames = colornames;
+ mColorInts = colorints;
+ }
+
+ public void setSizeAlertParams(CharSequence sizetitle,
+ CharSequence[] sizenames, CharSequence[] sizedisplayints,
+ CharSequence[] sizesendints) {
+ mSizeTitle = sizetitle;
+ mSizeNames = sizenames;
+ mSizeDisplayInts = sizedisplayints;
+ mSizeSendInts = sizesendints;
+ }
+
+ public boolean checkColorAlertParams() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- checkParams");
+ }
+ if (mBuilder == null) {
+ Log.e(LOG_TAG, "--- builder is null.");
+ return false;
+ } else if (mColorTitle == null || mColorNames == null
+ || mColorInts == null) {
+ Log.e(LOG_TAG, "--- color alert params are null.");
+ return false;
+ } else if (mColorNames.length != mColorInts.length) {
+ Log.e(LOG_TAG, "--- the length of color alert params are "
+ + "different.");
+ return false;
+ }
+ return true;
+ }
+
+ public boolean checkSizeAlertParams() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- checkParams");
+ }
+ if (mBuilder == null) {
+ Log.e(LOG_TAG, "--- builder is null.");
+ } else if (mSizeTitle == null || mSizeNames == null
+ || mSizeDisplayInts == null || mSizeSendInts == null) {
+ Log.e(LOG_TAG, "--- size alert params are null.");
+ } else if (mSizeNames.length != mSizeDisplayInts.length
+ && mSizeSendInts.length != mSizeDisplayInts.length) {
+ Log.e(LOG_TAG, "--- the length of size alert params are "
+ + "different.");
+ }
+ return true;
+ }
+
+ private void onShowColorAlertDialog() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onShowAlertDialog");
+ }
+ if (!checkColorAlertParams()) {
+ return;
+ }
+ mBuilder.setTitle(mColorTitle);
+ mBuilder.setIcon(0);
+ mBuilder.
+ setItems(mColorNames,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ Log.d("EETVM", "mBuilder.onclick:" + which);
+ int color = Integer.parseInt(
+ (String) mColorInts[which], 16) - 0x01000000;
+ mEST.setItemColor(color);
+ }
+ });
+ mBuilder.show();
+ }
+
+ private void onShowSizeAlertDialog() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onShowAlertDialog");
+ }
+ if (!checkColorAlertParams()) {
+ return;
+ }
+ mBuilder.setTitle(mSizeTitle);
+ mBuilder.setIcon(0);
+ mBuilder.
+ setItems(mSizeNames,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ Log.d("EETVM", "mBuilder.onclick:" + which);
+ int size = Integer
+ .parseInt((String) mSizeDisplayInts[which]);
+ mEST.setItemSize(size);
+ }
+ });
+ mBuilder.show();
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index a2673a5..f2ec064 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -16,175 +16,87 @@
package com.android.internal.widget;
-import android.content.res.TypedArray;
import android.os.Bundle;
-import android.os.Handler;
import android.text.Editable;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.TextUtils;
import android.text.method.KeyListener;
import android.util.Log;
-import android.util.LogPrinter;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.widget.TextView;
-class ComposingText {
-}
-
public class EditableInputConnection extends BaseInputConnection {
private static final boolean DEBUG = false;
private static final String TAG = "EditableInputConnection";
- public static final Object COMPOSING = new ComposingText();
-
private final TextView mTextView;
- private Object[] mDefaultComposingSpans;
-
public EditableInputConnection(TextView textview) {
- super(textview);
+ super(textview, false);
mTextView = textview;
}
- public static final void removeComposingSpans(Spannable text) {
- text.removeSpan(COMPOSING);
- Object[] sps = text.getSpans(0, text.length(), Object.class);
- if (sps != null) {
- for (int i=sps.length-1; i>=0; i--) {
- Object o = sps[i];
- if ((text.getSpanFlags(o)&Spanned.SPAN_COMPOSING) != 0) {
- text.removeSpan(o);
- }
- }
- }
- }
-
- public static void setComposingSpans(Spannable text) {
- final Object[] sps = text.getSpans(0, text.length(), Object.class);
- if (sps != null) {
- for (int i=sps.length-1; i>=0; i--) {
- final Object o = sps[i];
- if (o == COMPOSING) {
- text.removeSpan(o);
- continue;
- }
- final int fl = text.getSpanFlags(o);
- if ((fl&(Spanned.SPAN_COMPOSING|Spanned.SPAN_POINT_MARK_MASK))
- != (Spanned.SPAN_COMPOSING|Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)) {
- text.setSpan(o, text.getSpanStart(o), text.getSpanEnd(o),
- (fl&Spanned.SPAN_POINT_MARK_MASK)
- | Spanned.SPAN_COMPOSING
- | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
+ public Editable getEditable() {
+ TextView tv = mTextView;
+ if (tv != null) {
+ return tv.getEditableText();
}
-
- text.setSpan(COMPOSING, 0, text.length(),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
- }
-
- public static int getComposingSpanStart(Spannable text) {
- return text.getSpanStart(COMPOSING);
+ return null;
}
- public static int getComposingSpanEnd(Spannable text) {
- return text.getSpanEnd(COMPOSING);
+ public boolean beginBatchEdit() {
+ mTextView.beginBatchEdit();
+ return true;
}
- public boolean setComposingText(CharSequence text, int newCursorPosition) {
- if (DEBUG) Log.v(TAG, "setComposingText " + text);
- replaceText(text, newCursorPosition, true);
+ public boolean endBatchEdit() {
+ mTextView.endBatchEdit();
return true;
}
-
- public boolean finishComposingText() {
- if (DEBUG) Log.v(TAG, "finishComposingText");
+
+ public boolean clearMetaKeyStates(int states) {
final Editable content = getEditable();
- if (content != null) {
- removeComposingSpans(content);
+ if (content == null) return false;
+ KeyListener kl = mTextView.getKeyListener();
+ if (kl != null) {
+ try {
+ kl.clearMetaKeyState(mTextView, content, states);
+ } catch (AbstractMethodError e) {
+ // This is an old listener that doesn't implement the
+ // new method.
+ }
}
return true;
}
- public boolean commitText(CharSequence text, int newCursorPosition) {
- if (DEBUG) Log.v(TAG, "commitText " + text);
- replaceText(text, newCursorPosition, false);
- return true;
- }
-
public boolean commitCompletion(CompletionInfo text) {
if (DEBUG) Log.v(TAG, "commitCompletion " + text);
+ mTextView.beginBatchEdit();
mTextView.onCommitCompletion(text);
+ mTextView.endBatchEdit();
return true;
}
- public CharSequence getTextBeforeCursor(int length) {
- final Editable content = getEditable();
- if (content == null) return null;
-
- int a = Selection.getSelectionStart(content);
- int b = Selection.getSelectionEnd(content);
-
- if (a > b) {
- int tmp = a;
- a = b;
- b = tmp;
- }
-
- if (length > a) {
- length = a;
- }
-
- return content.subSequence(a - length, a);
- }
-
- public CharSequence getTextAfterCursor(int length) {
- final Editable content = getEditable();
- if (content == null) return null;
-
- int a = Selection.getSelectionStart(content);
- int b = Selection.getSelectionEnd(content);
-
- if (a > b) {
- int tmp = a;
- a = b;
- b = tmp;
- }
-
- if (b + length > content.length()) {
- length = content.length() - b;
- }
-
- return content.subSequence(b, b + length);
+ public boolean performEditorAction(int actionCode) {
+ if (DEBUG) Log.v(TAG, "performEditorAction " + actionCode);
+ mTextView.onEditorAction(actionCode);
+ return true;
}
-
- public int getCursorCapsMode(int reqModes) {
- final Editable content = getEditable();
- if (content == null) return 0;
-
- int a = Selection.getSelectionStart(content);
- int b = Selection.getSelectionEnd(content);
-
- if (a > b) {
- int tmp = a;
- a = b;
- b = tmp;
- }
-
- return TextUtils.getCapsMode(content, a, reqModes);
+
+ public boolean performContextMenuAction(int id) {
+ if (DEBUG) Log.v(TAG, "performContextMenuAction " + id);
+ mTextView.beginBatchEdit();
+ mTextView.onTextContextMenuItem(id);
+ mTextView.endBatchEdit();
+ return true;
}
public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
if (mTextView != null) {
ExtractedText et = new ExtractedText();
if (mTextView.extractText(request, et)) {
- if ((flags&EXTRACTED_TEXT_MONITOR) != 0) {
+ if ((flags&GET_EXTRACTED_TEXT_MONITOR) != 0) {
mTextView.setExtracting(request);
}
return et;
@@ -193,173 +105,25 @@ public class EditableInputConnection extends BaseInputConnection {
return null;
}
- public boolean deleteSurroundingText(int leftLength, int rightLength) {
- if (DEBUG) Log.v(TAG, "deleteSurroundingText " + leftLength
- + " / " + rightLength);
- final Editable content = getEditable();
- if (content == null) return false;
-
- int a = Selection.getSelectionStart(content);
- int b = Selection.getSelectionEnd(content);
-
- if (a > b) {
- int tmp = a;
- a = b;
- b = tmp;
- }
-
- // ignore the composing text.
- int ca = content.getSpanStart(COMPOSING);
- int cb = content.getSpanEnd(COMPOSING);
- if (cb < ca) {
- int tmp = ca;
- ca = cb;
- cb = tmp;
- }
- if (ca != -1 && cb != -1) {
- if (ca < a) a = ca;
- if (cb > b) b = cb;
- }
-
- int deleted = 0;
-
- if (leftLength > 0) {
- int start = a - leftLength;
- if (start < 0) start = 0;
- content.delete(start, a);
- deleted = a - start;
- }
-
- if (rightLength > 0) {
- b = b - deleted;
-
- int end = b + rightLength;
- if (end > content.length()) end = content.length();
-
- content.delete(b, end);
- }
-
- return true;
- }
-
- public boolean beginBatchEdit() {
- if (mTextView == null) return false;
- mTextView.onBeginBatchEdit();
- return true;
- }
-
- public boolean endBatchEdit() {
- if (mTextView == null) return false;
- mTextView.onEndBatchEdit();
- return true;
- }
-
- public boolean clearMetaKeyStates(int states) {
- final Editable content = getEditable();
- if (content == null) return false;
- KeyListener kl = mTextView.getKeyListener();
- if (kl != null) kl.clearMetaKeyState(mTextView, content, states);
- return true;
- }
-
public boolean performPrivateCommand(String action, Bundle data) {
- if (mTextView == null) return false;
mTextView.onPrivateIMECommand(action, data);
return true;
}
-
- private Editable getEditable() {
- TextView tv = mTextView;
- if (tv != null) {
- return tv.getEditableText();
- }
- return null;
- }
-
- private void replaceText(CharSequence text, int newCursorPosition,
- boolean composing) {
- final Editable content = getEditable();
-
- // delete composing text set previously.
- int a = content.getSpanStart(COMPOSING);
- int b = content.getSpanEnd(COMPOSING);
- if (DEBUG) Log.v(TAG, "Composing span: " + a + " to " + b);
-
- if (b < a) {
- int tmp = a;
- a = b;
- b = tmp;
+ @Override
+ public boolean commitText(CharSequence text, int newCursorPosition) {
+ if (mTextView == null) {
+ return super.commitText(text, newCursorPosition);
}
- if (a != -1 && b != -1) {
- removeComposingSpans(content);
- } else {
- a = Selection.getSelectionStart(content);
- b = Selection.getSelectionEnd(content);
- if (a >=0 && b>= 0 && a != b) {
- if (b < a) {
- int tmp = a;
- a = b;
- b = tmp;
- }
- }
- }
+ CharSequence errorBefore = mTextView.getError();
+ boolean success = super.commitText(text, newCursorPosition);
+ CharSequence errorAfter = mTextView.getError();
- if (composing) {
- Spannable sp = null;
- if (!(text instanceof Spannable)) {
- sp = new SpannableStringBuilder(text);
- text = sp;
- if (mDefaultComposingSpans == null) {
- TypedArray ta = mTextView.getContext().getTheme()
- .obtainStyledAttributes(new int[] {
- com.android.internal.R.attr.candidatesTextStyleSpans
- });
- CharSequence style = ta.getText(0);
- ta.recycle();
- if (style != null && style instanceof Spanned) {
- mDefaultComposingSpans = ((Spanned)style).getSpans(
- 0, style.length(), Object.class);
- }
- }
- if (mDefaultComposingSpans != null) {
- for (int i = 0; i < mDefaultComposingSpans.length; ++i) {
- sp.setSpan(mDefaultComposingSpans[i], 0, sp.length(),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- } else {
- sp = (Spannable)text;
- }
- setComposingSpans(sp);
+ if (errorAfter != null && errorBefore == errorAfter) {
+ mTextView.setError(null, null);
}
-
- // Adjust newCursorPosition to be relative the start of the text.
- newCursorPosition += a;
- if (DEBUG) Log.v(TAG, "Replacing from " + a + " to " + b + " with \""
- + text + "\", composing=" + composing
- + ", type=" + text.getClass().getCanonicalName());
-
- if (DEBUG) {
- LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG);
- lp.println("Current text:");
- TextUtils.dumpSpans(content, lp, " ");
- lp.println("Composing text:");
- TextUtils.dumpSpans(text, lp, " ");
- }
-
- content.replace(a, b, text);
- if (newCursorPosition < 0) newCursorPosition = 0;
- if (newCursorPosition > content.length())
- newCursorPosition = content.length();
- Selection.setSelection(content, newCursorPosition);
-
- if (DEBUG) {
- LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG);
- lp.println("Final text:");
- TextUtils.dumpSpans(content, lp, " ");
- }
+ return success;
}
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index ed1cd58..f0b311c 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -77,11 +77,11 @@ public class LockPatternUtils {
public static final int MIN_PATTERN_REGISTER_FAIL = 3;
private final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
+ private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
+ private final static String PATTERN_EVER_CHOSEN = "lockscreen.patterneverchosen";
private final ContentResolver mContentResolver;
- private long mLockoutDeadline = 0;
-
private static String sLockPatternFilename;
/**
@@ -140,6 +140,16 @@ public class LockPatternUtils {
}
/**
+ * Return true if the user has ever chosen a pattern. This is true even if the pattern is
+ * currently cleared.
+ *
+ * @return True if the user has ever chosen a pattern.
+ */
+ public boolean isPatternEverChosen() {
+ return getBoolean(PATTERN_EVER_CHOSEN);
+ }
+
+ /**
* Save a lock pattern.
* @param pattern The new pattern to save.
*/
@@ -156,6 +166,7 @@ public class LockPatternUtils {
raf.write(hash, 0, hash.length);
}
raf.close();
+ setBoolean(PATTERN_EVER_CHOSEN, true);
} catch (FileNotFoundException fnfe) {
// Cant do much, unless we want to fail over to using the settings provider
Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename);
@@ -270,12 +281,14 @@ public class LockPatternUtils {
}
/**
- * Store the lockout deadline, meaning the user can't attempt his/her unlock
- * pattern until the deadline has passed. Does not persist across reboots.
- * @param deadline The elapsed real time in millis in future.
+ * Set and store the lockout deadline, meaning the user can't attempt his/her unlock
+ * pattern until the deadline has passed.
+ * @return the chosen deadline.
*/
- public void setLockoutAttemptDeadline(long deadline) {
- mLockoutDeadline = deadline;
+ public long setLockoutAttemptDeadline() {
+ final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
+ setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline);
+ return deadline;
}
/**
@@ -284,7 +297,12 @@ public class LockPatternUtils {
* enter a pattern.
*/
public long getLockoutAttemptDeadline() {
- return (mLockoutDeadline <= SystemClock.elapsedRealtime()) ? 0 : mLockoutDeadline;
+ final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L);
+ final long now = SystemClock.elapsedRealtime();
+ if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
+ return 0L;
+ }
+ return deadline;
}
/**
@@ -341,5 +359,13 @@ public class LockPatternUtils {
enabled ? 1 : 0);
}
+ private long getLong(String systemSettingKey, long def) {
+ return android.provider.Settings.System.getLong(mContentResolver, systemSettingKey, def);
+ }
+
+ private void setLong(String systemSettingKey, long value) {
+ android.provider.Settings.System.putLong(mContentResolver, systemSettingKey, value);
+ }
+
}
diff --git a/core/java/com/android/internal/widget/NumberPicker.java b/core/java/com/android/internal/widget/NumberPicker.java
index 20ea6a6..2f08c8d 100644
--- a/core/java/com/android/internal/widget/NumberPicker.java
+++ b/core/java/com/android/internal/widget/NumberPicker.java
@@ -28,12 +28,9 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnLongClickListener;
-import android.view.animation.Animation;
-import android.view.animation.TranslateAnimation;
-import android.widget.EditText;
-import android.widget.LinearLayout;
import android.widget.TextView;
-import android.widget.ViewSwitcher;
+import android.widget.LinearLayout;
+import android.widget.EditText;
import com.android.internal.R;
@@ -71,25 +68,18 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
private final Runnable mRunnable = new Runnable() {
public void run() {
if (mIncrement) {
- changeCurrent(mCurrent + 1, mSlideUpInAnimation, mSlideUpOutAnimation);
+ changeCurrent(mCurrent + 1);
mHandler.postDelayed(this, mSpeed);
} else if (mDecrement) {
- changeCurrent(mCurrent - 1, mSlideDownInAnimation, mSlideDownOutAnimation);
+ changeCurrent(mCurrent - 1);
mHandler.postDelayed(this, mSpeed);
}
}
};
-
- private final LayoutInflater mInflater;
- private final TextView mText;
- private final InputFilter mInputFilter;
+
+ private final EditText mText;
private final InputFilter mNumberInputFilter;
-
- private final Animation mSlideUpOutAnimation;
- private final Animation mSlideUpInAnimation;
- private final Animation mSlideDownOutAnimation;
- private final Animation mSlideDownInAnimation;
-
+
private String[] mDisplayedValues;
private int mStart;
private int mEnd;
@@ -110,14 +100,14 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
this(context, attrs, 0);
}
- public NumberPicker(Context context, AttributeSet attrs,
- int defStyle) {
+ @SuppressWarnings({"UnusedDeclaration"})
+ public NumberPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
setOrientation(VERTICAL);
- mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mInflater.inflate(R.layout.number_picker, this, true);
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.number_picker, this, true);
mHandler = new Handler();
- mInputFilter = new NumberPickerInputFilter();
+ InputFilter inputFilter = new NumberPickerInputFilter();
mNumberInputFilter = new NumberRangeKeyListener();
mIncrementButton = (NumberPickerButton) findViewById(R.id.increment);
mIncrementButton.setOnClickListener(this);
@@ -128,32 +118,11 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
mDecrementButton.setOnLongClickListener(this);
mDecrementButton.setNumberPicker(this);
- mText = (TextView) findViewById(R.id.timepicker_input);
+ mText = (EditText) findViewById(R.id.timepicker_input);
mText.setOnFocusChangeListener(this);
- mText.setFilters(new InputFilter[] { mInputFilter });
+ mText.setFilters(new InputFilter[] {inputFilter});
mText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
-
- mSlideUpOutAnimation = new TranslateAnimation(
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
- 0, Animation.RELATIVE_TO_SELF, 0,
- Animation.RELATIVE_TO_SELF, -100);
- mSlideUpOutAnimation.setDuration(200);
- mSlideUpInAnimation = new TranslateAnimation(
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
- 0, Animation.RELATIVE_TO_SELF, 100,
- Animation.RELATIVE_TO_SELF, 0);
- mSlideUpInAnimation.setDuration(200);
- mSlideDownOutAnimation = new TranslateAnimation(
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
- 0, Animation.RELATIVE_TO_SELF, 0,
- Animation.RELATIVE_TO_SELF, 100);
- mSlideDownOutAnimation.setDuration(200);
- mSlideDownInAnimation = new TranslateAnimation(
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,
- 0, Animation.RELATIVE_TO_SELF, -100,
- Animation.RELATIVE_TO_SELF, 0);
- mSlideDownInAnimation.setDuration(200);
-
+
if (!isEnabled()) {
setEnabled(false);
}
@@ -220,17 +189,14 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
}
public void onClick(View v) {
-
- /* The text view may still have focus so clear it's focus which will
- * trigger the on focus changed and any typed values to be pulled.
- */
- mText.clearFocus();
+ validateInput(mText);
+ if (!mText.hasFocus()) mText.requestFocus();
// now perform the increment/decrement
if (R.id.increment == v.getId()) {
- changeCurrent(mCurrent + 1, mSlideUpInAnimation, mSlideUpOutAnimation);
+ changeCurrent(mCurrent + 1);
} else if (R.id.decrement == v.getId()) {
- changeCurrent(mCurrent - 1, mSlideDownInAnimation, mSlideDownOutAnimation);
+ changeCurrent(mCurrent - 1);
}
}
@@ -240,7 +206,7 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
: String.valueOf(value);
}
- private void changeCurrent(int current, Animation in, Animation out) {
+ private void changeCurrent(int current) {
// Wrap around the values if we go past the start or end
if (current > mEnd) {
@@ -271,6 +237,7 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
} else {
mText.setText(mDisplayedValues[mCurrent - mStart]);
}
+ mText.setSelection(mText.getText().length());
}
private void validateCurrentView(CharSequence str) {
@@ -289,16 +256,20 @@ public class NumberPicker extends LinearLayout implements OnClickListener,
* has valid values.
*/
if (!hasFocus) {
- String str = String.valueOf(((TextView) v).getText());
- if ("".equals(str)) {
-
- // Restore to the old value as we don't allow empty values
- updateView();
- } else {
-
- // Check the new value and ensure it's in range
- validateCurrentView(str);
- }
+ validateInput(v);
+ }
+ }
+
+ private void validateInput(View v) {
+ String str = String.valueOf(((TextView) v).getText());
+ if ("".equals(str)) {
+
+ // Restore to the old value as we don't allow empty values
+ updateView();
+ } else {
+
+ // Check the new value and ensure it's in range
+ validateCurrentView(str);
}
}
diff --git a/core/java/com/android/internal/widget/TextProgressBar.java b/core/java/com/android/internal/widget/TextProgressBar.java
new file mode 100644
index 0000000..aee7b76
--- /dev/null
+++ b/core/java/com/android/internal/widget/TextProgressBar.java
@@ -0,0 +1,180 @@
+/*
+ * 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.internal.widget;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Chronometer;
+import android.widget.Chronometer.OnChronometerTickListener;
+import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
+import android.widget.RemoteViews.RemoteView;
+
+/**
+ * Container that links together a {@link ProgressBar} and {@link Chronometer}
+ * as children. It subscribes to {@link Chronometer#OnChronometerTickListener}
+ * and updates the {@link ProgressBar} based on a preset finishing time.
+ * <p>
+ * This widget expects to contain two children with specific ids
+ * {@link android.R.id.progress} and {@link android.R.id.text1}.
+ * <p>
+ * If the {@link Chronometer} {@link android.R.attr#layout_width} is
+ * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}, then the
+ * {@link android.R.attr#gravity} will be used to automatically move it with
+ * respect to the {@link ProgressBar} position. For example, if
+ * {@link android.view.Gravity#LEFT} then the {@link Chronometer} will be placed
+ * just ahead of the leading edge of the {@link ProgressBar} position.
+ */
+@RemoteView
+public class TextProgressBar extends RelativeLayout implements OnChronometerTickListener {
+ public static final String TAG = "TextProgressBar";
+
+ static final int CHRONOMETER_ID = android.R.id.text1;
+ static final int PROGRESSBAR_ID = android.R.id.progress;
+
+ Chronometer mChronometer = null;
+ ProgressBar mProgressBar = null;
+
+ long mDurationBase = -1;
+ int mDuration = -1;
+
+ boolean mChronometerFollow = false;
+ int mChronometerGravity = Gravity.NO_GRAVITY;
+
+ public TextProgressBar(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public TextProgressBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public TextProgressBar(Context context) {
+ super(context);
+ }
+
+ /**
+ * Catch any interesting children when they are added.
+ */
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ super.addView(child, index, params);
+
+ int childId = child.getId();
+ if (childId == CHRONOMETER_ID && child instanceof Chronometer) {
+ mChronometer = (Chronometer) child;
+ mChronometer.setOnChronometerTickListener(this);
+
+ // Check if Chronometer should move with with ProgressBar
+ mChronometerFollow = (params.width == ViewGroup.LayoutParams.WRAP_CONTENT);
+ mChronometerGravity = (mChronometer.getGravity() & Gravity.HORIZONTAL_GRAVITY_MASK);
+
+ } else if (childId == PROGRESSBAR_ID && child instanceof ProgressBar) {
+ mProgressBar = (ProgressBar) child;
+ }
+ }
+
+ /**
+ * Set the expected termination time of the running {@link Chronometer}.
+ * This value is used to adjust the {@link ProgressBar} against the elapsed
+ * time.
+ * <p>
+ * Call this <b>after</b> adjusting the {@link Chronometer} base, if
+ * necessary.
+ *
+ * @param durationBase Use the {@link SystemClock#elapsedRealtime} time
+ * base.
+ */
+ @android.view.RemotableViewMethod
+ public void setDurationBase(long durationBase) {
+ mDurationBase = durationBase;
+
+ if (mProgressBar == null || mChronometer == null) {
+ throw new RuntimeException("Expecting child ProgressBar with id " +
+ "'android.R.id.progress' and Chronometer id 'android.R.id.text1'");
+ }
+
+ // Update the ProgressBar maximum relative to Chronometer base
+ mDuration = (int) (durationBase - mChronometer.getBase());
+ if (mDuration <= 0) {
+ mDuration = 1;
+ }
+ mProgressBar.setMax(mDuration);
+ }
+
+ /**
+ * Callback when {@link Chronometer} changes, indicating that we should
+ * update the {@link ProgressBar} and change the layout if necessary.
+ */
+ public void onChronometerTick(Chronometer chronometer) {
+ if (mProgressBar == null) {
+ throw new RuntimeException(
+ "Expecting child ProgressBar with id 'android.R.id.progress'");
+ }
+
+ // Stop Chronometer if we're past duration
+ long now = SystemClock.elapsedRealtime();
+ if (now >= mDurationBase) {
+ mChronometer.stop();
+ }
+
+ // Update the ProgressBar status
+ int remaining = (int) (mDurationBase - now);
+ mProgressBar.setProgress(mDuration - remaining);
+
+ // Move the Chronometer if gravity is set correctly
+ if (mChronometerFollow) {
+ RelativeLayout.LayoutParams params;
+
+ // Calculate estimate of ProgressBar leading edge position
+ params = (RelativeLayout.LayoutParams) mProgressBar.getLayoutParams();
+ int contentWidth = mProgressBar.getWidth() - (params.leftMargin + params.rightMargin);
+ int leadingEdge = ((contentWidth * mProgressBar.getProgress()) /
+ mProgressBar.getMax()) + params.leftMargin;
+
+ // Calculate any adjustment based on gravity
+ int adjustLeft = 0;
+ int textWidth = mChronometer.getWidth();
+ if (mChronometerGravity == Gravity.RIGHT) {
+ adjustLeft = -textWidth;
+ } else if (mChronometerGravity == Gravity.CENTER_HORIZONTAL) {
+ adjustLeft = -(textWidth / 2);
+ }
+
+ // Limit margin to keep text inside ProgressBar bounds
+ leadingEdge += adjustLeft;
+ int rightLimit = contentWidth - params.rightMargin - textWidth;
+ if (leadingEdge < params.leftMargin) {
+ leadingEdge = params.leftMargin;
+ } else if (leadingEdge > rightLimit) {
+ leadingEdge = rightLimit;
+ }
+
+ params = (RelativeLayout.LayoutParams) mChronometer.getLayoutParams();
+ params.leftMargin = leadingEdge;
+
+ // Request layout to move Chronometer
+ mChronometer.requestLayout();
+
+ }
+ }
+}
diff --git a/core/java/com/google/android/gdata/client/AndroidGDataClient.java b/core/java/com/google/android/gdata/client/AndroidGDataClient.java
index 1d8e9c5..fe7d860 100644
--- a/core/java/com/google/android/gdata/client/AndroidGDataClient.java
+++ b/core/java/com/google/android/gdata/client/AndroidGDataClient.java
@@ -21,6 +21,7 @@ import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.AbstractHttpEntity;
import android.content.ContentResolver;
+import android.content.Context;
import android.net.http.AndroidHttpClient;
import android.text.TextUtils;
import android.util.Config;
@@ -117,10 +118,7 @@ public class AndroidGDataClient implements GDataClient {
}
/**
- * Creates a new AndroidGDataClient.
- *
- * @param resolver The ContentResolver to get URL rewriting rules from
- * through the Android proxy server, using null to indicate not using proxy.
+ * @deprecated Use AndroidGDAtaClient(Context) instead.
*/
public AndroidGDataClient(ContentResolver resolver) {
mHttpClient = new GoogleHttpClient(resolver, USER_AGENT_APP_VERSION,
@@ -129,6 +127,21 @@ public class AndroidGDataClient implements GDataClient {
mResolver = resolver;
}
+ /**
+ * Creates a new AndroidGDataClient.
+ *
+ * @param context The ContentResolver to get URL rewriting rules from
+ * through the Android proxy server, using null to indicate not using proxy.
+ * The context will also be used by GoogleHttpClient for configuration of
+ * SSL session persistence.
+ */
+ public AndroidGDataClient(Context context) {
+ mHttpClient = new GoogleHttpClient(context, USER_AGENT_APP_VERSION,
+ true /* gzip capable */);
+ mHttpClient.enableCurlLogging(TAG, Log.VERBOSE);
+ mResolver = context.getContentResolver();
+ }
+
public void close() {
mHttpClient.close();
}
diff --git a/core/java/com/google/android/net/GoogleHttpClient.java b/core/java/com/google/android/net/GoogleHttpClient.java
index 4656aff..ac9ad73 100644
--- a/core/java/com/google/android/net/GoogleHttpClient.java
+++ b/core/java/com/google/android/net/GoogleHttpClient.java
@@ -16,44 +16,44 @@
package com.google.android.net;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.http.AndroidHttpClient;
+import android.os.Build;
+import android.os.NetStat;
+import android.os.SystemClock;
+import android.provider.Checkin;
+import android.util.Config;
+import android.util.Log;
+import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolException;
-import org.apache.http.impl.client.RequestWrapper;
-import org.apache.http.impl.client.EntityEnclosingRequestWrapper;
-import org.apache.http.client.HttpClient;
import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.impl.client.EntityEnclosingRequestWrapper;
+import org.apache.http.impl.client.RequestWrapper;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.os.SystemClock;
-import android.os.Build;
-import android.net.http.AndroidHttpClient;
-import android.provider.Checkin;
-import android.util.Config;
-import android.util.Log;
-
/**
* {@link AndroidHttpClient} wrapper that uses {@link UrlRules} to rewrite URLs
* and otherwise tweak HTTP requests.
*/
public class GoogleHttpClient implements HttpClient {
- private static final String TAG = "GoogleHttpClient";
- private final AndroidHttpClient mClient;
- private final ContentResolver mResolver;
- private final String mUserAgent;
+ private static final String TAG = "GoogleHttpClient";
/** Exception thrown when a request is blocked by the URL rules. */
public static class BlockedRequestException extends IOException {
@@ -64,11 +64,15 @@ public class GoogleHttpClient implements HttpClient {
}
}
+ private final AndroidHttpClient mClient;
+ private final ContentResolver mResolver;
+ private final String mUserAgent;
+
/**
* Create an HTTP client. Normally one client is shared throughout an app.
* @param resolver to use for accessing URL rewriting rules.
* @param userAgent to report in your HTTP requests.
- * @deprecated Use {@link #GoogleHttpClient(android.content.ContentResolver, String, boolean)}
+ * @deprecated Use {@link #GoogleHttpClient(android.content.ContentResolver, String, boolean)}
*/
public GoogleHttpClient(ContentResolver resolver, String userAgent) {
mClient = AndroidHttpClient.newInstance(userAgent);
@@ -77,6 +81,17 @@ public class GoogleHttpClient implements HttpClient {
}
/**
+ * GoogleHttpClient(Context, String, boolean) - without SSL session
+ * persistence.
+ *
+ * @deprecated use Context instead of ContentResolver.
+ */
+ public GoogleHttpClient(ContentResolver resolver, String appAndVersion,
+ boolean gzipCapable) {
+ this(resolver, null /* cache */, appAndVersion, gzipCapable);
+ }
+
+ /**
* Create an HTTP client. Normaly this client is shared throughout an app.
* The HTTP client will construct its User-Agent as follows:
*
@@ -85,7 +100,10 @@ public class GoogleHttpClient implements HttpClient {
* <appAndVersion> (<build device> <build id>); gzip
* (if gzip capable)
*
- * @param resolver to use for acccessing URL rewriting rules.
+ * The context has settings for URL rewriting rules and is used to enable
+ * SSL session persistence.
+ *
+ * @param context application context.
* @param appAndVersion Base app and version to use in the User-Agent.
* e.g., "MyApp/1.0"
* @param gzipCapable Whether or not this client is able to consume gzip'd
@@ -93,14 +111,19 @@ public class GoogleHttpClient implements HttpClient {
* headers. Needed because Google servers require gzip in the User-Agent
* in order to return gzip'd content.
*/
- public GoogleHttpClient(ContentResolver resolver, String appAndVersion,
- boolean gzipCapable) {
- String userAgent = appAndVersion
- + " (" + Build.DEVICE + " " + Build.ID + ")";
+ public GoogleHttpClient(Context context, String appAndVersion,
+ boolean gzipCapable) {
+ this(context.getContentResolver(), SSLClientSessionCacheFactory.getCache(context),
+ appAndVersion, gzipCapable);
+ }
+
+ private GoogleHttpClient(ContentResolver resolver, SSLClientSessionCache cache,
+ String appAndVersion, boolean gzipCapable) {
+ String userAgent = appAndVersion + " (" + Build.DEVICE + " " + Build.ID + ")";
if (gzipCapable) {
userAgent = userAgent + "; gzip";
}
- mClient = AndroidHttpClient.newInstance(userAgent);
+ mClient = AndroidHttpClient.newInstance(userAgent, cache);
mResolver = resolver;
mUserAgent = userAgent;
}
@@ -120,8 +143,37 @@ public class GoogleHttpClient implements HttpClient {
String code = "Error";
long start = SystemClock.elapsedRealtime();
try {
- HttpResponse response = mClient.execute(request, context);
- code = Integer.toString(response.getStatusLine().getStatusCode());
+ HttpResponse response;
+ // TODO: if we're logging network stats, and if the apache library is configured
+ // to follow redirects, count each redirect as an additional round trip.
+
+ // see if we're logging network stats.
+ boolean logNetworkStats = NetworkStatsEntity.shouldLogNetworkStats();
+
+ if (logNetworkStats) {
+ int uid = android.os.Process.myUid();
+ long startTx = NetStat.getUidTxBytes(uid);
+ long startRx = NetStat.getUidRxBytes(uid);
+
+ response = mClient.execute(request, context);
+ code = Integer.toString(response.getStatusLine().getStatusCode());
+
+ HttpEntity origEntity = response == null ? null : response.getEntity();
+ if (origEntity != null) {
+ // yeah, we compute the same thing below. we do need to compute this here
+ // so we can wrap the HttpEntity in the response.
+ long now = SystemClock.elapsedRealtime();
+ long elapsed = now - start;
+ NetworkStatsEntity entity = new NetworkStatsEntity(origEntity,
+ mUserAgent, uid, startTx, startRx,
+ elapsed /* response latency */, now /* processing start time */);
+ response.setEntity(entity);
+ }
+ } else {
+ response = mClient.execute(request, context);
+ code = Integer.toString(response.getStatusLine().getStatusCode());
+ }
+
return response;
} catch (IOException e) {
code = "IOException";
diff --git a/core/java/com/google/android/net/NetStats.java b/core/java/com/google/android/net/NetStats.java
deleted file mode 100644
index fee8219..0000000
--- a/core/java/com/google/android/net/NetStats.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.google.android.net;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
-
-/**
- * Gets network send/receive statistics for this process.
- * The statistics come from /proc/pid/stat, using the ATOP kernel modification.
- */
-public class NetStats {
- private static String statsFile = "/proc/" + android.os.Process.myPid() + "/stat";
-
- private static String TAG = "netstat";
-
- /**
- * Returns network stats for this process.
- * Returns stats of 0 if problem encountered.
- *
- * @return [bytes sent, bytes received]
- */
- public static long[] getStats() {
- long result[] = new long[2];
-
- try {
- BufferedReader br = new BufferedReader(new FileReader(statsFile), 512);
- String line = br.readLine(); // Skip first line
- line = br.readLine();
- StringTokenizer st = new StringTokenizer(line);
- st.nextToken(); // disk read
- st.nextToken(); // disk sectors
- st.nextToken(); // disk write
- st.nextToken(); // disk sectors
- st.nextToken(); // tcp send
- result[0] = Long.parseLong(st.nextToken()); // tcp bytes sent
- st.nextToken(); //tcp recv
- result[1] = Long.parseLong(st.nextToken()); // tcp bytes recv
- } catch (IOException e) {
- // Probably wrong kernel; no point logging exception
- } catch (NoSuchElementException e) {
- } catch (NullPointerException e) {
- }
- return result;
- }
-}
diff --git a/core/java/com/google/android/net/NetworkStatsEntity.java b/core/java/com/google/android/net/NetworkStatsEntity.java
new file mode 100644
index 0000000..f5d2349
--- /dev/null
+++ b/core/java/com/google/android/net/NetworkStatsEntity.java
@@ -0,0 +1,85 @@
+/*
+ * 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.google.android.net;
+
+import android.os.NetStat;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.util.EventLog;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.entity.HttpEntityWrapper;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+public class NetworkStatsEntity extends HttpEntityWrapper {
+
+ private static final int HTTP_STATS_EVENT = 52001;
+
+ private class NetworkStatsInputStream extends FilterInputStream {
+
+ public NetworkStatsInputStream(InputStream wrapped) {
+ super(wrapped);
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ super.close();
+ } finally {
+ long processingTime = SystemClock.elapsedRealtime() - mProcessingStartTime;
+ long tx = NetStat.getUidTxBytes(mUid);
+ long rx = NetStat.getUidRxBytes(mUid);
+
+ EventLog.writeEvent(HTTP_STATS_EVENT, mUa, mResponseLatency, processingTime,
+ tx - mStartTx, rx - mStartRx);
+ }
+ }
+ }
+
+ private final String mUa;
+ private final int mUid;
+ private final long mStartTx;
+ private final long mStartRx;
+ private final long mResponseLatency;
+ private final long mProcessingStartTime;
+
+ public NetworkStatsEntity(HttpEntity orig, String ua,
+ int uid, long startTx, long startRx, long responseLatency,
+ long processingStartTime) {
+ super(orig);
+ this.mUa = ua;
+ this.mUid = uid;
+ this.mStartTx = startTx;
+ this.mStartRx = startRx;
+ this.mResponseLatency = responseLatency;
+ this.mProcessingStartTime = processingStartTime;
+ }
+
+ public static boolean shouldLogNetworkStats() {
+ return "1".equals(SystemProperties.get("googlehttpclient.logstats"));
+ }
+
+ @Override
+ public InputStream getContent() throws IOException {
+ InputStream orig = super.getContent();
+ return new NetworkStatsInputStream(orig);
+ }
+}
diff --git a/core/java/com/google/android/net/SSLClientSessionCacheFactory.java b/core/java/com/google/android/net/SSLClientSessionCacheFactory.java
new file mode 100644
index 0000000..6570a9bd
--- /dev/null
+++ b/core/java/com/google/android/net/SSLClientSessionCacheFactory.java
@@ -0,0 +1,62 @@
+package com.google.android.net;
+
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
+import android.content.Context;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+
+import com.android.internal.net.DbSSLSessionCache;
+
+/**
+ * Factory that returns the appropriate implementation of a {@link SSLClientSessionCache} based
+ * on gservices.
+ *
+ * @hide
+ */
+// TODO: return a proxied implementation that is updated as the gservices value changes.
+public final class SSLClientSessionCacheFactory {
+
+ private static final String TAG = "SSLClientSessionCacheFactory";
+
+ public static final String DB = "db";
+ public static final String FILE = "file";
+
+ // utility class
+ private SSLClientSessionCacheFactory() {}
+
+ /**
+ * Returns a new {@link SSLClientSessionCache} based on the persistent cache that's specified,
+ * if any, in gservices. If no cache is specified, returns null.
+ * @param context The application context used for the per-process persistent cache.
+ * @return A new {@link SSLClientSessionCache}, or null if no persistent cache is configured.
+ */
+ public static SSLClientSessionCache getCache(Context context) {
+ String type = Settings.Gservices.getString(context.getContentResolver(),
+ Settings.Gservices.SSL_SESSION_CACHE);
+
+ if (type != null) {
+ if (DB.equals(type)) {
+ return DbSSLSessionCache.getInstanceForPackage(context);
+ } else if (FILE.equals(type)) {
+ File dir = context.getFilesDir();
+ File cacheDir = new File(dir, "sslcache");
+ if (!cacheDir.exists()) {
+ cacheDir.mkdir();
+ }
+ try {
+ return FileClientSessionCache.usingDirectory(cacheDir);
+ } catch (IOException ioe) {
+ Log.w(TAG, "Unable to create FileClientSessionCache in " + cacheDir.getName(), ioe);
+ return null;
+ }
+ } else {
+ Log.w(TAG, "Ignoring unrecognized type: '" + type + "'");
+ }
+ }
+ return null;
+ }
+}
diff --git a/core/java/com/google/android/util/GoogleWebContentHelper.java b/core/java/com/google/android/util/GoogleWebContentHelper.java
index 7500ec3..2911420 100644
--- a/core/java/com/google/android/util/GoogleWebContentHelper.java
+++ b/core/java/com/google/android/util/GoogleWebContentHelper.java
@@ -206,7 +206,7 @@ public class GoogleWebContentHelper {
WebSettings settings = mWebView.getSettings();
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
- mProgressBar = mLayout.findViewById(com.android.internal.R.id.progress);
+ mProgressBar = mLayout.findViewById(com.android.internal.R.id.progressContainer);
TextView message = (TextView) mProgressBar.findViewById(com.android.internal.R.id.message);
message.setText(com.android.internal.R.string.googlewebcontenthelper_loading);
diff --git a/core/java/com/google/android/util/SimplePullParser.java b/core/java/com/google/android/util/SimplePullParser.java
index 95f2ddb..031790b 100644
--- a/core/java/com/google/android/util/SimplePullParser.java
+++ b/core/java/com/google/android/util/SimplePullParser.java
@@ -23,6 +23,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.Reader;
+import java.io.Closeable;
import android.util.Xml;
import android.util.Log;
@@ -41,6 +42,7 @@ public class SimplePullParser {
private String mLogTag = null;
private final XmlPullParser mParser;
+ private Closeable source;
private String mCurrentStartTag;
/**
@@ -56,6 +58,7 @@ public class SimplePullParser {
moveToStartDocument(parser);
mParser = parser;
mCurrentStartTag = null;
+ source = stream;
} catch (XmlPullParserException e) {
throw new ParseException(e);
}
@@ -68,6 +71,7 @@ public class SimplePullParser {
public SimplePullParser(XmlPullParser parser) {
mParser = parser;
mCurrentStartTag = null;
+ source = null;
}
/**
@@ -89,6 +93,7 @@ public class SimplePullParser {
moveToStartDocument(parser);
mParser = parser;
mCurrentStartTag = null;
+ source = reader;
} catch (XmlPullParserException e) {
throw new ParseException(e);
}
@@ -171,6 +176,12 @@ public class SimplePullParser {
}
if (eventType == XmlPullParser.END_DOCUMENT && parentDepth == 0) {
+ // we could just rely on the caller calling close(), which it should, but try
+ // to auto-close for clients that might have missed doing so.
+ if (source != null) {
+ source.close();
+ source = null;
+ }
return null;
}
@@ -333,6 +344,20 @@ public class SimplePullParser {
}
/**
+ * Close this SimplePullParser and any underlying resources (e.g., its InputStream or
+ * Reader source) used by this SimplePullParser.
+ */
+ public void close() {
+ if (source != null) {
+ try {
+ source.close();
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+ }
+
+ /**
* Returns the string value of the named attribute. An exception will
* be thrown if the attribute is not present or is not a valid long.
*
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 4452b79..18f2878 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -27,6 +27,7 @@ LOCAL_SRC_FILES:= \
android_database_SQLiteProgram.cpp \
android_database_SQLiteQuery.cpp \
android_database_SQLiteStatement.cpp \
+ android_emoji_EmojiFactory.cpp \
android_view_Display.cpp \
android_view_Surface.cpp \
android_view_ViewRoot.cpp \
@@ -42,7 +43,6 @@ LOCAL_SRC_FILES:= \
android_os_SystemClock.cpp \
android_os_SystemProperties.cpp \
android_os_UEventObserver.cpp \
- android_os_NetStat.cpp \
android_os_Hardware.cpp \
android_net_LocalSocketImpl.cpp \
android_net_NetUtils.cpp \
@@ -133,6 +133,7 @@ LOCAL_C_INCLUDES += \
external/tremor/Tremor \
external/icu4c/i18n \
external/icu4c/common \
+ frameworks/opt/emoji
LOCAL_SHARED_LIBRARIES := \
libexpat \
@@ -146,7 +147,8 @@ LOCAL_SHARED_LIBRARIES := \
libcorecg \
libsqlite \
libdvm \
- libGLES_CM \
+ libEGL \
+ libGLESv1_CM \
libhardware \
libhardware_legacy \
libsonivox \
@@ -156,13 +158,13 @@ LOCAL_SHARED_LIBRARIES := \
libicui18n \
libicudata \
libmedia \
- libwpa_client
+ libwpa_client \
+ libemoji
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_C_INCLUDES += \
external/dbus \
- external/bluez/libs/include \
- system/bluetooth/bluedroid/include
+ system/bluetooth/bluez-clean-headers
LOCAL_CFLAGS += -DHAVE_BLUETOOTH
LOCAL_SHARED_LIBRARIES += libbluedroid libdbus
endif
@@ -191,5 +193,4 @@ LOCAL_MODULE:= libandroid_runtime
include $(BUILD_SHARED_LIBRARY)
-
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 097ffac..f4643f4 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -92,6 +92,7 @@ extern int register_android_util_EventLog(JNIEnv* env);
extern int register_android_util_Log(JNIEnv* env);
extern int register_android_content_StringBlock(JNIEnv* env);
extern int register_android_content_XmlBlock(JNIEnv* env);
+extern int register_android_emoji_EmojiFactory(JNIEnv* env);
extern int register_android_graphics_Canvas(JNIEnv* env);
extern int register_android_graphics_ColorFilter(JNIEnv* env);
extern int register_android_graphics_DrawFilter(JNIEnv* env);
@@ -129,7 +130,6 @@ extern int register_android_os_SystemClock(JNIEnv* env);
extern int register_android_os_FileObserver(JNIEnv *env);
extern int register_android_os_FileUtils(JNIEnv *env);
extern int register_android_os_UEventObserver(JNIEnv* env);
-extern int register_android_os_NetStat(JNIEnv* env);
extern int register_android_os_MemoryFile(JNIEnv* env);
extern int register_android_net_LocalSocketImpl(JNIEnv* env);
extern int register_android_net_NetworkUtils(JNIEnv* env);
@@ -220,7 +220,7 @@ int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
AndroidRuntime::AndroidRuntime()
{
- SkGraphics::Init(false); // true means run unittests (slow)
+ SkGraphics::Init();
// this sets our preference for 16bit images during decode
// in case the src is opaque and 24bit
SkImageDecoder::SetDeviceConfig(SkBitmap::kRGB_565_Config);
@@ -502,6 +502,7 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
JavaVMOption opt;
char propBuf[PROPERTY_VALUE_MAX];
char stackTraceFileBuf[PROPERTY_VALUE_MAX];
+ char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
char* stackTraceFile = NULL;
@@ -509,7 +510,6 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
char* cp;
bool checkJni = false;
bool logStdio = false;
- bool verifyJava = true;
enum { kEMDefault, kEMIntPortable, kEMIntFast } executionMode = kEMDefault;
blockSigpipe();
@@ -536,15 +536,6 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
}
}
- property_get("dalvik.vm.verify-bytecode", propBuf, "");
- if (strcmp(propBuf, "true") == 0) {
- verifyJava = true;
- } else if (strcmp(propBuf, "false") == 0) {
- verifyJava = false;
- } else {
- /* bad value or not defined; use default */
- }
-
property_get("dalvik.vm.execution-mode", propBuf, "");
if (strcmp(propBuf, "int:portable") == 0) {
executionMode = kEMIntPortable;
@@ -609,21 +600,49 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
mOptions.add(opt);
/*
- * Enable or disable bytecode verification.
- *
- * We don't optimize classes that haven't been verified, but that only
- * matters if we do "just-in-time" DEX optimization.
+ * Enable or disable dexopt features, such as bytecode verification and
+ * calculation of register maps for precise GC.
*/
- if (verifyJava) {
- opt.optionString = "-Xverify:all";
- mOptions.add(opt);
- opt.optionString = "-Xdexopt:verified";
- mOptions.add(opt);
- } else {
- opt.optionString = "-Xverify:none";
- mOptions.add(opt);
- opt.optionString = "-Xdexopt:verified";
- mOptions.add(opt);
+ property_get("dalvik.vm.dexopt-flags", dexoptFlagsBuf, "");
+ if (dexoptFlagsBuf[0] != '\0') {
+ const char* opc;
+ const char* val;
+
+ opc = strstr(dexoptFlagsBuf, "v="); /* verification */
+ if (opc != NULL) {
+ switch (*(opc+2)) {
+ case 'n': val = "-Xverify:none"; break;
+ case 'r': val = "-Xverify:remote"; break;
+ case 'a': val = "-Xverify:all"; break;
+ default: val = NULL; break;
+ }
+
+ if (val != NULL) {
+ opt.optionString = val;
+ mOptions.add(opt);
+ }
+ }
+
+ opc = strstr(dexoptFlagsBuf, "o="); /* optimization */
+ if (opc != NULL) {
+ switch (*(opc+2)) {
+ case 'n': val = "-Xdexopt:none"; break;
+ case 'v': val = "-Xdexopt:verified"; break;
+ case 'a': val = "-Xdexopt:all"; break;
+ default: val = NULL; break;
+ }
+
+ if (val != NULL) {
+ opt.optionString = val;
+ mOptions.add(opt);
+ }
+ }
+
+ opc = strstr(dexoptFlagsBuf, "m=y"); /* register map */
+ if (opc != NULL) {
+ opt.optionString = "-Xgenregmap";
+ mOptions.add(opt);
+ }
}
/* enable debugging; set suspend=y to pause during VM init */
@@ -1008,6 +1027,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
+ REG_JNI(register_android_emoji_EmojiFactory),
REG_JNI(register_android_security_Md5MessageDigest),
REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_KeyCharacterMap),
@@ -1066,7 +1086,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_net_LocalSocketImpl),
REG_JNI(register_android_net_NetworkUtils),
REG_JNI(register_android_net_wifi_WifiManager),
- REG_JNI(register_android_os_NetStat),
REG_JNI(register_android_os_MemoryFile),
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_android_hardware_Camera),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index be8526d..332b01c 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -1,3 +1,5 @@
+#define LOG_TAG "BitmapFactory"
+
#include "SkImageDecoder.h"
#include "SkPixelRef.h"
#include "SkStream.h"
@@ -481,6 +483,48 @@ static void nativeRequestCancel(JNIEnv*, jobject joptions) {
(void)AutoDecoderCancel::RequestCancel(joptions);
}
+static jbyteArray nativeScaleNinePatch(JNIEnv* env, jobject, jbyteArray chunkObject, jfloat scale,
+ jobject padding) {
+
+ jbyte* array = env->GetByteArrayElements(chunkObject, 0);
+ if (array != NULL) {
+ size_t chunkSize = env->GetArrayLength(chunkObject);
+ void* storage = alloca(chunkSize);
+ android::Res_png_9patch* chunk = static_cast<android::Res_png_9patch*>(storage);
+ memcpy(chunk, array, chunkSize);
+ android::Res_png_9patch::deserialize(chunk);
+
+ chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f);
+ chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f);
+ chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f);
+ chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f);
+
+ for (int i = 0; i < chunk->numXDivs; i++) {
+ chunk->xDivs[i] = int(chunk->xDivs[i] * scale + 0.5f);
+ if (i > 0 && chunk->xDivs[i] == chunk->xDivs[i - 1]) {
+ chunk->xDivs[i]++;
+ }
+ }
+
+ for (int i = 0; i < chunk->numYDivs; i++) {
+ chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f);
+ if (i > 0 && chunk->yDivs[i] == chunk->yDivs[i - 1]) {
+ chunk->yDivs[i]++;
+ }
+ }
+
+ memcpy(array, chunk, chunkSize);
+
+ if (padding) {
+ GraphicsJNI::set_jrect(env, padding, chunk->paddingLeft, chunk->paddingTop,
+ chunk->paddingRight, chunk->paddingBottom);
+ }
+
+ env->ReleaseByteArrayElements(chunkObject, array, 0);
+ }
+ return chunkObject;
+}
+
///////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gMethods[] = {
@@ -502,7 +546,13 @@ static JNINativeMethod gMethods[] = {
{ "nativeDecodeByteArray",
"([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
(void*)nativeDecodeByteArray
+ },
+
+ { "nativeScaleNinePatch",
+ "([BFLandroid/graphics/Rect;)[B",
+ (void*)nativeScaleNinePatch
}
+
};
static JNINativeMethod gOptionsMethods[] = {
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index b9e5f67..605e4b8 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -93,7 +93,7 @@ public:
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
return canvas->getDevice()->accessBitmap(false).height();
}
-
+
static void setViewport(JNIEnv* env, jobject, SkCanvas* canvas,
int width, int height) {
canvas->setViewport(width, height);
@@ -454,13 +454,32 @@ public:
#endif
}
- static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject,
+ static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas,
SkCanvas* canvas, SkBitmap* bitmap,
jfloat left, jfloat top,
- SkPaint* paint) {
+ SkPaint* paint,
+ jboolean autoScale, jfloat densityScale) {
SkScalar left_ = SkFloatToScalar(left);
SkScalar top_ = SkFloatToScalar(top);
- canvas->drawBitmap(*bitmap, left_, top_, paint);
+
+ if (!autoScale || densityScale <= 0.0f) {
+ canvas->drawBitmap(*bitmap, left_, top_, paint);
+ } else {
+ canvas->save();
+ SkScalar canvasScale = GraphicsJNI::getCanvasDensityScale(env, jcanvas);
+ SkScalar scale = canvasScale / SkFloatToScalar(densityScale);
+ canvas->scale(scale, scale);
+
+ SkPaint filteredPaint;
+ if (paint) {
+ filteredPaint = *paint;
+ }
+ filteredPaint.setFilterBitmap(true);
+
+ canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint);
+
+ canvas->restore();
+ }
}
static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap,
@@ -492,7 +511,7 @@ public:
static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas,
jintArray jcolors, int offset, int stride,
- int x, int y, int width, int height,
+ jfloat x, jfloat y, int width, int height,
jboolean hasAlpha, SkPaint* paint)
{
SkBitmap bitmap;
@@ -508,7 +527,8 @@ public:
return;
}
- canvas->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), paint);
+ canvas->drawBitmap(bitmap, SkFloatToScalar(x), SkFloatToScalar(y),
+ paint);
}
static void drawBitmapMatrix(JNIEnv* env, jobject, SkCanvas* canvas,
@@ -882,13 +902,13 @@ static JNINativeMethod gCanvasMethods[] = {
{"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V",
(void*) SkCanvasGlue::drawRoundRect},
{"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath},
- {"native_drawBitmap","(IIFFI)V",
+ {"native_drawBitmap","(IIFFIZF)V",
(void*) SkCanvasGlue::drawBitmap__BitmapFFPaint},
{"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;I)V",
(void*) SkCanvasGlue::drawBitmapRF},
{"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;I)V",
(void*) SkCanvasGlue::drawBitmapRR},
- {"native_drawBitmap", "(I[IIIIIIIZI)V",
+ {"native_drawBitmap", "(I[IIIFFIIZI)V",
(void*)SkCanvasGlue::drawBitmapArray},
{"nativeDrawBitmapMatrix", "(IIII)V",
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 65c2326..a285def 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -56,11 +56,14 @@ public:
break; // eof
}
- const jbyte* array = env->GetByteArrayElements(fJavaByteArray,
- NULL);
- memcpy(buffer, array, n);
- env->ReleaseByteArrayElements(fJavaByteArray,
- const_cast<jbyte*>(array), JNI_ABORT);
+ env->GetByteArrayRegion(fJavaByteArray, 0, n,
+ reinterpret_cast<jbyte*>(buffer));
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ SkDebugf("---- read:GetByteArrayRegion threw an exception\n");
+ return 0;
+ }
buffer = (void*)((char*)buffer + n);
bytesRead += n;
@@ -189,10 +192,15 @@ public:
requested = fCapacity;
}
- jbyte* array = env->GetByteArrayElements(storage, NULL);
- memcpy(array, buffer, requested);
- env->ReleaseByteArrayElements(storage, array, 0);
-
+ env->SetByteArrayRegion(storage, 0, requested,
+ reinterpret_cast<const jbyte*>(buffer));
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ SkDebugf("--- write:SetByteArrayElements threw an exception\n");
+ return false;
+ }
+
fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_writeMethodID,
storage, 0, requested);
if (env->ExceptionCheck()) {
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 44113e5..6eebbdc 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -162,6 +162,7 @@ static jfieldID gBitmapConfig_nativeInstanceID;
static jclass gCanvas_class;
static jfieldID gCanvas_nativeInstanceID;
+static jfieldID gCanvas_densityScaleID;
static jclass gPaint_class;
static jfieldID gPaint_nativeInstanceID;
@@ -318,6 +319,13 @@ SkCanvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) {
return c;
}
+SkScalar GraphicsJNI::getCanvasDensityScale(JNIEnv* env, jobject canvas) {
+ SkASSERT(env);
+ SkASSERT(canvas);
+ SkASSERT(env->IsInstanceOf(canvas, gCanvas_class));
+ return SkFloatToScalar(env->GetFloatField(canvas, gCanvas_densityScaleID));
+}
+
SkPaint* GraphicsJNI::getNativePaint(JNIEnv* env, jobject paint) {
SkASSERT(env);
SkASSERT(paint);
@@ -543,7 +551,8 @@ int register_android_graphics_Graphics(JNIEnv* env)
gCanvas_class = make_globalref(env, "android/graphics/Canvas");
gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvas", "I");
-
+ gCanvas_densityScaleID = getFieldIDCheck(env, gCanvas_class, "mDensityScale", "F");
+
gPaint_class = make_globalref(env, "android/graphics/Paint");
gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "I");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index e67b20b..e2dc9ac 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -38,6 +38,7 @@ public:
static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
static SkPicture* getNativePicture(JNIEnv*, jobject picture);
static SkRegion* getNativeRegion(JNIEnv*, jobject region);
+ static SkScalar getCanvasDensityScale(JNIEnv*, jobject canvas);
/** Return the corresponding native config from the java Config enum,
or kNo_Config if the java object is null.
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 9e943f3..b11edfc 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -47,19 +47,17 @@ public:
static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds,
const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
{
- const jbyte* array = env->GetByteArrayElements(chunkObj, 0);
- if (array != NULL) {
- size_t chunkSize = env->GetArrayLength(chunkObj);
+ size_t chunkSize = env->GetArrayLength(chunkObj);
+ void* storage = alloca(chunkSize);
+ env->GetByteArrayRegion(chunkObj, 0, chunkSize,
+ reinterpret_cast<jbyte*>(storage));
+ if (!env->ExceptionCheck()) {
// need to deserialize the chunk
- void* storage = alloca(chunkSize);
Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
- memcpy(chunk, array, chunkSize);
assert(chunkSize == chunk->serializedSize());
// this relies on deserialization being done in place
Res_png_9patch::deserialize(chunk);
NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
- env->ReleaseByteArrayElements(chunkObj, const_cast<jbyte*>(array),
- JNI_ABORT);
}
}
@@ -102,23 +100,20 @@ public:
SkRect bounds;
GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
- const jbyte* array = (jbyte*)env->GetByteArrayElements(chunkObj, 0);
- if (array != NULL) {
- size_t chunkSize = env->GetArrayLength(chunkObj);
+ size_t chunkSize = env->GetArrayLength(chunkObj);
+ void* storage = alloca(chunkSize);
+ env->GetByteArrayRegion(chunkObj, 0, chunkSize,
+ reinterpret_cast<jbyte*>(storage));
+ if (!env->ExceptionCheck()) {
// need to deserialize the chunk
- void* storage = alloca(chunkSize);
Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
- memcpy(chunk, array, chunkSize);
assert(chunkSize == chunk->serializedSize());
// this relies on deserialization being done in place
Res_png_9patch::deserialize(chunk);
SkRegion* region = NULL;
NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, &region);
- env->ReleaseByteArrayElements(chunkObj, const_cast<jbyte*>(array),
- JNI_ABORT);
return (jint)region;
}
-
return 0;
}
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 32954ce..e951431 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -32,11 +32,11 @@ static SkTypeface* Typeface_create(JNIEnv* env, jobject, jstring name,
SkTypeface* face;
if (NULL == name) {
- face = SkTypeface::Create(NULL, (SkTypeface::Style)style);
+ face = SkTypeface::CreateFromName(NULL, (SkTypeface::Style)style);
}
else {
AutoJavaStringToUTF8 str(env, name);
- face = SkTypeface::Create(str.c_str(), style);
+ face = SkTypeface::CreateFromName(str.c_str(), style);
}
return face;
}
@@ -50,7 +50,7 @@ static void Typeface_unref(JNIEnv* env, jobject obj, SkTypeface* face) {
}
static int Typeface_getStyle(JNIEnv* env, jobject obj, SkTypeface* face) {
- return face->getStyle();
+ return face->style();
}
class AssetStream : public SkStream {
diff --git a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
index 7f87d80..bf23650 100755
--- a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
+++ b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
@@ -49,8 +49,6 @@
#ifdef HAVE_BLUETOOTH
#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/sco.h>
#endif
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 66f0118..66858f9 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -45,6 +45,8 @@
#define INVALID_VERSION -1
#define SQLITE_SOFT_HEAP_LIMIT (4 * 1024 * 1024)
#define ANDROID_TABLE "android_metadata"
+/* uncomment the next line to force-enable logging of all statements */
+// #define DB_LOG_STATEMENTS
namespace android {
@@ -197,7 +199,11 @@ static void native_execSQL(JNIEnv* env, jobject object, jstring sqlString)
env->ReleaseStringUTFChars(sqlString, sql8);
}
- } else IF_LOGV() {
+ } else
+#ifndef DB_LOG_STATEMENTS
+ IF_LOGV()
+#endif
+ {
char const * sql8 = env->GetStringUTFChars(sqlString, NULL);
LOGV("Success on %p when executing '%s'\n", handle, sql8);
env->ReleaseStringUTFChars(sqlString, sql8);
diff --git a/core/jni/android_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
new file mode 100644
index 0000000..59f63a8
--- /dev/null
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -0,0 +1,292 @@
+#include "SkTypes.h"
+#include "SkImageDecoder.h"
+
+#define LOG_TAG "DoCoMoEmojiFactory_jni"
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "EmojiFactory.h"
+#include <nativehelper/JNIHelp.h>
+
+#include <dlfcn.h>
+// #include <pthread.h>
+
+namespace android {
+
+// Note: This class is originally developed so that libandroid_runtime does
+// not have to depend on libemoji which is optional library. However, we
+// cannot use this class, since current (2009-02-16) bionic libc does not allow
+// dlopen()-ing inside dlopen(), while not only this class but also libemoji
+// uses dlopen().
+class EmojiFactoryCaller {
+ public:
+ EmojiFactoryCaller();
+ virtual ~EmojiFactoryCaller();
+ EmojiFactory *TryCallGetImplementation(const char* name);
+ EmojiFactory *TryCallGetAvailableImplementation();
+ private:
+ void *m_handle;
+ EmojiFactory *(*m_get_implementation)(const char*);
+ EmojiFactory *(*m_get_available_implementation)();
+};
+
+EmojiFactoryCaller::EmojiFactoryCaller() {
+ m_handle = dlopen("libemoji.so", RTLD_LAZY | RTLD_LOCAL);
+ const char* error_str = dlerror();
+ if (error_str) {
+ LOGI("Failed to load libemoji.so: %s", error_str);
+ return;
+ }
+
+ m_get_implementation =
+ reinterpret_cast<EmojiFactory *(*)(const char*)>(
+ dlsym(m_handle, "GetImplementation"));
+ error_str = dlerror();
+ if (error_str) {
+ LOGE("Failed to get symbol of GetImplementation: %s", error_str);
+ dlclose(m_handle);
+ m_handle = NULL;
+ return;
+ }
+
+ m_get_available_implementation =
+ reinterpret_cast<EmojiFactory *(*)()>(
+ dlsym(m_handle,"GetAvailableImplementation"));
+ error_str = dlerror();
+ if (error_str) {
+ LOGE("Failed to get symbol of GetAvailableImplementation: %s", error_str);
+ dlclose(m_handle);
+ m_handle = NULL;
+ return;
+ }
+}
+
+EmojiFactoryCaller::~EmojiFactoryCaller() {
+ if (m_handle) {
+ dlclose(m_handle);
+ }
+}
+
+EmojiFactory *EmojiFactoryCaller::TryCallGetImplementation(
+ const char* name) {
+ if (NULL == m_handle) {
+ return NULL;
+ }
+ return m_get_implementation(name);
+}
+
+EmojiFactory *EmojiFactoryCaller::TryCallGetAvailableImplementation() {
+ if (NULL == m_handle) {
+ return NULL;
+ }
+ return m_get_available_implementation();
+}
+
+// Note: bionic libc's dlopen() does not allow recursive dlopen(). So currently
+// we cannot use EmojiFactoryCaller here.
+// static EmojiFactoryCaller* gCaller;
+// static pthread_once_t g_once = PTHREAD_ONCE_INIT;
+
+static jclass gString_class;
+
+static jclass gBitmap_class;
+static jmethodID gBitmap_constructorMethodID;
+
+static jclass gEmojiFactory_class;
+static jmethodID gEmojiFactory_constructorMethodID;
+
+// static void InitializeCaller() {
+// gCaller = new EmojiFactoryCaller();
+// }
+
+static jobject create_java_EmojiFactory(
+ JNIEnv* env, EmojiFactory* factory, jstring name) {
+ jobject obj = env->AllocObject(gEmojiFactory_class);
+ if (obj) {
+ env->CallVoidMethod(obj, gEmojiFactory_constructorMethodID,
+ (jint)factory, name);
+ if (env->ExceptionCheck() != 0) {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ obj = NULL;
+ }
+ }
+ return obj;
+}
+
+static jobject android_emoji_EmojiFactory_newInstance(
+ JNIEnv* env, jobject clazz, jstring name) {
+ // pthread_once(&g_once, InitializeCaller);
+
+ if (NULL == name) {
+ return NULL;
+ }
+
+ const jchar* jchars = env->GetStringChars(name, NULL);
+ jsize len = env->GetStringLength(name);
+ String8 str(String16(jchars, len));
+
+ // EmojiFactory *factory = gCaller->TryCallGetImplementation(str.string());
+ EmojiFactory *factory = EmojiFactory::GetImplementation(str.string());
+
+ env->ReleaseStringChars(name, jchars);
+
+ return create_java_EmojiFactory(env, factory, name);
+}
+
+static jobject android_emoji_EmojiFactory_newAvailableInstance(
+ JNIEnv* env, jobject clazz) {
+ // pthread_once(&g_once, InitializeCaller);
+
+ // EmojiFactory *factory = gCaller->TryCallGetAvailableImplementation();
+ EmojiFactory *factory = EmojiFactory::GetAvailableImplementation();
+ if (NULL == factory) {
+ return NULL;
+ }
+ String16 name_16(String8(factory->Name()));
+ jstring jname = env->NewString(name_16.string(), name_16.size());
+ if (NULL == jname) {
+ return NULL;
+ }
+
+ return create_java_EmojiFactory(env, factory, jname);
+}
+
+static jobject android_emoji_EmojiFactory_getBitmapFromAndroidPua(
+ JNIEnv* env, jobject clazz, jint nativeEmojiFactory, jint pua) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+
+ int size;
+ const char *bytes = factory->GetImageBinaryFromAndroidPua(pua, &size);
+ if (bytes == NULL) {
+ return NULL;
+ }
+
+ SkBitmap *bitmap = new SkBitmap;
+ if (!SkImageDecoder::DecodeMemory(bytes, size, bitmap)) {
+ LOGE("SkImageDecoder::DecodeMemory() failed.");
+ return NULL;
+ }
+
+ jobject obj = env->AllocObject(gBitmap_class);
+ if (obj) {
+ env->CallVoidMethod(obj, gBitmap_constructorMethodID,
+ reinterpret_cast<jint>(bitmap), false, NULL);
+ if (env->ExceptionCheck() != 0) {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ return NULL;
+ }
+ }
+
+ return obj;
+}
+
+static void android_emoji_EmojiFactory_destructor(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ delete factory;
+}
+
+static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory, jchar sjis) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetAndroidPuaFromVendorSpecificSjis(sjis);
+}
+
+static jint android_emoji_EmojiFactory_getVendorSpecificSjisFromAndroidPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint pua) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetVendorSpecificSjisFromAndroidPua(pua);
+}
+
+static jint android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint vsu) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetAndroidPuaFromVendorSpecificPua(vsu);
+}
+
+static jint android_emoji_EmojiFactory_getVendorSpecificPuaFromAndroidPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory, jint pua) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetVendorSpecificPuaFromAndroidPua(pua);
+}
+
+static jint android_emoji_EmojiFactory_getMaximumVendorSpecificPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetMaximumVendorSpecificPua();
+}
+
+static jint android_emoji_EmojiFactory_getMinimumVendorSpecificPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetMinimumVendorSpecificPua();
+}
+
+static jint android_emoji_EmojiFactory_getMaximumAndroidPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetMaximumAndroidPua();
+}
+
+static jint android_emoji_EmojiFactory_getMinimumAndroidPua(
+ JNIEnv* env, jobject obj, jint nativeEmojiFactory) {
+ EmojiFactory *factory = reinterpret_cast<EmojiFactory *>(nativeEmojiFactory);
+ return factory->GetMinimumAndroidPua();
+}
+
+static JNINativeMethod gMethods[] = {
+ { "newInstance", "(Ljava/lang/String;)Landroid/emoji/EmojiFactory;",
+ (void*)android_emoji_EmojiFactory_newInstance},
+ { "newAvailableInstance", "()Landroid/emoji/EmojiFactory;",
+ (void*)android_emoji_EmojiFactory_newAvailableInstance},
+ { "nativeDestructor", "(I)V",
+ (void*)android_emoji_EmojiFactory_destructor},
+ { "nativeGetBitmapFromAndroidPua", "(II)Landroid/graphics/Bitmap;",
+ (void*)android_emoji_EmojiFactory_getBitmapFromAndroidPua},
+ { "nativeGetAndroidPuaFromVendorSpecificSjis", "(IC)I",
+ (void*)android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificSjis},
+ { "nativeGetVendorSpecificSjisFromAndroidPua", "(II)I",
+ (void*)android_emoji_EmojiFactory_getVendorSpecificSjisFromAndroidPua},
+ { "nativeGetAndroidPuaFromVendorSpecificPua", "(II)I",
+ (void*)android_emoji_EmojiFactory_getAndroidPuaFromVendorSpecificPua},
+ { "nativeGetVendorSpecificPuaFromAndroidPua", "(II)I",
+ (void*)android_emoji_EmojiFactory_getVendorSpecificPuaFromAndroidPua},
+ { "nativeGetMaximumVendorSpecificPua", "(I)I",
+ (void*)android_emoji_EmojiFactory_getMaximumVendorSpecificPua},
+ { "nativeGetMinimumVendorSpecificPua", "(I)I",
+ (void*)android_emoji_EmojiFactory_getMinimumVendorSpecificPua},
+ { "nativeGetMaximumAndroidPua", "(I)I",
+ (void*)android_emoji_EmojiFactory_getMaximumAndroidPua},
+ { "nativeGetMinimumAndroidPua", "(I)I",
+ (void*)android_emoji_EmojiFactory_getMinimumAndroidPua}
+};
+
+static jclass make_globalref(JNIEnv* env, const char classname[])
+{
+ jclass c = env->FindClass(classname);
+ SkASSERT(c);
+ return (jclass)env->NewGlobalRef(c);
+}
+
+static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
+ const char fieldname[], const char type[])
+{
+ jfieldID id = env->GetFieldID(clazz, fieldname, type);
+ SkASSERT(id);
+ return id;
+}
+
+int register_android_emoji_EmojiFactory(JNIEnv* env) {
+ gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
+ gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
+ "(IZ[B)V");
+ gEmojiFactory_class = make_globalref(env, "android/emoji/EmojiFactory");
+ gEmojiFactory_constructorMethodID = env->GetMethodID(
+ gEmojiFactory_class, "<init>", "(ILjava/lang/String;)V");
+ return jniRegisterNativeMethods(env, "android/emoji/EmojiFactory",
+ gMethods, NELEM(gMethods));
+}
+
+} // namespace android
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index a81f252..f6cd211 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -15,7 +15,9 @@
** limitations under the License.
*/
+//#define LOG_NDEBUG 0
#define LOG_TAG "Camera-JNI"
+#include <utils/Log.h>
#include "jni.h"
#include "JNIHelp.h"
@@ -45,38 +47,43 @@ enum CameraError {
struct fields_t {
jfieldID context;
jfieldID surface;
- jfieldID listener_context;
jmethodID post_event;
};
static fields_t fields;
static Mutex sLock;
-struct callback_cookie {
- jclass camera_class;
- jobject camera_ref;
+struct camera_context_t {
+ jobject mCameraJObjectWeak; // weak reference to java object
+ jclass mCameraJClass; // strong reference to java class
+ sp<Camera> mCamera; // strong reference to native object
};
-sp<Camera> get_native_camera(JNIEnv *env, jobject thiz)
+sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pContext)
{
+ sp<Camera> camera;
Mutex::Autolock _l(sLock);
- sp<Camera> c = reinterpret_cast<Camera*>(env->GetIntField(thiz, fields.context));
- if (c == 0)
+ camera_context_t* context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context));
+ if (context != NULL) {
+ camera = context->mCamera;
+ }
+ LOGV("get_native_camera: context=%p, camera=%p", context, camera.get());
+ if (camera == 0) {
jniThrowException(env, "java/lang/RuntimeException", "Method called after release()");
+ }
- return c;
+ if (pContext != NULL) *pContext = context;
+ return camera;
}
static void err_callback(status_t err, void *cookie)
{
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (env == NULL) {
- LOGE("err_callback on dead VM");
- return;
- }
- callback_cookie *c = (callback_cookie *)cookie;
- int error;
+ camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
+ if ((context == NULL) || (context->mCamera == 0)) return;
+
+ LOGV("err_callback: context=%p, camera=%p", context, context->mCamera.get());
+ int error;
switch (err) {
case DEAD_OBJECT:
error = kCameraErrorMediaServer;
@@ -85,29 +92,32 @@ static void err_callback(status_t err, void *cookie)
error = kCameraErrorUnknown;
break;
}
- LOGV("err_callback: camera_ref=%x, cookie=%x", (int)c->camera_ref, (int)cookie);
- env->CallStaticVoidMethod(c->camera_class, fields.post_event,
- c->camera_ref, kErrorCallback, error, 0, NULL);
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (env == NULL) {
+ LOGE("err_callback on dead VM");
+ return;
+ }
+ env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
+ context->mCameraJObjectWeak, kErrorCallback, error, 0, NULL);
}
// connect to camera service
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
- sp<Camera> c = Camera::connect();
+ sp<Camera> camera = Camera::connect();
- if (c == NULL) {
+ if (camera == NULL) {
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
}
// make sure camera hardware is alive
- if (c->getStatus() != NO_ERROR) {
+ if (camera->getStatus() != NO_ERROR) {
jniThrowException(env, "java/io/IOException", "Camera initialization failed");
return;
}
- callback_cookie *cookie = new callback_cookie;
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
LOGE("Can't find android/hardware/Camera");
@@ -115,76 +125,87 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj
jniThrowException(env, "java/lang/Exception", NULL);
return;
}
- cookie->camera_class = (jclass)env->NewGlobalRef(clazz);
// We use a weak reference so the Camera object can be garbage collected.
// The reference is only used as a proxy for callbacks.
- cookie->camera_ref = env->NewGlobalRef(weak_this);
- env->SetIntField(thiz, fields.listener_context, (int)cookie);
-
- LOGV("native_setup: camera_ref=%x, camera_obj=%x, cookie=%x", (int)cookie->camera_ref, (int)thiz, (int)cookie);
+ camera_context_t* context = new camera_context_t;
+ context->mCameraJObjectWeak = env->NewGlobalRef(weak_this);
+ context->mCameraJClass = (jclass)env->NewGlobalRef(clazz);
+ context->mCamera = camera;
- // save camera object in opaque field
- env->SetIntField(thiz, fields.context, reinterpret_cast<int>(c.get()));
+ // save context in opaque field
+ env->SetIntField(thiz, fields.context, (int)context);
- c->setErrorCallback(err_callback, cookie);
+ LOGV("native_setup: mCameraJObjectWeak=%x, camera_obj=%x, context=%p",
+ (int)context->mCameraJObjectWeak, (int)thiz, context);
- // hold a strong reference so the camera doesn't go away while the app is still running
- c->incStrong(thiz);
+ // set error callback
+ camera->setErrorCallback(err_callback, context);
}
// disconnect from camera service
+// It's okay to call this when the native camera context is already null.
+// This handles the case where the user has called release() and the
+// finalizer is invoked later.
static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
{
- Mutex::Autolock _l(sLock);
- sp<Camera> c = reinterpret_cast<Camera*>(env->GetIntField(thiz, fields.context));
- // It's okay to call this when the native camera context is already null.
- // This handles the case where the user has called release() and the
- // finalizer is invoked later.
- if (c != 0) {
- // Make sure that we do not attempt to deliver an eror callback on a deleted
- // Java object.
- c->setErrorCallback(NULL, NULL);
- c->disconnect();
-
- // remove our strong reference created in native setup
- c->decStrong(thiz);
- env->SetIntField(thiz, fields.context, 0);
-
- callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
+ camera_context_t* context = NULL;
+ sp<Camera> camera;
+ {
+ Mutex::Autolock _l(sLock);
+ context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context));
- LOGV("release: camera_ref=%x, camera_obj=%x, cookie=%x", (int)cookie->camera_ref, (int)thiz, (int)cookie);
+ // Make sure we do not attempt to callback on a deleted Java object.
+ env->SetIntField(thiz, fields.context, 0);
+ }
- if (cookie) {
- env->DeleteGlobalRef(cookie->camera_ref);
- env->DeleteGlobalRef(cookie->camera_class);
- delete cookie;
- env->SetIntField(thiz, fields.listener_context, 0);
+ // clean up if release has not been called before
+ if (context != NULL) {
+ camera = context->mCamera;
+ context->mCamera.clear();
+ LOGV("native_release: context=%p camera=%p", context, camera.get());
+
+ // clear callbacks
+ if (camera != NULL) {
+ camera->setPreviewCallback(NULL, NULL, FRAME_CALLBACK_FLAG_NOOP);
+ camera->setErrorCallback(NULL, NULL);
+ camera->disconnect();
+ env->DeleteGlobalRef(context->mCameraJObjectWeak);
+ env->DeleteGlobalRef(context->mCameraJClass);
}
+
+ // remove context to prevent further Java access
+ delete context;
}
}
-static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject surface)
+static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return;
+ LOGV("setPreviewDisplay");
+ sp<Camera> camera = get_native_camera(env, thiz, NULL);
+ if (camera == 0) return;
- sp<Surface> s = (Surface *)env->GetIntField(surface, fields.surface);
- if (c->setPreviewDisplay(s) != NO_ERROR) {
+ sp<Surface> surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface));
+ if (camera->setPreviewDisplay(surface) != NO_ERROR) {
jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed");
- return;
}
}
static void preview_callback(const sp<IMemory>& mem, void *cookie)
{
+ LOGV("preview_callback");
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (env == NULL) {
LOGE("preview_callback on dead VM");
return;
}
- callback_cookie *c = (callback_cookie *)cookie;
+ camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
+ if ((context == NULL) || (context->mCamera == 0)) {
+ LOGW("context or camera is NULL in preview_callback");
+ return;
+ }
+ LOGV("native_release: context=%p camera=%p", context, context->mCamera.get());
+
int arg1 = 0, arg2 = 0;
jobject obj = NULL;
@@ -207,18 +228,18 @@ static void preview_callback(const sp<IMemory>& mem, void *cookie)
obj = array;
- env->CallStaticVoidMethod(c->camera_class, fields.post_event,
- c->camera_ref, kPreviewCallback, arg1, arg2, obj);
+ env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
+ context->mCameraJObjectWeak, kPreviewCallback, arg1, arg2, obj);
env->DeleteLocalRef(array);
}
static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return;
+ LOGV("startPreview");
+ sp<Camera> camera = get_native_camera(env, thiz, NULL);
+ if (camera == 0) return;
- if (c->startPreview() != NO_ERROR) {
+ if (camera->startPreview() != NO_ERROR) {
jniThrowException(env, "java/io/IOException", "startPreview failed");
return;
}
@@ -226,32 +247,30 @@ static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return;
+ LOGV("stopPreview");
+ sp<Camera> c = get_native_camera(env, thiz, NULL);
+ if (c == 0) return;
c->stopPreview();
}
static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return false;
+ LOGV("previewEnabled");
+ sp<Camera> c = get_native_camera(env, thiz, NULL);
+ if (c == 0) return false;
return c->previewEnabled();
}
static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean oneshot)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return;
-
// Important: Only install preview_callback if the Java code has called
// setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy
// each preview frame for nothing.
- callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
+ camera_context_t* context;
+ sp<Camera> camera = get_native_camera(env, thiz, &context);
+ if (camera == 0) return;
int callback_flag;
if (installed) {
@@ -259,31 +278,31 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t
} else {
callback_flag = FRAME_CALLBACK_FLAG_NOOP;
}
- c->setFrameCallback(installed ? preview_callback : NULL, cookie, callback_flag);
+ camera->setPreviewCallback(installed ? preview_callback : NULL, context, callback_flag);
}
static void autofocus_callback_impl(bool success, void *cookie)
{
+ LOGV("autoFocusCallback");
+ camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
+
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (env == NULL) {
LOGE("autofocus_callback on dead VM");
return;
}
- callback_cookie *c = (callback_cookie *)cookie;
- env->CallStaticVoidMethod(c->camera_class, fields.post_event,
- c->camera_ref, kAutoFocusCallback,
- success, 0, NULL);
+ env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
+ context->mCameraJObjectWeak, kAutoFocusCallback, success, 0, NULL);
}
-
-
static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return;
- callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
- c->setAutoFocusCallback(autofocus_callback_impl, cookie);
+ LOGV("autoFocus");
+ camera_context_t* context;
+ sp<Camera> c = get_native_camera(env, thiz, &context);
+ if (c == 0) return;
+
+ c->setAutoFocusCallback(autofocus_callback_impl, context);
if (c->autoFocus() != NO_ERROR) {
jniThrowException(env, "java/io/IOException", "autoFocus failed");
}
@@ -291,18 +310,20 @@ static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
static void jpeg_callback(const sp<IMemory>& mem, void *cookie)
{
+ LOGV("jpegCallback");
+ camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
+
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (env == NULL) {
LOGE("jpeg`_callback on dead VM");
return;
}
- callback_cookie *c = (callback_cookie *)cookie;
int arg1 = 0, arg2 = 0;
jobject obj = NULL;
if (mem == NULL) {
- env->CallStaticVoidMethod(c->camera_class, fields.post_event,
- c->camera_ref, kJpegCallback, arg1, arg2, NULL);
+ env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
+ context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, NULL);
return;
}
ssize_t offset;
@@ -331,48 +352,51 @@ static void jpeg_callback(const sp<IMemory>& mem, void *cookie)
obj = array;
- env->CallStaticVoidMethod(c->camera_class, fields.post_event,
- c->camera_ref, kJpegCallback, arg1, arg2, obj);
+ env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
+ context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, obj);
env->DeleteLocalRef(array);
}
static void shutter_callback_impl(void *cookie)
{
+ LOGV("shutterCallback");
+ camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
+
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (env == NULL) {
LOGE("shutter_callback on dead VM");
return;
}
- callback_cookie *c = (callback_cookie *)cookie;
- env->CallStaticVoidMethod(c->camera_class, fields.post_event,
- c->camera_ref, kShutterCallback, 0, 0, NULL);
+ env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
+ context->mCameraJObjectWeak, kShutterCallback, 0, 0, NULL);
}
static void raw_callback(const sp<IMemory>& mem __attribute__((unused)),
void *cookie)
{
+ LOGV("rawCallback");
+ camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
+
JNIEnv *env = AndroidRuntime::getJNIEnv();
if (env == NULL) {
LOGE("raw_callback on dead VM");
return;
}
- callback_cookie *c = (callback_cookie *)cookie;
- env->CallStaticVoidMethod(c->camera_class, fields.post_event,
- c->camera_ref, kRawCallback, 0, 0, NULL);
+ env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
+ context->mCameraJObjectWeak, kRawCallback, 0, 0, NULL);
}
static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return;
-
- callback_cookie *cookie =
- (callback_cookie *)env->GetIntField(thiz, fields.listener_context);
- c->setShutterCallback(shutter_callback_impl, cookie);
- c->setRawCallback(raw_callback, cookie);
- c->setJpegCallback(jpeg_callback, cookie);
- if (c->takePicture() != NO_ERROR) {
+ LOGV("takePicture");
+ camera_context_t* context;
+ sp<Camera> camera = get_native_camera(env, thiz, &context);
+ if (camera == 0) return;
+
+ camera->setShutterCallback(shutter_callback_impl, context);
+ camera->setRawCallback(raw_callback, context);
+ camera->setJpegCallback(jpeg_callback, context);
+ if (camera->takePicture() != NO_ERROR) {
jniThrowException(env, "java/io/IOException", "takePicture failed");
return;
}
@@ -382,9 +406,9 @@ static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return;
+ LOGV("setParameters");
+ sp<Camera> camera = get_native_camera(env, thiz, NULL);
+ if (camera == 0) return;
const jchar* str = env->GetStringCritical(params, 0);
String8 params8;
@@ -392,7 +416,7 @@ static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jst
params8 = String8(str, env->GetStringLength(params));
env->ReleaseStringCritical(params, str);
}
- if (c->setParameters(params8) != NO_ERROR) {
+ if (camera->setParameters(params8) != NO_ERROR) {
jniThrowException(env, "java/lang/IllegalArgumentException", "setParameters failed");
return;
}
@@ -400,20 +424,20 @@ static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jst
static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return 0;
+ LOGV("getParameters");
+ sp<Camera> camera = get_native_camera(env, thiz, NULL);
+ if (camera == 0) return 0;
- return env->NewStringUTF(c->getParameters().string());
+ return env->NewStringUTF(camera->getParameters().string());
}
static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return;
+ LOGV("reconnect");
+ sp<Camera> camera = get_native_camera(env, thiz, NULL);
+ if (camera == 0) return;
- if (c->reconnect() != NO_ERROR) {
+ if (camera->reconnect() != NO_ERROR) {
jniThrowException(env, "java/io/IOException", "reconnect failed");
return;
}
@@ -421,18 +445,18 @@ static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz)
static jint android_hardware_Camera_lock(JNIEnv *env, jobject thiz)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return INVALID_OPERATION;
- return (jint) c->lock();
+ LOGV("lock");
+ sp<Camera> camera = get_native_camera(env, thiz, NULL);
+ if (camera == 0) return INVALID_OPERATION;
+ return (jint) camera->lock();
}
static jint android_hardware_Camera_unlock(JNIEnv *env, jobject thiz)
{
- sp<Camera> c = get_native_camera(env, thiz);
- if (c == 0)
- return INVALID_OPERATION;
- return (jint) c->unlock();
+ LOGV("unlock");
+ sp<Camera> camera = get_native_camera(env, thiz, NULL);
+ if (camera == 0) return INVALID_OPERATION;
+ return (jint) camera->unlock();
}
//-------------------------------------------------
@@ -516,7 +540,6 @@ int register_android_hardware_Camera(JNIEnv *env)
{
field fields_to_find[] = {
{ "android/hardware/Camera", "mNativeContext", "I", &fields.context },
- { "android/hardware/Camera", "mListenerContext", "I", &fields.listener_context },
{ "android/view/Surface", "mSurface", "I", &fields.surface }
};
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index e4586d9..288433a 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -63,11 +63,11 @@ struct audiorecord_callback_cookie {
#define AUDIORECORD_ERROR -1
#define AUDIORECORD_ERROR_BAD_VALUE -2
#define AUDIORECORD_ERROR_INVALID_OPERATION -3
-#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -4
-#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT -5
-#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -6
-#define AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE -7
-#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -8
+#define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT -16
+#define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT -17
+#define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT -18
+#define AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE -19
+#define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED -20
jint android_media_translateRecorderErrorCode(int code) {
switch(code) {
@@ -267,7 +267,7 @@ static void android_media_AudioRecord_finalize(JNIEnv *env, jobject thiz) {
(AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
if (lpRecorder) {
- //LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder);
+ LOGV("About to delete lpRecorder: %x\n", (int)lpRecorder);
lpRecorder->stop();
delete lpRecorder;
}
@@ -449,6 +449,39 @@ static jint android_media_AudioRecord_get_pos_update_period(JNIEnv *env, jobjec
// ----------------------------------------------------------------------------
+// returns the minimum required size for the successful creation of an AudioRecord instance.
+// returns 0 if the parameter combination is not supported.
+// return -1 if there was an error querying the buffer size.
+static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env, jobject thiz,
+ jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
+
+ size_t inputBuffSize = 0;
+ LOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)", sampleRateInHertz, nbChannels, audioFormat);
+
+ status_t result = AudioSystem::getInputBufferSize(
+ sampleRateInHertz,
+ (audioFormat == javaAudioRecordFields.PCM16 ?
+ AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT),
+ nbChannels, &inputBuffSize);
+ switch(result) {
+ case(NO_ERROR):
+ if(inputBuffSize == 0) {
+ LOGV("Recording parameters are not supported: %dHz, %d channel(s), (java) format %d",
+ sampleRateInHertz, nbChannels, audioFormat);
+ return 0;
+ } else {
+ // the minimum buffer size is twice the hardware input buffer size
+ return 2*inputBuffSize;
+ }
+ break;
+ case(PERMISSION_DENIED):
+ default:
+ return -1;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
// name, signature, funcPtr
@@ -470,6 +503,8 @@ static JNINativeMethod gMethods[] = {
"(I)I", (void *)android_media_AudioRecord_set_pos_update_period},
{"native_get_pos_update_period",
"()I", (void *)android_media_AudioRecord_get_pos_update_period},
+ {"native_get_min_buff_size",
+ "(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
};
// field names found in android/media/AudioRecord.java
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 99785a2..692610e 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -53,11 +53,8 @@ static int
android_media_AudioSystem_setVolume(JNIEnv *env, jobject clazz, jint type, jint volume)
{
LOGV("setVolume(%d)", int(volume));
- if (int(type) == AudioTrack::VOICE_CALL) {
- return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, float(volume) / 100.0));
- } else {
- return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, AudioSystem::linearToLog(volume)));
- }
+
+ return check_AudioSystem_Command(AudioSystem::setStreamVolume(type, AudioSystem::linearToLog(volume)));
}
static int
@@ -66,12 +63,7 @@ android_media_AudioSystem_getVolume(JNIEnv *env, jobject clazz, jint type)
float v;
int v_int = -1;
if (AudioSystem::getStreamVolume(int(type), &v) == NO_ERROR) {
- // voice call volume is converted to log scale in the hardware
- if (int(type) == AudioTrack::VOICE_CALL) {
- v_int = lrint(v * 100.0);
- } else {
- v_int = AudioSystem::logToLinear(v);
- }
+ v_int = AudioSystem::logToLinear(v);
}
return v_int;
}
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 6bbcaee..f625ffb 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "AudioTrack-JNI"
@@ -53,6 +53,7 @@ struct fields_t {
int STREAM_MUSIC; //... stream type constants
int STREAM_ALARM; //... stream type constants
int STREAM_NOTIFICATION; //... stream type constants
+ int STREAM_BLUETOOTH_SCO; //... stream type constants
int MODE_STREAM; //... memory mode
int MODE_STATIC; //... memory mode
jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
@@ -71,6 +72,7 @@ class AudioTrackJniStorage {
sp<MemoryHeapBase> mMemHeap;
sp<MemoryBase> mMemBase;
audiotrack_callback_cookie mCallbackData;
+ int mStreamType;
AudioTrackJniStorage() {
}
@@ -95,13 +97,13 @@ class AudioTrackJniStorage {
#define AUDIOTRACK_SUCCESS 0
#define AUDIOTRACK_ERROR -1
-#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -2
-#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT -3
-#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -4
-#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -5
-#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -6
-#define AUDIOTRACK_ERROR_BAD_VALUE -7
-#define AUDIOTRACK_ERROR_INVALID_OPERATION -8
+#define AUDIOTRACK_ERROR_BAD_VALUE -2
+#define AUDIOTRACK_ERROR_INVALID_OPERATION -3
+#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
+#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELCOUNT -17
+#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
+#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
+#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
jint android_media_translateErrorCode(int code) {
@@ -162,16 +164,16 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
jint streamType, jint sampleRateInHertz, jint nbChannels,
jint audioFormat, jint buffSizeInBytes, jint memoryMode)
{
- //LOGV("sampleRate=%d, audioFormat(from Java)=%d, nbChannels=%d, buffSize=%d",
- // sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
+ LOGV("sampleRate=%d, audioFormat(from Java)=%d, nbChannels=%d, buffSize=%d",
+ sampleRateInHertz, audioFormat, nbChannels, buffSizeInBytes);
int afSampleRate;
int afFrameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+ if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
LOGE("Error creating AudioTrack: Could not get AudioSystem frame count.");
return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
}
- if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+ if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
LOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate.");
return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
}
@@ -182,23 +184,25 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
}
// check the stream type
- AudioTrack::stream_type atStreamType;
+ AudioSystem::stream_type atStreamType;
if (streamType == javaAudioTrackFields.STREAM_VOICE_CALL) {
- atStreamType = AudioTrack::VOICE_CALL;
+ atStreamType = AudioSystem::VOICE_CALL;
} else if (streamType == javaAudioTrackFields.STREAM_SYSTEM) {
- atStreamType = AudioTrack::SYSTEM;
+ atStreamType = AudioSystem::SYSTEM;
} else if (streamType == javaAudioTrackFields.STREAM_RING) {
- atStreamType = AudioTrack::RING;
+ atStreamType = AudioSystem::RING;
} else if (streamType == javaAudioTrackFields.STREAM_MUSIC) {
- atStreamType = AudioTrack::MUSIC;
+ atStreamType = AudioSystem::MUSIC;
} else if (streamType == javaAudioTrackFields.STREAM_ALARM) {
- atStreamType = AudioTrack::ALARM;
+ atStreamType = AudioSystem::ALARM;
} else if (streamType == javaAudioTrackFields.STREAM_NOTIFICATION) {
- atStreamType = AudioTrack::NOTIFICATION;
+ atStreamType = AudioSystem::NOTIFICATION;
+ } else if (streamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
+ atStreamType = AudioSystem::BLUETOOTH_SCO;
} else {
LOGE("Error creating AudioTrack: unknown stream type.");
return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
- }
+ }
// check the format.
// This function was called from Java, so we compare the format against the Java constants
@@ -206,7 +210,20 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
LOGE("Error creating AudioTrack: unsupported audio format.");
return AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
}
-
+
+ // for the moment 8bitPCM in MODE_STATIC is not supported natively in the AudioTrack C++ class
+ // so we declare everything as 16bitPCM, the 8->16bit conversion for MODE_STATIC will be handled
+ // in android_media_AudioTrack_native_write()
+ if ((audioFormat == javaAudioTrackFields.PCM8)
+ && (memoryMode == javaAudioTrackFields.MODE_STATIC)) {
+ LOGV("android_media_AudioTrack_native_setup(): requesting MODE_STATIC for 8bit \
+ buff size of %dbytes, switching to 16bit, buff size of %dbytes",
+ buffSizeInBytes, 2*buffSizeInBytes);
+ audioFormat = javaAudioTrackFields.PCM16;
+ // we will need twice the memory to store the data
+ buffSizeInBytes *= 2;
+ }
+
// compute the frame count
int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;
int format = audioFormat == javaAudioTrackFields.PCM16 ?
@@ -235,6 +252,8 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
// we use a weak reference so the AudioTrack object can be garbage collected.
lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
+ lpJniStorage->mStreamType = atStreamType;
+
// create the native AudioTrack object
AudioTrack* lpTrack = new AudioTrack();
if (lpTrack == NULL) {
@@ -381,13 +400,13 @@ android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, j
// ----------------------------------------------------------------------------
static void android_media_AudioTrack_native_finalize(JNIEnv *env, jobject thiz) {
- LOGV("android_media_AudioTrack_native_finalize jobject: %x\n", (int)thiz);
+ //LOGV("android_media_AudioTrack_native_finalize jobject: %x\n", (int)thiz);
// delete the AudioTrack object
AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
thiz, javaAudioTrackFields.nativeTrackInJavaObj);
if (lpTrack) {
- LOGV("deleting lpTrack: %x\n", (int)lpTrack);
+ //LOGV("deleting lpTrack: %x\n", (int)lpTrack);
lpTrack->stop();
delete lpTrack;
}
@@ -396,7 +415,7 @@ static void android_media_AudioTrack_native_finalize(JNIEnv *env, jobject thiz)
AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetIntField(
thiz, javaAudioTrackFields.jniData);
if (pJniStorage) {
- LOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
+ //LOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
delete pJniStorage;
}
}
@@ -416,7 +435,8 @@ static void android_media_AudioTrack_native_release(JNIEnv *env, jobject thiz)
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_native_write(JNIEnv *env, jobject thiz,
jbyteArray javaAudioData,
- jint offsetInBytes, jint sizeInBytes) {
+ jint offsetInBytes, jint sizeInBytes,
+ jint javaAudioFormat) {
jbyte* cAudioData = NULL;
AudioTrack *lpTrack = NULL;
//LOGV("android_media_AudioTrack_native_write(offset=%d, sizeInBytes=%d) called",
@@ -447,8 +467,22 @@ static jint android_media_AudioTrack_native_write(JNIEnv *env, jobject thiz,
if (lpTrack->sharedBuffer() == 0) {
written = lpTrack->write(cAudioData + offsetInBytes, sizeInBytes);
} else {
- memcpy(lpTrack->sharedBuffer()->pointer(), cAudioData + offsetInBytes, sizeInBytes);
- written = sizeInBytes;
+ if (javaAudioFormat == javaAudioTrackFields.PCM16) {
+ memcpy(lpTrack->sharedBuffer()->pointer(), cAudioData + offsetInBytes, sizeInBytes);
+ written = sizeInBytes;
+ } else if (javaAudioFormat == javaAudioTrackFields.PCM8) {
+ // cAudioData contains 8bit data we need to expand to 16bit before copying
+ // to the shared memory
+ int count = sizeInBytes;
+ int16_t *dst = (int16_t *)lpTrack->sharedBuffer()->pointer();
+ const int8_t *src = (const int8_t *)(cAudioData + offsetInBytes);
+ while(count--) {
+ *dst++ = (int16_t)(*src++^0x80) << 8;
+ }
+ // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
+ // the 8bit mixer restriction from the user of this function
+ written = sizeInBytes;
+ }
}
env->ReleasePrimitiveArrayCritical(javaAudioData, cAudioData, 0);
@@ -462,10 +496,12 @@ static jint android_media_AudioTrack_native_write(JNIEnv *env, jobject thiz,
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_native_write_short(JNIEnv *env, jobject thiz,
jshortArray javaAudioData,
- jint offsetInShorts, jint sizeInShorts) {
+ jint offsetInShorts, jint sizeInShorts,
+ jint javaAudioFormat) {
return (android_media_AudioTrack_native_write(env, thiz,
(jbyteArray) javaAudioData,
- offsetInShorts*2, sizeInShorts*2)
+ offsetInShorts*2, sizeInShorts*2,
+ javaAudioFormat)
/ 2);
}
@@ -652,9 +688,33 @@ static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
// ----------------------------------------------------------------------------
-static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz) {
+static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
+ jint javaStreamType) {
int afSamplingRate;
- if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {
+ // convert the stream type from Java to native value
+ // FIXME: code duplication with android_media_AudioTrack_native_setup()
+ AudioSystem::stream_type nativeStreamType;
+ if (javaStreamType == javaAudioTrackFields.STREAM_VOICE_CALL) {
+ nativeStreamType = AudioSystem::VOICE_CALL;
+ } else if (javaStreamType == javaAudioTrackFields.STREAM_SYSTEM) {
+ nativeStreamType = AudioSystem::SYSTEM;
+ } else if (javaStreamType == javaAudioTrackFields.STREAM_RING) {
+ nativeStreamType = AudioSystem::RING;
+ } else if (javaStreamType == javaAudioTrackFields.STREAM_MUSIC) {
+ nativeStreamType = AudioSystem::MUSIC;
+ } else if (javaStreamType == javaAudioTrackFields.STREAM_ALARM) {
+ nativeStreamType = AudioSystem::ALARM;
+ } else if (javaStreamType == javaAudioTrackFields.STREAM_NOTIFICATION) {
+ nativeStreamType = AudioSystem::NOTIFICATION;
+ } else if (javaStreamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
+ nativeStreamType = AudioSystem::BLUETOOTH_SCO;
+ } else {
+ nativeStreamType = AudioSystem::DEFAULT;
+ }
+
+ if (AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType) != NO_ERROR) {
+ LOGE("AudioSystem::getOutputSamplingRate() for stream type %d failed in AudioTrack JNI",
+ nativeStreamType);
return DEFAULT_OUTPUT_SAMPLE_RATE;
} else {
return afSamplingRate;
@@ -663,6 +723,36 @@ static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobjec
// ----------------------------------------------------------------------------
+// returns the minimum required size for the successful creation of a streaming AudioTrack
+// returns -1 if there was an error querying the hardware.
+static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
+ jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
+ int afSamplingRate;
+ int afFrameCount;
+ uint32_t afLatency;
+
+ if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {
+ return -1;
+ }
+ if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+ return -1;
+ }
+
+ if (AudioSystem::getOutputLatency(&afLatency) != NO_ERROR) {
+ return -1;
+ }
+
+ // Ensure that buffer depth covers at least audio hardware latency
+ uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSamplingRate);
+ uint32_t minFrameCount = (afFrameCount*sampleRateInHertz*minBufCount)/afSamplingRate;
+ int minBuffSize = minFrameCount
+ * (audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1)
+ * nbChannels;
+ return minBuffSize;
+}
+
+
+// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
// name, signature, funcPtr
@@ -674,8 +764,8 @@ static JNINativeMethod gMethods[] = {
(void *)android_media_AudioTrack_native_setup},
{"native_finalize", "()V", (void *)android_media_AudioTrack_native_finalize},
{"native_release", "()V", (void *)android_media_AudioTrack_native_release},
- {"native_write_byte", "([BII)I", (void *)android_media_AudioTrack_native_write},
- {"native_write_short", "([SII)I", (void *)android_media_AudioTrack_native_write_short},
+ {"native_write_byte", "([BIII)I", (void *)android_media_AudioTrack_native_write},
+ {"native_write_short", "([SIII)I", (void *)android_media_AudioTrack_native_write_short},
{"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
{"native_get_native_frame_count",
"()I", (void *)android_media_AudioTrack_get_native_frame_count},
@@ -694,25 +784,28 @@ static JNINativeMethod gMethods[] = {
{"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
{"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
{"native_get_output_sample_rate",
- "()I", (void *)android_media_AudioTrack_get_output_sample_rate},
+ "(I)I", (void *)android_media_AudioTrack_get_output_sample_rate},
+ {"native_get_min_buff_size",
+ "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
};
// field names found in android/media/AudioTrack.java
-#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
-#define JAVA_CONST_PCM16_NAME "ENCODING_PCM_16BIT"
-#define JAVA_CONST_PCM8_NAME "ENCODING_PCM_8BIT"
-#define JAVA_CONST_BUFFER_COUNT_NAME "BUFFER_COUNT"
-#define JAVA_CONST_STREAM_VOICE_CALL_NAME "STREAM_VOICE_CALL"
-#define JAVA_CONST_STREAM_SYSTEM_NAME "STREAM_SYSTEM"
-#define JAVA_CONST_STREAM_RING_NAME "STREAM_RING"
-#define JAVA_CONST_STREAM_MUSIC_NAME "STREAM_MUSIC"
-#define JAVA_CONST_STREAM_ALARM_NAME "STREAM_ALARM"
-#define JAVA_CONST_STREAM_NOTIFICATION_NAME "STREAM_NOTIFICATION"
-#define JAVA_CONST_MODE_STREAM_NAME "MODE_STREAM"
-#define JAVA_CONST_MODE_STATIC_NAME "MODE_STATIC"
-#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
-#define JAVA_JNIDATA_FIELD_NAME "mJniData"
+#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
+#define JAVA_CONST_PCM16_NAME "ENCODING_PCM_16BIT"
+#define JAVA_CONST_PCM8_NAME "ENCODING_PCM_8BIT"
+#define JAVA_CONST_BUFFER_COUNT_NAME "BUFFER_COUNT"
+#define JAVA_CONST_STREAM_VOICE_CALL_NAME "STREAM_VOICE_CALL"
+#define JAVA_CONST_STREAM_SYSTEM_NAME "STREAM_SYSTEM"
+#define JAVA_CONST_STREAM_RING_NAME "STREAM_RING"
+#define JAVA_CONST_STREAM_MUSIC_NAME "STREAM_MUSIC"
+#define JAVA_CONST_STREAM_ALARM_NAME "STREAM_ALARM"
+#define JAVA_CONST_STREAM_NOTIFICATION_NAME "STREAM_NOTIFICATION"
+#define JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME "STREAM_BLUETOOTH_SCO"
+#define JAVA_CONST_MODE_STREAM_NAME "MODE_STREAM"
+#define JAVA_CONST_MODE_STATIC_NAME "MODE_STATIC"
+#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
+#define JAVA_JNIDATA_FIELD_NAME "mJniData"
#define JAVA_AUDIOFORMAT_CLASS_NAME "android/media/AudioFormat"
#define JAVA_AUDIOMANAGER_CLASS_NAME "android/media/AudioManager"
@@ -810,28 +903,32 @@ int register_android_media_AudioTrack(JNIEnv *env)
LOGE("Can't find %s", JAVA_AUDIOMANAGER_CLASS_NAME);
return -1;
}
- if ( !android_media_getIntConstantFromClass(env, audioManagerClass,
- JAVA_AUDIOMANAGER_CLASS_NAME,
+ if ( !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
JAVA_CONST_STREAM_VOICE_CALL_NAME, &(javaAudioTrackFields.STREAM_VOICE_CALL))
- || !android_media_getIntConstantFromClass(env, audioManagerClass,
- JAVA_AUDIOMANAGER_CLASS_NAME,
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
JAVA_CONST_STREAM_MUSIC_NAME, &(javaAudioTrackFields.STREAM_MUSIC))
- || !android_media_getIntConstantFromClass(env, audioManagerClass,
- JAVA_AUDIOMANAGER_CLASS_NAME,
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
JAVA_CONST_STREAM_SYSTEM_NAME, &(javaAudioTrackFields.STREAM_SYSTEM))
- || !android_media_getIntConstantFromClass(env, audioManagerClass,
- JAVA_AUDIOMANAGER_CLASS_NAME,
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
JAVA_CONST_STREAM_RING_NAME, &(javaAudioTrackFields.STREAM_RING))
|| !android_media_getIntConstantFromClass(env, audioManagerClass,
- JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
JAVA_CONST_STREAM_ALARM_NAME, &(javaAudioTrackFields.STREAM_ALARM))
|| !android_media_getIntConstantFromClass(env, audioManagerClass,
- JAVA_AUDIOMANAGER_CLASS_NAME,
- JAVA_CONST_STREAM_NOTIFICATION_NAME, &(javaAudioTrackFields.STREAM_NOTIFICATION)) ) {
+ JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_CONST_STREAM_NOTIFICATION_NAME, &(javaAudioTrackFields.STREAM_NOTIFICATION))
+ || !android_media_getIntConstantFromClass(env, audioManagerClass,
+ JAVA_AUDIOMANAGER_CLASS_NAME,
+ JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME,
+ &(javaAudioTrackFields.STREAM_BLUETOOTH_SCO))) {
// error log performed in android_media_getIntConstantFromClass()
return -1;
}
-
+
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_media_JetPlayer.cpp b/core/jni/android_media_JetPlayer.cpp
index 994f161..e345af6 100644
--- a/core/jni/android_media_JetPlayer.cpp
+++ b/core/jni/android_media_JetPlayer.cpp
@@ -81,7 +81,7 @@ android_media_JetPlayer_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jint maxTracks, jint trackBufferSize)
{
//LOGV("android_media_JetPlayer_setup(): entering.");
- JetPlayer* lpJet = new JetPlayer(weak_this, maxTracks, trackBufferSize);
+ JetPlayer* lpJet = new JetPlayer(env->NewGlobalRef(weak_this), maxTracks, trackBufferSize);
EAS_RESULT result = lpJet->init();
@@ -127,7 +127,7 @@ android_media_JetPlayer_release(JNIEnv *env, jobject thiz)
// ----------------------------------------------------------------------------
static jboolean
-android_media_JetPlayer_openFile(JNIEnv *env, jobject thiz, jstring path)
+android_media_JetPlayer_loadFromFile(JNIEnv *env, jobject thiz, jstring path)
{
JetPlayer *lpJet = (JetPlayer *)env->GetIntField(
thiz, javaJetPlayerFields.nativePlayerInJavaObj);
@@ -139,7 +139,6 @@ android_media_JetPlayer_openFile(JNIEnv *env, jobject thiz, jstring path)
// set up event callback function
lpJet->setEventCallback(jetPlayerEventCallback);
-
const char *pathStr = env->GetStringUTFChars(path, NULL);
if (pathStr == NULL) { // Out of memory
LOGE("android_media_JetPlayer_openFile(): aborting, out of memory");
@@ -148,7 +147,7 @@ android_media_JetPlayer_openFile(JNIEnv *env, jobject thiz, jstring path)
}
LOGV("android_media_JetPlayer_openFile(): trying to open %s", pathStr );
- EAS_RESULT result = lpJet->openFile(pathStr);
+ EAS_RESULT result = lpJet->loadFromFile(pathStr);
env->ReleaseStringUTFChars(path, pathStr);
if(result==EAS_SUCCESS) {
@@ -164,7 +163,8 @@ android_media_JetPlayer_openFile(JNIEnv *env, jobject thiz, jstring path)
// ----------------------------------------------------------------------------
static jboolean
-android_media_JetPlayer_closeFile(JNIEnv *env, jobject thiz)
+android_media_JetPlayer_loadFromFileD(JNIEnv *env, jobject thiz,
+ jobject fileDescriptor, jlong offset, jlong length)
{
JetPlayer *lpJet = (JetPlayer *)env->GetIntField(
thiz, javaJetPlayerFields.nativePlayerInJavaObj);
@@ -173,6 +173,35 @@ android_media_JetPlayer_closeFile(JNIEnv *env, jobject thiz)
"Unable to retrieve JetPlayer pointer for openFile()");
}
+ // set up event callback function
+ lpJet->setEventCallback(jetPlayerEventCallback);
+
+ LOGV("android_media_JetPlayer_openFileDescr(): trying to load JET file through its fd" );
+ EAS_RESULT result = lpJet->loadFromFD(getParcelFileDescriptorFD(env, fileDescriptor),
+ (long long)offset, (long long)length); // cast params to types used by EAS_FILE
+
+ if(result==EAS_SUCCESS) {
+ LOGV("android_media_JetPlayer_openFileDescr(): file successfully opened");
+ return JNI_TRUE;
+ } else {
+ LOGE("android_media_JetPlayer_openFileDescr(): failed to open file with EAS error %d",
+ (int)result);
+ return JNI_FALSE;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+static jboolean
+android_media_JetPlayer_closeFile(JNIEnv *env, jobject thiz)
+{
+ JetPlayer *lpJet = (JetPlayer *)env->GetIntField(
+ thiz, javaJetPlayerFields.nativePlayerInJavaObj);
+ if (lpJet == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve JetPlayer pointer for closeFile()");
+ }
+
if( lpJet->closeFile()==EAS_SUCCESS) {
//LOGV("android_media_JetPlayer_closeFile(): file successfully closed");
return JNI_TRUE;
@@ -191,7 +220,7 @@ android_media_JetPlayer_play(JNIEnv *env, jobject thiz)
thiz, javaJetPlayerFields.nativePlayerInJavaObj);
if (lpJet == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve JetPlayer pointer for openFile()");
+ "Unable to retrieve JetPlayer pointer for play()");
}
EAS_RESULT result = lpJet->play();
@@ -214,7 +243,7 @@ android_media_JetPlayer_pause(JNIEnv *env, jobject thiz)
thiz, javaJetPlayerFields.nativePlayerInJavaObj);
if (lpJet == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve JetPlayer pointer for openFile()");
+ "Unable to retrieve JetPlayer pointer for pause()");
}
EAS_RESULT result = lpJet->pause();
@@ -243,7 +272,7 @@ android_media_JetPlayer_queueSegment(JNIEnv *env, jobject thiz,
thiz, javaJetPlayerFields.nativePlayerInJavaObj);
if (lpJet == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve JetPlayer pointer for openFile()");
+ "Unable to retrieve JetPlayer pointer for queueSegment()");
}
EAS_RESULT result
@@ -269,7 +298,7 @@ android_media_JetPlayer_queueSegmentMuteArray(JNIEnv *env, jobject thiz,
thiz, javaJetPlayerFields.nativePlayerInJavaObj);
if (lpJet == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve JetPlayer pointer for openFile()");
+ "Unable to retrieve JetPlayer pointer for queueSegmentMuteArray()");
}
EAS_RESULT result=EAS_FAILURE;
@@ -314,7 +343,7 @@ android_media_JetPlayer_setMuteFlags(JNIEnv *env, jobject thiz,
thiz, javaJetPlayerFields.nativePlayerInJavaObj);
if (lpJet == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve JetPlayer pointer for openFile()");
+ "Unable to retrieve JetPlayer pointer for setMuteFlags()");
}
EAS_RESULT result;
@@ -338,7 +367,7 @@ android_media_JetPlayer_setMuteArray(JNIEnv *env, jobject thiz,
thiz, javaJetPlayerFields.nativePlayerInJavaObj);
if (lpJet == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve JetPlayer pointer for openFile()");
+ "Unable to retrieve JetPlayer pointer for setMuteArray()");
}
EAS_RESULT result=EAS_FAILURE;
@@ -367,7 +396,8 @@ android_media_JetPlayer_setMuteArray(JNIEnv *env, jobject thiz,
//LOGV("android_media_JetPlayer_setMuteArray(): mute flags successfully updated");
return JNI_TRUE;
} else {
- LOGE("android_media_JetPlayer_setMuteArray(): failed to update mute flags with EAS error code %ld", result);
+ LOGE("android_media_JetPlayer_setMuteArray(): \
+ failed to update mute flags with EAS error code %ld", result);
return JNI_FALSE;
}
}
@@ -382,7 +412,7 @@ android_media_JetPlayer_setMuteFlag(JNIEnv *env, jobject thiz,
thiz, javaJetPlayerFields.nativePlayerInJavaObj);
if (lpJet == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve JetPlayer pointer for openFile()");
+ "Unable to retrieve JetPlayer pointer for setMuteFlag()");
}
EAS_RESULT result;
@@ -407,7 +437,7 @@ android_media_JetPlayer_triggerClip(JNIEnv *env, jobject thiz, jint clipId)
thiz, javaJetPlayerFields.nativePlayerInJavaObj);
if (lpJet == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve JetPlayer pointer for openFile()");
+ "Unable to retrieve JetPlayer pointer for triggerClip()");
}
EAS_RESULT result;
@@ -424,13 +454,39 @@ android_media_JetPlayer_triggerClip(JNIEnv *env, jobject thiz, jint clipId)
// ----------------------------------------------------------------------------
+static jboolean
+android_media_JetPlayer_clearQueue(JNIEnv *env, jobject thiz)
+{
+ JetPlayer *lpJet = (JetPlayer *)env->GetIntField(
+ thiz, javaJetPlayerFields.nativePlayerInJavaObj);
+ if (lpJet == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve JetPlayer pointer for clearQueue()");
+ }
+
+ EAS_RESULT result = lpJet->clearQueue();
+ if(result==EAS_SUCCESS) {
+ //LOGV("android_media_JetPlayer_clearQueue(): clearQueue successful");
+ return JNI_TRUE;
+ } else {
+ LOGE("android_media_JetPlayer_clearQueue(): clearQueue failed with EAS error code %ld",
+ result);
+ return JNI_FALSE;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
// name, signature, funcPtr
{"native_setup", "(Ljava/lang/Object;II)Z", (void *)android_media_JetPlayer_setup},
{"native_finalize", "()V", (void *)android_media_JetPlayer_finalize},
{"native_release", "()V", (void *)android_media_JetPlayer_release},
- {"native_openJetFile", "(Ljava/lang/String;)Z", (void *)android_media_JetPlayer_openFile},
+ {"native_loadJetFromFile",
+ "(Ljava/lang/String;)Z", (void *)android_media_JetPlayer_loadFromFile},
+ {"native_loadJetFromFileD", "(Ljava/io/FileDescriptor;JJ)Z",
+ (void *)android_media_JetPlayer_loadFromFileD},
{"native_closeJetFile","()Z", (void *)android_media_JetPlayer_closeFile},
{"native_playJet", "()Z", (void *)android_media_JetPlayer_play},
{"native_pauseJet", "()Z", (void *)android_media_JetPlayer_pause},
@@ -442,6 +498,7 @@ static JNINativeMethod gMethods[] = {
{"native_setMuteArray","([ZZ)Z", (void *)android_media_JetPlayer_setMuteArray},
{"native_setMuteFlag", "(IZZ)Z", (void *)android_media_JetPlayer_setMuteFlag},
{"native_triggerClip", "(I)Z", (void *)android_media_JetPlayer_triggerClip},
+ {"native_clearQueue", "()Z", (void *)android_media_JetPlayer_clearQueue},
};
#define JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME "mNativePlayerInJavaObj"
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 722b5b8..fcab813 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -287,6 +287,24 @@ static jboolean android_net_wifi_stopDriverCommand(JNIEnv* env, jobject clazz)
return doBooleanCommand("DRIVER STOP", "OK");
}
+static jboolean android_net_wifi_startPacketFiltering(JNIEnv* env, jobject clazz)
+{
+ return doBooleanCommand("DRIVER RXFILTER-ADD 0", "OK")
+ && doBooleanCommand("DRIVER RXFILTER-ADD 1", "OK")
+ && doBooleanCommand("DRIVER RXFILTER-START", "OK");
+}
+
+static jboolean android_net_wifi_stopPacketFiltering(JNIEnv* env, jobject clazz)
+{
+ jboolean result = doBooleanCommand("DRIVER RXFILTER-STOP", "OK");
+ if (result) {
+ (void)doBooleanCommand("DRIVER RXFILTER-REMOVE 1", "OK");
+ (void)doBooleanCommand("DRIVER RXFILTER-REMOVE 0", "OK");
+ }
+
+ return result;
+}
+
static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz)
{
char reply[256];
@@ -379,6 +397,16 @@ static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env,
return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
}
+static jboolean android_net_wifi_setBluetoothCoexistenceScanModeCommand(JNIEnv* env, jobject clazz, jboolean setCoexScanMode)
+{
+ char cmdstr[256];
+
+ int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER BTCOEXSCAN-%s", setCoexScanMode ? "START" : "STOP");
+ int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
+
+ return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+}
+
static jboolean android_net_wifi_saveConfigCommand(JNIEnv* env, jobject clazz)
{
// Make sure we never write out a value for AP_SCAN other than 1
@@ -478,11 +506,15 @@ static JNINativeMethod gWifiMethods[] = {
{ "setScanModeCommand", "(Z)Z", (void*) android_net_wifi_setScanModeCommand },
{ "startDriverCommand", "()Z", (void*) android_net_wifi_startDriverCommand },
{ "stopDriverCommand", "()Z", (void*) android_net_wifi_stopDriverCommand },
+ { "startPacketFiltering", "()Z", (void*) android_net_wifi_startPacketFiltering },
+ { "stopPacketFiltering", "()Z", (void*) android_net_wifi_stopPacketFiltering },
{ "setPowerModeCommand", "(I)Z", (void*) android_net_wifi_setPowerModeCommand },
{ "setNumAllowedChannelsCommand", "(I)Z", (void*) android_net_wifi_setNumAllowedChannelsCommand },
{ "getNumAllowedChannelsCommand", "()I", (void*) android_net_wifi_getNumAllowedChannelsCommand },
{ "setBluetoothCoexistenceModeCommand", "(I)Z",
(void*) android_net_wifi_setBluetoothCoexistenceModeCommand },
+ { "setBluetoothCoexistenceScanModeCommand", "(Z)Z",
+ (void*) android_net_wifi_setBluetoothCoexistenceScanModeCommand },
{ "getRssiCommand", "()I", (void*) android_net_wifi_getRssiCommand },
{ "getLinkSpeedCommand", "()I", (void*) android_net_wifi_getLinkSpeedCommand },
{ "getMacAddressCommand", "()Ljava/lang/String;", (void*) android_net_wifi_getMacAddressCommand },
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 6ba949c..a6b63d8 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -88,93 +88,101 @@ static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz)
#endif
}
-static int read_mapinfo(FILE *fp, stats_t* stats)
+static void read_mapinfo(FILE *fp, stats_t* stats)
{
char line[1024];
int len;
- int skip;
+ bool skip, done = false;
unsigned start = 0, size = 0, resident = 0, pss = 0;
unsigned shared_clean = 0, shared_dirty = 0;
unsigned private_clean = 0, private_dirty = 0;
unsigned referenced = 0;
+ unsigned temp;
int isNativeHeap;
int isDalvikHeap;
int isSqliteHeap;
-again:
- isNativeHeap = 0;
- isDalvikHeap = 0;
- isSqliteHeap = 0;
- skip = 0;
-
- if(fgets(line, 1024, fp) == 0) return 0;
+ if(fgets(line, 1024, fp) == 0) return;
+
+ while (!done) {
+ isNativeHeap = 0;
+ isDalvikHeap = 0;
+ isSqliteHeap = 0;
+ skip = false;
- len = strlen(line);
- if (len < 1) return 0;
- line[--len] = 0;
+ len = strlen(line);
+ if (len < 1) return;
+ line[--len] = 0;
- /* ignore guard pages */
- if (line[18] == '-') skip = 1;
+ /* ignore guard pages */
+ if (len > 18 && line[17] == '-') skip = true;
- start = strtoul(line, 0, 16);
+ start = strtoul(line, 0, 16);
- if (len >= 50) {
- if (!strcmp(line + 49, "[heap]")) {
+ if (strstr(line, "[heap]")) {
isNativeHeap = 1;
- } else if (!strncmp(line + 49, "/dalvik-LinearAlloc", strlen("/dalvik-LinearAlloc"))) {
+ } else if (strstr(line, "/dalvik-LinearAlloc")) {
isDalvikHeap = 1;
- } else if (!strncmp(line + 49, "/mspace/dalvik-heap", strlen("/mspace/dalvik-heap"))) {
+ } else if (strstr(line, "/mspace/dalvik-heap")) {
isDalvikHeap = 1;
- } else if (!strncmp(line + 49, "/dalvik-heap-bitmap/", strlen("/dalvik-heap-bitmap/"))) {
+ } else if (strstr(line, "/dalvik-heap-bitmap/")) {
isDalvikHeap = 1;
- } else if (!strncmp(line + 49, "/tmp/sqlite-heap", strlen("/tmp/sqlite-heap"))) {
+ } else if (strstr(line, "/tmp/sqlite-heap")) {
isSqliteHeap = 1;
}
- }
- // TODO: This needs to be fixed to be less fragile. If the order of this file changes or a new
- // line is add, this method will return without filling out any of the information.
-
- if (fgets(line, 1024, fp) == 0) return 0;
- if (sscanf(line, "Size: %d kB", &size) != 1) return 0;
- if (fgets(line, 1024, fp) == 0) return 0;
- if (sscanf(line, "Rss: %d kB", &resident) != 1) return 0;
- if (fgets(line, 1024, fp) == 0) return 0;
- if (sscanf(line, "Pss: %d kB", &pss) != 1) return 0;
- if (fgets(line, 1024, fp) == 0) return 0;
- if (sscanf(line, "Shared_Clean: %d kB", &shared_clean) != 1) return 0;
- if (fgets(line, 1024, fp) == 0) return 0;
- if (sscanf(line, "Shared_Dirty: %d kB", &shared_dirty) != 1) return 0;
- if (fgets(line, 1024, fp) == 0) return 0;
- if (sscanf(line, "Private_Clean: %d kB", &private_clean) != 1) return 0;
- if (fgets(line, 1024, fp) == 0) return 0;
- if (sscanf(line, "Private_Dirty: %d kB", &private_dirty) != 1) return 0;
- if (fgets(line, 1024, fp) == 0) return 0;
- if (sscanf(line, "Referenced: %d kB", &referenced) != 1) return 0;
-
- if (skip) {
- goto again;
- }
+ //LOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
+ // isSqliteHeap, line);
+
+ while (true) {
+ if (fgets(line, 1024, fp) == 0) {
+ done = true;
+ break;
+ }
+
+ if (sscanf(line, "Size: %d kB", &temp) == 1) {
+ size = temp;
+ } else if (sscanf(line, "Rss: %d kB", &temp) == 1) {
+ resident = temp;
+ } else if (sscanf(line, "Pss: %d kB", &temp) == 1) {
+ pss = temp;
+ } else if (sscanf(line, "Shared_Clean: %d kB", &temp) == 1) {
+ shared_clean = temp;
+ } else if (sscanf(line, "Shared_Dirty: %d kB", &temp) == 1) {
+ shared_dirty = temp;
+ } else if (sscanf(line, "Private_Clean: %d kB", &temp) == 1) {
+ private_clean = temp;
+ } else if (sscanf(line, "Private_Dirty: %d kB", &temp) == 1) {
+ private_dirty = temp;
+ } else if (sscanf(line, "Referenced: %d kB", &temp) == 1) {
+ referenced = temp;
+ } else if (strlen(line) > 40 && line[8] == '-' && line[17] == ' ') {
+ // looks like a new mapping
+ // example: "0000a000-00232000 rwxp 0000a000 00:00 0 [heap]"
+ break;
+ }
+ }
- if (isNativeHeap) {
- stats->nativePss += pss;
- stats->nativePrivateDirty += private_dirty;
- stats->nativeSharedDirty += shared_dirty;
- } else if (isDalvikHeap) {
- stats->dalvikPss += pss;
- stats->dalvikPrivateDirty += private_dirty;
- stats->dalvikSharedDirty += shared_dirty;
- } else if (isSqliteHeap) {
- // ignore
- } else {
- stats->otherPss += pss;
- stats->otherPrivateDirty += shared_dirty;
- stats->otherSharedDirty += private_dirty;
+ if (!skip) {
+ if (isNativeHeap) {
+ stats->nativePss += pss;
+ stats->nativePrivateDirty += private_dirty;
+ stats->nativeSharedDirty += shared_dirty;
+ } else if (isDalvikHeap) {
+ stats->dalvikPss += pss;
+ stats->dalvikPrivateDirty += private_dirty;
+ stats->dalvikSharedDirty += shared_dirty;
+ } else if ( isSqliteHeap) {
+ // ignore
+ } else {
+ stats->otherPss += pss;
+ stats->otherPrivateDirty += shared_dirty;
+ stats->otherSharedDirty += private_dirty;
+ }
+ }
}
-
- return 1;
}
static void load_maps(int pid, stats_t* stats)
@@ -185,10 +193,8 @@ static void load_maps(int pid, stats_t* stats)
sprintf(tmp, "/proc/%d/smaps", pid);
fp = fopen(tmp, "r");
if (fp == 0) return;
-
- while (read_mapinfo(fp, stats) != 0) {
- // Do nothing
- }
+
+ read_mapinfo(fp, stats);
fclose(fp);
}
diff --git a/core/jni/android_os_NetStat.cpp b/core/jni/android_os_NetStat.cpp
deleted file mode 100644
index 983f719..0000000
--- a/core/jni/android_os_NetStat.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-/* //device/libs/android_runtime/android_os_Wifi.cpp
-**
-** Copyright 2007, 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.
-*/
-
-#define LOG_TAG "NetStat"
-
-#include "jni.h"
-#include <utils/misc.h>
-#include <android_runtime/AndroidRuntime.h>
-#include <utils/Log.h>
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#if HAVE_ANDROID_OS
-#include <utils/Atomic.h>
-#endif
-
-namespace android {
-
-static jint android_os_netStatGetTxPkts(JNIEnv* env, jobject clazz)
-{
- int ret = 0;
- int fd = -1;
- char input[50];
-
- fd = open("/sys/class/net/rmnet0/statistics/tx_packets", O_RDONLY);
- if (fd <= 0) {
- fd = open("/sys/class/net/ppp0/statistics/tx_packets", O_RDONLY);
- }
-
- if (fd > 0) {
- int size = read(fd, input, 50);
- if (size > 0) {
- ret = atoi(input);
- }
- close(fd);
- }
-
- return (jint)ret;
-}
-
-static jint android_os_netStatGetRxPkts(JNIEnv* env, jobject clazz)
-{
- int ret = 0;
- int fd = -1;
- char input[50];
-
- fd = open("/sys/class/net/rmnet0/statistics/rx_packets", O_RDONLY);
- if (fd <= 0) {
- fd = open("/sys/class/net/ppp0/statistics/rx_packets", O_RDONLY);
- }
-
- if (fd > 0) {
- int size = read(fd, input, 50);
- if (size > 0) {
- ret = atoi(input);
- }
- close(fd);
- }
-
- return (jint)ret;
-}
-
-static jint android_os_netStatGetRxBytes(JNIEnv* env, jobject clazz)
-{
- int ret = 0;
- int fd = -1;
- char input[50];
-
- fd = open("/sys/class/net/rmnet0/statistics/rx_bytes", O_RDONLY);
- if (fd <= 0) {
- fd = open("/sys/class/net/ppp0/statistics/rx_bytes", O_RDONLY);
- }
-
- if (fd > 0) {
- int size = read(fd, input, 50);
- if (size > 0) {
- ret = atoi(input);
- }
- close(fd);
- }
-
- return (jint)ret;
-}
-
-
-static jint android_os_netStatGetTxBytes(JNIEnv* env, jobject clazz)
-{
- int ret = 0;
- int fd = -1;
- char input[50];
-
- fd = open("/sys/class/net/rmnet0/statistics/tx_bytes", O_RDONLY);
- if (fd <= 0) {
- fd = open("/sys/class/net/ppp0/statistics/tx_bytes", O_RDONLY);
- }
-
- if (fd > 0) {
- int size = read(fd, input, 50);
- if (size > 0) {
- ret = atoi(input);
- }
- close(fd);
- }
-
- return (jint)ret;
-}
-
-// ----------------------------------------------------------------------------
-
-/*
- * JNI registration.
- */
-static JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
-
- { "netStatGetTxPkts", "()I",
- (void*) android_os_netStatGetTxPkts },
-
- { "netStatGetRxPkts", "()I",
- (void*) android_os_netStatGetRxPkts },
-
- { "netStatGetTxBytes", "()I",
- (void*) android_os_netStatGetTxBytes },
-
- { "netStatGetRxBytes", "()I",
- (void*) android_os_netStatGetRxBytes },
-
-};
-
-int register_android_os_NetStat(JNIEnv* env)
-{
- jclass netStat = env->FindClass("android/os/NetStat");
- LOG_FATAL_IF(netStat == NULL, "Unable to find class android/os/NetStat");
-
- return AndroidRuntime::registerNativeMethods(env,
- "android/os/NetStat", gMethods, NELEM(gMethods));
-}
-
-}; // namespace android
-
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
index 465e233..971f87c 100644
--- a/core/jni/android_os_ParcelFileDescriptor.cpp
+++ b/core/jni/android_os_ParcelFileDescriptor.cpp
@@ -15,6 +15,8 @@
** limitations under the License.
*/
+//#define LOG_NDEBUG 0
+
#include "JNIHelp.h"
#include <fcntl.h>
@@ -45,6 +47,11 @@ static struct socket_impl_offsets_t
jfieldID mFileDescriptor;
} gSocketImplOffsets;
+static struct parcel_file_descriptor_offsets_t
+{
+ jclass mClass;
+ jfieldID mFileDescriptor;
+} gParcelFileDescriptorOffsets;
static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromSocket(JNIEnv* env,
jobject clazz, jobject object)
@@ -60,9 +67,53 @@ static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromSocket(JNIEn
return fileDescriptorClone;
}
+static jint getFd(JNIEnv* env, jobject clazz)
+{
+ jobject descriptor = env->GetObjectField(clazz, gParcelFileDescriptorOffsets.mFileDescriptor);
+ if (descriptor == NULL) return -1;
+ return env->GetIntField(descriptor, gFileDescriptorOffsets.mDescriptor);
+}
+
+static jlong android_os_ParcelFileDescriptor_getStatSize(JNIEnv* env,
+ jobject clazz)
+{
+ jint fd = getFd(env, clazz);
+ if (fd < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
+ return -1;
+ }
+
+ struct stat st;
+ if (fstat(fd, &st) != 0) {
+ return -1;
+ }
+
+ if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+ return st.st_size;
+ }
+
+ return -1;
+}
+
+static jlong android_os_ParcelFileDescriptor_seekTo(JNIEnv* env,
+ jobject clazz, jlong pos)
+{
+ jint fd = getFd(env, clazz);
+ if (fd < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
+ return -1;
+ }
+
+ return lseek(fd, pos, SEEK_SET);
+}
+
static const JNINativeMethod gParcelFileDescriptorMethods[] = {
{"getFileDescriptorFromSocket", "(Ljava/net/Socket;)Ljava/io/FileDescriptor;",
- (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket}
+ (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket},
+ {"getStatSize", "()J",
+ (void*)android_os_ParcelFileDescriptor_getStatSize},
+ {"seekTo", "(J)J",
+ (void*)android_os_ParcelFileDescriptor_seekTo}
};
const char* const kParcelFileDescriptorPathName = "android/os/ParcelFileDescriptor";
@@ -93,6 +144,10 @@ int register_android_os_ParcelFileDescriptor(JNIEnv* env)
clazz = env->FindClass(kParcelFileDescriptorPathName);
LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
+ gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gParcelFileDescriptorOffsets.mFileDescriptor = env->GetFieldID(clazz, "mFileDescriptor", "Ljava/io/FileDescriptor;");
+ LOG_FATAL_IF(gParcelFileDescriptorOffsets.mFileDescriptor == NULL,
+ "Unable to find mFileDescriptor field in android.os.ParcelFileDescriptor");
return AndroidRuntime::registerNativeMethods(
env, kParcelFileDescriptorPathName,
diff --git a/core/jni/android_server_BluetoothDeviceService.cpp b/core/jni/android_server_BluetoothDeviceService.cpp
index 61a4a26..796da15 100644
--- a/core/jni/android_server_BluetoothDeviceService.cpp
+++ b/core/jni/android_server_BluetoothDeviceService.cpp
@@ -428,36 +428,6 @@ static void disconnectRemoteDeviceNative(JNIEnv *env, jobject object, jstring ad
#endif
}
-static jboolean isConnectableNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "IsConnectable",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean isDiscoverableNative(JNIEnv *env, jobject object) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "IsDiscoverable",
- DBUS_TYPE_INVALID);
- return reply ? dbus_returns_boolean(env, reply) : JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
static jstring getModeNative(JNIEnv *env, jobject object) {
#ifdef HAVE_BLUETOOTH
LOGV(__FUNCTION__);
@@ -495,26 +465,6 @@ static jboolean setModeNative(JNIEnv *env, jobject object, jstring mode) {
return JNI_FALSE;
}
-static void common_Bonding(JNIEnv *env, jobject object, int timeout_ms,
- const char *func, jstring address) {
-#ifdef HAVE_BLUETOOTH
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- LOGV("... address = %s", c_address);
- DBusMessage *reply =
- dbus_func_args_timeout(env, nat->conn, timeout_ms, nat->adapter,
- DBUS_CLASS_NAME, func,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- if (reply) {
- dbus_message_unref(reply);
- }
- }
-#endif
-}
-
static jboolean createBondingNative(JNIEnv *env, jobject object,
jstring address, jint timeout_ms) {
LOGV(__FUNCTION__);
@@ -540,15 +490,64 @@ static jboolean createBondingNative(JNIEnv *env, jobject object,
return JNI_FALSE;
}
-static void cancelBondingProcessNative(JNIEnv *env, jobject object,
+static jboolean cancelBondingProcessNative(JNIEnv *env, jobject object,
jstring address) {
LOGV(__FUNCTION__);
- common_Bonding(env, object, -1, "CancelBondingProcess", address);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ LOGV("... address = %s", c_address);
+ DBusMessage *reply =
+ dbus_func_args_timeout(env, nat->conn, -1, nat->adapter,
+ DBUS_CLASS_NAME, "CancelBondingProcess",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ if (reply) {
+ dbus_message_unref(reply);
+ }
+ return JNI_TRUE;
+ }
+#endif
+ return JNI_FALSE;
}
-static void removeBondingNative(JNIEnv *env, jobject object, jstring address) {
+static jboolean removeBondingNative(JNIEnv *env, jobject object, jstring address) {
LOGV(__FUNCTION__);
- common_Bonding(env, object, -1, "RemoveBonding", address);
+ jboolean result = JNI_FALSE;
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ LOGV("... address = %s", c_address);
+ DBusError err;
+ dbus_error_init(&err);
+ DBusMessage *reply =
+ dbus_func_args_error(env, nat->conn, &err, nat->adapter,
+ DBUS_CLASS_NAME, "RemoveBonding",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ if (dbus_error_is_set(&err)) {
+ if (dbus_error_has_name(&err,
+ BLUEZ_DBUS_BASE_IFC ".Error.DoesNotExist")) {
+ LOGW("%s: Warning: %s (%s)", __FUNCTION__, err.message,
+ c_address);
+ result = JNI_TRUE;
+ } else {
+ LOGE("%s: D-Bus error %s (%s)", __FUNCTION__, err.name,
+ err.message);
+ }
+ } else {
+ result = JNI_TRUE;
+ }
+
+ env->ReleaseStringUTFChars(address, c_address);
+ dbus_error_free(&err);
+ if (reply) dbus_message_unref(reply);
+ }
+#endif
+ return result;
}
static jobjectArray listBondingsNative(JNIEnv *env, jobject object) {
@@ -660,14 +659,6 @@ static jboolean setNameNative(JNIEnv *env, jobject obj, jstring name) {
return JNI_FALSE;
}
-static jstring getMajorClassNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetMajorClass");
-}
-
-static jstring getMinorClassNative(JNIEnv *env, jobject obj) {
- return common_Get(env, obj, "GetMinorClass");
-}
-
static jstring common_getRemote(JNIEnv *env, jobject object, const char *func,
jstring address) {
LOGV("%s:%s", __FUNCTION__, func);
@@ -704,66 +695,6 @@ static jstring common_getRemote(JNIEnv *env, jobject object, const char *func,
return NULL;
}
-static jstring getRemoteAliasNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteAlias", address);
-}
-
-static jboolean setRemoteAliasNative(JNIEnv *env, jobject obj,
- jstring address, jstring alias) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, obj);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
- const char *c_alias = env->GetStringUTFChars(alias, NULL);
-
- LOGV("... address = %s alias = %s", c_address, c_alias);
-
- DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "SetRemoteAlias",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_STRING, &c_alias,
- DBUS_TYPE_INVALID);
-
- env->ReleaseStringUTFChars(address, c_address);
- env->ReleaseStringUTFChars(alias, c_alias);
- if (reply)
- {
- dbus_message_unref(reply);
- return JNI_TRUE;
- }
- return JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
-static jboolean clearRemoteAliasNative(JNIEnv *env, jobject obj, jstring address) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, obj);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
-
- LOGV("... address = %s", c_address);
-
- DBusMessage *reply = dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "ClearRemoteAlias",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
-
- env->ReleaseStringUTFChars(address, c_address);
- if (reply)
- {
- dbus_message_unref(reply);
- return JNI_TRUE;
- }
- return JNI_FALSE;
- }
-#endif
- return JNI_FALSE;
-}
-
static jstring getRemoteVersionNative(JNIEnv *env, jobject obj, jstring address) {
return common_getRemote(env, obj, "GetRemoteVersion", address);
}
@@ -780,14 +711,6 @@ static jstring getRemoteCompanyNative(JNIEnv *env, jobject obj, jstring address)
return common_getRemote(env, obj, "GetRemoteCompany", address);
}
-static jstring getRemoteMajorClassNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteMajorClass", address);
-}
-
-static jstring getRemoteMinorClassNative(JNIEnv *env, jobject obj, jstring address) {
- return common_getRemote(env, obj, "GetRemoteMinorClass", address);
-}
-
static jstring getRemoteNameNative(JNIEnv *env, jobject obj, jstring address) {
return common_getRemote(env, obj, "GetRemoteName", address);
}
@@ -800,28 +723,6 @@ static jstring lastUsedNative(JNIEnv *env, jobject obj, jstring address) {
return common_getRemote(env, obj, "LastUsed", address);
}
-static jobjectArray getRemoteServiceClassesNative(JNIEnv *env, jobject object,
- jstring address) {
-#ifdef HAVE_BLUETOOTH
- LOGV(__FUNCTION__);
- native_data_t *nat = get_native_data(env, object);
- if (nat) {
- const char *c_address = env->GetStringUTFChars(address, NULL);
-
- LOGV("... address = %s", c_address);
-
- DBusMessage *reply =
- dbus_func_args(env, nat->conn, nat->adapter,
- DBUS_CLASS_NAME, "GetRemoteServiceClasses",
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID);
- env->ReleaseStringUTFChars(address, c_address);
- return reply ? dbus_returns_array_of_strings(env, reply) : NULL;
- }
-#endif
- return NULL;
-}
-
static jint getRemoteClassNative(JNIEnv *env, jobject object, jstring address) {
#ifdef HAVE_BLUETOOTH
LOGV(__FUNCTION__);
@@ -1070,8 +971,6 @@ static JNINativeMethod sMethods[] = {
{"getAddressNative", "()Ljava/lang/String;", (void *)getAddressNative},
{"getNameNative", "()Ljava/lang/String;", (void*)getNameNative},
{"setNameNative", "(Ljava/lang/String;)Z", (void *)setNameNative},
- {"getMajorClassNative", "()Ljava/lang/String;", (void *)getMajorClassNative},
- {"getMinorClassNative", "()Ljava/lang/String;", (void *)getMinorClassNative},
{"getVersionNative", "()Ljava/lang/String;", (void *)getVersionNative},
{"getRevisionNative", "()Ljava/lang/String;", (void *)getRevisionNative},
{"getManufacturerNative", "()Ljava/lang/String;", (void *)getManufacturerNative},
@@ -1100,17 +999,11 @@ static JNINativeMethod sMethods[] = {
{"removeBondingNative", "(Ljava/lang/String;)Z", (void *)removeBondingNative},
{"getRemoteNameNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteNameNative},
- {"getRemoteAliasNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteAliasNative},
- {"setRemoteAliasNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)setRemoteAliasNative},
- {"clearRemoteAliasNative", "(Ljava/lang/String;)Z", (void *)clearRemoteAliasNative},
{"getRemoteVersionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteVersionNative},
{"getRemoteRevisionNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteRevisionNative},
{"getRemoteClassNative", "(Ljava/lang/String;)I", (void *)getRemoteClassNative},
{"getRemoteManufacturerNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteManufacturerNative},
{"getRemoteCompanyNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteCompanyNative},
- {"getRemoteMajorClassNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteMajorClassNative},
- {"getRemoteMinorClassNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)getRemoteMinorClassNative},
- {"getRemoteServiceClassesNative", "(Ljava/lang/String;)[Ljava/lang/String;", (void *)getRemoteServiceClassesNative},
{"getRemoteServiceChannelNative", "(Ljava/lang/String;S)Z", (void *)getRemoteServiceChannelNative},
{"getRemoteFeaturesNative", "(Ljava/lang/String;)[B", (void *)getRemoteFeaturesNative},
{"lastSeenNative", "(Ljava/lang/String;)Ljava/lang/String;", (void *)lastSeenNative},
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 3468265..c03bab6 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -47,8 +47,6 @@ static jmethodID method_onRemoteDeviceDisappeared;
static jmethodID method_onRemoteClassUpdated;
static jmethodID method_onRemoteNameUpdated;
static jmethodID method_onRemoteNameFailed;
-static jmethodID method_onRemoteAliasChanged;
-static jmethodID method_onRemoteAliasCleared;
static jmethodID method_onRemoteDeviceConnected;
static jmethodID method_onRemoteDeviceDisconnectRequested;
static jmethodID method_onRemoteDeviceDisconnected;
@@ -60,6 +58,10 @@ static jmethodID method_onGetRemoteServiceChannelResult;
static jmethodID method_onPasskeyAgentRequest;
static jmethodID method_onPasskeyAgentCancel;
+static jmethodID method_onAuthAgentAuthorize;
+static jmethodID method_onAuthAgentCancel;
+
+static jmethodID method_onRestartRequired;
typedef event_loop_native_data_t native_data_t;
@@ -85,7 +87,6 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
method_onRemoteClassUpdated = env->GetMethodID(clazz, "onRemoteClassUpdated", "(Ljava/lang/String;I)V");
method_onRemoteNameUpdated = env->GetMethodID(clazz, "onRemoteNameUpdated", "(Ljava/lang/String;Ljava/lang/String;)V");
method_onRemoteNameFailed = env->GetMethodID(clazz, "onRemoteNameFailed", "(Ljava/lang/String;)V");
- method_onRemoteAliasChanged = env->GetMethodID(clazz, "onRemoteAliasChanged", "(Ljava/lang/String;Ljava/lang/String;)V");
method_onRemoteDeviceConnected = env->GetMethodID(clazz, "onRemoteDeviceConnected", "(Ljava/lang/String;)V");
method_onRemoteDeviceDisconnectRequested = env->GetMethodID(clazz, "onRemoteDeviceDisconnectRequested", "(Ljava/lang/String;)V");
method_onRemoteDeviceDisconnected = env->GetMethodID(clazz, "onRemoteDeviceDisconnected", "(Ljava/lang/String;)V");
@@ -96,8 +97,12 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
method_onPasskeyAgentRequest = env->GetMethodID(clazz, "onPasskeyAgentRequest", "(Ljava/lang/String;I)V");
method_onPasskeyAgentCancel = env->GetMethodID(clazz, "onPasskeyAgentCancel", "(Ljava/lang/String;)V");
+ method_onAuthAgentAuthorize = env->GetMethodID(clazz, "onAuthAgentAuthorize", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z");
+ method_onAuthAgentCancel = env->GetMethodID(clazz, "onAuthAgentCancel", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
method_onGetRemoteServiceChannelResult = env->GetMethodID(clazz, "onGetRemoteServiceChannelResult", "(Ljava/lang/String;I)V");
+ method_onRestartRequired = env->GetMethodID(clazz, "onRestartRequired", "()V");
+
field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
#endif
}
@@ -139,12 +144,12 @@ static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
#ifdef HAVE_BLUETOOTH
static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
void *data);
-static DBusHandlerResult passkey_agent_event_filter(DBusConnection *conn,
- DBusMessage *msg,
- void *data);
+static DBusHandlerResult agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data);
-static const DBusObjectPathVTable passkey_agent_vtable = {
- NULL, passkey_agent_event_filter, NULL, NULL, NULL, NULL
+static const DBusObjectPathVTable agent_vtable = {
+ NULL, agent_event_filter, NULL, NULL, NULL, NULL
};
#endif
@@ -164,6 +169,13 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) {
// Set which messages will be processed by this dbus connection
dbus_bus_add_match(nat->conn,
+ "type='signal',interface='org.freedesktop.DBus'",
+ &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ return JNI_FALSE;
+ }
+ dbus_bus_add_match(nat->conn,
"type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'",
&err);
if (dbus_error_is_set(&err)) {
@@ -193,9 +205,9 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) {
}
// Add an object handler for passkey agent method calls
- const char *path = "/android/bluetooth/PasskeyAgent";
+ const char *path = "/android/bluetooth/Agent";
if (!dbus_connection_register_object_path(nat->conn, path,
- &passkey_agent_vtable, NULL)) {
+ &agent_vtable, NULL)) {
LOGE("%s: Can't register object path %s for agent!",
__FUNCTION__, path);
return JNI_FALSE;
@@ -204,7 +216,7 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) {
// RegisterDefaultPasskeyAgent() will fail until hcid is up, so keep
// trying for 10 seconds.
int attempt;
- for (attempt = 1000; attempt > 0; attempt--) {
+ for (attempt = 0; attempt < 1000; attempt++) {
DBusMessage *reply = dbus_func_args_error(env, nat->conn, &err,
BLUEZ_DBUS_BASE_PATH,
"org.bluez.Security", "RegisterDefaultPasskeyAgent",
@@ -213,7 +225,8 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) {
if (reply) {
// Success
dbus_message_unref(reply);
- return JNI_TRUE;
+ LOGV("Registered agent on attempt %d of 1000\n", attempt);
+ break;
} else if (dbus_error_has_name(&err,
"org.freedesktop.DBus.Error.ServiceUnknown")) {
// hcid is still down, retry
@@ -225,9 +238,25 @@ static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) {
return JNI_FALSE;
}
}
- LOGE("Time-out trying to call RegisterDefaultPasskeyAgent(), "
- "is hcid running?");
- return JNI_FALSE;
+ if (attempt == 1000) {
+ LOGE("Time-out trying to call RegisterDefaultPasskeyAgent(), "
+ "is hcid running?");
+ return JNI_FALSE;
+ }
+
+ // Now register the Auth agent
+ DBusMessage *reply = dbus_func_args_error(env, nat->conn, &err,
+ BLUEZ_DBUS_BASE_PATH,
+ "org.bluez.Security", "RegisterDefaultAuthorizationAgent",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ if (!reply) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ return JNI_FALSE;
+ }
+
+ dbus_message_unref(reply);
+ return JNI_TRUE;
}
#endif
@@ -243,12 +272,19 @@ static void tearDownEventLoopNative(JNIEnv *env, jobject object) {
DBusError err;
dbus_error_init(&err);
- const char *path = "/android/bluetooth/PasskeyAgent";
+ const char *path = "/android/bluetooth/Agent";
DBusMessage *reply =
dbus_func_args(env, nat->conn, BLUEZ_DBUS_BASE_PATH,
- "org.bluez.Security", "UnregisterDefaultPasskeyAgent",
- DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
+ "org.bluez.Security", "UnregisterDefaultPasskeyAgent",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ if (reply) dbus_message_unref(reply);
+
+ reply =
+ dbus_func_args(env, nat->conn, BLUEZ_DBUS_BASE_PATH,
+ "org.bluez.Security", "UnregisterDefaultAuthorizationAgent",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
if (reply) dbus_message_unref(reply);
dbus_connection_unregister_object_path(nat->conn, path);
@@ -277,6 +313,12 @@ static void tearDownEventLoopNative(JNIEnv *env, jobject object) {
if (dbus_error_is_set(&err)) {
LOG_AND_FREE_DBUS_ERROR(&err);
}
+ dbus_bus_remove_match(nat->conn,
+ "type='signal',interface='org.freedesktop.DBus'",
+ &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
dbus_connection_remove_filter(nat->conn, event_filter, nat);
}
@@ -395,34 +437,6 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
return DBUS_HANDLER_RESULT_HANDLED;
} else if (dbus_message_is_signal(msg,
"org.bluez.Adapter",
- "RemoteAliasChanged")) {
- char *c_address, *c_alias;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_STRING, &c_alias,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s, alias = %s", c_address, c_alias);
- env->CallVoidMethod(nat->me,
- method_onRemoteAliasChanged,
- env->NewStringUTF(c_address),
- env->NewStringUTF(c_alias));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
- "RemoteAliasCleared")) {
- char *c_address;
- if (dbus_message_get_args(msg, &err,
- DBUS_TYPE_STRING, &c_address,
- DBUS_TYPE_INVALID)) {
- LOGV("... address = %s", c_address);
- env->CallVoidMethod(nat->me,
- method_onRemoteAliasCleared,
- env->NewStringUTF(c_address));
- } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
- return DBUS_HANDLER_RESULT_HANDLED;
- } else if (dbus_message_is_signal(msg,
- "org.bluez.Adapter",
"RemoteDeviceConnected")) {
char *c_address;
if (dbus_message_get_args(msg, &err,
@@ -512,15 +526,36 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
env->NewStringUTF(c_name));
} else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.freedesktop.DBus",
+ "NameOwnerChanged")) {
+ char *c_name;
+ char *c_old_owner;
+ char *c_new_owner;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_name,
+ DBUS_TYPE_STRING, &c_old_owner,
+ DBUS_TYPE_STRING, &c_new_owner,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... name = %s", c_name);
+ LOGV("... old_owner = %s", c_old_owner);
+ LOGV("... new_owner = %s", c_new_owner);
+ if (!strcmp(c_name, "org.bluez") && c_new_owner[0] != '\0') {
+ // New owner of org.bluez. This can only happen when hcid
+ // restarts. Need to restart framework BT services to recover.
+ LOGE("Looks like hcid restarted");
+ env->CallVoidMethod(nat->me, method_onRestartRequired);
+ }
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
}
return a2dp_event_filter(msg, env);
}
// Called by dbus during WaitForAndDispatchEventNative()
-static DBusHandlerResult passkey_agent_event_filter(DBusConnection *conn,
- DBusMessage *msg,
- void *data) {
+static DBusHandlerResult agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg, void *data) {
native_data_t *nat = event_loop_nat;
JNIEnv *env;
@@ -573,11 +608,120 @@ static DBusHandlerResult passkey_agent_event_filter(DBusConnection *conn,
env->CallVoidMethod(nat->me, method_onPasskeyAgentCancel,
env->NewStringUTF(address));
+ // reply
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply\n", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(reply);
return DBUS_HANDLER_RESULT_HANDLED;
} else if (dbus_message_is_method_call(msg,
"org.bluez.PasskeyAgent", "Release")) {
- LOGE("We are no longer the passkey agent!");
+ LOGW("We are no longer the passkey agent!");
+
+ // reply
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply\n", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.AuthorizationAgent", "Authorize")) {
+ const char *adapter;
+ const char *address;
+ const char *service;
+ const char *uuid;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &adapter,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &service,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for Authorize() method", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ LOGV("... address = %s", address);
+ LOGV("... service = %s", service);
+ LOGV("... uuid = %s", uuid);
+
+ bool auth_granted = env->CallBooleanMethod(nat->me,
+ method_onAuthAgentAuthorize, env->NewStringUTF(address),
+ env->NewStringUTF(service), env->NewStringUTF(uuid));
+
+ // reply
+ if (auth_granted) {
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply\n", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(reply);
+ } else {
+ DBusMessage *reply = dbus_message_new_error(msg,
+ "org.bluez.Error.Rejected", "Authorization rejected");
+ if (!reply) {
+ LOGE("%s: Cannot create message reply\n", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(reply);
+ }
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.AuthorizationAgent", "Cancel")) {
+ const char *adapter;
+ const char *address;
+ const char *service;
+ const char *uuid;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &adapter,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &service,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for Cancel() method", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ LOGV("... address = %s", address);
+ LOGV("... service = %s", service);
+ LOGV("... uuid = %s", uuid);
+
+ env->CallVoidMethod(nat->me,
+ method_onAuthAgentCancel, env->NewStringUTF(address),
+ env->NewStringUTF(service), env->NewStringUTF(uuid));
+
+ // reply
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply\n", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.AuthorizationAgent", "Release")) {
+ LOGW("We are no longer the auth agent!");
+
+ // reply
+ DBusMessage *reply = dbus_message_new_method_return(msg);
+ if (!reply) {
+ LOGE("%s: Cannot create message reply\n", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_connection_send(nat->conn, reply, NULL);
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
} else {
LOGV("... ignored");
}
@@ -614,7 +758,9 @@ static jboolean waitForAndDispatchEventNative(JNIEnv *env, jobject object,
#define BOND_RESULT_SUCCESS 0
#define BOND_RESULT_AUTH_FAILED 1
#define BOND_RESULT_AUTH_REJECTED 2
-#define BOND_RESULT_REMOTE_DEVICE_DOWN 3
+#define BOND_RESULT_AUTH_CANCELED 3
+#define BOND_RESULT_REMOTE_DEVICE_DOWN 4
+#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
void onCreateBondingResult(DBusMessage *msg, void *user) {
LOGV(__FUNCTION__);
@@ -637,21 +783,38 @@ void onCreateBondingResult(DBusMessage *msg, void *user) {
// happens if either side presses 'cancel' at the pairing dialog.
LOGV("... error = %s (%s)\n", err.name, err.message);
result = BOND_RESULT_AUTH_REJECTED;
- } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".ConnectionAttemptFailed")) {
+ } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationCanceled")) {
+ // Not sure if this happens
+ LOGV("... error = %s (%s)\n", err.name, err.message);
+ result = BOND_RESULT_AUTH_CANCELED;
+ } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.ConnectionAttemptFailed")) {
// Other device is not responding at all
LOGV("... error = %s (%s)\n", err.name, err.message);
result = BOND_RESULT_REMOTE_DEVICE_DOWN;
+ } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AlreadyExists")) {
+ // already bonded
+ LOGV("... error = %s (%s)\n", err.name, err.message);
+ result = BOND_RESULT_SUCCESS;
+ } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
+ !strcmp(err.message, "Bonding in progress")) {
+ LOGV("... error = %s (%s)\n", err.name, err.message);
+ goto done;
+ } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") &&
+ !strcmp(err.message, "Discover in progress")) {
+ LOGV("... error = %s (%s)\n", err.name, err.message);
+ result = BOND_RESULT_DISCOVERY_IN_PROGRESS;
} else {
LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
result = BOND_RESULT_ERROR;
}
- dbus_error_free(&err);
}
env->CallVoidMethod(event_loop_nat->me,
method_onCreateBondingResult,
env->NewStringUTF(address),
result);
+done:
+ dbus_error_free(&err);
free(user);
}
diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp
index 8e41ec7..923e1aa 100644
--- a/core/jni/android_text_format_Time.cpp
+++ b/core/jni/android_text_format_Time.cpp
@@ -52,6 +52,9 @@ static jfieldID g_dateTimeFormatField = 0;
static jfieldID g_amField = 0;
static jfieldID g_pmField = 0;
static jfieldID g_dateCommandField = 0;
+static jfieldID g_localeField = 0;
+
+static jclass g_timeClass = NULL;
static inline bool java2time(JNIEnv* env, Time* t, jobject o)
{
@@ -183,56 +186,101 @@ static jstring android_text_format_Time_format2445(JNIEnv* env, jobject This)
static jstring android_text_format_Time_format(JNIEnv* env, jobject This,
jstring formatObject)
{
- Time t;
- struct strftime_locale locale;
- jclass timeClass = env->FindClass("android/text/format/Time");
- jstring js_mon[12], js_month[12], js_wday[7], js_weekday[7];
- jstring js_X_fmt, js_x_fmt, js_c_fmt, js_am, js_pm, js_date_fmt;
- jobjectArray ja;
+ // We only teardown and setup our 'locale' struct and other state
+ // when the Java-side locale changed. This is safe to do here
+ // without locking because we're always called from Java code
+ // synchronized on the class instance.
+ static jobject js_locale_previous = NULL;
+ static struct strftime_locale locale;
+ static jstring js_mon[12], js_month[12], js_wday[7], js_weekday[7];
+ static jstring js_X_fmt, js_x_fmt, js_c_fmt, js_am, js_pm, js_date_fmt;
+ Time t;
if (!java2time(env, &t, This)) return env->NewStringUTF("");
- ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortMonthsField);
- for (int i = 0; i < 12; i++) {
- js_mon[i] = (jstring) env->GetObjectArrayElement(ja, i);
- locale.mon[i] = env->GetStringUTFChars(js_mon[i], NULL);
- }
+ jclass timeClass = g_timeClass;
+ jobject js_locale = (jobject) env->GetStaticObjectField(timeClass, g_localeField);
+ if (js_locale_previous != js_locale) {
+ if (js_locale_previous != NULL) {
+ // Free the old one.
+ for (int i = 0; i < 12; i++) {
+ env->ReleaseStringUTFChars(js_mon[i], locale.mon[i]);
+ env->ReleaseStringUTFChars(js_month[i], locale.month[i]);
+ env->DeleteGlobalRef(js_mon[i]);
+ env->DeleteGlobalRef(js_month[i]);
+ }
+
+ for (int i = 0; i < 7; i++) {
+ env->ReleaseStringUTFChars(js_wday[i], locale.wday[i]);
+ env->ReleaseStringUTFChars(js_weekday[i], locale.weekday[i]);
+ env->DeleteGlobalRef(js_wday[i]);
+ env->DeleteGlobalRef(js_weekday[i]);
+ }
+
+ env->ReleaseStringUTFChars(js_X_fmt, locale.X_fmt);
+ env->ReleaseStringUTFChars(js_x_fmt, locale.x_fmt);
+ env->ReleaseStringUTFChars(js_c_fmt, locale.c_fmt);
+ env->ReleaseStringUTFChars(js_am, locale.am);
+ env->ReleaseStringUTFChars(js_pm, locale.pm);
+ env->ReleaseStringUTFChars(js_date_fmt, locale.date_fmt);
+ env->DeleteGlobalRef(js_X_fmt);
+ env->DeleteGlobalRef(js_x_fmt);
+ env->DeleteGlobalRef(js_c_fmt);
+ env->DeleteGlobalRef(js_am);
+ env->DeleteGlobalRef(js_pm);
+ env->DeleteGlobalRef(js_date_fmt);
+ }
+ js_locale_previous = js_locale;
- ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longMonthsField);
- for (int i = 0; i < 12; i++) {
- js_month[i] = (jstring) env->GetObjectArrayElement(ja, i);
- locale.month[i] = env->GetStringUTFChars(js_month[i], NULL);
- }
+ jobjectArray ja;
+ ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortMonthsField);
+ for (int i = 0; i < 12; i++) {
+ js_mon[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
+ locale.mon[i] = env->GetStringUTFChars(js_mon[i], NULL);
+ }
- ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortWeekdaysField);
- for (int i = 0; i < 7; i++) {
- js_wday[i] = (jstring) env->GetObjectArrayElement(ja, i);
- locale.wday[i] = env->GetStringUTFChars(js_wday[i], NULL);
- }
+ ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longMonthsField);
+ for (int i = 0; i < 12; i++) {
+ js_month[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
+ locale.month[i] = env->GetStringUTFChars(js_month[i], NULL);
+ }
- ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longWeekdaysField);
- for (int i = 0; i < 7; i++) {
- js_weekday[i] = (jstring) env->GetObjectArrayElement(ja, i);
- locale.weekday[i] = env->GetStringUTFChars(js_weekday[i], NULL);
- }
+ ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortWeekdaysField);
+ for (int i = 0; i < 7; i++) {
+ js_wday[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
+ locale.wday[i] = env->GetStringUTFChars(js_wday[i], NULL);
+ }
- js_X_fmt = (jstring) env->GetStaticObjectField(timeClass, g_timeOnlyFormatField);
- locale.X_fmt = env->GetStringUTFChars(js_X_fmt, NULL);
+ ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longWeekdaysField);
+ for (int i = 0; i < 7; i++) {
+ js_weekday[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
+ locale.weekday[i] = env->GetStringUTFChars(js_weekday[i], NULL);
+ }
+
+ js_X_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
+ timeClass, g_timeOnlyFormatField));
+ locale.X_fmt = env->GetStringUTFChars(js_X_fmt, NULL);
- js_x_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateOnlyFormatField);
- locale.x_fmt = env->GetStringUTFChars(js_x_fmt, NULL);
+ js_x_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
+ timeClass, g_dateOnlyFormatField));
+ locale.x_fmt = env->GetStringUTFChars(js_x_fmt, NULL);
- js_c_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateTimeFormatField);
- locale.c_fmt = env->GetStringUTFChars(js_c_fmt, NULL);
+ js_c_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
+ timeClass, g_dateTimeFormatField));
+ locale.c_fmt = env->GetStringUTFChars(js_c_fmt, NULL);
- js_am = (jstring) env->GetStaticObjectField(timeClass, g_amField);
- locale.am = env->GetStringUTFChars(js_am, NULL);
+ js_am = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
+ timeClass, g_amField));
+ locale.am = env->GetStringUTFChars(js_am, NULL);
- js_pm = (jstring) env->GetStaticObjectField(timeClass, g_pmField);
- locale.pm = env->GetStringUTFChars(js_pm, NULL);
+ js_pm = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
+ timeClass, g_pmField));
+ locale.pm = env->GetStringUTFChars(js_pm, NULL);
- js_date_fmt = (jstring) env->GetStaticObjectField(timeClass, g_dateCommandField);
- locale.date_fmt = env->GetStringUTFChars(js_date_fmt, NULL);
+ js_date_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
+ timeClass, g_dateCommandField));
+ locale.date_fmt = env->GetStringUTFChars(js_date_fmt, NULL);
+ }
ACQUIRE_TIMEZONE(This, t)
@@ -243,23 +291,6 @@ static jstring android_text_format_Time_format(JNIEnv* env, jobject This,
env->ReleaseStringUTFChars(formatObject, format);
RELEASE_TIMEZONE(This, t)
- for (int i = 0; i < 12; i++) {
- env->ReleaseStringUTFChars(js_mon[i], locale.mon[i]);
- env->ReleaseStringUTFChars(js_month[i], locale.month[i]);
- }
-
- for (int i = 0; i < 7; i++) {
- env->ReleaseStringUTFChars(js_wday[i], locale.wday[i]);
- env->ReleaseStringUTFChars(js_weekday[i], locale.weekday[i]);
- }
-
- env->ReleaseStringUTFChars(js_X_fmt, locale.X_fmt);
- env->ReleaseStringUTFChars(js_x_fmt, locale.x_fmt);
- env->ReleaseStringUTFChars(js_c_fmt, locale.c_fmt);
- env->ReleaseStringUTFChars(js_am, locale.am);
- env->ReleaseStringUTFChars(js_pm, locale.pm);
- env->ReleaseStringUTFChars(js_date_fmt, locale.date_fmt);
-
return env->NewStringUTF(r.string());
}
@@ -307,7 +338,6 @@ static void android_text_format_Time_set(JNIEnv* env, jobject This, jlong millis
{
env->SetBooleanField(This, g_allDayField, JNI_FALSE);
Time t;
- if (!java2time(env, &t, This)) return;
ACQUIRE_TIMEZONE(This, t)
t.set(millis);
@@ -592,6 +622,8 @@ int register_android_text_format_Time(JNIEnv* env)
{
jclass timeClass = env->FindClass("android/text/format/Time");
+ g_timeClass = (jclass) env->NewGlobalRef(timeClass);
+
g_allDayField = env->GetFieldID(timeClass, "allDay", "Z");
g_secField = env->GetFieldID(timeClass, "second", "I");
g_minField = env->GetFieldID(timeClass, "minute", "I");
@@ -615,9 +647,9 @@ int register_android_text_format_Time(JNIEnv* env)
g_amField = env->GetStaticFieldID(timeClass, "sAm", "Ljava/lang/String;");
g_pmField = env->GetStaticFieldID(timeClass, "sPm", "Ljava/lang/String;");
g_dateCommandField = env->GetStaticFieldID(timeClass, "sDateCommand", "Ljava/lang/String;");
+ g_localeField = env->GetStaticFieldID(timeClass, "sLocale", "Ljava/util/Locale;");
return AndroidRuntime::registerNativeMethods(env, "android/text/format/Time", gMethods, NELEM(gMethods));
}
}; // namespace android
-
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index add1080..d147bcc 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -44,6 +44,7 @@ static struct typedvalue_offsets_t
jfieldID mAssetCookie;
jfieldID mResourceId;
jfieldID mChangingConfigurations;
+ jfieldID mDensity;
} gTypedValueOffsets;
static struct assetfiledescriptor_offsets_t
@@ -83,7 +84,11 @@ enum {
static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
const Res_value& value, uint32_t ref, ssize_t block,
- uint32_t typeSpecFlags)
+ uint32_t typeSpecFlags, ResTable_config* config = NULL);
+
+jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
+ const Res_value& value, uint32_t ref, ssize_t block,
+ uint32_t typeSpecFlags, ResTable_config* config)
{
env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
@@ -93,6 +98,9 @@ static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
typeSpecFlags);
+ if (config != NULL) {
+ env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
+ }
return block;
}
@@ -703,13 +711,14 @@ static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject
const ResTable& res(am->getResources());
Res_value value;
+ ResTable_config config;
uint32_t typeSpecFlags;
- ssize_t block = res.getResource(ident, &value, false, &typeSpecFlags);
+ ssize_t block = res.getResource(ident, &value, false, &typeSpecFlags, &config);
uint32_t ref = ident;
if (resolve) {
block = res.resolveReference(&value, block, &ref);
}
- return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
+ return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
}
static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
@@ -1648,6 +1657,8 @@ int register_android_content_AssetManager(JNIEnv* env)
gTypedValueOffsets.mChangingConfigurations
= env->GetFieldID(typedValue, "changingConfigurations", "I");
LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
+ gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
+ LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 24404a8..7325432 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -1223,6 +1223,7 @@ static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz,
if (mode&0x08000000) flags |= O_CREAT;
if (mode&0x04000000) flags |= O_TRUNC;
+ if (mode&0x02000000) flags |= O_APPEND;
int realMode = S_IRWXU|S_IRWXG;
if (mode&0x00000001) realMode |= S_IROTH;
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index d0cac18..5e5103a 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -19,7 +19,7 @@
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include "jni.h"
-#include "utils/logger.h"
+#include "cutils/logger.h"
#define END_DELIMITER '\n'
#define INT_BUFFER_SIZE (sizeof(jbyte)+sizeof(jint)+sizeof(END_DELIMITER))
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index f09bd4c..8baaa84 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -212,7 +212,9 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
dirty.top = env->GetIntField(dirtyRect, ro.t);
dirty.right = env->GetIntField(dirtyRect, ro.r);
dirty.bottom= env->GetIntField(dirtyRect, ro.b);
- dirtyRegion.set(dirty);
+ if (dirty.left < dirty.right && dirty.top < dirty.bottom) {
+ dirtyRegion.set(dirty);
+ }
} else {
dirtyRegion.set(Rect(0x3FFF,0x3FFF));
}
@@ -246,6 +248,14 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
int saveCount = nativeCanvas->save();
env->SetIntField(clazz, so.saveCount, saveCount);
+ if (dirtyRect) {
+ Rect bounds(dirtyRegion.bounds());
+ env->SetIntField(dirtyRect, ro.l, bounds.left);
+ env->SetIntField(dirtyRect, ro.t, bounds.top);
+ env->SetIntField(dirtyRect, ro.r, bounds.right);
+ env->SetIntField(dirtyRect, ro.b, bounds.bottom);
+ }
+
return canvas;
}
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 8bacc74..fbbd852 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -18,7 +18,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
#include <GLES/gl.h>
#include <ui/EGLNativeWindowSurface.h>
diff --git a/core/res/Android.mk b/core/res/Android.mk
index 5fca5d0..cb5524a 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -24,7 +24,7 @@ LOCAL_CERTIFICATE := platform
# since these resources will be used by many apps.
LOCAL_AAPT_FLAGS := -x
-LOCAL_MODULE_TAGS := user development
+LOCAL_MODULE_TAGS := user
# Install this alongside the libraries.
LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ded909f..1b145af 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -18,7 +18,8 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android" android:sharedUserId="android.uid.system">
+ package="android" android:sharedUserId="android.uid.system"
+ android:sharedUserLabel="@string/android_system_label">
<!-- ====================================== -->
<!-- Permissions for things that cost money -->
@@ -549,6 +550,13 @@
android:label="@string/permlab_mount_unmount_filesystems"
android:description="@string/permdesc_mount_unmount_filesystems" />
+ <!-- Allows formatting file systems for removable storage. -->
+ <permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_mount_format_filesystems"
+ android:description="@string/permdesc_mount_format_filesystems" />
+
<!-- Allows applications to disable the keyguard -->
<permission android:name="android.permission.DISABLE_KEYGUARD"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -696,7 +704,7 @@
<permission android:name="android.permission.STATUS_BAR"
android:label="@string/permlab_statusBar"
android:description="@string/permdesc_statusBar"
- android:protectionLevel="signature" />
+ android:protectionLevel="signatureOrSystem" />
<!-- Allows an application to force any currently running process to be
in the foreground. -->
@@ -725,8 +733,9 @@
android:description="@string/permdesc_fotaUpdate"
android:protectionLevel="signature" />
- <!-- Allows an application to update the collected battery statistics -->
- <permission android:name="android.permission.BATTERY_STATS"
+ <!-- Allows an application to update device statistics. Not for
+ use by third party apps. -->
+ <permission android:name="android.permission.UPDATE_DEVICE_STATS"
android:label="@string/permlab_batteryStats"
android:description="@string/permdesc_batteryStats"
android:protectionLevel="signature" />
@@ -902,10 +911,43 @@
android:description="@string/permdesc_checkinProperties"
android:protectionLevel="signature" />
+ <!-- Allows an application to collect component usage
+ statistics -->
+ <permission android:name="android.permission.PACKAGE_USAGE_STATS"
+ android:label="@string/permlab_pkgUsageStats"
+ android:description="@string/permdesc_pkgUsageStats"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to collect battery statistics -->
+ <permission android:name="android.permission.BATTERY_STATS"
+ android:label="@string/permlab_batteryStats"
+ android:description="@string/permdesc_batteryStats"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to tell the AppWidget service which application
+ can access AppWidget's data. The normal user flow is that a user
+ picks an AppWidget to go into a particular host, thereby giving that
+ host application access to the private data from the AppWidget app.
+ An application that has this permission should honor that contract.
+ Very few applications should need to use this permission. -->
+ <permission android:name="android.permission.BIND_APPWIDGET"
+ android:permissionGroup="android.permission-group.PERSONAL_INFO"
+ android:label="@string/permlab_bindGadget"
+ android:description="@string/permdesc_bindGadget"
+ android:protectionLevel="signature" />
+
+ <!-- Allows applications to change the background data setting
+ @hide pending API council -->
+ <permission android:name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature"
+ android:description="@string/permdesc_changeBackgroundDataSetting"
+ android:label="@string/permlab_changeBackgroundDataSetting" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
- android:label="Android System"
+ android:label="@string/android_system_label"
android:allowClearUserData="false"
android:icon="@drawable/ic_launcher_android">
<activity android:name="com.android.internal.app.ChooserActivity"
@@ -930,43 +972,27 @@
android:theme="@style/Theme.Dialog.Alert"
android:excludeFromRecents="true">
</activity>
- <provider android:name=".server.checkin.CheckinProvider"
- android:authorities="android.server.checkin"
- android:multiprocess="false" />
+ <activity android:name="com.android.internal.app.UsbStorageStopActivity"
+ android:theme="@style/Theme.Dialog.Alert"
+ android:excludeFromRecents="true">
+ </activity>
+ <activity android:name="com.android.internal.app.ExternalMediaFormatActivity"
+ android:theme="@style/Theme.Dialog.Alert"
+ android:excludeFromRecents="true">
+ </activity>
+
<provider android:name=".content.SyncProvider"
android:authorities="sync" android:multiprocess="false" />
<service android:name="com.android.server.LoadAverageService"
android:exported="true" />
- <receiver
- android:name=".server.checkin.UpdateReceiver$DownloadCompletedBroadcastReceiver"
- android:exported="true" />
-
- <receiver android:name="com.google.android.server.checkin.SecretCodeReceiver">
- <intent-filter>
- <action android:name="android.provider.Telephony.SECRET_CODE" />
- <data android:scheme="android_secret_code"
- android:host="682" /> <!-- 682 = "OTA" on dialpad -->
- <data android:scheme="android_secret_code"
- android:host="682364" /> <!-- 682364 = "OTAENG" -->
- <data android:scheme="android_secret_code"
- android:host="682226" /> <!-- 682226 = "OTACAN" -->
- <data android:scheme="android_secret_code"
- android:host="682668" /> <!-- 682668 = "OTANOT" -->
- </intent-filter>
- </receiver>
<receiver android:name="com.android.server.BootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
- <receiver android:name="com.android.server.BrickReceiver"
- android:permission="android.permission.BRICK" >
- <intent-filter>
- <action android:name="android.intent.action.BRICK" />
- </intent-filter>
- </receiver>
+
<receiver android:name="com.android.server.MasterClearReceiver"
android:permission="android.permission.MASTER_CLEAR" >
<intent-filter>
diff --git a/core/res/assets/webkit/nullplugin.png b/core/res/assets/webkit/nullPlugin.png
index 96a52e3..96a52e3 100644
--- a/core/res/assets/webkit/nullplugin.png
+++ b/core/res/assets/webkit/nullPlugin.png
Binary files differ
diff --git a/core/res/res/anim/app_starting_exit.xml b/core/res/res/anim/app_starting_exit.xml
index c6f94b0..0675575 100644
--- a/core/res/res/anim/app_starting_exit.xml
+++ b/core/res/res/anim/app_starting_exit.xml
@@ -19,6 +19,6 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/dialog_enter.xml b/core/res/res/anim/dialog_enter.xml
index fd08cd0..cc409e8 100644
--- a/core/res/res/anim/dialog_enter.xml
+++ b/core/res/res/anim/dialog_enter.xml
@@ -20,10 +20,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
- <scale android:fromXScale="0.5" android:toXScale="1.0"
- android:fromYScale="0.5" android:toYScale="1.0"
+ <scale android:fromXScale="0.9" android:toXScale="1.0"
+ android:fromYScale="0.9" android:toYScale="1.0"
android:pivotX="50%" android:pivotY="50%"
- android:duration="200" />
+ android:duration="@android:integer/config_shortAnimTime" />
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="200" />
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/dialog_exit.xml b/core/res/res/anim/dialog_exit.xml
index e1b7a77..8bf8082 100644
--- a/core/res/res/anim/dialog_exit.xml
+++ b/core/res/res/anim/dialog_exit.xml
@@ -19,10 +19,10 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/accelerate_interpolator">
- <scale android:fromXScale="1.0" android:toXScale="0.5"
- android:fromYScale="1.0" android:toYScale="0.5"
+ <scale android:fromXScale="1.0" android:toXScale="0.9"
+ android:fromYScale="1.0" android:toYScale="0.9"
android:pivotX="50%" android:pivotY="50%"
- android:duration="200" />
+ android:duration="@android:integer/config_shortAnimTime" />
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:duration="200"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/fade_in.xml b/core/res/res/anim/fade_in.xml
index 32eea01..57310d9 100644
--- a/core/res/res/anim/fade_in.xml
+++ b/core/res/res/anim/fade_in.xml
@@ -18,4 +18,7 @@
*/
-->
-<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" />
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_longAnimTime" />
diff --git a/core/res/res/anim/fade_out.xml b/core/res/res/anim/fade_out.xml
index e8ae9c1..dc76276 100644
--- a/core/res/res/anim/fade_out.xml
+++ b/core/res/res/anim/fade_out.xml
@@ -21,5 +21,5 @@
<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.0"
- android:duration="300"
+ android:duration="@android:integer/config_mediumAnimTime"
/>
diff --git a/core/res/res/anim/grow_fade_in.xml b/core/res/res/anim/grow_fade_in.xml
index 0969857..5dc41cb 100644
--- a/core/res/res/anim/grow_fade_in.xml
+++ b/core/res/res/anim/grow_fade_in.xml
@@ -21,6 +21,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale="0.3" android:toYScale="1.0"
- android:pivotX="0%" android:pivotY="0%" android:duration="125" />
- <alpha android:interpolator="@anim/decelerate_interpolator" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+ android:pivotX="0%" android:pivotY="0%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/decelerate_interpolator"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/grow_fade_in_center.xml b/core/res/res/anim/grow_fade_in_center.xml
index 01d7a77..c07a82e 100644
--- a/core/res/res/anim/grow_fade_in_center.xml
+++ b/core/res/res/anim/grow_fade_in_center.xml
@@ -21,6 +21,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="0.6" android:toXScale="1.0"
android:fromYScale="0.6" android:toYScale="1.0"
- android:pivotX="50%" android:pivotY="50%" android:duration="125" />
- <alpha android:interpolator="@anim/decelerate_interpolator" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/decelerate_interpolator"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/grow_fade_in_from_bottom.xml b/core/res/res/anim/grow_fade_in_from_bottom.xml
index d3e468d..848c677 100644
--- a/core/res/res/anim/grow_fade_in_from_bottom.xml
+++ b/core/res/res/anim/grow_fade_in_from_bottom.xml
@@ -21,6 +21,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="0.5" android:toXScale="1.0"
android:fromYScale="0.5" android:toYScale="1.0"
- android:pivotX="0%" android:pivotY="100%" android:duration="125" />
- <alpha android:interpolator="@anim/decelerate_interpolator" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+ android:pivotX="0%" android:pivotY="100%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/decelerate_interpolator"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/input_method_enter.xml b/core/res/res/anim/input_method_enter.xml
index 572a266..3858651 100644
--- a/core/res/res/anim/input_method_enter.xml
+++ b/core/res/res/anim/input_method_enter.xml
@@ -20,13 +20,8 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
- <!--
- <scale android:fromXScale="2.0" android:toXScale="1.0"
- android:fromYScale="2.0" android:toYScale="1.0"
- android:pivotX="50%" android:pivotY="50%"
- android:duration="100" />
- -->
- <translate android:fromYDelta="20%" android:toYDelta="0" android:duration="100"/>
+ <translate android:fromYDelta="20%" android:toYDelta="0"
+ android:duration="@android:integer/config_shortAnimTime"/>
<alpha android:fromAlpha="0.5" android:toAlpha="1.0"
- android:duration="100" />
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/input_method_exit.xml b/core/res/res/anim/input_method_exit.xml
index d28313a..25369ab 100644
--- a/core/res/res/anim/input_method_exit.xml
+++ b/core/res/res/anim/input_method_exit.xml
@@ -19,13 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/accelerate_interpolator">
- <!--
- <scale android:fromXScale="1.0" android:toXScale="2.0"
- android:fromYScale="1.0" android:toYScale="2.0"
- android:pivotX="50%" android:pivotY="50%"
- android:duration="100" />
- -->
- <translate android:fromYDelta="0" android:toYDelta="20%" android:duration="100"/>
+ <translate android:fromYDelta="0" android:toYDelta="20%"
+ android:duration="@android:integer/config_shortAnimTime"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:duration="100"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/drawable/checkbox.xml b/core/res/res/anim/input_method_fancy_enter.xml
index 7a22185..c6949b3 100644
--- a/core/res/res/drawable/checkbox.xml
+++ b/core/res/res/anim/input_method_fancy_enter.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* //device/apps/common/res/drawable/checkbox.xml
+/* //device/apps/common/res/anim/fade_in.xml
**
** Copyright 2007, The Android Open Source Project
**
@@ -18,12 +18,12 @@
*/
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="true" android:state_focused="true"
- android:drawable="@drawable/checkbox_on_background_focus_yellow" />
- <item android:state_checked="false" android:state_focused="true"
- android:drawable="@drawable/checkbox_off_background_focus_yellow" />
- <item android:state_checked="false" android:drawable="@drawable/checkbox_off_background" />
- <item android:state_checked="true" android:drawable="@drawable/checkbox_on_background" />
-</selector>
-
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator">
+ <scale android:fromXScale="2.0" android:toXScale="1.0"
+ android:fromYScale="2.0" android:toYScale="1.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <translate android:fromYDelta="100%" android:toYDelta="0"
+ android:duration="@android:integer/config_shortAnimTime"/>
+</set>
diff --git a/core/res/res/anim/input_method_fancy_exit.xml b/core/res/res/anim/input_method_fancy_exit.xml
new file mode 100644
index 0000000..7333cca
--- /dev/null
+++ b/core/res/res/anim/input_method_fancy_exit.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/fade_out.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_interpolator">
+ <scale android:fromXScale="1.0" android:toXScale="2.0"
+ android:fromYScale="1.0" android:toYScale="2.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <translate android:fromYDelta="0" android:toYDelta="100%"
+ android:duration="@android:integer/config_shortAnimTime"/>
+</set>
diff --git a/core/res/res/drawable/radiobutton.xml b/core/res/res/anim/lock_screen_exit.xml
index a72c825..55c5ec9 100644
--- a/core/res/res/drawable/radiobutton.xml
+++ b/core/res/res/anim/lock_screen_exit.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* //device/apps/common/res/drawable/radiobutton.xml
+/* //device/apps/common/res/anim/options_panel_exit.xml
**
** Copyright 2007, The Android Open Source Project
**
@@ -18,11 +18,7 @@
*/
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="false" android:state_focused="true"
- android:drawable="@drawable/radiobutton_off_background_focus_yellow" />
- <item android:state_checked="true" android:state_focused="true"
- android:drawable="@drawable/radiobutton_on_background_focus_yellow" />
- <item android:state_checked="false" android:drawable="@drawable/radiobutton_off_background" />
- <item android:state_checked="true" android:drawable="@drawable/radiobutton_on_background" />
-</selector>
+<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator">
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
+</set>
diff --git a/core/res/res/anim/options_panel_enter.xml b/core/res/res/anim/options_panel_enter.xml
index 9614014..d81866b 100644
--- a/core/res/res/anim/options_panel_enter.xml
+++ b/core/res/res/anim/options_panel_enter.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+ <translate android:fromYDelta="25%" android:toYDelta="0"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/options_panel_exit.xml b/core/res/res/anim/options_panel_exit.xml
index c9bee1d..4e7af7a 100644
--- a/core/res/res/anim/options_panel_exit.xml
+++ b/core/res/res/anim/options_panel_exit.xml
@@ -19,7 +19,9 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator">
- <translate android:fromYDelta="0" android:toYDelta="50%" android:duration="50"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
+ <translate android:fromYDelta="0" android:toYDelta="50%"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/push_down_in.xml b/core/res/res/anim/push_down_in.xml
index 1cb1597..6ab9a04 100644
--- a/core/res/res/anim/push_down_in.xml
+++ b/core/res/res/anim/push_down_in.xml
@@ -15,6 +15,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="-100%p" android:toYDelta="0" android:duration="300"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" />
+ <translate android:fromYDelta="-100%p" android:toYDelta="0"
+ android:duration="@android:integer/config_longAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_longAnimTime" />
</set>
diff --git a/core/res/res/anim/push_down_out.xml b/core/res/res/anim/push_down_out.xml
index 1ad49b0..ce36458 100644
--- a/core/res/res/anim/push_down_out.xml
+++ b/core/res/res/anim/push_down_out.xml
@@ -15,6 +15,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="0" android:toYDelta="100%p" android:duration="300"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="300" />
+ <translate android:fromYDelta="0" android:toYDelta="100%p"
+ android:duration="@android:integer/config_longAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_longAnimTime" />
</set>
diff --git a/core/res/res/anim/push_up_in.xml b/core/res/res/anim/push_up_in.xml
index a2f47e9..6ef582c 100644
--- a/core/res/res/anim/push_up_in.xml
+++ b/core/res/res/anim/push_up_in.xml
@@ -15,6 +15,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="100%p" android:toYDelta="0" android:duration="300"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" />
+ <translate android:fromYDelta="100%p" android:toYDelta="0"
+ android:duration="@android:integer/config_longAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_longAnimTime" />
</set>
diff --git a/core/res/res/anim/push_up_out.xml b/core/res/res/anim/push_up_out.xml
index 2803435..2b267d5 100644
--- a/core/res/res/anim/push_up_out.xml
+++ b/core/res/res/anim/push_up_out.xml
@@ -15,6 +15,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="0" android:toYDelta="-100%p" android:duration="300"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="300" />
+ <translate android:fromYDelta="0" android:toYDelta="-100%p"
+ android:duration="@android:integer/config_longAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_longAnimTime" />
</set>
diff --git a/core/res/res/anim/search_bar_enter.xml b/core/res/res/anim/search_bar_enter.xml
index ecb86c1..c85caaa 100644
--- a/core/res/res/anim/search_bar_enter.xml
+++ b/core/res/res/anim/search_bar_enter.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromYDelta="-25%" android:toYDelta="0" android:duration="75"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+ <translate android:fromYDelta="-25%" android:toYDelta="0"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/search_bar_exit.xml b/core/res/res/anim/search_bar_exit.xml
index db7142e..1609a12 100644
--- a/core/res/res/anim/search_bar_exit.xml
+++ b/core/res/res/anim/search_bar_exit.xml
@@ -19,7 +19,9 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator">
- <translate android:fromYDelta="0" android:toYDelta="-50%" android:duration="50"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
+ <translate android:fromYDelta="0" android:toYDelta="-50%"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/shrink_fade_out.xml b/core/res/res/anim/shrink_fade_out.xml
index ae15ff9..4000c23 100644
--- a/core/res/res/anim/shrink_fade_out.xml
+++ b/core/res/res/anim/shrink_fade_out.xml
@@ -20,6 +20,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale="1.0" android:toYScale="0.3"
- android:pivotX="0%" android:pivotY="0%" android:duration="125" />
- <alpha android:interpolator="@anim/accelerate_interpolator" android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="75"/>
+ android:pivotX="0%" android:pivotY="0%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/accelerate_interpolator"
+ android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/shrink_fade_out_center.xml b/core/res/res/anim/shrink_fade_out_center.xml
index 7b0be34..a41731e 100644
--- a/core/res/res/anim/shrink_fade_out_center.xml
+++ b/core/res/res/anim/shrink_fade_out_center.xml
@@ -20,6 +20,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="1.0" android:toXScale="0.5"
android:fromYScale="1.0" android:toYScale="0.5"
- android:pivotX="50%" android:pivotY="50%" android:duration="125" />
- <alpha android:interpolator="@anim/accelerate_interpolator" android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="75"/>
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/accelerate_interpolator"
+ android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/shrink_fade_out_from_bottom.xml b/core/res/res/anim/shrink_fade_out_from_bottom.xml
index 61f29d5..345a2e0 100644
--- a/core/res/res/anim/shrink_fade_out_from_bottom.xml
+++ b/core/res/res/anim/shrink_fade_out_from_bottom.xml
@@ -20,6 +20,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale="1.0" android:toYScale="0.3"
- android:pivotX="0%" android:pivotY="100%" android:duration="125" />
- <alpha android:interpolator="@anim/accelerate_interpolator" android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="75"/>
+ android:pivotX="0%" android:pivotY="100%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/accelerate_interpolator"
+ android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/slide_in_bottom.xml b/core/res/res/anim/slide_in_bottom.xml
index 569d974..d111854 100644
--- a/core/res/res/anim/slide_in_bottom.xml
+++ b/core/res/res/anim/slide_in_bottom.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="50%p" android:toYDelta="0" android:duration="200"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
+ <translate android:fromYDelta="50%p" android:toYDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_in_child_bottom.xml b/core/res/res/anim/slide_in_child_bottom.xml
index ce51c36..2ab0f66 100644
--- a/core/res/res/anim/slide_in_child_bottom.xml
+++ b/core/res/res/anim/slide_in_child_bottom.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromYDelta="100%" android:toYDelta="0" android:duration="200"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
+ <translate android:fromYDelta="100%" android:toYDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_in_left.xml b/core/res/res/anim/slide_in_left.xml
index 033bfe2..9a585f5 100644
--- a/core/res/res/anim/slide_in_left.xml
+++ b/core/res/res/anim/slide_in_left.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="-50%p" android:toXDelta="0" android:duration="200"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
+ <translate android:fromXDelta="-50%p" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_in_right.xml b/core/res/res/anim/slide_in_right.xml
index 76b336c..125060e 100644
--- a/core/res/res/anim/slide_in_right.xml
+++ b/core/res/res/anim/slide_in_right.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="50%p" android:toXDelta="0" android:duration="200"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
+ <translate android:fromXDelta="50%p" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_in_top.xml b/core/res/res/anim/slide_in_top.xml
index 15df913..f4810ab 100644
--- a/core/res/res/anim/slide_in_top.xml
+++ b/core/res/res/anim/slide_in_top.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="-50%p" android:toYDelta="0" android:duration="200"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
+ <translate android:fromYDelta="-50%p" android:toYDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_out_bottom.xml b/core/res/res/anim/slide_out_bottom.xml
index 8f6e8b0..8ddcd59 100644
--- a/core/res/res/anim/slide_out_bottom.xml
+++ b/core/res/res/anim/slide_out_bottom.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="0" android:toYDelta="50%p" android:duration="200"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
+ <translate android:fromYDelta="0" android:toYDelta="50%p"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_out_left.xml b/core/res/res/anim/slide_out_left.xml
index 979d10a..73337d4 100644
--- a/core/res/res/anim/slide_out_left.xml
+++ b/core/res/res/anim/slide_out_left.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="0" android:toXDelta="-50%p" android:duration="200"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
+ <translate android:fromXDelta="0" android:toXDelta="-50%p"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_out_right.xml b/core/res/res/anim/slide_out_right.xml
index b5f9bb9..de8c512 100644
--- a/core/res/res/anim/slide_out_right.xml
+++ b/core/res/res/anim/slide_out_right.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="0" android:toXDelta="50%p" android:duration="200"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
+ <translate android:fromXDelta="0" android:toXDelta="50%p"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_out_top.xml b/core/res/res/anim/slide_out_top.xml
index b15323e..3134a57 100644
--- a/core/res/res/anim/slide_out_top.xml
+++ b/core/res/res/anim/slide_out_top.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="0" android:toYDelta="-50%p" android:duration="200"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
+ <translate android:fromYDelta="0" android:toYDelta="-50%p"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/status_bar_enter.xml b/core/res/res/anim/status_bar_enter.xml
index 2df1af4..d308ad5 100644
--- a/core/res/res/anim/status_bar_enter.xml
+++ b/core/res/res/anim/status_bar_enter.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromYDelta="-100%" android:toYDelta="0" android:duration="400"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="400" />
+ <translate android:fromYDelta="-75%" android:toYDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/status_bar_exit.xml b/core/res/res/anim/status_bar_exit.xml
index c72d014..43a1b9a 100644
--- a/core/res/res/anim/status_bar_exit.xml
+++ b/core/res/res/anim/status_bar_exit.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator">
- <translate android:fromYDelta="0" android:toYDelta="-100%" android:duration="400"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="400" />
+ <translate android:fromYDelta="0" android:toYDelta="-75%"
+ android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/submenu_enter.xml b/core/res/res/anim/submenu_enter.xml
index 32a8054..5a94971 100644
--- a/core/res/res/anim/submenu_enter.xml
+++ b/core/res/res/anim/submenu_enter.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromXDelta="-25%" android:toXDelta="0" android:duration="100"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="100" />
+ <translate android:fromXDelta="-25%" android:toXDelta="0"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/submenu_exit.xml b/core/res/res/anim/submenu_exit.xml
index 9283751..20fbefc 100644
--- a/core/res/res/anim/submenu_exit.xml
+++ b/core/res/res/anim/submenu_exit.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="0" android:toXDelta="25%" android:duration="50"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
+ <translate android:fromXDelta="0" android:toXDelta="25%"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml
index 6bef7a4..c289869 100644
--- a/core/res/res/anim/task_close_enter.xml
+++ b/core/res/res/anim/task_close_enter.xml
@@ -21,5 +21,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator"
android:zAdjustment="top">
- <translate android:fromXDelta="-100%" android:toXDelta="0" android:duration="200"/>
+ <translate android:fromXDelta="-100%" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index 48dc31a..96fff94 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -20,5 +20,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromXDelta="0%" android:toXDelta="33%" android:duration="200"/>
+ <translate android:fromXDelta="0%" android:toXDelta="33%"
+ android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index e498c9d..8e7d049 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -20,5 +20,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromXDelta="33%" android:toXDelta="0" android:duration="200"/>
+ <translate android:fromXDelta="33%" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 8ef4006..5e5c66d 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -21,5 +21,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator"
android:zAdjustment="top">
- <translate android:fromXDelta="0%" android:toXDelta="-100%" android:duration="200"/>
+ <translate android:fromXDelta="0%" android:toXDelta="-100%"
+ android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/toast_enter.xml b/core/res/res/anim/toast_enter.xml
index 83cb1fe..57310d9 100644
--- a/core/res/res/anim/toast_enter.xml
+++ b/core/res/res/anim/toast_enter.xml
@@ -20,4 +20,5 @@
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator"
- android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="400" />
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_longAnimTime" />
diff --git a/core/res/res/anim/toast_exit.xml b/core/res/res/anim/toast_exit.xml
index f922085..b7c5fa0 100644
--- a/core/res/res/anim/toast_exit.xml
+++ b/core/res/res/anim/toast_exit.xml
@@ -20,5 +20,6 @@
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/accelerate_interpolator"
- android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="400"
+ android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_longAnimTime"
/>
diff --git a/core/res/res/color/tertiary_text_dark.xml b/core/res/res/color/tertiary_text_dark.xml
index 7e61fc8..7ce3580 100644
--- a/core/res/res/color/tertiary_text_dark.xml
+++ b/core/res/res/color/tertiary_text_dark.xml
@@ -18,7 +18,7 @@
<item android:state_enabled="false" android:color="#808080"/>
 <item android:state_window_focused="false" android:color="#808080"/>
<item android:state_pressed="true" android:color="#808080"/>
- <item android:state_selected="true" android:color="#808080"/>
+ <item android:state_selected="true" android:color="@android:color/dim_foreground_light"/>
<item android:color="#808080"/> <!-- not selected -->
</selector>
diff --git a/core/res/res/drawable-land/statusbar_background.png b/core/res/res/drawable-land/statusbar_background.png
index 9e82f75..2a351a5 100644
--- a/core/res/res/drawable-land/statusbar_background.png
+++ b/core/res/res/drawable-land/statusbar_background.png
Binary files differ
diff --git a/core/res/res/drawable-land/title_bar_tall.png b/core/res/res/drawable-land/title_bar_tall.png
new file mode 100644
index 0000000..16290fb
--- /dev/null
+++ b/core/res/res/drawable-land/title_bar_tall.png
Binary files differ
diff --git a/core/res/res/drawable/activity_title_bar.9.png b/core/res/res/drawable/activity_title_bar.9.png
new file mode 100644
index 0000000..bd0680d
--- /dev/null
+++ b/core/res/res/drawable/activity_title_bar.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_browser_zoom_fit_page.xml b/core/res/res/drawable/btn_browser_zoom_fit_page.xml
new file mode 100644
index 0000000..2f4761a
--- /dev/null
+++ b/core/res/res/drawable/btn_browser_zoom_fit_page.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@android:drawable/btn_square_overlay" />
+ <item android:drawable="@android:drawable/ic_btn_square_browser_zoom_fit_page" />
+</layer-list>
diff --git a/core/res/res/drawable/btn_browser_zoom_page_overview.xml b/core/res/res/drawable/btn_browser_zoom_page_overview.xml
new file mode 100644
index 0000000..16fb1e6
--- /dev/null
+++ b/core/res/res/drawable/btn_browser_zoom_page_overview.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@android:drawable/btn_square_overlay" />
+ <item android:drawable="@android:drawable/ic_btn_square_browser_zoom_page_overview" />
+</layer-list>
diff --git a/core/res/res/drawable/btn_check_off_disable.png b/core/res/res/drawable/btn_check_off_disable.png
index 6c065bd..e012afd 100644
--- a/core/res/res/drawable/btn_check_off_disable.png
+++ b/core/res/res/drawable/btn_check_off_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_disable_focused.png b/core/res/res/drawable/btn_check_off_disable_focused.png
index cf23690..0837bbd 100644
--- a/core/res/res/drawable/btn_check_off_disable_focused.png
+++ b/core/res/res/drawable/btn_check_off_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_pressed.png b/core/res/res/drawable/btn_check_off_pressed.png
index 47c1a46..984dfd7 100644
--- a/core/res/res/drawable/btn_check_off_pressed.png
+++ b/core/res/res/drawable/btn_check_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_off_selected.png b/core/res/res/drawable/btn_check_off_selected.png
index cf53075..20842d4 100644
--- a/core/res/res/drawable/btn_check_off_selected.png
+++ b/core/res/res/drawable/btn_check_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_disable.png b/core/res/res/drawable/btn_check_on_disable.png
index 8e9f633..6cb02f3 100644
--- a/core/res/res/drawable/btn_check_on_disable.png
+++ b/core/res/res/drawable/btn_check_on_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_disable_focused.png b/core/res/res/drawable/btn_check_on_disable_focused.png
index 0abb051..8a73b33 100644
--- a/core/res/res/drawable/btn_check_on_disable_focused.png
+++ b/core/res/res/drawable/btn_check_on_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_pressed.png b/core/res/res/drawable/btn_check_on_pressed.png
index ee2175d..300d64a 100644
--- a/core/res/res/drawable/btn_check_on_pressed.png
+++ b/core/res/res/drawable/btn_check_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_on_selected.png b/core/res/res/drawable/btn_check_on_selected.png
index 9356456..0b36adb 100644
--- a/core/res/res/drawable/btn_check_on_selected.png
+++ b/core/res/res/drawable/btn_check_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle.xml b/core/res/res/drawable/btn_circle.xml
new file mode 100644
index 0000000..9208010
--- /dev/null
+++ b/core/res/res/drawable/btn_circle.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_window_focused="false" android:state_enabled="true"
+ android:drawable="@drawable/btn_circle_normal" />
+ <item android:state_window_focused="false" android:state_enabled="false"
+ android:drawable="@drawable/btn_circle_disable" />
+ <item android:state_pressed="true"
+ android:drawable="@drawable/btn_circle_pressed" />
+ <item android:state_focused="true" android:state_enabled="true"
+ android:drawable="@drawable/btn_circle_selected" />
+ <item android:state_enabled="true"
+ android:drawable="@drawable/btn_circle_normal" />
+ <item android:state_focused="true"
+ android:drawable="@drawable/btn_circle_disable_focused" />
+ <item
+ android:drawable="@drawable/btn_circle_disable" />
+</selector>
diff --git a/core/res/res/drawable/btn_circle_disable.png b/core/res/res/drawable/btn_circle_disable.png
new file mode 100644
index 0000000..33b74a6
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_disable.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_disable_focused.png b/core/res/res/drawable/btn_circle_disable_focused.png
new file mode 100644
index 0000000..005ad8d
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_disable_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_longpress.png b/core/res/res/drawable/btn_circle_longpress.png
new file mode 100644
index 0000000..f27d411
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_longpress.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_normal.png b/core/res/res/drawable/btn_circle_normal.png
new file mode 100644
index 0000000..fc5af1c
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_pressed.png b/core/res/res/drawable/btn_circle_pressed.png
new file mode 100644
index 0000000..8f40afd
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_circle_selected.png b/core/res/res/drawable/btn_circle_selected.png
new file mode 100644
index 0000000..c74fac2
--- /dev/null
+++ b/core/res/res/drawable/btn_circle_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_normal.9.png b/core/res/res/drawable/btn_default_normal.9.png
index ad1634a..a2d5ccd 100644
--- a/core/res/res/drawable/btn_default_normal.9.png
+++ b/core/res/res/drawable/btn_default_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_normal_disable.9.png b/core/res/res/drawable/btn_default_normal_disable.9.png
index a89f37d..edd3a3e 100644
--- a/core/res/res/drawable/btn_default_normal_disable.9.png
+++ b/core/res/res/drawable/btn_default_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_normal_disable_focused.9.png b/core/res/res/drawable/btn_default_normal_disable_focused.9.png
index b71dae9..f506179 100644
--- a/core/res/res/drawable/btn_default_normal_disable_focused.9.png
+++ b/core/res/res/drawable/btn_default_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_pressed.9.png b/core/res/res/drawable/btn_default_pressed.9.png
index f496a86..033bf89 100644
--- a/core/res/res/drawable/btn_default_pressed.9.png
+++ b/core/res/res/drawable/btn_default_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_selected.9.png b/core/res/res/drawable/btn_default_selected.9.png
index c9e7e64..1e900bf 100644
--- a/core/res/res/drawable/btn_default_selected.9.png
+++ b/core/res/res/drawable/btn_default_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_normal.9.png b/core/res/res/drawable/btn_default_small_normal.9.png
index faac205..bcedd5f 100644
--- a/core/res/res/drawable/btn_default_small_normal.9.png
+++ b/core/res/res/drawable/btn_default_small_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_normal_disable.9.png b/core/res/res/drawable/btn_default_small_normal_disable.9.png
index ce4fd28..ac6260f 100644
--- a/core/res/res/drawable/btn_default_small_normal_disable.9.png
+++ b/core/res/res/drawable/btn_default_small_normal_disable.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png b/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png
index 1f04c18..4ee1b3f 100644
--- a/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png
+++ b/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_pressed.9.png b/core/res/res/drawable/btn_default_small_pressed.9.png
index dab005b..25e38f4 100644
--- a/core/res/res/drawable/btn_default_small_pressed.9.png
+++ b/core/res/res/drawable/btn_default_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default_small_selected.9.png b/core/res/res/drawable/btn_default_small_selected.9.png
index 5dec504..cc209c6 100644
--- a/core/res/res/drawable/btn_default_small_selected.9.png
+++ b/core/res/res/drawable/btn_default_small_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_normal.9.png b/core/res/res/drawable/btn_keyboard_key_normal.9.png
index 5c8a945..7ba18dd 100644
--- a/core/res/res/drawable/btn_keyboard_key_normal.9.png
+++ b/core/res/res/drawable/btn_keyboard_key_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_normal_off.9.png b/core/res/res/drawable/btn_keyboard_key_normal_off.9.png
index e6e640a..bda9b83 100644
--- a/core/res/res/drawable/btn_keyboard_key_normal_off.9.png
+++ b/core/res/res/drawable/btn_keyboard_key_normal_off.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_normal_on.9.png b/core/res/res/drawable/btn_keyboard_key_normal_on.9.png
index ce97a44..0c16ed5 100644
--- a/core/res/res/drawable/btn_keyboard_key_normal_on.9.png
+++ b/core/res/res/drawable/btn_keyboard_key_normal_on.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_pressed.9.png b/core/res/res/drawable/btn_keyboard_key_pressed.9.png
index f2e9f04..39b9314 100755
--- a/core/res/res/drawable/btn_keyboard_key_pressed.9.png
+++ b/core/res/res/drawable/btn_keyboard_key_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png b/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png
index d541f95..bdcf06e 100644
--- a/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png
+++ b/core/res/res/drawable/btn_keyboard_key_pressed_off.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png b/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png
index 1cd6d45..79621a9 100644
--- a/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png
+++ b/core/res/res/drawable/btn_keyboard_key_pressed_on.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_off_pressed.png b/core/res/res/drawable/btn_radio_off_pressed.png
index 41120ae..d6d8a9d 100644
--- a/core/res/res/drawable/btn_radio_off_pressed.png
+++ b/core/res/res/drawable/btn_radio_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_off_selected.png b/core/res/res/drawable/btn_radio_off_selected.png
index 8b5535d..53f3e87 100644
--- a/core/res/res/drawable/btn_radio_off_selected.png
+++ b/core/res/res/drawable/btn_radio_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on.png b/core/res/res/drawable/btn_radio_on.png
index 7286b31..25a3ccc 100644
--- a/core/res/res/drawable/btn_radio_on.png
+++ b/core/res/res/drawable/btn_radio_on.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on_pressed.png b/core/res/res/drawable/btn_radio_on_pressed.png
index 20ce0ec..c904a35 100644
--- a/core/res/res/drawable/btn_radio_on_pressed.png
+++ b/core/res/res/drawable/btn_radio_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_radio_on_selected.png b/core/res/res/drawable/btn_radio_on_selected.png
index ed53dc7..78e1fc0 100644
--- a/core/res/res/drawable/btn_radio_on_selected.png
+++ b/core/res/res/drawable/btn_radio_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_off_normal.png b/core/res/res/drawable/btn_rating_star_off_normal.png
index bb15404..a99441d 100644
--- a/core/res/res/drawable/btn_rating_star_off_normal.png
+++ b/core/res/res/drawable/btn_rating_star_off_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_off_pressed.png b/core/res/res/drawable/btn_rating_star_off_pressed.png
index 45482b9..f47a454 100644
--- a/core/res/res/drawable/btn_rating_star_off_pressed.png
+++ b/core/res/res/drawable/btn_rating_star_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_off_selected.png b/core/res/res/drawable/btn_rating_star_off_selected.png
index 3fbe92a..5f71e08 100644
--- a/core/res/res/drawable/btn_rating_star_off_selected.png
+++ b/core/res/res/drawable/btn_rating_star_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_on_normal.png b/core/res/res/drawable/btn_rating_star_on_normal.png
index 1c329a1..b7825d3 100644
--- a/core/res/res/drawable/btn_rating_star_on_normal.png
+++ b/core/res/res/drawable/btn_rating_star_on_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_on_pressed.png b/core/res/res/drawable/btn_rating_star_on_pressed.png
index 2a965a7..4052445 100644
--- a/core/res/res/drawable/btn_rating_star_on_pressed.png
+++ b/core/res/res/drawable/btn_rating_star_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_rating_star_on_selected.png b/core/res/res/drawable/btn_rating_star_on_selected.png
index 2c1e207..5d139b6 100644
--- a/core/res/res/drawable/btn_rating_star_on_selected.png
+++ b/core/res/res/drawable/btn_rating_star_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_square_overlay.xml b/core/res/res/drawable/btn_square_overlay.xml
new file mode 100644
index 0000000..a2c698c
--- /dev/null
+++ b/core/res/res/drawable/btn_square_overlay.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:state_focused="true"
+ android:state_window_focused="true"
+ android:drawable="@drawable/btn_square_overlay_disabled_focused" />
+ <item android:state_enabled="false" android:drawable="@drawable/btn_square_overlay_disabled" />
+ <item android:state_pressed="true" android:drawable="@drawable/btn_square_overlay_pressed" />
+ <item android:state_focused="true" android:state_window_focused="true"
+ android:drawable="@drawable/btn_square_overlay_selected" />
+ <item android:drawable="@drawable/btn_square_overlay_normal" />
+</selector> \ No newline at end of file
diff --git a/core/res/res/drawable/btn_square_overlay_disabled.png b/core/res/res/drawable/btn_square_overlay_disabled.png
new file mode 100644
index 0000000..cf7e4ea
--- /dev/null
+++ b/core/res/res/drawable/btn_square_overlay_disabled.png
Binary files differ
diff --git a/core/res/res/drawable/btn_square_overlay_disabled_focused.png b/core/res/res/drawable/btn_square_overlay_disabled_focused.png
new file mode 100644
index 0000000..5aa1143
--- /dev/null
+++ b/core/res/res/drawable/btn_square_overlay_disabled_focused.png
Binary files differ
diff --git a/core/res/res/drawable/btn_square_overlay_normal.png b/core/res/res/drawable/btn_square_overlay_normal.png
new file mode 100644
index 0000000..45fa4fe
--- /dev/null
+++ b/core/res/res/drawable/btn_square_overlay_normal.png
Binary files differ
diff --git a/core/res/res/drawable/btn_square_overlay_pressed.png b/core/res/res/drawable/btn_square_overlay_pressed.png
new file mode 100644
index 0000000..952571b
--- /dev/null
+++ b/core/res/res/drawable/btn_square_overlay_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_square_overlay_selected.png b/core/res/res/drawable/btn_square_overlay_selected.png
new file mode 100644
index 0000000..ce4515e
--- /dev/null
+++ b/core/res/res/drawable/btn_square_overlay_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_off.png b/core/res/res/drawable/btn_star_big_off.png
index 21ba557..7e9342b 100755
--- a/core/res/res/drawable/btn_star_big_off.png
+++ b/core/res/res/drawable/btn_star_big_off.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_off_pressed.png b/core/res/res/drawable/btn_star_big_off_pressed.png
index 2c704ee..f1b8912 100755
--- a/core/res/res/drawable/btn_star_big_off_pressed.png
+++ b/core/res/res/drawable/btn_star_big_off_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_off_selected.png b/core/res/res/drawable/btn_star_big_off_selected.png
index 101357d..0be64c4 100755
--- a/core/res/res/drawable/btn_star_big_off_selected.png
+++ b/core/res/res/drawable/btn_star_big_off_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_on.png b/core/res/res/drawable/btn_star_big_on.png
index 9c2f7d2..a9bdb05 100755
--- a/core/res/res/drawable/btn_star_big_on.png
+++ b/core/res/res/drawable/btn_star_big_on.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_on_pressed.png b/core/res/res/drawable/btn_star_big_on_pressed.png
index 8ac4bab..159a84b 100755
--- a/core/res/res/drawable/btn_star_big_on_pressed.png
+++ b/core/res/res/drawable/btn_star_big_on_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/btn_star_big_on_selected.png b/core/res/res/drawable/btn_star_big_on_selected.png
index d453eab..0592d51 100755
--- a/core/res/res/drawable/btn_star_big_on_selected.png
+++ b/core/res/res/drawable/btn_star_big_on_selected.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_down.xml b/core/res/res/drawable/btn_zoom_down.xml
new file mode 100644
index 0000000..e7449aa
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_down.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:state_focused="true"
+ android:state_window_focused="true"
+ android:drawable="@drawable/btn_zoom_down_disabled_focused" />
+ <item android:state_enabled="false" android:drawable="@drawable/btn_zoom_down_disabled" />
+ <item android:state_pressed="true" android:drawable="@drawable/btn_zoom_down_pressed" />
+ <item android:state_focused="true" android:state_window_focused="true"
+ android:drawable="@drawable/btn_zoom_down_selected" />
+ <item android:drawable="@drawable/btn_zoom_down_normal" />
+</selector>
+
diff --git a/core/res/res/drawable/btn_zoom_down_disabled.9.png b/core/res/res/drawable/btn_zoom_down_disabled.9.png
new file mode 100644
index 0000000..7780bd7
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_down_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_down_disabled_focused.9.png b/core/res/res/drawable/btn_zoom_down_disabled_focused.9.png
new file mode 100644
index 0000000..39131c5
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_down_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_down_longpress.9.png b/core/res/res/drawable/btn_zoom_down_longpress.9.png
new file mode 100644
index 0000000..09a3bb3
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_down_longpress.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_down_normal.9.png b/core/res/res/drawable/btn_zoom_down_normal.9.png
new file mode 100644
index 0000000..b589a84
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_down_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_down_pressed.9.png b/core/res/res/drawable/btn_zoom_down_pressed.9.png
new file mode 100644
index 0000000..a8ca467
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_down_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_down_selected.9.png b/core/res/res/drawable/btn_zoom_down_selected.9.png
new file mode 100644
index 0000000..af551e7
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_down_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_up.xml b/core/res/res/drawable/btn_zoom_up.xml
new file mode 100644
index 0000000..045b3c3
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_up.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:state_focused="true"
+ android:state_window_focused="true"
+ android:drawable="@drawable/btn_zoom_up_disabled_focused" />
+ <item android:state_enabled="false" android:drawable="@drawable/btn_zoom_up_disabled" />
+ <item android:state_pressed="true" android:drawable="@drawable/btn_zoom_up_pressed" />
+ <item android:state_focused="true" android:state_window_focused="true"
+ android:drawable="@drawable/btn_zoom_up_selected" />
+ <item android:drawable="@drawable/btn_zoom_up_normal" />
+</selector>
+
diff --git a/core/res/res/drawable/btn_zoom_up_disabled.9.png b/core/res/res/drawable/btn_zoom_up_disabled.9.png
new file mode 100644
index 0000000..5203630
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_up_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_up_disabled_focused.9.png b/core/res/res/drawable/btn_zoom_up_disabled_focused.9.png
new file mode 100644
index 0000000..c72c9cd
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_up_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_up_longpress.9.png b/core/res/res/drawable/btn_zoom_up_longpress.9.png
new file mode 100644
index 0000000..8de48d1
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_up_longpress.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_up_normal.9.png b/core/res/res/drawable/btn_zoom_up_normal.9.png
new file mode 100644
index 0000000..5027348
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_up_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_up_pressed.9.png b/core/res/res/drawable/btn_zoom_up_pressed.9.png
new file mode 100644
index 0000000..1a93e3a
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_up_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_zoom_up_selected.9.png b/core/res/res/drawable/btn_zoom_up_selected.9.png
new file mode 100644
index 0000000..26aafee
--- /dev/null
+++ b/core/res/res/drawable/btn_zoom_up_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/checkbox_label_background.9.png b/core/res/res/drawable/checkbox_label_background.9.png
deleted file mode 100644
index e6af4b0..0000000
--- a/core/res/res/drawable/checkbox_label_background.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/checkbox_off_background_focus_yellow.png b/core/res/res/drawable/checkbox_off_background_focus_yellow.png
deleted file mode 100644
index ffde6f8..0000000
--- a/core/res/res/drawable/checkbox_off_background_focus_yellow.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/checkbox_on_background_focus_yellow.png b/core/res/res/drawable/checkbox_on_background_focus_yellow.png
deleted file mode 100644
index 3018009..0000000
--- a/core/res/res/drawable/checkbox_on_background_focus_yellow.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/dark_header.9.png b/core/res/res/drawable/dark_header.9.png
new file mode 100644
index 0000000..8fa5f09
--- /dev/null
+++ b/core/res/res/drawable/dark_header.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_horizontal_bright.9.png b/core/res/res/drawable/divider_horizontal_bright.9.png
index a1ba2d3..144fc22 100644
--- a/core/res/res/drawable/divider_horizontal_bright.9.png
+++ b/core/res/res/drawable/divider_horizontal_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_horizontal_dark.9.png b/core/res/res/drawable/divider_horizontal_dark.9.png
index 7b32381..08838ca 100644
--- a/core/res/res/drawable/divider_horizontal_dark.9.png
+++ b/core/res/res/drawable/divider_horizontal_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_horizontal_dim_dark.9.png b/core/res/res/drawable/divider_horizontal_dim_dark.9.png
index 20bc4dc..08838ca 100644
--- a/core/res/res/drawable/divider_horizontal_dim_dark.9.png
+++ b/core/res/res/drawable/divider_horizontal_dim_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/extract_edit_text.xml b/core/res/res/drawable/extract_edit_text.xml
new file mode 100644
index 0000000..c7f66f6
--- /dev/null
+++ b/core/res/res/drawable/extract_edit_text.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:drawable="@drawable/keyboard_textfield_selected" />
+ <item android:drawable="@drawable/textfield_disabled" />
+</selector>
+
diff --git a/core/res/res/drawable/ic_btn_round_more.xml b/core/res/res/drawable/ic_btn_round_more.xml
new file mode 100644
index 0000000..82b7593
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_round_more.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:drawable="@drawable/ic_btn_round_more_disabled" />
+ <item
+ android:drawable="@drawable/ic_btn_round_more_normal" />
+</selector>
diff --git a/core/res/res/drawable/ic_btn_round_more_disabled.png b/core/res/res/drawable/ic_btn_round_more_disabled.png
new file mode 100644
index 0000000..1ab98c9
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_round_more_disabled.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_round_more_normal.png b/core/res/res/drawable/ic_btn_round_more_normal.png
new file mode 100644
index 0000000..ebdc55c
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_round_more_normal.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_speak_now.png b/core/res/res/drawable/ic_btn_speak_now.png
new file mode 100644
index 0000000..83ee68b
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_speak_now.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page.xml b/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page.xml
new file mode 100644
index 0000000..bec869a
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:drawable="@drawable/ic_btn_square_browser_zoom_fit_page_disabled" />
+ <item android:drawable="@drawable/ic_btn_square_browser_zoom_fit_page_normal" />
+</selector> \ No newline at end of file
diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_disabled.png b/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_disabled.png
new file mode 100644
index 0000000..326397c
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_disabled.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_normal.png b/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_normal.png
new file mode 100644
index 0000000..5583401
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_square_browser_zoom_fit_page_normal.png
Binary files differ
diff --git a/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.png b/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.png
new file mode 100644
index 0000000..4e8ff35
--- /dev/null
+++ b/core/res/res/drawable/ic_btn_square_browser_zoom_page_overview.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_airplane_mode.png b/core/res/res/drawable/ic_lock_airplane_mode.png
new file mode 100755
index 0000000..caafcb2
--- /dev/null
+++ b/core/res/res/drawable/ic_lock_airplane_mode.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_airplane_mode_off.png b/core/res/res/drawable/ic_lock_airplane_mode_off.png
new file mode 100755
index 0000000..cb2cbdf
--- /dev/null
+++ b/core/res/res/drawable/ic_lock_airplane_mode_off.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_power_off.png b/core/res/res/drawable/ic_lock_power_off.png
index 14c002e..4405b43 100644
--- a/core/res/res/drawable/ic_lock_power_off.png
+++ b/core/res/res/drawable/ic_lock_power_off.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_silent_mode.png b/core/res/res/drawable/ic_lock_silent_mode.png
index c89291a..439a6f5 100644
--- a/core/res/res/drawable/ic_lock_silent_mode.png
+++ b/core/res/res/drawable/ic_lock_silent_mode.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lock_silent_mode_off.png b/core/res/res/drawable/ic_lock_silent_mode_off.png
index 4748b9e..fc7e960 100644
--- a/core/res/res/drawable/ic_lock_silent_mode_off.png
+++ b/core/res/res/drawable/ic_lock_silent_mode_off.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_accessory_bg_landscape.9.png b/core/res/res/drawable/keyboard_accessory_bg_landscape.9.png
new file mode 100644
index 0000000..8f828f6
--- /dev/null
+++ b/core/res/res/drawable/keyboard_accessory_bg_landscape.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_background.9.png b/core/res/res/drawable/keyboard_background.9.png
index 595acc5..1d3ce05 100644
--- a/core/res/res/drawable/keyboard_background.9.png
+++ b/core/res/res/drawable/keyboard_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_suggest_strip_shadow.9.png b/core/res/res/drawable/keyboard_suggest_strip_shadow.9.png
new file mode 100644
index 0000000..d231ae6
--- /dev/null
+++ b/core/res/res/drawable/keyboard_suggest_strip_shadow.9.png
Binary files differ
diff --git a/core/res/res/drawable/keyboard_textfield_selected.9.png b/core/res/res/drawable/keyboard_textfield_selected.9.png
new file mode 100644
index 0000000..6e703af
--- /dev/null
+++ b/core/res/res/drawable/keyboard_textfield_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/menu_background.9.png b/core/res/res/drawable/menu_background.9.png
index e7266b2..ee99583 100644
--- a/core/res/res/drawable/menu_background.9.png
+++ b/core/res/res/drawable/menu_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/popup_inline_error_above.9.png b/core/res/res/drawable/popup_inline_error_above.9.png
new file mode 100644
index 0000000..2e601d0
--- /dev/null
+++ b/core/res/res/drawable/popup_inline_error_above.9.png
Binary files differ
diff --git a/core/res/res/drawable/presence_away.png b/core/res/res/drawable/presence_away.png
index a539ec7..f8120df 100644
--- a/core/res/res/drawable/presence_away.png
+++ b/core/res/res/drawable/presence_away.png
Binary files differ
diff --git a/core/res/res/drawable/presence_busy.png b/core/res/res/drawable/presence_busy.png
index 1e3f547..9d7620b 100644
--- a/core/res/res/drawable/presence_busy.png
+++ b/core/res/res/drawable/presence_busy.png
Binary files differ
diff --git a/core/res/res/drawable/presence_invisible.png b/core/res/res/drawable/presence_invisible.png
index fb86cf1..21399a4 100644
--- a/core/res/res/drawable/presence_invisible.png
+++ b/core/res/res/drawable/presence_invisible.png
Binary files differ
diff --git a/core/res/res/drawable/presence_offline.png b/core/res/res/drawable/presence_offline.png
index da54fe7..3941b82 100644
--- a/core/res/res/drawable/presence_offline.png
+++ b/core/res/res/drawable/presence_offline.png
Binary files differ
diff --git a/core/res/res/drawable/presence_online.png b/core/res/res/drawable/presence_online.png
index 879a762..22d5683 100644
--- a/core/res/res/drawable/presence_online.png
+++ b/core/res/res/drawable/presence_online.png
Binary files differ
diff --git a/core/res/res/drawable/radiobutton_label_background.9.png b/core/res/res/drawable/radiobutton_label_background.9.png
deleted file mode 100644
index e6af4b0..0000000
--- a/core/res/res/drawable/radiobutton_label_background.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/radiobutton_off_background_focus_yellow.png b/core/res/res/drawable/radiobutton_off_background_focus_yellow.png
deleted file mode 100644
index 1a092e3..0000000
--- a/core/res/res/drawable/radiobutton_off_background_focus_yellow.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/radiobutton_on_background_focus_yellow.png b/core/res/res/drawable/radiobutton_on_background_focus_yellow.png
deleted file mode 100644
index aa59771..0000000
--- a/core/res/res/drawable/radiobutton_on_background_focus_yellow.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/scrollbar_handle_accelerated_anim2.9.png b/core/res/res/drawable/scrollbar_handle_accelerated_anim2.9.png
index d96cb3f..85caddd 100755
--- a/core/res/res/drawable/scrollbar_handle_accelerated_anim2.9.png
+++ b/core/res/res/drawable/scrollbar_handle_accelerated_anim2.9.png
Binary files differ
diff --git a/core/res/res/drawable/scrollbar_handle_horizontal.9.png b/core/res/res/drawable/scrollbar_handle_horizontal.9.png
index f333733..8584d1f 100755
--- a/core/res/res/drawable/scrollbar_handle_horizontal.9.png
+++ b/core/res/res/drawable/scrollbar_handle_horizontal.9.png
Binary files differ
diff --git a/core/res/res/drawable/scrollbar_handle_vertical.9.png b/core/res/res/drawable/scrollbar_handle_vertical.9.png
index ff08295..331a05d 100755
--- a/core/res/res/drawable/scrollbar_handle_vertical.9.png
+++ b/core/res/res/drawable/scrollbar_handle_vertical.9.png
Binary files differ
diff --git a/core/res/res/drawable/seek_thumb.xml b/core/res/res/drawable/seek_thumb.xml
index 7fe51b3..c7a862d 100644
--- a/core/res/res/drawable/seek_thumb.xml
+++ b/core/res/res/drawable/seek_thumb.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<!-- This is the rating bar drawable that is used to a show a filled star. -->
+<!-- This is the thumb on the seek bar. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
diff --git a/core/res/res/drawable/seek_thumb_normal.png b/core/res/res/drawable/seek_thumb_normal.png
index dbaae91..e9f2e23 100644
--- a/core/res/res/drawable/seek_thumb_normal.png
+++ b/core/res/res/drawable/seek_thumb_normal.png
Binary files differ
diff --git a/core/res/res/drawable/seek_thumb_pressed.png b/core/res/res/drawable/seek_thumb_pressed.png
index dbaae91..3ea5051 100644
--- a/core/res/res/drawable/seek_thumb_pressed.png
+++ b/core/res/res/drawable/seek_thumb_pressed.png
Binary files differ
diff --git a/core/res/res/drawable/seek_thumb_selected.png b/core/res/res/drawable/seek_thumb_selected.png
index dbaae91..98b7ba0 100644
--- a/core/res/res/drawable/seek_thumb_selected.png
+++ b/core/res/res/drawable/seek_thumb_selected.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_phone_call.png b/core/res/res/drawable/stat_sys_phone_call.png
index ad53693..c44d062 100644
--- a/core/res/res/drawable/stat_sys_phone_call.png
+++ b/core/res/res/drawable/stat_sys_phone_call.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_phone_call_bluetooth.png b/core/res/res/drawable/stat_sys_phone_call_bluetooth.png
new file mode 100644
index 0000000..7abfd19
--- /dev/null
+++ b/core/res/res/drawable/stat_sys_phone_call_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_ringer_silent.png b/core/res/res/drawable/stat_sys_ringer_silent.png
index d125ce5..d62f32d 100644
--- a/core/res/res/drawable/stat_sys_ringer_silent.png
+++ b/core/res/res/drawable/stat_sys_ringer_silent.png
Binary files differ
diff --git a/core/res/res/drawable/stat_sys_signal_flightmode.png b/core/res/res/drawable/stat_sys_signal_flightmode.png
index 516ec2f..2f4fd4f 100755..100644
--- a/core/res/res/drawable/stat_sys_signal_flightmode.png
+++ b/core/res/res/drawable/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/core/res/res/drawable/statusbar_background.png b/core/res/res/drawable/statusbar_background.png
index 6af7329..2d8aa7a 100644
--- a/core/res/res/drawable/statusbar_background.png
+++ b/core/res/res/drawable/statusbar_background.png
Binary files differ
diff --git a/core/res/res/drawable/sym_action_add.png b/core/res/res/drawable/sym_action_add.png
new file mode 100644
index 0000000..af637b3
--- /dev/null
+++ b/core/res/res/drawable/sym_action_add.png
Binary files differ
diff --git a/core/res/res/drawable/sym_action_call.png b/core/res/res/drawable/sym_action_call.png
index bcd9010..a442758 100644
--- a/core/res/res/drawable/sym_action_call.png
+++ b/core/res/res/drawable/sym_action_call.png
Binary files differ
diff --git a/core/res/res/drawable/sym_action_chat.png b/core/res/res/drawable/sym_action_chat.png
index 625e0e8..9f6419e 100644
--- a/core/res/res/drawable/sym_action_chat.png
+++ b/core/res/res/drawable/sym_action_chat.png
Binary files differ
diff --git a/core/res/res/drawable/sym_action_email.png b/core/res/res/drawable/sym_action_email.png
index 5f79e92..5fea417 100644
--- a/core/res/res/drawable/sym_action_email.png
+++ b/core/res/res/drawable/sym_action_email.png
Binary files differ
diff --git a/core/res/res/drawable/sym_action_map.png b/core/res/res/drawable/sym_action_map.png
deleted file mode 100644
index b45b7a8..0000000
--- a/core/res/res/drawable/sym_action_map.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/sym_action_sms.png b/core/res/res/drawable/sym_action_sms.png
deleted file mode 100644
index 50ce0ea..0000000
--- a/core/res/res/drawable/sym_action_sms.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/textfield_default.9.png b/core/res/res/drawable/textfield_default.9.png
index ab99aeb..cc78e6c 100644
--- a/core/res/res/drawable/textfield_default.9.png
+++ b/core/res/res/drawable/textfield_default.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_disabled.9.png b/core/res/res/drawable/textfield_disabled.9.png
index 0070158..9c77149 100644
--- a/core/res/res/drawable/textfield_disabled.9.png
+++ b/core/res/res/drawable/textfield_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_disabled_selected.9.png b/core/res/res/drawable/textfield_disabled_selected.9.png
index 139d606..6d47708 100755..100644
--- a/core/res/res/drawable/textfield_disabled_selected.9.png
+++ b/core/res/res/drawable/textfield_disabled_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_pressed.9.png b/core/res/res/drawable/textfield_pressed.9.png
index 7b1350f..c909ad2 100644
--- a/core/res/res/drawable/textfield_pressed.9.png
+++ b/core/res/res/drawable/textfield_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/textfield_selected.9.png b/core/res/res/drawable/textfield_selected.9.png
index 7286ba5..0c1b446 100644
--- a/core/res/res/drawable/textfield_selected.9.png
+++ b/core/res/res/drawable/textfield_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_down_disabled.9.png b/core/res/res/drawable/timepicker_down_disabled.9.png
index af72d22..7d8e0b9 100755
--- a/core/res/res/drawable/timepicker_down_disabled.9.png
+++ b/core/res/res/drawable/timepicker_down_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_down_disabled_focused.9.png b/core/res/res/drawable/timepicker_down_disabled_focused.9.png
index 2d80424..6f2373e 100755
--- a/core/res/res/drawable/timepicker_down_disabled_focused.9.png
+++ b/core/res/res/drawable/timepicker_down_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_down_normal.9.png b/core/res/res/drawable/timepicker_down_normal.9.png
index c427fc3..a946355 100755
--- a/core/res/res/drawable/timepicker_down_normal.9.png
+++ b/core/res/res/drawable/timepicker_down_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_down_pressed.9.png b/core/res/res/drawable/timepicker_down_pressed.9.png
index ac6ac53..fb4d817 100755
--- a/core/res/res/drawable/timepicker_down_pressed.9.png
+++ b/core/res/res/drawable/timepicker_down_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_down_selected.9.png b/core/res/res/drawable/timepicker_down_selected.9.png
index f710b57..1db8bc1 100755
--- a/core/res/res/drawable/timepicker_down_selected.9.png
+++ b/core/res/res/drawable/timepicker_down_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_input_disabled.9.png b/core/res/res/drawable/timepicker_input_disabled.9.png
index 97da87a..f73658e 100755
--- a/core/res/res/drawable/timepicker_input_disabled.9.png
+++ b/core/res/res/drawable/timepicker_input_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_input_normal.9.png b/core/res/res/drawable/timepicker_input_normal.9.png
index eb101c5..8032ada 100755
--- a/core/res/res/drawable/timepicker_input_normal.9.png
+++ b/core/res/res/drawable/timepicker_input_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_input_pressed.9.png b/core/res/res/drawable/timepicker_input_pressed.9.png
index c83b1eb..30d8d5f 100755
--- a/core/res/res/drawable/timepicker_input_pressed.9.png
+++ b/core/res/res/drawable/timepicker_input_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_input_selected.9.png b/core/res/res/drawable/timepicker_input_selected.9.png
index e152848..874f18f 100755
--- a/core/res/res/drawable/timepicker_input_selected.9.png
+++ b/core/res/res/drawable/timepicker_input_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_up_disabled.9.png b/core/res/res/drawable/timepicker_up_disabled.9.png
index 1814bb4..93d0db4 100755
--- a/core/res/res/drawable/timepicker_up_disabled.9.png
+++ b/core/res/res/drawable/timepicker_up_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_up_disabled_focused.9.png b/core/res/res/drawable/timepicker_up_disabled_focused.9.png
index 9ad5b85..b5bf68d 100755
--- a/core/res/res/drawable/timepicker_up_disabled_focused.9.png
+++ b/core/res/res/drawable/timepicker_up_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_up_normal.9.png b/core/res/res/drawable/timepicker_up_normal.9.png
index 35fc221..978251d 100755
--- a/core/res/res/drawable/timepicker_up_normal.9.png
+++ b/core/res/res/drawable/timepicker_up_normal.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_up_pressed.9.png b/core/res/res/drawable/timepicker_up_pressed.9.png
index c910777..924b03c 100755
--- a/core/res/res/drawable/timepicker_up_pressed.9.png
+++ b/core/res/res/drawable/timepicker_up_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable/timepicker_up_selected.9.png b/core/res/res/drawable/timepicker_up_selected.9.png
index 549a7e5..5c94d0d 100755
--- a/core/res/res/drawable/timepicker_up_selected.9.png
+++ b/core/res/res/drawable/timepicker_up_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable/title_bar.9.png b/core/res/res/drawable/title_bar.9.png
deleted file mode 100644
index 8d18339..0000000
--- a/core/res/res/drawable/title_bar.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/title_bar.xml b/core/res/res/drawable/title_bar.xml
new file mode 100644
index 0000000..24402dc
--- /dev/null
+++ b/core/res/res/drawable/title_bar.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/activity_title_bar"
+ android:dither="true"
+/>
diff --git a/core/res/res/drawable/title_bar_shadow.9.png b/core/res/res/drawable/title_bar_shadow.9.png
new file mode 100644
index 0000000..0872366
--- /dev/null
+++ b/core/res/res/drawable/title_bar_shadow.9.png
Binary files differ
diff --git a/core/res/res/drawable/title_bar_shadow.png b/core/res/res/drawable/title_bar_shadow.png
deleted file mode 100644
index a717814..0000000
--- a/core/res/res/drawable/title_bar_shadow.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/title_bar_tall.png b/core/res/res/drawable/title_bar_tall.png
new file mode 100644
index 0000000..cd565dc
--- /dev/null
+++ b/core/res/res/drawable/title_bar_tall.png
Binary files differ
diff --git a/core/res/res/layout/activity_list.xml b/core/res/res/layout/activity_list.xml
new file mode 100644
index 0000000..2967f0f
--- /dev/null
+++ b/core/res/res/layout/activity_list.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ />
+
+ <TextView
+ android:id="@android:id/empty"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center"
+ android:text="@string/activity_list_empty"
+ android:visibility="gone"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ />
+
+</FrameLayout>
diff --git a/core/res/res/layout/activity_list_item_2.xml b/core/res/res/layout/activity_list_item_2.xml
new file mode 100644
index 0000000..78eca02
--- /dev/null
+++ b/core/res/res/layout/activity_list_item_2.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:gravity="center_vertical"
+ android:drawablePadding="14dip"
+ android:paddingLeft="15dip"
+ android:paddingRight="15dip" />
diff --git a/core/res/res/layout/alert_dialog_simple_text.xml b/core/res/res/layout/alert_dialog_simple_text.xml
new file mode 100644
index 0000000..ab82be7
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_simple_text.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This layout can be set as the AlertDialog's view to display vertically centered text. -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:padding="10dip"
+ />
+
+
diff --git a/core/res/res/layout/date_picker.xml b/core/res/res/layout/date_picker.xml
index a398bd0..0760cc0 100644
--- a/core/res/res/layout/date_picker.xml
+++ b/core/res/res/layout/date_picker.xml
@@ -24,6 +24,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/parent"
android:orientation="horizontal"
+ android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
diff --git a/core/res/res/layout/date_picker_dialog.xml b/core/res/res/layout/date_picker_dialog.xml
index 879f339..949c8a3 100644
--- a/core/res/res/layout/date_picker_dialog.xml
+++ b/core/res/res/layout/date_picker_dialog.xml
@@ -17,11 +17,9 @@
*/
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="5dip">
- <DatePicker android:id="@+id/datePicker"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"/>
-</FrameLayout>
+<DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/datePicker"
+ android:padding="5dip"
+ android:layout_gravity="center_horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
diff --git a/core/res/res/layout/expanded_menu_layout.xml b/core/res/res/layout/expanded_menu_layout.xml
index cd4ea12..5d98773 100644
--- a/core/res/res/layout/expanded_menu_layout.xml
+++ b/core/res/res/layout/expanded_menu_layout.xml
@@ -16,5 +16,5 @@
<com.android.internal.view.menu.ExpandedMenuView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+android:id/expanded_menu"
- android:layout_width="320dip"
+ android:layout_width="296dip"
android:layout_height="wrap_content" />
diff --git a/core/res/res/layout/global_actions_item.xml b/core/res/res/layout/global_actions_item.xml
index 4383127..63bb0f4 100644
--- a/core/res/res/layout/global_actions_item.xml
+++ b/core/res/res/layout/global_actions_item.xml
@@ -14,38 +14,48 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:paddingTop="10dip"
- android:paddingBottom="10dip"
- android:minHeight="?android:attr/listPreferredItemHeight"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+
+ android:paddingLeft="11dip"
+ android:paddingTop="6dip"
+ android:paddingBottom="6dip"
>
<ImageView android:id="@+id/icon"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="6dip"
- android:layout_gravity="center_vertical"
+ android:layout_height="fill_parent"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:layout_marginRight="9dip"
/>
- <LinearLayout android:orientation="vertical"
- android:layout_width="wrap_content"
+
+ <TextView android:id="@+id/status"
+ android:layout_width="fill_parent"
+ android:layout_height="26dip"
+
+ android:layout_toRightOf="@id/icon"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+
+ android:textAppearance="?android:attr/textAppearanceSmallInverse"
+ />
+
+
+ <TextView android:id="@+id/message"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical">
- <TextView android:id="@+id/message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
- />
+ android:layout_toRightOf="@id/icon"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_above="@id/status"
+ android:layout_alignWithParentIfMissing="true"
+ android:gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ />
- <TextView android:id="@+id/status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmallInverse"
- />
- </LinearLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/layout/google_web_content_helper_layout.xml b/core/res/res/layout/google_web_content_helper_layout.xml
index 7409621..40f84bf 100644
--- a/core/res/res/layout/google_web_content_helper_layout.xml
+++ b/core/res/res/layout/google_web_content_helper_layout.xml
@@ -20,7 +20,7 @@
<!-- Include the indeterminate progress dialog's layout. -->
<include
- android:id="@+id/progress"
+ android:id="@+id/progressContainer"
layout="@android:layout/progress_dialog" />
<WebView
diff --git a/core/res/res/layout/input_method.xml b/core/res/res/layout/input_method.xml
index ec75cf1..a21bbe8 100644
--- a/core/res/res/layout/input_method.xml
+++ b/core/res/res/layout/input_method.xml
@@ -27,7 +27,7 @@
<FrameLayout android:id="@android:id/extractArea"
android:layout_width="fill_parent"
- android:layout_height="wrap_content"
+ android:layout_height="0px"
android:layout_weight="1"
android:visibility="gone">
</FrameLayout>
diff --git a/core/res/res/layout/input_method_extract_view.xml b/core/res/res/layout/input_method_extract_view.xml
index f8a4bde..1244c1d 100644
--- a/core/res/res/layout/input_method_extract_view.xml
+++ b/core/res/res/layout/input_method_extract_view.xml
@@ -18,11 +18,38 @@
*/
-->
-<android.inputmethodservice.ExtractEditText
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/inputExtractEditText"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:inputType="text"
- >
-</android.inputmethodservice.ExtractEditText>
+ android:orientation="horizontal">
+
+ <android.inputmethodservice.ExtractEditText
+ android:id="@+id/inputExtractEditText"
+ android:layout_width="0px"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:scrollbars="vertical"
+ android:gravity="top"
+ android:minLines="1"
+ android:inputType="text"
+ android:background="@android:drawable/extract_edit_text"
+ >
+ </android.inputmethodservice.ExtractEditText>
+
+ <FrameLayout
+ android:id="@+id/inputExtractAccessories"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:paddingLeft="10dip"
+ android:paddingRight="10dip"
+ android:background="@android:drawable/keyboard_accessory_bg_landscape"
+ >
+
+ <android.inputmethodservice.ExtractButton android:id="@+id/inputExtractAction"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ />
+
+ </FrameLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout/js_prompt.xml b/core/res/res/layout/js_prompt.xml
index 9ab9d09..86974ba 100644
--- a/core/res/res/layout/js_prompt.xml
+++ b/core/res/res/layout/js_prompt.xml
@@ -20,16 +20,17 @@
android:layout_height="wrap_content"
android:gravity="center_horizontal"
>
-
+
<TextView android:id="@+id/message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
-
+
<EditText android:id="@+id/value"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
+ android:inputType="text"
android:selectAllOnFocus="true"
android:scrollHorizontally="true"
android:layout_marginTop="6dip"
diff --git a/core/res/res/layout/keyguard_screen_glogin_unlock.xml b/core/res/res/layout/keyguard_screen_glogin_unlock.xml
index 9f306cc..4834b28 100644
--- a/core/res/res/layout/keyguard_screen_glogin_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_glogin_unlock.xml
@@ -16,100 +16,112 @@
** limitations under the License.
*/
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:background="#FF000000"
+ android:orientation="vertical"
+ android:background="@android:color/background_dark"
>
-
- <TextView
- android:id="@+id/topHeader"
+ <ScrollView
android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:textSize="24sp"
- android:layout_marginTop="8dip"
- android:drawableLeft="@drawable/ic_lock_idle_lock"
- android:drawablePadding="5dip"
- android:text="@android:string/lockscreen_glogin_too_many_attempts"
- />
-
- <!-- spacer below header -->
+ android:layout_height="0px"
+ android:layout_weight="1"
+ android:layout_above="@+id/emergencyCall">
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+
+ <TextView
+ android:id="@+id/topHeader"
+ android:layout_width="fill_parent"
+ android:layout_height="64dip"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="4dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:gravity="center_vertical"
+ android:drawableLeft="@drawable/ic_lock_idle_lock"
+ android:drawablePadding="5dip"
+ android:text="@android:string/lockscreen_glogin_too_many_attempts"
+ />
+
+ <!-- spacer below header -->
+ <View
+ android:id="@+id/spacerTop"
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:layout_below="@id/topHeader"
+ android:background="@drawable/divider_horizontal_dark"/>
+
+ <TextView
+ android:id="@+id/instructions"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/spacerTop"
+ android:layout_marginTop="8dip"
+ android:layout_marginLeft="9dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@android:string/lockscreen_glogin_instructions"
+ />
+
+ <EditText
+ android:id="@+id/login"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/instructions"
+ android:layout_marginTop="8dip"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:hint="@android:string/lockscreen_glogin_username_hint"
+ android:inputType="textEmailAddress"
+ />
+
+ <EditText
+ android:id="@+id/password"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/login"
+ android:layout_marginTop="15dip"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:inputType="textPassword"
+ android:hint="@android:string/lockscreen_glogin_password_hint"
+ android:nextFocusRight="@+id/ok"
+ android:nextFocusDown="@+id/ok"
+ />
+
+ <!-- ok below password, aligned to right of screen -->
+ <Button
+ android:id="@+id/ok"
+ android:layout_width="85dip"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/password"
+ android:layout_marginTop="7dip"
+ android:layout_marginRight="7dip"
+ android:layout_alignParentRight="true"
+ android:text="@android:string/lockscreen_glogin_submit_button"
+ />
+
+ </RelativeLayout>
+ </ScrollView>
+
+ <!-- spacer above emergency call -->
<View
- android:id="@+id/spacerTop"
android:layout_width="fill_parent"
android:layout_height="1dip"
- android:layout_below="@id/topHeader"
- android:layout_marginTop="8dip"
- android:background="@android:drawable/divider_horizontal_bright"/>
-
- <TextView
- android:id="@+id/instructions"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@+id/spacerTop"
- android:layout_marginTop="8dip"
- android:gravity="center"
- android:textSize="18sp"
- android:text="@android:string/lockscreen_glogin_instructions"
- />
-
- <EditText
- android:id="@+id/login"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/instructions"
- android:layout_marginTop="8dip"
- android:hint="@android:string/lockscreen_glogin_username_hint"
- android:singleLine="true"
- />
+ android:layout_marginBottom="4dip"
- <EditText
- android:id="@+id/password"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/login"
- android:layout_marginTop="8dip"
- android:password="true"
- android:hint="@android:string/lockscreen_glogin_password_hint"
- android:singleLine="true"
- android:nextFocusRight="@+id/ok"
- android:nextFocusDown="@+id/ok"
- />
-
- <!-- ok below password, aligned to right of screen -->
- <Button
- android:id="@+id/ok"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/password"
- android:layout_marginTop="8dip"
- android:layout_alignParentRight="true"
- android:textSize="18sp"
- android:text="@android:string/lockscreen_glogin_submit_button"
- />
+ android:background="@drawable/divider_horizontal_dark"/>
<!-- emergency call button at bottom center -->
<Button
android:id="@+id/emergencyCall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_marginBottom="8dip"
- android:layout_centerHorizontal="true"
- android:textSize="18sp"
+ android:layout_gravity="center"
android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="3dip"
android:text="@android:string/lockscreen_emergency_call"
/>
- <!-- spacer above emergency call (doesn't fit in landscape...)-->
- <!--View
- android:layout_width="fill_parent"
- android:layout_height="1dip"
- android:layout_above="@id/emergencyCall"
- android:layout_marginBottom="8dip"
- android:background="@android:drawable/divider_horizontal_bright"/-->
-
-
-</RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/keyguard_screen_lock.xml b/core/res/res/layout/keyguard_screen_lock.xml
index f5c850a..952fc5d 100644
--- a/core/res/res/layout/keyguard_screen_lock.xml
+++ b/core/res/res/layout/keyguard_screen_lock.xml
@@ -24,7 +24,6 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="bottom"
- android:background="#FF000000"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
@@ -37,6 +36,8 @@
android:layout_marginBottom="15dip"
android:layout_marginLeft="15dip"
android:layout_marginRight="15dip"
+ android:paddingTop="20dip"
+ android:paddingBottom="20dip"
android:background="@android:drawable/popup_full_dark"
>
@@ -58,20 +59,22 @@
android:layout_height="wrap_content"
android:gravity="center"
android:text="@android:string/lockscreen_missing_sim_message"
- android:textSize="22sp"/>
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView android:id="@+id/headerSimBad2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="7dip"
+ android:layout_marginBottom="7dip"
android:gravity="center"
android:text="@android:string/lockscreen_missing_sim_instructions"
- android:textSize="20sp"/>
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
<!-- spacer after carrier info / sim messages -->
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:layout_marginTop="8dip"
- android:background="@android:drawable/divider_horizontal_bright"/>
+ android:background="@android:drawable/divider_horizontal_dark"/>
<!-- time and date -->
<TextView android:id="@+id/time"
@@ -91,7 +94,7 @@
android:layout_width="fill_parent"
android:layout_height="1dip"
android:layout_marginBottom="8dip"
- android:background="@android:drawable/divider_horizontal_bright"
+ android:background="@android:drawable/divider_horizontal_dark"
/>
<!-- battery info -->
@@ -125,7 +128,7 @@
android:layout_height="1dip"
android:layout_marginTop="8dip"
android:layout_marginBottom="8dip"
- android:background="@android:drawable/divider_horizontal_bright"
+ android:background="@android:drawable/divider_horizontal_dark"
/>
<!-- next alarm info -->
@@ -160,7 +163,7 @@
android:layout_height="1dip"
android:layout_marginTop="8dip"
android:layout_marginBottom="8dip"
- android:background="@android:drawable/divider_horizontal_bright"/>
+ android:background="@android:drawable/divider_horizontal_dark"/>
<!-- lock icon with 'screen locked' message
(shown when SIM card is present) -->
@@ -194,6 +197,7 @@
<TextView android:id="@+id/lockInstructions"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
+ android:layout_marginBottom="5dip"
android:gravity="center"
android:textSize="14sp"/>
@@ -201,18 +205,15 @@
<!-- emergency call button shown when sim is missing or PUKd -->
<Button
android:id="@+id/emergencyCallButton"
- android:layout_width="fill_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="5dip"
android:layout_marginBottom="5dip"
android:layout_marginTop="5dip"
- android:drawableTop="@drawable/ic_emergency"
+ android:layout_gravity="center_horizontal"
+ android:drawableLeft="@drawable/ic_emergency"
android:drawablePadding="3dip"
android:text="@android:string/lockscreen_emergency_call"
- android:textSize="14sp"
/>
-
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml b/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
index fd70f50..881652b 100644
--- a/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
@@ -20,7 +20,7 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:background="#FF000000"
+ android:background="@android:color/background_dark"
>
<!-- displays dots as user enters pin -->
@@ -45,11 +45,10 @@
android:maxLines="1"
android:background="@null"
android:textSize="32sp"
- android:password="true"
+ android:inputType="textPassword"
/>
<ImageButton android:id="@+id/backspace"
- style="@android:style/Widget.Button.Inset"
android:src="@android:drawable/ic_input_delete"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
diff --git a/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml b/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml
index 566da21..fc82e3f 100644
--- a/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml
@@ -16,231 +16,251 @@
** limitations under the License.
*/
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:background="#FF000000"
+ android:background="@android:color/background_dark"
>
- <!-- header text ('Enter Pin Code') -->
- <TextView android:id="@+id/headerText"
+ <LinearLayout android:id="@+id/topDisplayGroup"
android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textSize="26sp"
- />
+ android:layout_height="115dip"
+ android:layout_alignParentTop="true"
+ android:orientation="vertical"
+ >
+
+ <!-- header text ('Enter Pin Code') -->
+ <TextView android:id="@+id/headerText"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="9dip"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ />
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="18dip"
+ android:layout_marginRight="6dip"
+ android:layout_marginLeft="6dip"
+ android:background="@android:drawable/edit_text"
+ >
+
+ <!-- displays dots as user enters pin -->
+ <TextView android:id="@+id/pinDisplay"
+ android:layout_width="wrap_content"
+ android:layout_height="64dip"
+ android:layout_centerInParent="true"
+ android:maxLines="1"
+ android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:textStyle="bold"
+ android:inputType="textPassword"
+ />
+
+ <ImageButton android:id="@+id/backspace"
+ android:src="@android:drawable/ic_input_delete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="1dip"
+ />
+ </RelativeLayout>
+
- <!-- displays dots as user enters pin -->
- <LinearLayout
- android:orientation="horizontal"
+ </LinearLayout>
+
+ <!-- Keypad section -->
+ <LinearLayout android:id="@+id/keyPad"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:addStatesFromChildren="true"
- android:gravity="center_vertical"
- android:baselineAligned="false"
- android:paddingRight="0dip"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="5dip"
- android:layout_marginLeft="5dip"
- android:background="@android:drawable/edit_text"
- >
-
- <EditText android:id="@+id/pinDisplay"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="fill_parent"
- android:maxLines="1"
- android:background="@null"
- android:password="true"
+ android:layout_below="@id/topDisplayGroup"
+ android:orientation="vertical"
+ >
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="64dip"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:orientation="horizontal"
+ >
+
+ <Button android:id="@+id/one"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
/>
- <ImageButton android:id="@+id/backspace"
- style="@android:style/Widget.Button.Inset"
- android:src="@android:drawable/ic_input_delete"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:layout_marginTop="2dip"
- android:layout_marginRight="2dip"
- android:layout_marginBottom="2dip"
- android:gravity="center"
+ <Button android:id="@+id/two"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
/>
- </LinearLayout>
+ <Button android:id="@+id/three"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
+ </LinearLayout>
- <!-- Keypad section -->
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="0sp"
- android:layout_weight="1"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="4dip"
- android:orientation="horizontal"
- >
-
- <Button android:id="@+id/one"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="64dip"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:orientation="horizontal"
+ >
- <Button android:id="@+id/two"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <Button android:id="@+id/four"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
- <Button android:id="@+id/three"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
- </LinearLayout>
+ <Button android:id="@+id/five"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="0sp"
- android:layout_weight="1"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="4dip"
- android:orientation="horizontal"
- >
-
- <Button android:id="@+id/four"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <Button android:id="@+id/six"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
+ </LinearLayout>
- <Button android:id="@+id/five"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="64dip"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:orientation="horizontal"
+ >
- <Button android:id="@+id/six"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
- </LinearLayout>
+ <Button android:id="@+id/seven"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="0sp"
- android:layout_weight="1"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="4dip"
- android:orientation="horizontal"
- >
-
- <Button android:id="@+id/seven"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <Button android:id="@+id/eight"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
- <Button android:id="@+id/eight"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <Button android:id="@+id/nine"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
+ </LinearLayout>
- <Button android:id="@+id/nine"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
- </LinearLayout>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="64dip"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:orientation="horizontal"
+ >
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="0sp"
- android:layout_weight="1"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="4dip"
- android:orientation="horizontal"
- >
-
- <Button android:id="@+id/ok"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="18sp"
- android:text="@android:string/ok"
- />
+ <Button android:id="@+id/ok"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
+ android:text="@android:string/ok"
+ />
- <Button android:id="@+id/zero"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <Button android:id="@+id/zero"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
- <Button android:id="@+id/cancel"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="18sp"
- android:text="@android:string/cancel"
- />
+ <Button android:id="@+id/cancel"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
+ android:text="@android:string/cancel"
+ />
+ </LinearLayout>
+
+ <!-- end keypad -->
</LinearLayout>
<!-- emergency call button -->
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- >
+ <Button
+ android:id="@+id/emergencyCall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentBottom="true"
+ android:drawableLeft="@android:drawable/ic_emergency"
+ android:drawablePadding="3dip"
+ android:text="@android:string/lockscreen_emergency_call"
+ />
- <Button
- android:id="@+id/emergencyCall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:drawableLeft="@drawable/ic_emergency"
- android:drawablePadding="3dip"
- android:paddingTop="4dip"
- android:paddingBottom="4dip"
- android:text="@android:string/lockscreen_emergency_call"
- />
+ <!-- spacer below keypad -->
+ <View
+ android:id="@+id/spacerBottom"
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:layout_marginBottom="6dip"
+ android:layout_above="@id/emergencyCall"
+ android:background="@android:drawable/divider_horizontal_dark"/>
- </RelativeLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index 175a3a5..ba1640a 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -23,9 +23,9 @@
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
- android:background="#FF000000"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
+ android:background="#A0000000"
>
<!-- left side: instructions and emergency call button -->
@@ -114,11 +114,11 @@
</FrameLayout>
</LinearLayout>
- <View
+ <!--View
android:background="@android:drawable/code_lock_left"
android:layout_width="2dip"
- android:layout_height="fill_parent" />
-
+ android:layout_height="fill_parent" /-->
+
<!-- right side: lock pattern -->
<com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
android:layout_width="wrap_content"
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index b591b10..f09c422 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -23,9 +23,9 @@
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
- android:background="#FF000000"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
+ android:background="#A0000000"
>
<!-- lock icon and header message -->
@@ -53,17 +53,18 @@
android:textSize="18sp"/>
</LinearLayout>
- <View
+ <!--View
android:background="@android:drawable/code_lock_top"
android:layout_width="fill_parent"
- android:layout_height="2dip" />
+ android:layout_height="2dip" /-->
<com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <View
+ android:layout_height="wrap_content"
+ />
+ <!--View
android:background="@android:drawable/code_lock_bottom"
android:layout_width="fill_parent"
- android:layout_height="8dip" />
+ android:layout_height="8dip" /-->
<!-- footer -->
<FrameLayout
@@ -100,6 +101,10 @@
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="1.0"
+ android:layout_marginTop="4dip"
+ android:layout_marginBottom="4dip"
+ android:layout_marginLeft="4dip"
+ android:layout_marginRight="2dip"
android:text="@android:string/lockscreen_emergency_call"
android:textSize="14sp"
android:drawableLeft="@drawable/ic_emergency"
@@ -109,6 +114,10 @@
android:layout_width="0dip"
android:layout_height="fill_parent"
android:layout_weight="1.0"
+ android:layout_marginTop="4dip"
+ android:layout_marginBottom="4dip"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="4dip"
android:textSize="14sp"
android:visibility="invisible"
/>
diff --git a/core/res/res/layout/list_menu_item_layout.xml b/core/res/res/layout/list_menu_item_layout.xml
index 20c46a7..df4958f 100644
--- a/core/res/res/layout/list_menu_item_layout.xml
+++ b/core/res/res/layout/list_menu_item_layout.xml
@@ -18,7 +18,7 @@
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight">
- <!-- Icon, checkbox, and/or radio button will be inserted here. -->
+ <!-- Icon will be inserted here. -->
<!-- The title and summary have some gap between them, and this 'group' should be centered vertically. -->
<RelativeLayout
@@ -54,4 +54,6 @@
</RelativeLayout>
+ <!-- Checkbox, and/or radio button will be inserted here. -->
+
</com.android.internal.view.menu.ListMenuItemView>
diff --git a/core/res/res/layout/number_picker.xml b/core/res/res/layout/number_picker.xml
index 422733a..bbdb31c 100644
--- a/core/res/res/layout/number_picker.xml
+++ b/core/res/res/layout/number_picker.xml
@@ -22,23 +22,21 @@
<com.android.internal.widget.NumberPickerButton android:id="@+id/increment"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:background="@drawable/timepicker_up_btn"
- />
-
- <EditText android:id="@+id/timepicker_input"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:singleLine="true"
- style="?android:attr/textAppearanceLargeInverse"
- android:textSize="30sp"
- android:background="@drawable/timepicker_input"
- />
-
+ android:background="@drawable/timepicker_up_btn" />
+
+ <EditText android:id="@+id/timepicker_input"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:singleLine="true"
+ style="?android:attr/textAppearanceLargeInverse"
+ android:textColor="@android:color/primary_text_light"
+ android:textSize="30sp"
+ android:background="@drawable/timepicker_input" />
+
<com.android.internal.widget.NumberPickerButton android:id="@+id/decrement"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:background="@drawable/timepicker_down_btn"
- />
-
+ android:background="@drawable/timepicker_down_btn" />
+
</merge>
diff --git a/core/res/res/layout/number_picker_edit.xml b/core/res/res/layout/number_picker_edit.xml
index 46f4845..f3af6e9 100644
--- a/core/res/res/layout/number_picker_edit.xml
+++ b/core/res/res/layout/number_picker_edit.xml
@@ -23,6 +23,7 @@
android:gravity="center_horizontal"
android:singleLine="true"
style="?android:attr/textAppearanceLargeInverse"
+ android:textColor="@android:color/primary_text_light"
android:textSize="30sp"
android:background="@drawable/timepicker_input"
/>
diff --git a/core/res/res/layout/preference.xml b/core/res/res/layout/preference.xml
index ac6dd76..00745b4 100644
--- a/core/res/res/layout/preference.xml
+++ b/core/res/res/layout/preference.xml
@@ -27,10 +27,10 @@
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="16sp"
- android:layout_marginRight="6sp"
- android:layout_marginTop="6sp"
- android:layout_marginBottom="6sp"
+ android:layout_marginLeft="15dip"
+ android:layout_marginRight="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView android:id="@+android:id/title"
diff --git a/core/res/res/layout/preference_child.xml b/core/res/res/layout/preference_child.xml
index 1d626b9..5f8ddd4 100644
--- a/core/res/res/layout/preference_child.xml
+++ b/core/res/res/layout/preference_child.xml
@@ -17,29 +17,35 @@
<!-- Layout for a visually child-like Preference in a PreferenceActivity. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingRight="?android:attr/scrollbarSize">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="20sp"
+ android:layout_marginLeft="20dip"
+ android:layout_marginRight="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView android:id="@+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceLarge" />
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
<TextView android:id="@+android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignLeft="@android:id/title"
- android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceSmall"
+ android:maxLines="2"
android:textColor="?android:attr/textColorSecondary" />
</RelativeLayout>
@@ -48,6 +54,7 @@
<LinearLayout android:id="@+android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
- />
+ android:gravity="center_vertical"
+ android:orientation="vertical" />
</LinearLayout>
diff --git a/core/res/res/layout/preferences.xml b/core/res/res/layout/preferences.xml
index e6876ff..f0c2535 100644
--- a/core/res/res/layout/preferences.xml
+++ b/core/res/res/layout/preferences.xml
@@ -19,7 +19,8 @@
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginRight="7dip"
+ android:layout_marginRight="4dip"
android:layout_gravity="center_vertical"
- android:src="@drawable/ic_settings_indicator_next_page" />
+ android:background="@drawable/btn_circle"
+ android:src="@drawable/ic_btn_round_more" />
diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml
index da35e97..5e296c5 100644
--- a/core/res/res/layout/resolve_list_item.xml
+++ b/core/res/res/layout/resolve_list_item.xml
@@ -17,37 +17,38 @@
** limitations under the License.
*/
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
android:minHeight="?android:attr/listPreferredItemHeight"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
android:paddingLeft="14dip"
android:paddingRight="15dip">
-
<!-- Activity icon when presenting dialog -->
<ImageView android:id="@+id/icon"
android:layout_width="@android:dimen/app_icon_size"
android:layout_height="@android:dimen/app_icon_size"
- android:layout_alignParentLeft="true"
android:scaleType="fitCenter" />
- <!-- Activity name -->
- <TextView android:id="@android:id/text1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
- android:layout_toRightOf="@id/icon"
- android:paddingLeft="6dip" />
-
- <!-- Extended activity info to distinguish between duplicate activity names -->
- <TextView android:id="@android:id/text2"
+ <LinearLayout
+ android:orientation="vertical"
+ android:gravity="center_vertical"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMediumInverse"
- android:layout_toRightOf="@id/icon"
- android:layout_below="@id/text1"
- android:paddingLeft="6dip" />
-</RelativeLayout>
+ android:layout_height="wrap_content" >
+ <!-- Activity name -->
+ <TextView android:id="@android:id/text1"
+ android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="6dip" />
+ <!-- Extended activity info to distinguish between duplicate activity names -->
+ <TextView android:id="@android:id/text2"
+ android:textAppearance="?android:attr/textAppearanceMediumInverse"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="6dip" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/search_bar.xml b/core/res/res/layout/search_bar.xml
index 6678bc2..ef347da 100644
--- a/core/res/res/layout/search_bar.xml
+++ b/core/res/res/layout/search_bar.xml
@@ -33,6 +33,7 @@
shadow, plus the desired padding of "8" against the user-visible (grey)
pixels, minus "1" to correct for positioning of the edittext & button. -->
<LinearLayout
+ android:id="@+id/search_plate"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@@ -77,7 +78,11 @@
android:layout_weight="1.0"
android:paddingLeft="8dip"
android:paddingRight="6dip"
- android:inputType="text|textAutoComplete" />
+ android:inputType="text|textAutoComplete"
+ android:dropDownWidth="fill_parent"
+ android:dropDownAnchor="@id/search_plate"
+ android:dropDownVerticalOffset="-15dip"
+ />
<!-- android:focusableInTouchMode="false" -->
<!-- android:singleLine="true" -->
<!-- android:selectAllOnFocus="true" -->
@@ -91,6 +96,11 @@
android:drawableLeft="@android:drawable/ic_btn_search"
/>
+ <ImageButton android:id="@+id/search_voice_btn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@android:drawable/ic_btn_speak_now"
+ />
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/select_dialog_item.xml b/core/res/res/layout/select_dialog_item.xml
index 0983b66..f1840ba 100644
--- a/core/res/res/layout/select_dialog_item.xml
+++ b/core/res/res/layout/select_dialog_item.xml
@@ -28,7 +28,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="@android:color/bright_foreground_light"
android:gravity="center_vertical"
android:paddingLeft="14dip"
android:paddingRight="15dip"
diff --git a/core/res/res/layout/select_dialog_singlechoice.xml b/core/res/res/layout/select_dialog_singlechoice.xml
index ec97d7b..3e07f23 100644
--- a/core/res/res/layout/select_dialog_singlechoice.xml
+++ b/core/res/res/layout/select_dialog_singlechoice.xml
@@ -19,7 +19,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="@android:color/bright_foreground_light"
android:gravity="center_vertical"
android:paddingLeft="12dip"
android:paddingRight="7dip"
diff --git a/core/res/res/layout/status_bar.xml b/core/res/res/layout/status_bar.xml
index dfdaf66..9a6b7e8 100644
--- a/core/res/res/layout/status_bar.xml
+++ b/core/res/res/layout/status_bar.xml
@@ -90,7 +90,7 @@
<com.android.server.status.DateView android:id="@+id/date"
android:layout_width="wrap_content"
- android:layout_height="25dp"
+ android:layout_height="fill_parent"
android:singleLine="true"
android:textSize="16sp"
android:textStyle="bold"
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index fbe4c32..eeb9d9d 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -22,6 +22,8 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
android:textStyle="bold"
android:textSize="18sp"
android:paddingLeft="4dp"
@@ -38,6 +40,8 @@
android:layout_weight="1"
android:textColor="#ff000000"
android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
android:textSize="14sp"
android:paddingLeft="4dp"
/>
diff --git a/core/res/res/layout/time_picker.xml b/core/res/res/layout/time_picker.xml
index bdfe490..c601e0e 100644
--- a/core/res/res/layout/time_picker.xml
+++ b/core/res/res/layout/time_picker.xml
@@ -21,6 +21,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
+ android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
@@ -55,5 +56,6 @@
android:paddingLeft="20dip"
android:paddingRight="20dip"
style="?android:attr/textAppearanceLargeInverse"
+ android:textColor="@android:color/primary_text_light_nodisable"
/>
</LinearLayout>
diff --git a/core/res/res/layout/time_picker_dialog.xml b/core/res/res/layout/time_picker_dialog.xml
index 6dc1bf6..d5a6b5e 100644
--- a/core/res/res/layout/time_picker_dialog.xml
+++ b/core/res/res/layout/time_picker_dialog.xml
@@ -17,11 +17,9 @@
*/
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="5dip">
- <TimePicker android:id="@+id/timePicker"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"/>
-</FrameLayout>
+<TimePicker xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/timePicker"
+ android:layout_gravity="center_horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="5dip" />
diff --git a/core/res/res/layout/zoom_browser_accessory_buttons.xml b/core/res/res/layout/zoom_browser_accessory_buttons.xml
new file mode 100644
index 0000000..4bf2bdf
--- /dev/null
+++ b/core/res/res/layout/zoom_browser_accessory_buttons.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <ImageView android:id="@+id/zoom_fit_page"
+ android:background="@android:drawable/btn_browser_zoom_fit_page"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|left"
+ android:layout_marginLeft="7dip"
+ />
+ <ImageView android:id="@+id/zoom_page_overview"
+ android:background="@android:drawable/btn_browser_zoom_page_overview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|right"
+ android:layout_marginRight="7dip"
+ />
+</merge>
diff --git a/core/res/res/layout/zoom_container.xml b/core/res/res/layout/zoom_container.xml
new file mode 100644
index 0000000..52bc635
--- /dev/null
+++ b/core/res/res/layout/zoom_container.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <ZoomControls android:id="@+id/zoomControls"
+ android:layout_gravity="center_horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@style/ZoomControls"
+ android:gravity="center_horizontal"
+ android:background="@null"
+ />
+</merge>
diff --git a/core/res/res/layout/zoom_controls.xml b/core/res/res/layout/zoom_controls.xml
index 729af1b..95cf1d5 100644
--- a/core/res/res/layout/zoom_controls.xml
+++ b/core/res/res/layout/zoom_controls.xml
@@ -18,13 +18,13 @@
*/
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <ZoomButton android:id="@+id/zoomIn"
- android:background="@android:drawable/btn_plus"
+ <ZoomButton android:id="@+id/zoomOut"
+ android:background="@android:drawable/btn_zoom_down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
- <ZoomButton android:id="@+id/zoomOut"
- android:background="@android:drawable/btn_minus"
+ <ZoomButton android:id="@+id/zoomIn"
+ android:background="@android:drawable/btn_zoom_up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
diff --git a/core/res/res/layout/zoom_magnify.xml b/core/res/res/layout/zoom_magnify.xml
index 08a5f7b..374819e 100644
--- a/core/res/res/layout/zoom_magnify.xml
+++ b/core/res/res/layout/zoom_magnify.xml
@@ -19,16 +19,14 @@
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ZoomControls android:id="@+id/zoomControls"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
+ android:layout_gravity="bottom|center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/ZoomControls"
/>
<ImageView android:id="@+id/zoomMagnify"
android:focusable="true"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
+ android:layout_gravity="bottom|right"
android:paddingRight="2dip"
android:src="@drawable/btn_zoom_page"
android:layout_width="wrap_content"
diff --git a/core/res/res/values-cs-rCZ/strings.xml b/core/res/res/values-cs-rCZ/strings.xml
deleted file mode 100644
index e1eb3f4..0000000
--- a/core/res/res/values-cs-rCZ/strings.xml
+++ /dev/null
@@ -1,1112 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for byteShort (2850097084724465606) -->
- <skip />
- <!-- no translation found for kilobyteShort (5865542430193761682) -->
- <skip />
- <!-- no translation found for megabyteShort (112984851085937882) -->
- <skip />
- <!-- no translation found for gigabyteShort (8586075069559273847) -->
- <skip />
- <!-- no translation found for terabyteShort (5828502357595687794) -->
- <skip />
- <!-- no translation found for petabyteShort (7523248732657962413) -->
- <skip />
- <string name="untitled">"&lt;bez názvu&gt;"</string>
- <string name="ellipsis">"…"</string>
- <string name="emptyPhoneNumber">"(žádné telefonní číslo)"</string>
- <string name="unknownName">"(neznámý)"</string>
- <string name="defaultVoiceMailAlphaTag">"Hlasová schránka"</string>
- <string name="defaultMsisdnAlphaTag">"Msisdn1"</string>
- <string name="mmiError">"Chyba sítě nebo neplatný kód MMI."</string>
- <string name="serviceEnabled">"Služba povolena"</string>
- <string name="serviceEnabledFor">"Služba povolena pro:"</string>
- <string name="serviceDisabled">"Služba zakázána"</string>
- <string name="serviceRegistered">"Registrace úspěšná"</string>
- <string name="serviceErased">"Odstranění úspěšné"</string>
- <string name="passwordIncorrect">"Nesprávné heslo."</string>
- <string name="mmiComplete">"MMI dokončeno"</string>
- <!-- no translation found for badPin (5103184589972647739) -->
- <skip />
- <!-- no translation found for badPuk (2200634943393540609) -->
- <skip />
- <!-- no translation found for mismatchPin (5055729703806180857) -->
- <skip />
- <!-- no translation found for invalidPin (6201854814319326475) -->
- <skip />
- <!-- no translation found for needPuk (4788728144863892764) -->
- <skip />
- <!-- no translation found for needPuk2 (7056908944942451033) -->
- <skip />
- <!-- no translation found for ClipMmi (5649729434121615509) -->
- <skip />
- <!-- no translation found for ClirMmi (5220979296096544477) -->
- <skip />
- <!-- no translation found for CfMmi (4998483717856803914) -->
- <skip />
- <!-- no translation found for CwMmi (5678103638951836350) -->
- <skip />
- <!-- no translation found for BaMmi (6030555200442855833) -->
- <skip />
- <!-- no translation found for PwdMmi (2549941247959366670) -->
- <skip />
- <!-- no translation found for PinMmi (2463353963837922189) -->
- <skip />
- <string name="CLIRDefaultOnNextCallOn">"Výchozí nastavení omezení ID - omezení. Další hovor: omezení"</string>
- <string name="CLIRDefaultOnNextCallOff">"Výchozí nastavení omezení ID - omezení. Další hovor: bez omezení"</string>
- <string name="CLIRDefaultOffNextCallOn">"Výchozí nastavení omezení ID - bez omezení. Další hovor: omezení"</string>
- <string name="CLIRDefaultOffNextCallOff">"Výchozí nastavení omezení ID - bez omezení. Další hovor: bez omezení"</string>
- <string name="serviceNotProvisioned">"Služba není poskytována."</string>
- <string name="CLIRPermanent">"Omezení ID v trvalém režimu."</string>
- <string name="serviceClassVoice">"Hlasový záznam"</string>
- <string name="serviceClassData">"Data"</string>
- <string name="serviceClassFAX">"FAX"</string>
- <string name="serviceClassSMS">"SMS"</string>
- <string name="serviceClassDataAsync">"Asynchronní"</string>
- <string name="serviceClassDataSync">"Synchronizace"</string>
- <string name="serviceClassPacket">"Pakety"</string>
- <string name="serviceClassPAD">"PAD"</string>
- <string name="cfTemplateNotForwarded">"{0}: Nepřesměrováno"</string>
- <string name="cfTemplateForwarded">"{0}: {1}"</string>
- <string name="cfTemplateForwardedTime">"{0}: {1} po {2} sekundách"</string>
- <string name="cfTemplateRegistered">"{0}: Nepřesměrováno ({1})"</string>
- <string name="cfTemplateRegisteredTime">"{0}: Nepřesměrováno ({1} po {2} sekundách)"</string>
- <string name="httpErrorOk">"OK"</string>
- <string name="httpError">"Neznámá chyba"</string>
- <string name="httpErrorLookup">"Neznámý hostitel"</string>
- <string name="httpErrorUnsupportedAuthScheme">"Nepodporované schéma ověření. Ověření se nezdařilo."</string>
- <string name="httpErrorAuth">"Ověřování se nezdařilo"</string>
- <string name="httpErrorProxyAuth">"Ověření serverem proxy se nezdařilo"</string>
- <string name="httpErrorConnect">"Připojení k serveru se nezdařilo"</string>
- <string name="httpErrorIO">"Čtení nebo zápis na server se nezdařil"</string>
- <string name="httpErrorTimeout">"Časový limit připojení k serveru vypršel"</string>
- <string name="httpErrorRedirectLoop">"Příliš mnoho přesměrování serverů"</string>
- <string name="httpErrorUnsupportedScheme">"Nepodporovaný protokol"</string>
- <string name="httpErrorFailedSslHandshake">"Navázání spojení typu SSL handshake se nezdařilo"</string>
- <string name="httpErrorBadUrl">"Nepodařilo se analyzovat URL"</string>
- <string name="httpErrorFile">"File error"</string>
- <string name="httpErrorFileNotFound">"File not found"</string>
- <!-- no translation found for httpErrorTooManyRequests (3764334538393544875) -->
- <skip />
- <string name="contentServiceSync">"Synchronizace"</string>
- <string name="contentServiceSyncNotificationTitle">"Synchronizace"</string>
- <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8477597194404210723) -->
- <skip />
- <!-- no translation found for low_memory (4191592786596642367) -->
- <skip />
- <!-- no translation found for me (4616693653158602117) -->
- <skip />
- <string name="power_dialog">"Možnosti napájení"</string>
- <string name="silent_mode">"Tichý režim"</string>
- <string name="turn_on_radio">"Zapnout rádio"</string>
- <string name="turn_off_radio">"Vypnout rádio"</string>
- <!-- no translation found for screen_lock (1560333453597081877) -->
- <skip />
- <string name="power_off">"Vypnuto"</string>
- <!-- no translation found for shutdown_progress (3735034517335251808) -->
- <skip />
- <!-- no translation found for shutdown_confirm (699224922526414097) -->
- <skip />
- <!-- no translation found for no_recent_tasks (1367712919998349373) -->
- <skip />
- <!-- no translation found for global_actions (8299888906525675157) -->
- <skip />
- <!-- no translation found for global_action_lock (5943677976245541105) -->
- <skip />
- <!-- no translation found for global_action_power_off (3143027278596694254) -->
- <skip />
- <!-- no translation found for global_action_toggle_silent_mode (5849335789367070450) -->
- <skip />
- <!-- no translation found for global_action_silent_mode_on_status (6053429980569202260) -->
- <skip />
- <!-- no translation found for global_action_silent_mode_off_status (1994514127029249081) -->
- <skip />
- <!-- no translation found for safeMode (3375134507868534320) -->
- <skip />
- <!-- no translation found for permgrouplab_costMoney (904087853776533085) -->
- <skip />
- <!-- no translation found for permgroupdesc_costMoney (4662370555643969515) -->
- <skip />
- <!-- no translation found for permgrouplab_messages (2984053976424233925) -->
- <skip />
- <!-- no translation found for permgroupdesc_messages (2129093134354989379) -->
- <skip />
- <!-- no translation found for permgrouplab_personalInfo (4548406335021507392) -->
- <skip />
- <!-- no translation found for permgroupdesc_personalInfo (8499310823817958034) -->
- <skip />
- <!-- no translation found for permgrouplab_location (8535677827151907069) -->
- <skip />
- <!-- no translation found for permgroupdesc_location (2341662219604651887) -->
- <skip />
- <!-- no translation found for permgrouplab_network (3597781730625751831) -->
- <skip />
- <!-- no translation found for permgroupdesc_network (8332572695347918340) -->
- <skip />
- <!-- no translation found for permgrouplab_accounts (8631201594657951893) -->
- <skip />
- <!-- no translation found for permgroupdesc_accounts (443982868906396781) -->
- <skip />
- <!-- no translation found for permgrouplab_hardwareControls (5074512938567152139) -->
- <skip />
- <!-- no translation found for permgroupdesc_hardwareControls (8772503144945278440) -->
- <skip />
- <!-- no translation found for permgrouplab_phoneCalls (7096448531266882376) -->
- <skip />
- <!-- no translation found for permgroupdesc_phoneCalls (6703873478653366233) -->
- <skip />
- <!-- no translation found for permgrouplab_systemTools (1840847965111633430) -->
- <skip />
- <!-- no translation found for permgroupdesc_systemTools (2810337951496685271) -->
- <skip />
- <!-- no translation found for permgrouplab_developmentTools (692844635256963358) -->
- <skip />
- <!-- no translation found for permgroupdesc_developmentTools (5253915519857796400) -->
- <skip />
- <!-- no translation found for permlab_statusBar (8789506912215455922) -->
- <skip />
- <!-- no translation found for permdesc_statusBar (5034247171231682403) -->
- <skip />
- <!-- no translation found for permlab_expandStatusBar (6382500803293284173) -->
- <skip />
- <!-- no translation found for permdesc_expandStatusBar (90953162060681436) -->
- <skip />
- <!-- no translation found for permlab_processOutgoingCalls (786316295241100144) -->
- <skip />
- <!-- no translation found for permdesc_processOutgoingCalls (1655242138991854396) -->
- <skip />
- <string name="permlab_receiveSms">"Příjem zpráv SMS"</string>
- <string name="permdesc_receiveSms">"Umožňuje aplikacím přijímat a zpracovávat zprávy SMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."</string>
- <string name="permlab_receiveMms">"Příjem zpráv MMS"</string>
- <string name="permdesc_receiveMms">"Umožňuje aplikacím přijímat a zpracovávat zprávy MMS. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."</string>
- <!-- no translation found for permlab_sendSms (4713837923748234081) -->
- <skip />
- <!-- no translation found for permdesc_sendSms (7126594387176704010) -->
- <skip />
- <!-- no translation found for permlab_readSms (4256004535185449429) -->
- <skip />
- <!-- no translation found for permdesc_readSms (4586480500886941902) -->
- <skip />
- <!-- no translation found for permlab_writeSms (8453452414726246828) -->
- <skip />
- <!-- no translation found for permdesc_writeSms (1036408118901361812) -->
- <skip />
- <string name="permlab_receiveWapPush">"Příjem zpráv WAP"</string>
- <string name="permdesc_receiveWapPush">"Umožňuje aplikacím přijímat a zpracovávat zprávy WAP. Škodlivé aplikace mohou sledovat vaše zprávy nebo je odstraňovat, aniž by se zobrazily."</string>
- <string name="permlab_getTasks">"Získat informace o úkolech"</string>
- <string name="permdesc_getTasks">"Umožňuje aplikacím načítat informace o aktuálně a naposledy spuštěných úkolech. Umožňuje škodlivým aplikacím zjišťovat soukromé informace o jiných aplikacích."</string>
- <!-- no translation found for permlab_reorderTasks (4758862288285224517) -->
- <skip />
- <!-- no translation found for permdesc_reorderTasks (7507060843941912021) -->
- <skip />
- <!-- no translation found for permlab_setDebugApp (2973363275929449444) -->
- <skip />
- <!-- no translation found for permdesc_setDebugApp (5720449860498265972) -->
- <skip />
- <!-- no translation found for permlab_changeConfiguration (8581093564179818627) -->
- <skip />
- <!-- no translation found for permdesc_changeConfiguration (4055366453803187171) -->
- <skip />
- <!-- no translation found for permlab_restartPackages (5836367540766044606) -->
- <skip />
- <!-- no translation found for permdesc_restartPackages (1764965996765573321) -->
- <skip />
- <!-- no translation found for permlab_setProcessForeground (4860990420780868638) -->
- <skip />
- <!-- no translation found for permdesc_setProcessForeground (3795477299954784360) -->
- <skip />
- <!-- no translation found for permlab_forceBack (4737517869935566733) -->
- <skip />
- <!-- no translation found for permdesc_forceBack (5579316297001154697) -->
- <skip />
- <string name="permlab_dump">"Výpis stavu systému"</string>
- <string name="permdesc_dump">"Umožňuje aplikacím načítat vnitřní stav systému. Škodlivé aplikace mohou načítat široký rozsah soukromých a důvěrných informací, jež by obvykle neměly nikdy vyžadovat."</string>
- <string name="permlab_addSystemService">"Přidat systémovou službu"</string>
- <string name="permdesc_addSystemService">"Umožňuje aplikacím vydávat vlastní systémové služby nižší úrovně. Škodlivé aplikace mohou napadnout systém a vykrást nebo poškodit jeho data."</string>
- <string name="permlab_runSetActivityWatcher">"Nastavení sledování činností"</string>
- <string name="permdesc_runSetActivityWatcher">"Umožňuje aplikacím sledovat a řídit spouštění činností systému. Škodlivé aplikace mohou zcela zničit systém. Toto oprávnění je nutné pouze pro vývoj, nikdy pro normální používání zařízení."</string>
- <string name="permlab_broadcastPackageRemoved">"Sada vysílání odebrána"</string>
- <string name="permdesc_broadcastPackageRemoved">"Umožňuje aplikacím vysílat oznámení o odebrání sady aplikací. Škodlivé aplikace toho mohou využít k likvidaci jiné spuštěné aplikace."</string>
- <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
- <skip />
- <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
- <skip />
- <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
- <skip />
- <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
- <skip />
- <!-- no translation found for permlab_setProcessLimit (5190694306017260601) -->
- <skip />
- <!-- no translation found for permdesc_setProcessLimit (593938303319848578) -->
- <skip />
- <!-- no translation found for permlab_setAlwaysFinish (8745533365504920540) -->
- <skip />
- <!-- no translation found for permdesc_setAlwaysFinish (2437195869854312148) -->
- <skip />
- <string name="permlab_fotaUpdate">"Instalace aktualizace systému"</string>
- <string name="permdesc_fotaUpdate">"Umožňuje aplikacím přijímat oznámení o aktualizacích systému čekajících na dokončení a spouštět jejich instalaci. Škodlivé aplikace toho mohou využít k poškození systému neautorizovanými aktualizacemi nebo obecně k zásahům do aktualizačního procesu."</string>
- <!-- no translation found for permlab_batteryStats (1598947993704535568) -->
- <skip />
- <!-- no translation found for permdesc_batteryStats (6247598531831307989) -->
- <skip />
- <string name="permlab_internalSystemWindow">"Okno vnitřního systému"</string>
- <string name="permdesc_internalSystemWindow">"Umožňuje vytváření oken určených k použití uživatelským rozhraním vnitřního systému . Není určeno k použití normálními aplikacemi."</string>
- <string name="permlab_systemAlertWindow">"Okno systémových výstrah"</string>
- <string name="permdesc_systemAlertWindow">"Umožňuje aplikacím zobrazovat okna systémových výstrah. Škodlivé aplikace mohou ovládnout celou obrazovku zařízení."</string>
- <!-- no translation found for permlab_setAnimationScale (2419250686027992384) -->
- <skip />
- <!-- no translation found for permdesc_setAnimationScale (8518027785481727264) -->
- <skip />
- <!-- no translation found for permlab_manageAppTokens (1033424552444304594) -->
- <skip />
- <!-- no translation found for permdesc_manageAppTokens (7285840918912623550) -->
- <skip />
- <!-- no translation found for permlab_injectEvents (1383601196263145482) -->
- <skip />
- <!-- no translation found for permdesc_injectEvents (840097509341464737) -->
- <skip />
- <!-- no translation found for permlab_readInputState (2723668746963882102) -->
- <skip />
- <!-- no translation found for permdesc_readInputState (4651137638757852001) -->
- <skip />
- <!-- no translation found for permlab_setOrientation (1112555600323148680) -->
- <skip />
- <!-- no translation found for permdesc_setOrientation (1960269530378827858) -->
- <skip />
- <string name="permlab_signalPersistentProcesses">"Signálové trvalé procesy"</string>
- <string name="permdesc_signalPersistentProcesses">"Umožňuje aplikacím vyžadovat, aby se přiváděný signál odesílal do všech trvalých procesů."</string>
- <!-- no translation found for permlab_persistentActivity (8163108526929094627) -->
- <skip />
- <!-- no translation found for permdesc_persistentActivity (5258975883823299624) -->
- <skip />
- <string name="permlab_deletePackages">"Odstranit sady"</string>
- <string name="permdesc_deletePackages">"Umožňuje aplikacím odstranit sady systému Android. Škodlivé aplikace toho mohou využít k odstranění důležitých aplikací."</string>
- <!-- no translation found for permlab_clearAppUserData (3858185484601410171) -->
- <skip />
- <!-- no translation found for permdesc_clearAppUserData (7233537744753081136) -->
- <skip />
- <!-- no translation found for permlab_deleteCacheFiles (7362746182961997888) -->
- <skip />
- <!-- no translation found for permdesc_deleteCacheFiles (8293849509208181266) -->
- <skip />
- <!-- no translation found for permlab_getPackageSize (6743556676630447973) -->
- <skip />
- <!-- no translation found for permdesc_getPackageSize (2893996655828539776) -->
- <skip />
- <string name="permlab_installPackages">"Instalovat sady"</string>
- <string name="permdesc_installPackages">"Umožňuje aplikacím instalovat nové nebo aktualizované sady systému Android. Škodlivé aplikace toho mohou využít k přidání nových aplikací s libovolně silnými oprávněními."</string>
- <!-- no translation found for permlab_clearAppCache (7860214328511700776) -->
- <skip />
- <!-- no translation found for permdesc_clearAppCache (5203820862573167878) -->
- <skip />
- <!-- no translation found for permlab_readLogs (6653488552442991707) -->
- <skip />
- <!-- no translation found for permdesc_readLogs (356352685800884319) -->
- <skip />
- <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
- <skip />
- <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
- <skip />
- <string name="permlab_changeComponentState">"Povolit nebo zakázat součásti aplikací"</string>
- <string name="permdesc_changeComponentState">"Umožňuje změnu aplikace bez ohledu na to, zda je součást další aplikace povolená nebo zakázaná. Škodlivá aplikace toho může využít k zakázání důležitých funkcí zařízení. Je třeba nakládat s oprávněními opatrně, protože se mohou součásti aplikace dostat do stavu nepoužitelnosti, nekonzistence nebo nestability."</string>
- <string name="permlab_setPreferredApplications">"Nastavení upřednostňovaných aplikací"</string>
- <string name="permdesc_setPreferredApplications">"Umožňuje aplikacím upravovat oblíbené aplikace. Škodlivé aplikace tak mohou bez upozornění měnit spouštěné aplikace a klamně využívat stávající aplikace ke shromažďování vašich soukromých dat."</string>
- <string name="permlab_writeSettings">"Nastavení systému pro zápis"</string>
- <string name="permdesc_writeSettings">"Umožňuje aplikacím upravovat data nastavení systému. Škodlivé aplikace mohou narušit systémovou konfiguraci."</string>
- <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
- <skip />
- <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
- <skip />
- <!-- no translation found for permlab_writeGservices (296370685945777755) -->
- <skip />
- <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
- <skip />
- <string name="permlab_receiveBootCompleted">"Spustit při spouštění"</string>
- <string name="permdesc_receiveBootCompleted">"Umožňuje aplikacím spouštět se po dokončení spuštění systému. Tím se může prodlužovat doba spouštění zařízení a aplikace může svým stálým spouštěním zpomalovat celé zařízení."</string>
- <string name="permlab_broadcastSticky">"Vysílat lepivý obsah (sticky)"</string>
- <string name="permdesc_broadcastSticky">"Umožňuje aplikacím odesílat tzv. lepivé (sticky) vysílání, které zůstává i po ukončení vysílání. Škodlivé aplikace mohou zpomalit zařízení nebo narušit jeho stabilitu vynucením využívání příliš velké části paměti."</string>
- <string name="permlab_readContacts">"Čtení dat o kontaktech"</string>
- <string name="permdesc_readContacts">"Umožňuje aplikacím číst všechna data o kontaktech (adresy) uložená v zařízení. Škodlivé aplikace toho mohou využívat k odesílání vašich dat jiným osobám."</string>
- <string name="permlab_writeContacts">"Zápis dat o kontaktech"</string>
- <string name="permdesc_writeContacts">"Umožňuje aplikacím upravovat data o kontaktech (adresy) uložená v zařízení. Škodlivé aplikace toho mohou využívat k vymazání nebo úpravě dat o kontaktech."</string>
- <!-- no translation found for permlab_writeOwnerData (8036840529708535113) -->
- <skip />
- <!-- no translation found for permdesc_writeOwnerData (5873447528845878348) -->
- <skip />
- <!-- no translation found for permlab_readOwnerData (1847040178513733757) -->
- <skip />
- <!-- no translation found for permdesc_readOwnerData (7563299529149214764) -->
- <skip />
- <!-- no translation found for permlab_readCalendar (2111238731453410895) -->
- <skip />
- <!-- no translation found for permdesc_readCalendar (4408253940601239114) -->
- <skip />
- <!-- no translation found for permlab_writeCalendar (7518052789370653396) -->
- <skip />
- <!-- no translation found for permdesc_writeCalendar (8057304232140147596) -->
- <skip />
- <!-- no translation found for permlab_accessMockLocation (321094551062270213) -->
- <skip />
- <!-- no translation found for permdesc_accessMockLocation (3651565866471419739) -->
- <skip />
- <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
- <skip />
- <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
- <skip />
- <string name="permlab_accessFineLocation">"Používat službu GPS"</string>
- <string name="permdesc_accessFineLocation">"Technologii GPS v zařízení lze používat, pokud je k dispozici. Toto oprávnění vyžaduje oprávnění ACCESS_LOCATION. Škodlivé aplikace toho mohou využívat k určení vaší polohy a mohou spotřebovávat zbytečně energii baterie."</string>
- <string name="permlab_accessCoarseLocation">"Používat službu Cell ID"</string>
- <string name="permdesc_accessCoarseLocation">"Identifikátory pro technologii využívající polohu vysílačů mobilních sítí (je-li k dispozici) se používají k určení přibližné polohy zařízení. Toto oprávnění vyžaduje oprávnění ACCESS_LOCATION. Škodlivé aplikace toho mohou využívat k určení vaší přibližné polohy."</string>
- <string name="permlab_accessSurfaceFlinger">"Používat službu SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger">"Umožňuje aplikacím používat funkce nižší úrovně SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer">"Čtení vyrovnávací paměti rámce"</string>
- <string name="permdesc_readFrameBuffer">"Umožňuje aplikacím používat čtení obsahu vyrovnávací paměti rámce."</string>
- <!-- no translation found for permlab_modifyAudioSettings (1587341813207960943) -->
- <skip />
- <!-- no translation found for permdesc_modifyAudioSettings (1447143004892708149) -->
- <skip />
- <!-- no translation found for permlab_recordAudio (4447848534036991667) -->
- <skip />
- <!-- no translation found for permdesc_recordAudio (6936874682400894820) -->
- <skip />
- <!-- no translation found for permlab_camera (1944473855727060380) -->
- <skip />
- <!-- no translation found for permdesc_camera (5978058582323766022) -->
- <skip />
- <!-- no translation found for permlab_brick (4749832243303289777) -->
- <skip />
- <!-- no translation found for permdesc_brick (7428524578693695766) -->
- <skip />
- <!-- no translation found for permlab_reboot (8844650672567077423) -->
- <skip />
- <!-- no translation found for permdesc_reboot (4704919552870918328) -->
- <skip />
- <!-- no translation found for permlab_mount_unmount_filesystems (1009574821038043781) -->
- <skip />
- <!-- no translation found for permdesc_mount_unmount_filesystems (100792065894811109) -->
- <skip />
- <!-- no translation found for permlab_vibrate (61984555644467146) -->
- <skip />
- <!-- no translation found for permdesc_vibrate (7831723100758509238) -->
- <skip />
- <!-- no translation found for permlab_flashlight (9097145977808182652) -->
- <skip />
- <!-- no translation found for permdesc_flashlight (7851502731988978358) -->
- <skip />
- <!-- no translation found for permlab_hardware_test (4103324677866524254) -->
- <skip />
- <!-- no translation found for permdesc_hardware_test (7315242723603994769) -->
- <skip />
- <string name="permlab_callPhone">"Volat telefonní čísla"</string>
- <string name="permdesc_callPhone">"Umožňuje aplikacím volat telefonní čísla bez vašeho zásahu. Škodlivé aplikace mohou přinést na váš telefonní účet neočekávané hovory."</string>
- <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
- <skip />
- <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
- <skip />
- <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
- <skip />
- <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
- <skip />
- <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
- <skip />
- <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
- <skip />
- <!-- no translation found for permlab_modifyPhoneState (7791696535097912313) -->
- <skip />
- <!-- no translation found for permdesc_modifyPhoneState (6352405226410454770) -->
- <skip />
- <!-- no translation found for permlab_readPhoneState (7320082586621086653) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (8004450067066407969) -->
- <skip />
- <!-- no translation found for permlab_wakeLock (1591164750935072136) -->
- <skip />
- <!-- no translation found for permdesc_wakeLock (160471538196734936) -->
- <skip />
- <!-- no translation found for permlab_devicePower (9214865067086065548) -->
- <skip />
- <!-- no translation found for permdesc_devicePower (5608364066480036402) -->
- <skip />
- <!-- no translation found for permlab_factoryTest (7786199300637896247) -->
- <skip />
- <!-- no translation found for permdesc_factoryTest (3466066005210542042) -->
- <skip />
- <!-- no translation found for permlab_setWallpaper (2256730637138641725) -->
- <skip />
- <!-- no translation found for permdesc_setWallpaper (3034653140208685093) -->
- <skip />
- <!-- no translation found for permlab_setWallpaperHints (4192438316932517807) -->
- <skip />
- <!-- no translation found for permdesc_setWallpaperHints (738757439960921674) -->
- <skip />
- <!-- no translation found for permlab_masterClear (6155403967270586906) -->
- <skip />
- <!-- no translation found for permdesc_masterClear (4213553172342689754) -->
- <skip />
- <!-- no translation found for permlab_setTimeZone (477196167239548690) -->
- <skip />
- <!-- no translation found for permdesc_setTimeZone (8564892020460841198) -->
- <skip />
- <!-- no translation found for permlab_getAccounts (2764070033402295170) -->
- <skip />
- <!-- no translation found for permdesc_getAccounts (1203491378748649898) -->
- <skip />
- <!-- no translation found for permlab_accessNetworkState (2032916924886010827) -->
- <skip />
- <!-- no translation found for permdesc_accessNetworkState (7081329402551195933) -->
- <skip />
- <!-- no translation found for permlab_createNetworkSockets (4706698319966917864) -->
- <skip />
- <!-- no translation found for permdesc_createNetworkSockets (2580337178778551792) -->
- <skip />
- <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
- <skip />
- <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
- <skip />
- <!-- no translation found for permlab_changeNetworkState (2710779001260856872) -->
- <skip />
- <!-- no translation found for permdesc_changeNetworkState (8076109230787022270) -->
- <skip />
- <!-- no translation found for permlab_accessWifiState (3613679494230374297) -->
- <skip />
- <!-- no translation found for permdesc_accessWifiState (8226508433563326925) -->
- <skip />
- <!-- no translation found for permlab_changeWifiState (6043889338995432957) -->
- <skip />
- <!-- no translation found for permdesc_changeWifiState (7829372845909567994) -->
- <skip />
- <!-- no translation found for permlab_bluetoothAdmin (5513286736585647334) -->
- <skip />
- <!-- no translation found for permdesc_bluetoothAdmin (1838208497914347365) -->
- <skip />
- <!-- no translation found for permlab_bluetooth (6378797624765639115) -->
- <skip />
- <!-- no translation found for permdesc_bluetooth (8592386018922265273) -->
- <skip />
- <!-- no translation found for permlab_disableKeyguard (4574886811903233903) -->
- <skip />
- <!-- no translation found for permdesc_disableKeyguard (815972646344251271) -->
- <skip />
- <!-- no translation found for permlab_readSyncSettings (8818819977141505127) -->
- <skip />
- <!-- no translation found for permdesc_readSyncSettings (8454705401908767847) -->
- <skip />
- <!-- no translation found for permlab_writeSyncSettings (4514911143753152941) -->
- <skip />
- <!-- no translation found for permdesc_writeSyncSettings (7630627689635091836) -->
- <skip />
- <!-- no translation found for permlab_readSyncStats (5748337739678952863) -->
- <skip />
- <!-- no translation found for permdesc_readSyncStats (582551457321957183) -->
- <skip />
- <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
- <skip />
- <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
- <skip />
- <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
- <skip />
- <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
- <skip />
- <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
- <string-array name="emailAddressTypes">
- <item>"Výchozí"</item>
- <item>"Zaměstnání"</item>
- <item>"Primární"</item>
- <item>"Vlastní…"</item>
- </string-array>
- <string-array name="postalAddressTypes">
- <item>"Poštovní"</item>
- <item>"Výchozí"</item>
- <item>"Zaměstnání"</item>
- <item>"Vlastní…"</item>
- </string-array>
- <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
- <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
- <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
- <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
- <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
- <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
- <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
- <!-- no translation found for imProtocols:0 (3318725788774688043) -->
- <!-- no translation found for imProtocols:1 (1787713387022932886) -->
- <!-- no translation found for imProtocols:2 (6751174158442316516) -->
- <!-- no translation found for imProtocols:3 (1151283347465052653) -->
- <!-- no translation found for imProtocols:4 (2157980008878817934) -->
- <!-- no translation found for imProtocols:5 (7836237460308230767) -->
- <!-- no translation found for imProtocols:6 (1180789904462172516) -->
- <!-- no translation found for imProtocols:7 (21955111672779862) -->
- <!-- no translation found for keyguard_password_enter_pin_code (6779835451906812518) -->
- <skip />
- <!-- no translation found for keyguard_password_wrong_pin_code (230312338493035499) -->
- <skip />
- <string name="keyguard_label_text">"Telefon odemknete stisknutím tlačítka nabídky a poté 0."</string>
- <!-- no translation found for emergency_call_dialog_number_for_display (6256361184251050511) -->
- <skip />
- <!-- no translation found for lockscreen_carrier_default (5222269885486229730) -->
- <skip />
- <!-- no translation found for lockscreen_screen_locked (1922273663462058967) -->
- <skip />
- <!-- no translation found for lockscreen_instructions_when_pattern_enabled (7535864145009679967) -->
- <skip />
- <!-- no translation found for lockscreen_instructions_when_pattern_disabled (6526504555912746785) -->
- <skip />
- <!-- no translation found for lockscreen_pattern_instructions (8984964506352089877) -->
- <skip />
- <!-- no translation found for lockscreen_emergency_call (422835617844547383) -->
- <skip />
- <!-- no translation found for lockscreen_pattern_correct (7104753084746383672) -->
- <skip />
- <!-- no translation found for lockscreen_pattern_wrong (7517004470797680361) -->
- <skip />
- <!-- no translation found for lockscreen_plugged_in (8806977650003537118) -->
- <skip />
- <!-- no translation found for lockscreen_low_battery (9002637795199621345) -->
- <skip />
- <!-- no translation found for lockscreen_missing_sim_message_short (5051192587315492957) -->
- <skip />
- <!-- no translation found for lockscreen_missing_sim_message (8912914495901434841) -->
- <skip />
- <!-- no translation found for lockscreen_missing_sim_instructions (8125847194365725429) -->
- <skip />
- <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
- <skip />
- <!-- no translation found for lockscreen_sim_puk_locked_message (1005803622871256359) -->
- <skip />
- <!-- no translation found for lockscreen_sim_puk_locked_instructions (5033160098036646955) -->
- <skip />
- <!-- no translation found for lockscreen_sim_locked_message (7398401200962556379) -->
- <skip />
- <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (5939537246164692076) -->
- <skip />
- <!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6709066241494622136) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_almost_glogin (1569017295989454551) -->
- <skip />
- <!-- no translation found for lockscreen_too_many_failed_attempts_countdown (8823588000022797566) -->
- <skip />
- <!-- no translation found for lockscreen_forgot_pattern_button_text (4219994639843985488) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_too_many_attempts (7504679498838839295) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_instructions (6542400673357252011) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_username_hint (6378418320242015111) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_password_hint (3224230234042131153) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_submit_button (5562051040043760034) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
- <skip />
- <!-- no translation found for status_bar_time_format (2168573805413119180) -->
- <skip />
- <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
- <skip />
- <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
- <skip />
- <!-- no translation found for hour_ampm (7665432130905376251) -->
- <skip />
- <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
- <skip />
- <!-- no translation found for status_bar_clear_all_button (2202004591253243750) -->
- <skip />
- <!-- no translation found for status_bar_no_notifications_title (5123133188102094464) -->
- <skip />
- <!-- no translation found for status_bar_ongoing_events_title (799961521630569167) -->
- <skip />
- <!-- no translation found for status_bar_latest_events_title (5414094466807164279) -->
- <skip />
- <!-- no translation found for battery_status_text_percent_format (7391464609447031944) -->
- <skip />
- <!-- no translation found for battery_status_charging (5078780715755132756) -->
- <skip />
- <!-- no translation found for battery_low_title (3665400828395001695) -->
- <skip />
- <!-- no translation found for battery_low_subtitle (7537149915372180016) -->
- <skip />
- <!-- no translation found for battery_low_percent_format (8635359708781261154) -->
- <skip />
- <string name="factorytest_failed">"Výrobní test skončil chybou"</string>
- <string name="factorytest_not_system">"Akce FACTORY_TEST je podporována pouze pro sady instalované v adresáři /system/app."</string>
- <string name="factorytest_no_action">"Nebyla nalezena žádná sada, která zajišťuje akci FACTORY_TEST."</string>
- <string name="factorytest_reboot">"Restartovat"</string>
- <!-- no translation found for save_password_label (4129493019621348626) -->
- <skip />
- <!-- no translation found for save_password_message (7412617920202682045) -->
- <skip />
- <!-- no translation found for save_password_notnow (3887362423496820832) -->
- <skip />
- <!-- no translation found for save_password_remember (4319688896716308569) -->
- <skip />
- <!-- no translation found for save_password_never (1836981952883642377) -->
- <skip />
- <!-- no translation found for open_permission_deny (6408502671105717111) -->
- <skip />
- <!-- no translation found for text_copied (6106873823411904723) -->
- <skip />
- <string name="more_item_label">"Další"</string>
- <string name="prepend_shortcut_label">"Menu+"</string>
- <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
- <skip />
- <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
- <skip />
- <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
- <skip />
- <string name="search_go">"PŘEJÍT"</string>
- <string name="today">"Dnes"</string>
- <string name="yesterday">"Včera"</string>
- <string name="tomorrow">"Zítra"</string>
- <!-- no translation found for oneMonthDurationPast (3402179395240209557) -->
- <skip />
- <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
- <skip />
- <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
- <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
- <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
- <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
- <!-- no translation found for num_hours_ago:one (853404611989669641) -->
- <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
- <!-- no translation found for num_days_ago:one (4222479980812128212) -->
- <!-- no translation found for num_days_ago:other (5445701370433601703) -->
- <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
- <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
- <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
- <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
- <!-- no translation found for in_num_hours:one (6501470863235186391) -->
- <!-- no translation found for in_num_hours:other (4415358752953289251) -->
- <!-- no translation found for in_num_days:one (5608475533104443893) -->
- <!-- no translation found for in_num_days:other (3827193006163842267) -->
- <!-- no translation found for preposition_for_date (2689847983632851560) -->
- <skip />
- <!-- no translation found for preposition_for_time (2613388053493148013) -->
- <skip />
- <!-- no translation found for preposition_for_year (6968468294728152393) -->
- <skip />
- <string name="day">"den"</string>
- <string name="days">"dnů"</string>
- <string name="hour">"hodinu"</string>
- <string name="hours">"hodin"</string>
- <string name="minute">"minutu"</string>
- <string name="minutes">"minut"</string>
- <string name="second">"sekund"</string>
- <string name="seconds">"sekund"</string>
- <string name="week">"týden"</string>
- <string name="weeks">"týdnů"</string>
- <!-- no translation found for year (8024790425994085153) -->
- <skip />
- <!-- no translation found for years (8592090054773244417) -->
- <skip />
- <string name="sunday">"Neděle"</string>
- <string name="monday">"Pondělí"</string>
- <string name="tuesday">"Úterý"</string>
- <string name="wednesday">"Středa"</string>
- <string name="thursday">"Čtvrtek"</string>
- <string name="friday">"Pátek"</string>
- <string name="saturday">"Sobota"</string>
- <string name="every_weekday">"Každý den v týdnu (Po–Pá)"</string>
- <string name="daily">"Denně"</string>
- <string name="weekly">"Týdně (%s)"</string>
- <string name="monthly">"Měsíčně"</string>
- <string name="yearly">"Ročně"</string>
- <!-- no translation found for VideoView_error_title (1024334251681931859) -->
- <skip />
- <!-- no translation found for VideoView_error_text_unknown (3398417247398476771) -->
- <skip />
- <!-- no translation found for VideoView_error_button (3144127115413163445) -->
- <skip />
- <string name="am">"dop."</string>
- <string name="pm">"odp."</string>
- <!-- no translation found for numeric_date (5120078478872821100) -->
- <skip />
- <!-- no translation found for wday1_date1_time1_wday2_date2_time2 (7066878981949584861) -->
- <skip />
- <!-- no translation found for wday1_date1_wday2_date2 (8671068747172261907) -->
- <skip />
- <!-- no translation found for date1_time1_date2_time2 (3645498975775629615) -->
- <skip />
- <!-- no translation found for date1_date2 (377057563556488062) -->
- <skip />
- <!-- no translation found for time1_time2 (3173474242109288305) -->
- <skip />
- <!-- no translation found for time_wday_date (8928955562064570313) -->
- <skip />
- <!-- no translation found for wday_date (8794741400546136975) -->
- <skip />
- <!-- no translation found for time_date (1922644512833014496) -->
- <skip />
- <!-- no translation found for time_wday (1422050241301754712) -->
- <skip />
- <!-- no translation found for full_date_month_first (6011143962222283357) -->
- <skip />
- <!-- no translation found for full_date_day_first (8621594762705478189) -->
- <skip />
- <!-- no translation found for medium_date_month_first (48990963718825728) -->
- <skip />
- <!-- no translation found for medium_date_day_first (2898992016440387123) -->
- <skip />
- <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
- <skip />
- <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
- <skip />
- <!-- no translation found for noon (8390796001560682897) -->
- <skip />
- <!-- no translation found for Noon (7698941576181064429) -->
- <skip />
- <!-- no translation found for midnight (7773339795626486146) -->
- <skip />
- <!-- no translation found for Midnight (1260172107848123187) -->
- <skip />
- <!-- no translation found for month_day (3356633704511426364) -->
- <skip />
- <!-- no translation found for month (3017405760734206414) -->
- <skip />
- <!-- no translation found for month_day_year (2435948225709176752) -->
- <skip />
- <!-- no translation found for month_year (6228414124777343135) -->
- <skip />
- <!-- no translation found for time_of_day (8375993139317154157) -->
- <skip />
- <!-- no translation found for date_and_time (9197690194373107109) -->
- <skip />
- <!-- no translation found for same_year_md1_md2 (9199324363135981317) -->
- <skip />
- <!-- no translation found for same_year_wday1_md1_wday2_md2 (6006392413355305178) -->
- <skip />
- <!-- no translation found for same_year_mdy1_mdy2 (1576657593937827090) -->
- <skip />
- <!-- no translation found for same_year_wday1_mdy1_wday2_mdy2 (9135935796468891580) -->
- <skip />
- <!-- no translation found for same_year_md1_time1_md2_time2 (2172964106375558081) -->
- <skip />
- <!-- no translation found for same_year_wday1_md1_time1_wday2_md2_time2 (1702879534101786310) -->
- <skip />
- <!-- no translation found for same_year_mdy1_time1_mdy2_time2 (2476443311723358767) -->
- <skip />
- <!-- no translation found for same_year_wday1_mdy1_time1_wday2_mdy2_time2 (1564837340334069879) -->
- <skip />
- <!-- no translation found for numeric_md1_md2 (8908376522875100300) -->
- <skip />
- <!-- no translation found for numeric_wday1_md1_wday2_md2 (3239690882018292077) -->
- <skip />
- <!-- no translation found for numeric_mdy1_mdy2 (8883797176939233525) -->
- <skip />
- <!-- no translation found for numeric_wday1_mdy1_wday2_mdy2 (4150475769255828954) -->
- <skip />
- <!-- no translation found for numeric_md1_time1_md2_time2 (3624746590607741419) -->
- <skip />
- <!-- no translation found for numeric_wday1_md1_time1_wday2_md2_time2 (4258040955467298134) -->
- <skip />
- <!-- no translation found for numeric_mdy1_time1_mdy2_time2 (3598215409314517987) -->
- <skip />
- <!-- no translation found for numeric_wday1_mdy1_time1_wday2_mdy2_time2 (264076937155877259) -->
- <skip />
- <!-- no translation found for same_month_md1_md2 (2393563617438036111) -->
- <skip />
- <!-- no translation found for same_month_wday1_md1_wday2_md2 (1208946773794057819) -->
- <skip />
- <!-- no translation found for same_month_mdy1_mdy2 (3713236637869030492) -->
- <skip />
- <!-- no translation found for same_month_wday1_mdy1_wday2_mdy2 (389638922479870472) -->
- <skip />
- <!-- no translation found for same_month_md1_time1_md2_time2 (7477075526337542685) -->
- <skip />
- <!-- no translation found for same_month_wday1_md1_time1_wday2_md2_time2 (3516978303779391173) -->
- <skip />
- <!-- no translation found for same_month_mdy1_time1_mdy2_time2 (7320410992514057310) -->
- <skip />
- <!-- no translation found for same_month_wday1_mdy1_time1_wday2_mdy2_time2 (1332950588774239228) -->
- <skip />
- <!-- no translation found for abbrev_month_day_year (5767271534015320250) -->
- <skip />
- <!-- no translation found for abbrev_month_year (8058929633673942490) -->
- <skip />
- <!-- no translation found for abbrev_month_day (458867920693482757) -->
- <skip />
- <!-- no translation found for abbrev_month (1674509986330181349) -->
- <skip />
- <!-- no translation found for day_of_week_long_sunday (9057662850446501884) -->
- <skip />
- <!-- no translation found for day_of_week_long_monday (7358451993082888343) -->
- <skip />
- <!-- no translation found for day_of_week_long_tuesday (2282901451170509613) -->
- <skip />
- <!-- no translation found for day_of_week_long_wednesday (2100217950343286482) -->
- <skip />
- <!-- no translation found for day_of_week_long_thursday (5475158963242863176) -->
- <skip />
- <!-- no translation found for day_of_week_long_friday (4081018004819837155) -->
- <skip />
- <!-- no translation found for day_of_week_long_saturday (1929694088305891795) -->
- <skip />
- <!-- no translation found for day_of_week_medium_sunday (6462580883948669820) -->
- <skip />
- <!-- no translation found for day_of_week_medium_monday (6960587654241349502) -->
- <skip />
- <!-- no translation found for day_of_week_medium_tuesday (7004462235990108936) -->
- <skip />
- <!-- no translation found for day_of_week_medium_wednesday (5688564741951314696) -->
- <skip />
- <!-- no translation found for day_of_week_medium_thursday (1784339868453982400) -->
- <skip />
- <!-- no translation found for day_of_week_medium_friday (4314577583604069357) -->
- <skip />
- <!-- no translation found for day_of_week_medium_saturday (70321191398427845) -->
- <skip />
- <!-- no translation found for day_of_week_short_sunday (7403409454572591357) -->
- <skip />
- <!-- no translation found for day_of_week_short_monday (5278358100012478239) -->
- <skip />
- <!-- no translation found for day_of_week_short_tuesday (5121116040712487059) -->
- <skip />
- <!-- no translation found for day_of_week_short_wednesday (1601079579293330319) -->
- <skip />
- <!-- no translation found for day_of_week_short_thursday (5863422096017401812) -->
- <skip />
- <!-- no translation found for day_of_week_short_friday (2916686031099723960) -->
- <skip />
- <!-- no translation found for day_of_week_short_saturday (8521564973195542073) -->
- <skip />
- <!-- no translation found for day_of_week_shorter_sunday (1650484495176707638) -->
- <skip />
- <!-- no translation found for day_of_week_shorter_monday (9133193697786876074) -->
- <skip />
- <!-- no translation found for day_of_week_shorter_tuesday (4012095408481489663) -->
- <skip />
- <!-- no translation found for day_of_week_shorter_wednesday (6279056612496078470) -->
- <skip />
- <!-- no translation found for day_of_week_shorter_thursday (2748599403545071011) -->
- <skip />
- <!-- no translation found for day_of_week_shorter_friday (5037282109124849673) -->
- <skip />
- <!-- no translation found for day_of_week_shorter_saturday (3208167155877833783) -->
- <skip />
- <!-- no translation found for day_of_week_shortest_sunday (4683862964821549758) -->
- <skip />
- <!-- no translation found for day_of_week_shortest_monday (6701142261471667000) -->
- <skip />
- <!-- no translation found for day_of_week_shortest_tuesday (9098171980161292477) -->
- <skip />
- <!-- no translation found for day_of_week_shortest_wednesday (655049238289460956) -->
- <skip />
- <!-- no translation found for day_of_week_shortest_thursday (7816913627500884083) -->
- <skip />
- <!-- no translation found for day_of_week_shortest_friday (903301878650619398) -->
- <skip />
- <!-- no translation found for day_of_week_shortest_saturday (5359692489649817988) -->
- <skip />
- <!-- no translation found for month_long_january (7128497801440564337) -->
- <skip />
- <!-- no translation found for month_long_february (7808570514581190617) -->
- <skip />
- <!-- no translation found for month_long_march (2061328556983796034) -->
- <skip />
- <!-- no translation found for month_long_april (6575007959043269919) -->
- <skip />
- <!-- no translation found for month_long_may (8404051103463071121) -->
- <skip />
- <!-- no translation found for month_long_june (6255771619238859451) -->
- <skip />
- <!-- no translation found for month_long_july (4129177743136800884) -->
- <skip />
- <!-- no translation found for month_long_august (5494331003296804494) -->
- <skip />
- <!-- no translation found for month_long_september (2691137479752033087) -->
- <skip />
- <!-- no translation found for month_long_october (7501261567327243313) -->
- <skip />
- <!-- no translation found for month_long_november (8759690753068763664) -->
- <skip />
- <!-- no translation found for month_long_december (4505008719696569497) -->
- <skip />
- <!-- no translation found for month_medium_january (2315492772833932512) -->
- <skip />
- <!-- no translation found for month_medium_february (118412521324313430) -->
- <skip />
- <!-- no translation found for month_medium_march (5546835583839352358) -->
- <skip />
- <!-- no translation found for month_medium_april (7052559668687733702) -->
- <skip />
- <!-- no translation found for month_medium_may (2825303871720116018) -->
- <skip />
- <!-- no translation found for month_medium_june (829843667101495271) -->
- <skip />
- <!-- no translation found for month_medium_july (5029778226925324789) -->
- <skip />
- <!-- no translation found for month_medium_august (8851230594641162805) -->
- <skip />
- <!-- no translation found for month_medium_september (8420590486625304647) -->
- <skip />
- <!-- no translation found for month_medium_october (1787382806172930239) -->
- <skip />
- <!-- no translation found for month_medium_november (675513809622370603) -->
- <skip />
- <!-- no translation found for month_medium_december (2934948295928978783) -->
- <skip />
- <!-- no translation found for month_shortest_january (6070060405144675883) -->
- <skip />
- <!-- no translation found for month_shortest_february (5632605004902176653) -->
- <skip />
- <!-- no translation found for month_shortest_march (4304231552356086624) -->
- <skip />
- <!-- no translation found for month_shortest_april (1166434066469385532) -->
- <skip />
- <!-- no translation found for month_shortest_may (9131326028845529001) -->
- <skip />
- <!-- no translation found for month_shortest_june (1875723154506665289) -->
- <skip />
- <!-- no translation found for month_shortest_july (2003596275389810773) -->
- <skip />
- <!-- no translation found for month_shortest_august (9120245162625763214) -->
- <skip />
- <!-- no translation found for month_shortest_september (7980651111022693669) -->
- <skip />
- <!-- no translation found for month_shortest_october (3640405450427788312) -->
- <skip />
- <!-- no translation found for month_shortest_november (4002935318566146993) -->
- <skip />
- <!-- no translation found for month_shortest_december (6213739417171334040) -->
- <skip />
- <!-- no translation found for elapsed_time_short_format_mm_ss (1294409362352514646) -->
- <skip />
- <!-- no translation found for elapsed_time_short_format_h_mm_ss (2997059666628785039) -->
- <skip />
- <!-- no translation found for selectAll (691691810023908884) -->
- <skip />
- <!-- no translation found for cut (5845613239192595662) -->
- <skip />
- <!-- no translation found for cutAll (4474519683293791451) -->
- <skip />
- <!-- no translation found for copy (8603721575469529820) -->
- <skip />
- <!-- no translation found for copyAll (4777548804630476932) -->
- <skip />
- <!-- no translation found for paste (6458036735811828538) -->
- <skip />
- <!-- no translation found for copyUrl (5785708478767435812) -->
- <skip />
- <!-- no translation found for inputMethod (7911866729148111492) -->
- <skip />
- <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
- <skip />
- <!-- no translation found for low_internal_storage_view_title (5997772070488639934) -->
- <skip />
- <!-- no translation found for low_internal_storage_view_text (2230118755295375293) -->
- <skip />
- <!-- no translation found for ok (4003878536083514869) -->
- <skip />
- <!-- no translation found for cancel (1527674037280267012) -->
- <skip />
- <!-- no translation found for yes (8185296114406773873) -->
- <skip />
- <!-- no translation found for no (2300685350903156262) -->
- <skip />
- <!-- no translation found for capital_on (8418242581217554942) -->
- <skip />
- <!-- no translation found for capital_off (8870368560477693851) -->
- <skip />
- <!-- no translation found for whichApplication (2828159696176255212) -->
- <skip />
- <!-- no translation found for alwaysUse (6433627451071144629) -->
- <skip />
- <!-- no translation found for clearDefaultHintMsg (5742432113023174321) -->
- <skip />
- <!-- no translation found for chooseActivity (7588691622928031978) -->
- <skip />
- <!-- no translation found for noApplications (4068560364116066745) -->
- <skip />
- <!-- no translation found for aerr_title (2654390351574026098) -->
- <skip />
- <!-- no translation found for aerr_application (4917288809565116720) -->
- <skip />
- <!-- no translation found for aerr_process (1273819861108073461) -->
- <skip />
- <!-- no translation found for anr_title (3305935690891435915) -->
- <skip />
- <!-- no translation found for anr_activity_application (1653036325679156678) -->
- <skip />
- <!-- no translation found for anr_activity_process (2674027618362070465) -->
- <skip />
- <!-- no translation found for anr_application_process (2163656674970221928) -->
- <skip />
- <!-- no translation found for anr_process (7747550780123472160) -->
- <skip />
- <!-- no translation found for force_close (9020954128872810669) -->
- <skip />
- <!-- no translation found for wait (7973775702304037058) -->
- <skip />
- <!-- no translation found for debug (857932504764728770) -->
- <skip />
- <!-- no translation found for sendText (6158329286172492543) -->
- <skip />
- <!-- no translation found for volume_ringtone (4121694816346562058) -->
- <skip />
- <!-- no translation found for volume_music (4869950240104717493) -->
- <skip />
- <!-- no translation found for volume_call (5723421277753250395) -->
- <skip />
- <!-- no translation found for volume_alarm (2752102730973081294) -->
- <skip />
- <!-- no translation found for volume_unknown (6908187627672375742) -->
- <skip />
- <!-- no translation found for ringtone_default (2873893375149093475) -->
- <skip />
- <!-- no translation found for ringtone_default_with_actual (5474076151665761913) -->
- <skip />
- <!-- no translation found for ringtone_silent (7477159279081654685) -->
- <skip />
- <!-- no translation found for ringtone_picker_title (7055241890764367884) -->
- <skip />
- <!-- no translation found for ringtone_unknown (6888219771401173795) -->
- <skip />
- <!-- no translation found for wifi_available:one (8168012881468888470) -->
- <!-- no translation found for wifi_available:other (4666122955807117718) -->
- <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
- <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
- <!-- no translation found for select_character (3735110139249491726) -->
- <skip />
- <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
- <skip />
- <!-- no translation found for sms_control_title (2742400596989418394) -->
- <skip />
- <!-- no translation found for sms_control_message (3447126217666595989) -->
- <skip />
- <!-- no translation found for sms_control_yes (8839660939359273650) -->
- <skip />
- <!-- no translation found for sms_control_no (909756849988183801) -->
- <skip />
- <!-- no translation found for date_time_set (2495199891239480952) -->
- <skip />
- <!-- no translation found for default_permission_group (7742780381379652409) -->
- <skip />
- <!-- no translation found for no_permissions (85461124044682315) -->
- <skip />
- <!-- no translation found for perms_hide (4145325555929151849) -->
- <skip />
- <!-- no translation found for perms_show_all (6040194843455403173) -->
- <skip />
- <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
- <skip />
- <!-- no translation found for usb_storage_title (8699631567051394409) -->
- <skip />
- <!-- no translation found for usb_storage_message (5344039189213308733) -->
- <skip />
- <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
- <skip />
- <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
- <skip />
- <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
- <skip />
- <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
- <skip />
- <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
- <skip />
- <!-- no translation found for select_input_method (2658280517827502015) -->
- <skip />
- <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
- <skip />
- <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
- <skip />
- <!-- no translation found for candidates_style (7738463880139922176) -->
- <skip />
-</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 76232de..13aca371 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -103,7 +103,15 @@
<string name="global_action_toggle_silent_mode">"Tichý režim"</string>
<string name="global_action_silent_mode_on_status">"Zvuk je VYPNUTÝ."</string>
<string name="global_action_silent_mode_off_status">"Zvuk je zapnutý"</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
<string name="safeMode">"Nouzový režim"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
<string name="permgrouplab_costMoney">"Zpoplatněné služby"</string>
<string name="permgroupdesc_costMoney">"Umožňuje aplikacím provádět činnosti, které vás mohou stát peníze."</string>
<string name="permgrouplab_messages">"Vaše zprávy"</string>
@@ -262,6 +270,8 @@
<string name="permdesc_reboot">"Umožňuje aplikaci vynutit restartování telefonu."</string>
<string name="permlab_mount_unmount_filesystems">"připojení a odpojení souborových systémů"</string>
<string name="permdesc_mount_unmount_filesystems">"Umožňuje aplikaci připojit či odpojit souborové systémy ve vyměnitelných úložištích."</string>
+ <string name="permlab_mount_format_filesystems">"formátovat externí úložiště"</string>
+ <string name="permdesc_mount_format_filesystems">"Umožňuje aplikaci formátovat vyměnitelná úložiště."</string>
<string name="permlab_vibrate">"ovládání vibrací"</string>
<string name="permdesc_vibrate">"Umožňuje aplikaci ovládat vibrace."</string>
<string name="permlab_flashlight">"ovládání kontrolky"</string>
@@ -276,6 +286,8 @@
<string name="permdesc_locationUpdates">"Umožňuje povolit či zakázat aktualizace polohy prostřednictvím bezdrátového připojení. Aplikace toto nastavení obvykle nepoužívají."</string>
<string name="permlab_checkinProperties">"přístup k vlastnostem Checkin"</string>
<string name="permdesc_checkinProperties">"Umožňuje čtení i zápis vlastností nahraných službou Checkin. Běžné aplikace toto nastavení obvykle nevyužívají."</string>
+ <string name="permlab_bindGadget">"zvolit gadgety"</string>
+ <string name="permdesc_bindGadget">"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."</string>
<string name="permlab_modifyPhoneState">"změny stavu telefonu"</string>
<string name="permdesc_modifyPhoneState">"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í."</string>
<string name="permlab_readPhoneState">"zjistit stav telefonu"</string>
@@ -304,6 +316,8 @@
<string name="permdesc_writeApnSettings">"Umožňuje aplikaci změnit nastavení APN, jako je například proxy či port APN."</string>
<string name="permlab_changeNetworkState">"změna připojení k síti"</string>
<string name="permdesc_changeNetworkState">"Umožňuje aplikaci změnit stav připojení k síti."</string>
+ <string name="permlab_changeBackgroundDataSetting">"změnit nastavení použití dat na pozadí"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Umožňuje aplikaci změnit nastavení použití dat na pozadí."</string>
<string name="permlab_accessWifiState">"zobrazení stavu WiFi"</string>
<string name="permdesc_accessWifiState">"Umožňuje aplikaci zobrazit informace o stavu připojení WiFi."</string>
<string name="permlab_changeWifiState">"Změnit stav WiFi"</string>
@@ -324,14 +338,10 @@
<string name="permdesc_subscribedFeedsRead">"Umožňuje aplikaci získat podrobnosti o aktuálně synchronizovaných zdrojích."</string>
<string name="permlab_subscribedFeedsWrite">"zápis odebíraných zdrojů"</string>
<string name="permdesc_subscribedFeedsWrite">"Umožňuje aplikaci upravit vaše aktuálně synchronizované zdroje. To může škodlivým aplikacím umožnit změnu vašich synchronizovaných zdrojů."</string>
- <!-- no translation found for permlab_readDictionary (432535716804748781) -->
- <skip />
- <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
- <skip />
- <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
- <skip />
- <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
- <skip />
+ <string name="permlab_readDictionary">"číst slovník definovaný uživatelem"</string>
+ <string name="permdesc_readDictionary">"Umožní aplikaci číst soukromá slova, jména a fráze, která uživatel mohl uložit do svého slovníku."</string>
+ <string name="permlab_writeDictionary">"zapisovat do slovníku definovaného uživatelem"</string>
+ <string name="permdesc_writeDictionary">"Umožní aplikaci zapisovat nová slova do uživatelského slovníku."</string>
<string-array name="phoneTypes">
<item>"Domů"</item>
<item>"Mobil"</item>
@@ -387,9 +397,10 @@
<string name="lockscreen_emergency_call">"Tísňové volání"</string>
<string name="lockscreen_pattern_correct">"Správně!"</string>
<string name="lockscreen_pattern_wrong">"Zkuste to prosím znovu"</string>
- <string name="lockscreen_plugged_in">"Nabíjení (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
<string name="lockscreen_low_battery">"Připojte dobíjecí zařízení."</string>
- <string name="lockscreen_missing_sim_message_short">"Není vložena karta SIM."</string>
+ <string name="lockscreen_missing_sim_message_short">"Není vložena SIM karta."</string>
<string name="lockscreen_missing_sim_message">"V telefonu není žádná karta SIM."</string>
<string name="lockscreen_missing_sim_instructions">"Prosím vložte kartu SIM."</string>
<string name="lockscreen_network_locked_message">"Síť je blokována"</string>
@@ -397,8 +408,8 @@
<string name="lockscreen_sim_puk_locked_instructions">"Prosím kontaktujte podporu zákazníků."</string>
<string name="lockscreen_sim_locked_message">"Karta SIM je zablokována."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message">"Odblokování karty SIM..."</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste použili nesprávné gesto pro odemčení. "\n\n"Opakujte prosím akci za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="lockscreen_failed_attempts_almost_glogin">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své gesto odemknutí. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádání o odemčení telefonu pomocí přihlášení Google."\n\n" Akci prosím opakujte za několik sekund (<xliff:g id="NUMBER_2">%d</xliff:g>)."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nakreslili nesprávné bezpečnostní gesto. "\n\n"Opakujte prosím akci za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své bezpečnostní gesto. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádáni o odemčení telefonu pomocí přihlášení do účtu Google."\n\n" Akci prosím opakujte za několik sekund (<xliff:g id="NUMBER_2">%d</xliff:g>)."</string>
<string name="lockscreen_too_many_failed_attempts_countdown">"Sekundy zbývající do dalšího pokusu: <xliff:g id="NUMBER">%d</xliff:g>."</string>
<string name="lockscreen_forgot_pattern_button_text">"Zapomněli jste gesto?"</string>
<string name="lockscreen_glogin_too_many_attempts">"Gesta: Příliš mnoho pokusů"</string>
@@ -410,15 +421,15 @@
<string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
<string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <!-- no translation found for hour_ampm (7618670480400517084) -->
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
<skip />
- <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
<skip />
<string name="status_bar_clear_all_button">"Vymazat oznámení"</string>
<string name="status_bar_no_notifications_title">"Žádná oznámení"</string>
<string name="status_bar_ongoing_events_title">"Probíhající"</string>
<string name="status_bar_latest_events_title">"Oznámení"</string>
- <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
<skip />
<string name="battery_status_charging">"Nabíjení..."</string>
<string name="battery_low_title">"Prosím připojte dobíjecí zařízení"</string>
@@ -428,12 +439,9 @@
<string name="factorytest_not_system">"Test FACTORY_TEST lze provést pouze u balíčků nainstalovaných ve složce /system/app."</string>
<string name="factorytest_no_action">"Nebyl nalezen žádný balíček umožňující test FACTORY_TEST."</string>
<string name="factorytest_reboot">"Restartovat"</string>
- <!-- no translation found for js_dialog_title (8143918455087008109) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
- <skip />
+ <string name="js_dialog_title">"Stránka <xliff:g id="TITLE">%s</xliff:g> uvádí:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Chcete opustit tuto stránku?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Vyberte OK, chcete-li pokračovat, nebo Zrušit, chcete-li na stránce zůstat."</string>
<string name="save_password_label">"Potvrdit"</string>
<string name="save_password_message">"Chcete, aby si prohlížeč zapamatoval toto heslo?"</string>
<string name="save_password_notnow">"Nyní ne"</string>
@@ -484,22 +492,38 @@
<item quantity="one">"zítra"</item>
<item quantity="other">"zbývající počet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
</plurals>
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"před 1 s"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"před 1 min."</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"před 1 hodinou"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> hod."</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"včera"</item>
+ <item quantity="other">"před <xliff:g id="COUNT">%d</xliff:g> dny"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"za 1 s"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> s"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"za 1 min."</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> min."</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"za 1 hodinu"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> hod."</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"zítra"</item>
+ <item quantity="other">"zbývající počet dní: <xliff:g id="COUNT">%d</xliff:g>"</item>
+ </plurals>
<string name="preposition_for_date">"%s"</string>
<string name="preposition_for_time">"%s"</string>
<string name="preposition_for_year">"v roce %s"</string>
@@ -541,27 +565,25 @@
<string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
- <!-- no translation found for date_time (6104442718633642836) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
- <string name="full_date_month_first">"<xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="DAY">dd</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="full_date_day_first">"<xliff:g id="DAY">dd</xliff:g>. <xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_month_first">"<xliff:g id="DAY">dd</xliff:g>. <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g>. <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
- <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>'. '<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="DAY">d</xliff:g>'. '<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>'. '<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
<string name="noon">"poledne"</string>
<string name="Noon">"Poledne"</string>
<string name="midnight">"půlnoc"</string>
<string name="Midnight">"Půlnoc"</string>
- <!-- no translation found for month_day (5565829181417740906) -->
+ <!-- no translation found for month_day (3693060561170538204) -->
<skip />
- <!-- no translation found for month (7026169712234774086) -->
+ <!-- no translation found for month (1976700695144952053) -->
<skip />
<string name="month_day_year">"<xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for month_year (9219019380312413367) -->
+ <!-- no translation found for month_year (2106203387378728384) -->
<skip />
<string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="DAY">%-d</xliff:g>. <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
@@ -590,11 +612,11 @@
<string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="abbrev_month_day_year">"<xliff:g id="DAY">%-d</xliff:g>. <xliff:g id="MONTH">%b</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
<skip />
- <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
<skip />
- <!-- no translation found for abbrev_month (3131032032850777433) -->
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
<skip />
<string name="day_of_week_long_sunday">"neděle"</string>
<string name="day_of_week_long_monday">"pondělí"</string>
@@ -679,6 +701,7 @@
<string name="paste">"Vložit"</string>
<string name="copyUrl">"Kopírovat adresu URL"</string>
<string name="inputMethod">"Metoda zadávání dat"</string>
+ <string name="addToDictionary">"Přidat „%s“ do slovníku"</string>
<string name="editTextMenuTitle">"Úpravy textu"</string>
<string name="low_internal_storage_view_title">"Málo paměti"</string>
<string name="low_internal_storage_view_text">"V telefonu zbývá málo místa pro ukládání dat."</string>
@@ -686,6 +709,7 @@
<string name="cancel">"Zrušit"</string>
<string name="yes">"OK"</string>
<string name="no">"Zrušit"</string>
+ <string name="dialog_alert_title">"Upozornění"</string>
<string name="capital_on">"ZAPNUTO"</string>
<string name="capital_off">"VYPNOUT"</string>
<string name="whichApplication">"Dokončit akci pomocí aplikace"</string>
@@ -698,8 +722,8 @@
<string name="aerr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> byl neočekávaně ukončen. Opakujte prosím akci."</string>
<string name="anr_title">"Omlouváme se"</string>
<string name="anr_activity_application">"Činnost <xliff:g id="ACTIVITY">%1$s</xliff:g> (v aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>) neodpovídá."</string>
- <string name="anr_activity_process">"Činnost <xliff:g id="ACTIVITY">%1$s</xliff:g> (v procesu <xliff:g id="PROCESS">%2$s</xliff:g>) neodpovídá."</string>
- <string name="anr_application_process">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (v procesu <xliff:g id="PROCESS">%2$s</xliff:g>) neodpovídá."</string>
+ <string name="anr_activity_process">"Služba <xliff:g id="ACTIVITY">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>) nereaguje."</string>
+ <string name="anr_application_process">"Služba <xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>) nereaguje."</string>
<string name="anr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> neodpovídá."</string>
<string name="force_close">"Ukončit aplikaci"</string>
<string name="wait">"Počkat"</string>
@@ -709,7 +733,7 @@
<string name="volume_music">"Hlasitost médií"</string>
<string name="volume_music_hint_playing_through_bluetooth">"Přehrávání pomocí rozhraní Bluetooth"</string>
<string name="volume_call">"Hlasitost hovoru"</string>
- <string name="volume_call_hint_playing_through_bluetooth">"Přehrávání pomocí rozhraní Bluetooth"</string>
+ <string name="volume_bluetooth_call">"Hlasitost příchozích hovorů při připojení Bluetooth"</string>
<string name="volume_alarm">"Hlasitost upozornění a budíku"</string>
<string name="volume_notification">"Hlasitost oznámení"</string>
<string name="volume_unknown">"Hlasitost"</string>
@@ -719,11 +743,11 @@
<string name="ringtone_picker_title">"Vyzváněcí tóny"</string>
<string name="ringtone_unknown">"Neznámý vyzváněcí tón"</string>
<plurals name="wifi_available">
- <item quantity="one">"Je k dispozici síť WiFi."</item>
+ <item quantity="one">"K dispozici je síť WiFi."</item>
<item quantity="other">"Jsou k dispozici sítě WiFi."</item>
</plurals>
<plurals name="wifi_available_detailed">
- <item quantity="one">"Je k dispozici veřejná síť WiFi"</item>
+ <item quantity="one">"K dispozici je veřejná síť WiFi"</item>
<item quantity="other">"Jsou k dispozici veřejné sítě WiFi"</item>
</plurals>
<string name="select_character">"Vkládání znaků"</string>
@@ -745,8 +769,47 @@
<string name="usb_storage_error_message">"Při používání vaší karty SD jako úložiště USB došlo k problému."</string>
<string name="usb_storage_notification_title">"USB připojeno"</string>
<string name="usb_storage_notification_message">"Vyberte, chcete-li kopírovat soubory do nebo z počítače."</string>
+ <string name="usb_storage_stop_notification_title">"Vypnout úložiště USB"</string>
+ <string name="usb_storage_stop_notification_message">"Vyberte, chcete-li vypnout úložiště USB."</string>
+ <string name="usb_storage_stop_title">"Vypnout úložiště USB"</string>
+ <string name="usb_storage_stop_message">"Před vypnutím úložiště USB se přesvědčte, zda byl hostitel USB odpojen. Úložiště USB vypnete volbou Vypnout."</string>
+ <string name="usb_storage_stop_button_mount">"Vypnout"</string>
+ <string name="usb_storage_stop_button_unmount">"Zrušit"</string>
+ <string name="usb_storage_stop_error_message">"Při vypínání úložiště USB došlo k problémům. Zkontrolujte, zda byl hostitel USB odpojen, a zkuste to znovu."</string>
+ <string name="extmedia_format_title">"Formátovat kartu SD"</string>
+ <string name="extmedia_format_message">"Opravdu chcete kartu SD naformátovat? Všechna data na kartě budou ztracena."</string>
+ <string name="extmedia_format_button_format">"Formátovat"</string>
<string name="select_input_method">"Výběr metody zadávání dat"</string>
- <string name="fast_scroll_alphabet">"AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
- <string name="fast_scroll_numeric_alphabet">"0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
- <string name="candidates_style"><font fgcolor="#ff000000" bgcolor="#ff8080ff"><u>"kandidáti"</u>"u&gt;"</font></string>
+ <string name="fast_scroll_alphabet">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
+ <string name="candidates_style"><u>"kandidáti"</u></string>
+ <string name="ext_media_checking_notification_title">"Příprava karty SD"</string>
+ <string name="ext_media_checking_notification_message">"Kontrola chyb"</string>
+ <string name="ext_media_nofs_notification_title">"Prázdná karta SD"</string>
+ <string name="ext_media_nofs_notification_message">"Karta SD je prázdná nebo používá nepodporovaný systém souborů."</string>
+ <string name="ext_media_unmountable_notification_title">"Poškozená karta SD"</string>
+ <string name="ext_media_unmountable_notification_message">"Karta SD je poškozena. Pravděpodobně ji bude nutné znovu formátovat."</string>
+ <string name="ext_media_badremoval_notification_title">"Karta SD byla neočekávaně odebrána"</string>
+ <string name="ext_media_badremoval_notification_message">"Chcete-li zabránit ztrátě dat, kartu SD před odebráním odpojte."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Kartu SD je možné bezpečně odebrat"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Kartu SD lze nyní bezpečně vyjmout."</string>
+ <string name="ext_media_nomedia_notification_title">"Karta SD byla odstraněna"</string>
+ <string name="ext_media_nomedia_notification_message">"Karta SD byla odebrána. Chcete-li zvětšit úložiště svého zařízení, vložte kartu SD."</string>
+ <string name="activity_list_empty">"Nebyly nalezeny žádné odpovídající aktivity."</string>
+ <string name="permlab_pkgUsageStats">"aktualizovat statistiku použití součástí"</string>
+ <string name="permdesc_pkgUsageStats">"Umožňuje změnu shromážděných statistických údajů o použití součástí. Není určeno pro běžné aplikace."</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index a8115a8..cda8cbc 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -89,7 +89,7 @@
<string name="low_memory">"Telefonspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
<string name="me">"Eigene"</string>
<string name="power_dialog">"Telefonoptionen"</string>
- <string name="silent_mode">"Lautlos"</string>
+ <string name="silent_mode">"Lautlos-Modus"</string>
<string name="turn_on_radio">"Funk einschalten"</string>
<string name="turn_off_radio">"Funk ausschalten"</string>
<string name="screen_lock">"Bildschirmsperre"</string>
@@ -101,9 +101,17 @@
<string name="global_action_lock">"Bildschirmsperre"</string>
<string name="global_action_power_off">"Ausschalten"</string>
<string name="global_action_toggle_silent_mode">"Lautlos"</string>
- <string name="global_action_silent_mode_on_status">"Ton ist ausgeschaltet."</string>
- <string name="global_action_silent_mode_off_status">"Ton ist EINGESCHALTET"</string>
+ <string name="global_action_silent_mode_on_status">"Ton ist bereits AUS"</string>
+ <string name="global_action_silent_mode_off_status">"Ton ist momentan AN"</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
<string name="safeMode">"Abgesicherter Modus"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
<string name="permgrouplab_costMoney">"Kostenpflichtige Dienste"</string>
<string name="permgroupdesc_costMoney">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen."</string>
<string name="permgrouplab_messages">"Ihre Nachrichten"</string>
@@ -262,6 +270,8 @@
<string name="permdesc_reboot">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen."</string>
<string name="permlab_mount_unmount_filesystems">"Dateisysteme bereitstellen oder Bereitstellung aufheben"</string>
<string name="permdesc_mount_unmount_filesystems">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Speicherplätze bereitzustellen oder die Bereitstellung aufzuheben."</string>
+ <string name="permlab_mount_format_filesystems">"Externen Speicher formatieren"</string>
+ <string name="permdesc_mount_format_filesystems">"Erlaubt der Anwendung, austauschbaren Speicher zu formatieren."</string>
<string name="permlab_vibrate">"Vibrationsalarm steuern"</string>
<string name="permdesc_vibrate">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern."</string>
<string name="permlab_flashlight">"Lichtanzeige steuern"</string>
@@ -276,6 +286,8 @@
<string name="permdesc_locationUpdates">"Ermöglicht die Aktivierung/Deaktivierung der Radio-Benachrichtigungen über Standort-Updates. Nicht für normale Anwendungen vorgesehen."</string>
<string name="permlab_checkinProperties">"Auf Check-In-Eigenschaften zugreifen"</string>
<string name="permdesc_checkinProperties">"Ermöglicht den Schreib-/Lesezugriff auf vom Check-In-Service hochgeladene Elemente. Nicht für normale Anwendungen vorgesehen."</string>
+ <string name="permlab_bindGadget">"Gadgets auswählen"</string>
+ <string name="permdesc_bindGadget">"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."</string>
<string name="permlab_modifyPhoneState">"Telefonstatus ändern"</string>
<string name="permdesc_modifyPhoneState">"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."</string>
<string name="permlab_readPhoneState">"Telefonstatus lesen"</string>
@@ -304,6 +316,8 @@
<string name="permdesc_writeApnSettings">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern."</string>
<string name="permlab_changeNetworkState">"Netzwerkkonnektivität ändern"</string>
<string name="permdesc_changeNetworkState">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern."</string>
+ <string name="permlab_changeBackgroundDataSetting">"Einstellung zur Verwendung von Hintergrunddaten ändern"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Ermöglicht einer Anwendung, die Einstellung der Verwendung von Hintergrunddaten zu ändern."</string>
<string name="permlab_accessWifiState">"WLAN-Status anzeigen"</string>
<string name="permdesc_accessWifiState">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen."</string>
<string name="permlab_changeWifiState">"WLAN-Status ändern"</string>
@@ -324,14 +338,10 @@
<string name="permdesc_subscribedFeedsRead">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen."</string>
<string name="permlab_subscribedFeedsWrite">"Abonnierte Feeds schreiben"</string>
<string name="permdesc_subscribedFeedsWrite">"Ermöglicht einer Anwendung, Änderungen an den kürzlich synchronisierten Feeds vorzunehmen. Schädliche Anwendungen könnten so Ihre synchronisierten Feeds ändern."</string>
- <!-- no translation found for permlab_readDictionary (432535716804748781) -->
- <skip />
- <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
- <skip />
- <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
- <skip />
- <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
- <skip />
+ <string name="permlab_readDictionary">"Nutzerdefiniertes Wörterbuch lesen"</string>
+ <string name="permdesc_readDictionary">"Erlaubt einer Anwendung, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat."</string>
+ <string name="permlab_writeDictionary">"in nutzerdefiniertes Wörterbuch schreiben"</string>
+ <string name="permdesc_writeDictionary">"Erlaubt einer Anwendung, neue Wörter in das Wörterbuch des Nutzers zu schreiben."</string>
<string-array name="phoneTypes">
<item>"Privat"</item>
<item>"Mobil"</item>
@@ -381,13 +391,14 @@
<string name="emergency_call_dialog_number_for_display">"Notrufnummer"</string>
<string name="lockscreen_carrier_default">"(kein Dienst)"</string>
<string name="lockscreen_screen_locked">"Display gesperrt."</string>
- <string name="lockscreen_instructions_when_pattern_enabled">"Drücken Sie auf die \"Menü\", um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Drücken Sie auf \"Menü\", um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
<string name="lockscreen_instructions_when_pattern_disabled">"Drücken Sie zum Entsperren auf \"Menü\"."</string>
<string name="lockscreen_pattern_instructions">"Schema für Entsperrung zeichnen"</string>
<string name="lockscreen_emergency_call">"Notruf"</string>
<string name="lockscreen_pattern_correct">"Korrekt!"</string>
<string name="lockscreen_pattern_wrong">"Tut uns leid. Versuchen Sie es noch einmal."</string>
- <string name="lockscreen_plugged_in">"Wird aufgeladen (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
<string name="lockscreen_low_battery">"Bitte Ladegerät anschließen"</string>
<string name="lockscreen_missing_sim_message_short">"Keine SIM-Karte."</string>
<string name="lockscreen_missing_sim_message">"Keine SIM-Karte im Telefon."</string>
@@ -410,15 +421,15 @@
<string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
<string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <!-- no translation found for hour_ampm (7618670480400517084) -->
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
<skip />
- <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
<skip />
<string name="status_bar_clear_all_button">"Benachrichtigungen löschen"</string>
<string name="status_bar_no_notifications_title">"Keine Benachrichtigungen"</string>
<string name="status_bar_ongoing_events_title">"Aktuell"</string>
<string name="status_bar_latest_events_title">"Benachrichtigungen"</string>
- <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
<skip />
<string name="battery_status_charging">"Wird aufgeladen..."</string>
<string name="battery_low_title">"Ladegerät anschließen"</string>
@@ -428,12 +439,9 @@
<string name="factorytest_not_system">"Die Aktion FACTORY_TEST wird nur für unter \"/system/app\" gespeicherte Pakete unterstützt."</string>
<string name="factorytest_no_action">"Es wurden kein Paket mit der Aktion FACTORY_TEST gefunden."</string>
<string name="factorytest_reboot">"Neu booten"</string>
- <!-- no translation found for js_dialog_title (8143918455087008109) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
- <skip />
+ <string name="js_dialog_title">"Die Seite auf \'<xliff:g id="TITLE">%s</xliff:g>\' sagt:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Von dieser Seite navigieren?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wählen Sie \"OK\", um fortzufahren, oder wählen Sie \"Abbrechen\", um auf der aktuellen Seite zu bleiben."</string>
<string name="save_password_label">"Bestätigen"</string>
<string name="save_password_message">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
<string name="save_password_notnow">"Nicht jetzt"</string>
@@ -484,22 +492,38 @@
<item quantity="one">"morgen"</item>
<item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
</plurals>
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"vor 1 Sekunde"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"vor 1 Minute"</item>
+ <item quantity="other">"vor <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"Vor 1 Stunde"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"Gestern"</item>
+ <item quantity="other">"Vor <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"in 1 Sekunde"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Sekunden"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"in 1 Minute"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Minuten"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"in 1 Stunde"</item>
+ <item quantity="other">"In <xliff:g id="COUNT">%d</xliff:g> Stunden"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"morgen"</item>
+ <item quantity="other">"in <xliff:g id="COUNT">%d</xliff:g> Tagen"</item>
+ </plurals>
<string name="preposition_for_date">"am %s"</string>
<string name="preposition_for_time">"am %s"</string>
<string name="preposition_for_year">"in %s"</string>
@@ -530,8 +554,7 @@
<string name="VideoView_error_title">"Video kann nicht wiedergegeben werden."</string>
<string name="VideoView_error_text_unknown">"Dieses Video kann leider nicht abgespielt werden."</string>
<string name="VideoView_error_button">"OK"</string>
- <!-- no translation found for am (4885350190794996052) -->
- <skip />
+ <string name="am">"AM"</string>
<string name="pm">".."</string>
<string name="numeric_date">"<xliff:g id="DAY">%d</xliff:g>/<xliff:g id="MONTH">%m</xliff:g>/<xliff:g id="YEAR">%Y</xliff:g>"</string>
<string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
@@ -542,27 +565,25 @@
<string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
- <!-- no translation found for date_time (6104442718633642836) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
- <string name="full_date_month_first">"<xliff:g id="DAY">dd</xliff:g>. <xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="full_date_day_first">"<xliff:g id="DAY">dd</xliff:g>. <xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_month_first">"<xliff:g id="DAY">dd</xliff:g>. <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g>. <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
- <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="DAY">d</xliff:g>'. '<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>'. '<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="DAY">d</xliff:g>'. '<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>'. '<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
<string name="noon">"Mittag"</string>
<string name="Noon">"Mittag"</string>
<string name="midnight">"Mitternacht"</string>
<string name="Midnight">"Mitternacht"</string>
- <!-- no translation found for month_day (5565829181417740906) -->
+ <!-- no translation found for month_day (3693060561170538204) -->
<skip />
- <!-- no translation found for month (7026169712234774086) -->
+ <!-- no translation found for month (1976700695144952053) -->
<skip />
<string name="month_day_year">"<xliff:g id="DAY">%-d</xliff:g>. <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for month_year (9219019380312413367) -->
+ <!-- no translation found for month_year (2106203387378728384) -->
<skip />
<string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="DAY">%-d</xliff:g>. <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
@@ -591,11 +612,11 @@
<string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="abbrev_month_day_year">"<xliff:g id="DAY">%-d</xliff:g>. <xliff:g id="MONTH">%b</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
<skip />
- <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
<skip />
- <!-- no translation found for abbrev_month (3131032032850777433) -->
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
<skip />
<string name="day_of_week_long_sunday">"Sonntag"</string>
<string name="day_of_week_long_monday">"Montag"</string>
@@ -680,6 +701,7 @@
<string name="paste">"Einfügen"</string>
<string name="copyUrl">"URL kopieren"</string>
<string name="inputMethod">"Eingabemethode"</string>
+ <string name="addToDictionary">"\"%s\" dem Wörterbuch hinzufügen"</string>
<string name="editTextMenuTitle">"Text bearbeiten"</string>
<string name="low_internal_storage_view_title">"Geringer Speicher"</string>
<string name="low_internal_storage_view_text">"Kaum noch freier Telefonspeicher verfügbar."</string>
@@ -687,6 +709,7 @@
<string name="cancel">"Abbrechen"</string>
<string name="yes">"OK"</string>
<string name="no">"Abbrechen"</string>
+ <string name="dialog_alert_title">"Achtung"</string>
<string name="capital_on">"EIN"</string>
<string name="capital_off">"AUS"</string>
<string name="whichApplication">"Aktion beenden mit"</string>
@@ -709,8 +732,8 @@
<string name="volume_ringtone">"Klingeltonlautstärke"</string>
<string name="volume_music">"Medienlautstärke"</string>
<string name="volume_music_hint_playing_through_bluetooth">"Wiedergabe durch Bluetooth"</string>
- <string name="volume_call">"Lautstärke bei eingehendem Anruf"</string>
- <string name="volume_call_hint_playing_through_bluetooth">"Wiedergabe durch Bluetooth"</string>
+ <string name="volume_call">"Hörerlautstärke"</string>
+ <string name="volume_bluetooth_call">"Lautstärke bei eingehendem Bluetooth-Anruf"</string>
<string name="volume_alarm">"Lautstärke für Alarm"</string>
<string name="volume_notification">"Benachrichtigungslautstärke"</string>
<string name="volume_unknown">"Lautstärke"</string>
@@ -746,8 +769,47 @@
<string name="usb_storage_error_message">"Bei der Verwendung Ihrer SD-Karte als USB-Speicher ist ein Problem aufgetreten."</string>
<string name="usb_storage_notification_title">"USB-Verbindung"</string>
<string name="usb_storage_notification_message">"Wählen Sie die Dateien aus, die von Ihrem oder auf Ihren Computer kopiert werden sollen."</string>
+ <string name="usb_storage_stop_notification_title">"USB-Speicher deaktivieren"</string>
+ <string name="usb_storage_stop_notification_message">"Auswählen, um USB-Speicher zu deaktivieren."</string>
+ <string name="usb_storage_stop_title">"USB-Speicher deaktivieren"</string>
+ <string name="usb_storage_stop_message">"Bevor Sie den USB-Speicher deaktivieren, stellen Sie sicher, dass Sie Ihn vom USB-Host getrennt haben. Wählen Sie \"Deaktivieren\", um den USB-Speicher zu deaktivieren."</string>
+ <string name="usb_storage_stop_button_mount">"Ausschalten"</string>
+ <string name="usb_storage_stop_button_unmount">"Abbrechen"</string>
+ <string name="usb_storage_stop_error_message">"Wir haben beim Deaktivieren des USB-Speichers ein Problem festgestellt. Überprüfen Sie, ob Sie den USB-Host getrennt haben, und versuchen Sie es erneut."</string>
+ <string name="extmedia_format_title">"SD-Karte formatieren"</string>
+ <string name="extmedia_format_message">"Möchten Sie die SD-Karte wirklich formatieren? Alle Daten auf Ihrer Karte gehen dann verloren."</string>
+ <string name="extmedia_format_button_format">"Format"</string>
<string name="select_input_method">"Eingabemethode auswählen"</string>
- <string name="fast_scroll_alphabet">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style"><font fgcolor="#ff000000" bgcolor="#ff8080ff"><u>"Kandidaten"</u>"u&gt;"</font></string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"Kandidaten"</u></string>
+ <string name="ext_media_checking_notification_title">"SD-Karte wird vorbereitet"</string>
+ <string name="ext_media_checking_notification_message">"Nach Fehlern wird gesucht"</string>
+ <string name="ext_media_nofs_notification_title">"SD-Karte leer"</string>
+ <string name="ext_media_nofs_notification_message">"Die SD-Karte ist leer oder verwendet ein Dateisystem, das nicht unterstützt wird."</string>
+ <string name="ext_media_unmountable_notification_title">"Beschädigte SD-Karte"</string>
+ <string name="ext_media_unmountable_notification_message">"Die SD-Karte ist beschädigt. Sie müssen Ihre Karte eventuell neu formatieren."</string>
+ <string name="ext_media_badremoval_notification_title">"SD-Karte unerwartet entfernt"</string>
+ <string name="ext_media_badremoval_notification_message">"SD-Karte vor dem Entnehmen trennen, um Datenverlust zu vermeiden."</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD-Karte\nkann entfernt werden."</string>
+ <string name="ext_media_safe_unmount_notification_message">"Die SD-Karte kann jetzt entfernt werden."</string>
+ <string name="ext_media_nomedia_notification_title">"SD-Karte entfernt"</string>
+ <string name="ext_media_nomedia_notification_message">"Die SD-Karte wurde entfernt. Legen Sie eine neue SD-Karte ein, um den Speicherplatz Ihres Geräts zu erweitern."</string>
+ <string name="activity_list_empty">"Keine passenden Aktivitäten gefunden"</string>
+ <string name="permlab_pkgUsageStats">"Nutzungsstatistik der Komponente aktualisieren"</string>
+ <string name="permdesc_pkgUsageStats">"Ermöglicht die Änderung von gesammelten Nutzungsstatistiken der Komponente. Nicht für normale Anwendungen vorgesehen."</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index b9df983..9da879b 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -710,7 +710,7 @@
<!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
<skip />
<!-- no translation found for status_bar_time_format (2168573805413119180) -->
- <skip />
+ <string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<!-- no translation found for hour_minute_ampm (1850330605794978742) -->
<skip />
<!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
@@ -861,34 +861,38 @@
<skip />
<!-- no translation found for pm (7206933220587555766) -->
<skip />
- <!-- no translation found for numeric_date (5120078478872821100) -->
+ <!-- from values-de/strings.xml and removal of all the german craziyness-->
<skip />
+ <!-- no translation found for numeric_date (5120078478872821100) -->
+ <string name="numeric_date">"<xliff:g id="DAY">%d</xliff:g>/<xliff:g id="MONTH">%m</xliff:g>/<xliff:g id="YEAR">%Y</xliff:g>"</string>
<!-- no translation found for wday1_date1_time1_wday2_date2_time2 (7066878981949584861) -->
- <skip />
+ <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
<!-- no translation found for wday1_date1_wday2_date2 (8671068747172261907) -->
+ <string name="wday1_date1_wday2_date2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>"</string>
+ <!-- no translation found for numeric_date (5537215108967329745) -->
<skip />
<!-- no translation found for date1_time1_date2_time2 (3645498975775629615) -->
- <skip />
+ <string name="date1_time1_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
<!-- no translation found for date1_date2 (377057563556488062) -->
- <skip />
+ <string name="date1_date2">"<xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>"</string>
<!-- no translation found for time1_time2 (3173474242109288305) -->
- <skip />
+ <string name="time1_time2">"<xliff:g id="TIME1">%1$s</xliff:g> – <xliff:g id="TIME2">%2$s</xliff:g>"</string>
<!-- no translation found for time_wday_date (8928955562064570313) -->
- <skip />
+ <string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<!-- no translation found for wday_date (8794741400546136975) -->
- <skip />
+ <string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<!-- no translation found for time_date (1922644512833014496) -->
- <skip />
+ <string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<!-- no translation found for time_wday (1422050241301754712) -->
<skip />
<!-- no translation found for full_date_month_first (6011143962222283357) -->
<skip />
<!-- no translation found for full_date_day_first (8621594762705478189) -->
- <skip />
+ <string name="full_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
<!-- no translation found for medium_date_month_first (48990963718825728) -->
<skip />
<!-- no translation found for medium_date_day_first (2898992016440387123) -->
- <skip />
+ <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
<!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
<skip />
<!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
@@ -902,71 +906,73 @@
<!-- no translation found for Midnight (1260172107848123187) -->
<skip />
<!-- no translation found for month_day (3356633704511426364) -->
- <skip />
+ <string name="month_day">"<xliff:g id="day" example="9">%-d</xliff:g> <xliff:g id="month" example="October">%B</xliff:g>"</string>
<!-- no translation found for month (3017405760734206414) -->
<skip />
<!-- no translation found for month_day_year (2435948225709176752) -->
- <skip />
+ <string name="month_day_year">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
<!-- no translation found for month_year (6228414124777343135) -->
<skip />
<!-- no translation found for time_of_day (8375993139317154157) -->
- <skip />
+ <string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<!-- no translation found for date_and_time (9197690194373107109) -->
<skip />
<!-- no translation found for same_year_md1_md2 (9199324363135981317) -->
- <skip />
+ <string name="same_year_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<!-- no translation found for same_year_wday1_md1_wday2_md2 (6006392413355305178) -->
- <skip />
+ <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+ <!-- no translation found for date_and_time (353898423108629694) -->
+ <string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
<!-- no translation found for same_year_mdy1_mdy2 (1576657593937827090) -->
- <skip />
+ <string name="same_year_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR">%9$s</xliff:g>"</string>
<!-- no translation found for same_year_wday1_mdy1_wday2_mdy2 (9135935796468891580) -->
- <skip />
+ <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR">%9$s</xliff:g>"</string>
<!-- no translation found for same_year_md1_time1_md2_time2 (2172964106375558081) -->
- <skip />
+ <string name="same_year_md1_time1_md2_time2">" <xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_year_wday1_md1_time1_wday2_md2_time2 (1702879534101786310) -->
- <skip />
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_year_mdy1_time1_mdy2_time2 (2476443311723358767) -->
- <skip />
+ <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_year_wday1_mdy1_time1_wday2_mdy2_time2 (1564837340334069879) -->
- <skip />
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for numeric_md1_md2 (8908376522875100300) -->
- <skip />
+ <string name="numeric_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<!-- no translation found for numeric_wday1_md1_wday2_md2 (3239690882018292077) -->
- <skip />
+ <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<!-- no translation found for numeric_mdy1_mdy2 (8883797176939233525) -->
- <skip />
+ <string name="numeric_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
<!-- no translation found for numeric_wday1_mdy1_wday2_mdy2 (4150475769255828954) -->
- <skip />
+ <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
<!-- no translation found for numeric_md1_time1_md2_time2 (3624746590607741419) -->
- <skip />
+ <string name="numeric_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for numeric_wday1_md1_time1_wday2_md2_time2 (4258040955467298134) -->
- <skip />
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for numeric_mdy1_time1_mdy2_time2 (3598215409314517987) -->
- <skip />
+ <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for numeric_wday1_mdy1_time1_wday2_mdy2_time2 (264076937155877259) -->
- <skip />
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_month_md1_md2 (2393563617438036111) -->
- <skip />
+ <string name="same_month_md1_md2">"<xliff:g id="DAY1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="DAY2" example="3">%8$s</xliff:g> <xliff:g id="MONTH1" example="Oct">%2$s</xliff:g>"</string>
<!-- no translation found for same_month_wday1_md1_wday2_md2 (1208946773794057819) -->
- <skip />
+ <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<!-- no translation found for same_month_mdy1_mdy2 (3713236637869030492) -->
- <skip />
+ <string name="same_month_mdy1_mdy2">"<xliff:g id="DAY1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="DAY2" example="3">%8$s</xliff:g> <xliff:g id="MONTH1" example="Oct">%2$s</xliff:g> <xliff:g id="YEAR2" example="2007">%9$s</xliff:g>"</string>
<!-- no translation found for same_month_wday1_mdy1_wday2_mdy2 (389638922479870472) -->
- <skip />
+ <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
<!-- no translation found for same_month_md1_time1_md2_time2 (7477075526337542685) -->
- <skip />
+ <string name="same_month_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_month_wday1_md1_time1_wday2_md2_time2 (3516978303779391173) -->
- <skip />
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_month_mdy1_time1_mdy2_time2 (7320410992514057310) -->
- <skip />
+ <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_month_wday1_mdy1_time1_wday2_mdy2_time2 (1332950588774239228) -->
- <skip />
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for abbrev_month_day_year (5767271534015320250) -->
- <skip />
+ <string name="abbrev_month_day_year">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%b</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
<!-- no translation found for abbrev_month_year (8058929633673942490) -->
<skip />
<!-- no translation found for abbrev_month_day (458867920693482757) -->
- <skip />
+ <string name="abbrev_month_day">"<xliff:g id="day" example="31">%-d</xliff:g> <xliff:g id="month" example="Oct">%b</xliff:g>"</string>
<!-- no translation found for abbrev_month (1674509986330181349) -->
<skip />
<!-- no translation found for day_of_week_long_sunday (9057662850446501884) -->
@@ -1112,9 +1118,9 @@
<!-- no translation found for month_shortest_december (6213739417171334040) -->
<skip />
<!-- no translation found for elapsed_time_short_format_mm_ss (1294409362352514646) -->
- <skip />
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<!-- no translation found for elapsed_time_short_format_h_mm_ss (2997059666628785039) -->
- <skip />
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<!-- no translation found for selectAll (691691810023908884) -->
<skip />
<!-- no translation found for cut (5845613239192595662) -->
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index fa1710d..d9cf3d5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1,765 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort">"B"</string>
- <string name="kilobyteShort">"KB"</string>
- <string name="megabyteShort">"MB"</string>
- <string name="gigabyteShort">"GB"</string>
- <string name="terabyteShort">"TB"</string>
- <string name="petabyteShort">"PB"</string>
- <string name="untitled">"&lt;untitled&gt;"</string>
- <string name="ellipsis">"…"</string>
- <string name="emptyPhoneNumber">"(No phone number)"</string>
- <string name="unknownName">"(Unknown)"</string>
- <string name="defaultVoiceMailAlphaTag">"Voicemail"</string>
- <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
- <string name="mmiError">"Connection problem or invalid MMI code."</string>
- <string name="serviceEnabled">"Service was enabled."</string>
- <string name="serviceEnabledFor">"Service was enabled for:"</string>
- <string name="serviceDisabled">"Service has been disabled."</string>
- <string name="serviceRegistered">"Registration was successful."</string>
- <string name="serviceErased">"Erasure was successful."</string>
- <string name="passwordIncorrect">"Incorrect password."</string>
- <string name="mmiComplete">"MMI complete."</string>
- <string name="badPin">"The old PIN you typed is not correct."</string>
- <string name="badPuk">"The PUK you typed is not correct."</string>
- <string name="mismatchPin">"The PINs you entered do not match."</string>
- <string name="invalidPin">"Type a PIN that is 4 to 8 numbers."</string>
- <!-- no translation found for needPuk (4788728144863892764) -->
- <skip />
- <string name="needPuk2">"Type PUK2 to unblock SIM card."</string>
- <string name="ClipMmi">"Incoming Caller ID"</string>
- <string name="ClirMmi">"Outgoing Caller ID"</string>
- <string name="CfMmi">"Call forwarding"</string>
- <string name="CwMmi">"Call waiting"</string>
- <string name="BaMmi">"Call barring"</string>
- <string name="PwdMmi">"Password change"</string>
- <string name="PinMmi">"PIN change"</string>
- <string name="CLIRDefaultOnNextCallOn">"Caller ID defaults to restricted. Next call: Restricted"</string>
- <string name="CLIRDefaultOnNextCallOff">"Caller ID defaults to restricted. Next call: Not restricted"</string>
- <string name="CLIRDefaultOffNextCallOn">"Caller ID defaults to not restricted. Next call: Restricted"</string>
- <string name="CLIRDefaultOffNextCallOff">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
- <string name="serviceNotProvisioned">"Service not provisioned."</string>
- <string name="CLIRPermanent">"The caller ID setting cannot be changed."</string>
- <string name="serviceClassVoice">"Voice"</string>
- <string name="serviceClassData">"Data"</string>
- <string name="serviceClassFAX">"FAX"</string>
- <string name="serviceClassSMS">"SMS"</string>
- <string name="serviceClassDataAsync">"Async"</string>
- <string name="serviceClassDataSync">"Sync"</string>
- <string name="serviceClassPacket">"Packet"</string>
- <string name="serviceClassPAD">"PAD"</string>
- <string name="cfTemplateNotForwarded">"{0}: Not forwarded"</string>
- <string name="cfTemplateForwarded">"{0}: {1}"</string>
- <string name="cfTemplateForwardedTime">"{0}: {1} after {2} seconds"</string>
- <string name="cfTemplateRegistered">"{0}: Not forwarded"</string>
- <string name="cfTemplateRegisteredTime">"{0}: Not forwarded"</string>
- <string name="httpErrorOk">"OK"</string>
- <string name="httpError">"The Web page contains an error."</string>
- <string name="httpErrorLookup">"The URL could not be found."</string>
- <string name="httpErrorUnsupportedAuthScheme">"The site authentication scheme is not supported."</string>
- <string name="httpErrorAuth">"Authentication was unsuccessful."</string>
- <string name="httpErrorProxyAuth">"Authentication via the proxy server was unsuccessful."</string>
- <string name="httpErrorConnect">"The connection to the server was unsuccessful."</string>
- <string name="httpErrorIO">"The server failed to communicate. Try again later."</string>
- <string name="httpErrorTimeout">"The connection to the server timed out."</string>
- <string name="httpErrorRedirectLoop">"The page contains too many server redirects."</string>
- <string name="httpErrorUnsupportedScheme">"The protocol is not supported."</string>
- <string name="httpErrorFailedSslHandshake">"A secure connection could not be established."</string>
- <string name="httpErrorBadUrl">"The page could not be opened because the URL is invalid."</string>
- <string name="httpErrorFile">"The file could not be accessed."</string>
- <string name="httpErrorFileNotFound">"The requested file was not found."</string>
- <string name="httpErrorTooManyRequests">"Too many requests are being processed. Try again later."</string>
- <string name="contentServiceSync">"Sync"</string>
- <string name="contentServiceSyncNotificationTitle">"Sync"</string>
- <string name="contentServiceTooManyDeletesNotificationDesc">"Too many %s deletes."</string>
- <string name="low_memory">"Phone storage is full! Delete some files to free space."</string>
- <string name="me">"Me"</string>
- <string name="power_dialog">"Phone options"</string>
- <string name="silent_mode">"Silent mode"</string>
- <string name="turn_on_radio">"Turn on wireless"</string>
- <string name="turn_off_radio">"Turn off wireless"</string>
- <string name="screen_lock">"Screen lock"</string>
- <string name="power_off">"Power off"</string>
- <string name="shutdown_progress">"Shutting down…"</string>
- <string name="shutdown_confirm">"Your phone will shut down."</string>
- <string name="no_recent_tasks">"No recent applications."</string>
- <string name="global_actions">"Phone options"</string>
- <string name="global_action_lock">"Screen lock"</string>
- <string name="global_action_power_off">"Power off"</string>
- <string name="global_action_toggle_silent_mode">"Silent mode"</string>
- <string name="global_action_silent_mode_on_status">"Sound is OFF"</string>
- <string name="global_action_silent_mode_off_status">"Sound is ON"</string>
- <string name="safeMode">"Safe mode"</string>
- <string name="permgrouplab_costMoney">"Cost you money"</string>
- <string name="permgroupdesc_costMoney">"Allow applications to do things that can cost you money."</string>
- <string name="permgrouplab_messages">"Your messages"</string>
- <string name="permgroupdesc_messages">"Read and write your SMS, e-mail, and other messages."</string>
- <string name="permgrouplab_personalInfo">"Your personal information"</string>
- <string name="permgroupdesc_personalInfo">"Direct access to your contacts and calendar stored on the phone."</string>
- <string name="permgrouplab_location">"Your location"</string>
- <string name="permgroupdesc_location">"Monitor your physical location"</string>
- <string name="permgrouplab_network">"Network communication"</string>
- <string name="permgroupdesc_network">"Allow applications to access various network features."</string>
- <string name="permgrouplab_accounts">"Your Google accounts"</string>
- <string name="permgroupdesc_accounts">"Access the available Google accounts."</string>
- <string name="permgrouplab_hardwareControls">"Hardware controls"</string>
- <string name="permgroupdesc_hardwareControls">"Direct access to hardware on the handset."</string>
- <string name="permgrouplab_phoneCalls">"Phone calls"</string>
- <string name="permgroupdesc_phoneCalls">"Monitor, record, and process phone calls."</string>
- <string name="permgrouplab_systemTools">"System tools"</string>
- <string name="permgroupdesc_systemTools">"Lower-level access and control of the system."</string>
- <string name="permgrouplab_developmentTools">"Development tools"</string>
- <string name="permgroupdesc_developmentTools">"Features only needed for application developers."</string>
- <string name="permlab_statusBar">"disable or modify status bar"</string>
- <string name="permdesc_statusBar">"Allows application to disable the status bar or add and remove system icons."</string>
- <string name="permlab_expandStatusBar">"expand/collapse status bar"</string>
- <string name="permdesc_expandStatusBar">"Allows application to expand or collapse the status bar."</string>
- <string name="permlab_processOutgoingCalls">"intercept outgoing calls"</string>
- <string name="permdesc_processOutgoingCalls">"Allows application to process outgoing calls and change the number to be dialed. Malicious applications may monitor, redirect, or prevent outgoing calls."</string>
- <string name="permlab_receiveSms">"receive SMS"</string>
- <string name="permdesc_receiveSms">"Allows application to receive and process SMS messages. Malicious applications may monitor your messages or delete them without showing them to you."</string>
- <string name="permlab_receiveMms">"receive MMS"</string>
- <string name="permdesc_receiveMms">"Allows application to receive and process MMS messages. Malicious applications may monitor your messages or delete them without showing them to you."</string>
- <string name="permlab_sendSms">"send SMS messages"</string>
- <string name="permdesc_sendSms">"Allows application to send SMS messages. Malicious applications may cost you money by sending messages without your confirmation."</string>
- <string name="permlab_readSms">"read SMS or MMS"</string>
- <string name="permdesc_readSms">"Allows application to read SMS messages stored on your phone or SIM card. Malicious applications may read your confidential messages."</string>
- <string name="permlab_writeSms">"edit SMS or MMS"</string>
- <string name="permdesc_writeSms">"Allows application to write to SMS messages stored on your phone or SIM card. Malicious applications may delete your messages."</string>
- <string name="permlab_receiveWapPush">"receive WAP"</string>
- <string name="permdesc_receiveWapPush">"Allows application to receive and process WAP messages. Malicious applications may monitor your messages or delete them without showing them to you."</string>
- <string name="permlab_getTasks">"retrieve running applications"</string>
- <string name="permdesc_getTasks">"Allows application to retrieve information about currently and recently running tasks. May allow malicious applications to discover private information about other applications."</string>
- <string name="permlab_reorderTasks">"reorder running applications"</string>
- <string name="permdesc_reorderTasks">"Allows an application to move tasks to the foreground and background. Malicious applications can force themselves to the front without your control."</string>
- <string name="permlab_setDebugApp">"enable application debugging"</string>
- <string name="permdesc_setDebugApp">"Allows an application to turn on debugging for another application. Malicious applications can use this to kill other applications."</string>
- <string name="permlab_changeConfiguration">"change your UI settings"</string>
- <string name="permdesc_changeConfiguration">"Allows an application to change the current configuration, such as the locale or overall font size."</string>
- <string name="permlab_restartPackages">"restart other applications"</string>
- <string name="permdesc_restartPackages">"Allows an application to forcibly restart other applications."</string>
- <string name="permlab_setProcessForeground">"keep from being stopped"</string>
- <!-- unknown placeholder BREAK in permdesc_setProcessForeground -->
- <skip />
- <string name="permlab_forceBack">"force application to close"</string>
- <string name="permdesc_forceBack">"Allows an application to force any activity that is in the foreground to close and go back. Should never be needed for normal applications."</string>
- <string name="permlab_dump">"retrieve system internal state"</string>
- <string name="permdesc_dump">"Allows application to retrieve internal state of the system. Malicious applications may retrieve a wide variety of private and secure information that they should never normally need."</string>
- <string name="permlab_addSystemService">"publish low-level services"</string>
- <string name="permdesc_addSystemService">"Allows application to publish its own low-level system services. Malicious applications may hijack the system, and steal or corrupt any data on it."</string>
- <string name="permlab_runSetActivityWatcher">"monitor and control all application launching"</string>
- <string name="permdesc_runSetActivityWatcher">"Allows an application to monitor and control how the system launches activities. Malicious applications may completely compromise the system. This permission is only needed for development, never for normal phone usage."</string>
- <string name="permlab_broadcastPackageRemoved">"send package removed broadcast"</string>
- <string name="permdesc_broadcastPackageRemoved">"Allows an application to broadcast a notification that an application package has been removed. Malicious applications may use this to kill any other running application."</string>
- <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
- <skip />
- <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
- <skip />
- <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
- <skip />
- <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
- <skip />
- <string name="permlab_setProcessLimit">"limit number of running processes"</string>
- <string name="permdesc_setProcessLimit">"Allows an application to control the maximum number of processes that will run. Never needed for normal applications."</string>
- <string name="permlab_setAlwaysFinish">"make all background applications close"</string>
- <string name="permdesc_setAlwaysFinish">"Allows an application to control whether activities are always finished as soon as they go to the background. Never needed for normal applications."</string>
- <string name="permlab_fotaUpdate">"automatically install system updates"</string>
- <string name="permdesc_fotaUpdate">"Allows an application to receive notifications about pending system updates and trigger their installation. Malicious applications may use this to corrupt the system with unauthorized updates, or generally interfere with the update process."</string>
- <string name="permlab_batteryStats">"modify battery statistics"</string>
- <string name="permdesc_batteryStats">"Allows the modification of collected battery statistics. Not for use by normal applications."</string>
- <string name="permlab_internalSystemWindow">"display unauthorized windows"</string>
- <string name="permdesc_internalSystemWindow">"Allows the creation of windows that are intended to be used by the internal system user interface. Not for use by normal applications."</string>
- <string name="permlab_systemAlertWindow">"display system-level alerts"</string>
- <string name="permdesc_systemAlertWindow">"Allows an application to show system alert windows. Malicious applications can take over the entire screen of the phone."</string>
- <string name="permlab_setAnimationScale">"modify global animation speed"</string>
- <string name="permdesc_setAnimationScale">"Allows an application to change the global animation speed (faster or slower animations) at any time."</string>
- <string name="permlab_manageAppTokens">"manage application tokens"</string>
- <string name="permdesc_manageAppTokens">"Allows applications to create and manage their own tokens, bypassing their normal Z-ordering. Should never be needed for normal applications."</string>
- <string name="permlab_injectEvents">"press keys and control buttons"</string>
- <string name="permdesc_injectEvents">"Allows an application to deliver its own input events (key presses, etc.) to other applications. Malicious applications can use this to take over the phone."</string>
- <string name="permlab_readInputState">"record what you type and actions you take"</string>
- <string name="permdesc_readInputState">"Allows applications to watch the keys you press even when interacting with another application (such as entering a password). Should never be needed for normal applications."</string>
- <string name="permlab_setOrientation">"change screen orientation"</string>
- <string name="permdesc_setOrientation">"Allows an application to change the rotation of the screen at any time. Should never be needed for normal applications."</string>
- <string name="permlab_signalPersistentProcesses">"send Linux signals to applications"</string>
- <string name="permdesc_signalPersistentProcesses">"Allows application to request that the supplied signal be sent to all persistent processes."</string>
- <string name="permlab_persistentActivity">"make application always run"</string>
- <!-- unknown placeholder BREAK in permdesc_persistentActivity -->
- <skip />
- <string name="permlab_deletePackages">"delete applications"</string>
- <string name="permdesc_deletePackages">"Allows an application to delete Android packages. Malicious applications can use this to delete important applications."</string>
- <string name="permlab_clearAppUserData">"delete other applications data"</string>
- <string name="permdesc_clearAppUserData">"Allows an application to clear user data."</string>
- <string name="permlab_deleteCacheFiles">"delete other applications cache"</string>
- <string name="permdesc_deleteCacheFiles">"Allows an application to delete cache files."</string>
- <string name="permlab_getPackageSize">"measure application storage space"</string>
- <string name="permdesc_getPackageSize">"Allows an application to retrieve its code, data, and cache sizes"</string>
- <string name="permlab_installPackages">"directly install applications"</string>
- <string name="permdesc_installPackages">"Allows an application to install new or updated Android packages. Malicious applications can use this to add new applications with arbitrarily powerful permissions."</string>
- <string name="permlab_clearAppCache">"delete all application cache data"</string>
- <string name="permdesc_clearAppCache">"Allows an application to free phone storage by deleting files in application cache directory. Access is very restricted usually to system process."</string>
- <string name="permlab_readLogs">"read system log files"</string>
- <!-- unknown placeholder BREAK_0 in permdesc_readLogs -->
- <skip />
- <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
- <skip />
- <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
- <skip />
- <string name="permlab_changeComponentState">"enable or disable application components"</string>
- <string name="permdesc_changeComponentState">"Allows an application to change whether a component of another application is enabled or not. Malicious applications can use this to disable important phone capabilities. Care must be used with permission, as it is possible to get application components into an unusable, inconsistant, or unstable state."</string>
- <string name="permlab_setPreferredApplications">"set preferred applications"</string>
- <string name="permdesc_setPreferredApplications">"Allows an application to modify your preferred applications. This can allow malicious applications to silently change the applications that are run, spoofing your existing applications to collect private data from you."</string>
- <string name="permlab_writeSettings">"modify global system settings"</string>
- <string name="permdesc_writeSettings">"Allows an application to modify the systems settings data. Malicious applications can corrupt your systems configuration."</string>
- <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
- <skip />
- <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
- <skip />
- <!-- no translation found for permlab_writeGservices (296370685945777755) -->
- <skip />
- <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
- <skip />
- <string name="permlab_receiveBootCompleted">"automatically start at boot"</string>
- <string name="permdesc_receiveBootCompleted">"Allows an application to have itself started as soon as the system has finished booting. This can make it take longer to start the phone and allow the application to slow down the overall phone by always running."</string>
- <string name="permlab_broadcastSticky">"send sticky broadcast"</string>
- <string name="permdesc_broadcastSticky">"Allows an application to send sticky broadcasts, which remain after the broadcast ends. Malicious applications can make the phone slow or unstable by causing it to use too much memory."</string>
- <string name="permlab_readContacts">"read contact data"</string>
- <string name="permdesc_readContacts">"Allows an application to read all of the contact (address) data stored on your phone. Malicious applications can use this to send your data to other people."</string>
- <string name="permlab_writeContacts">"write contact data"</string>
- <string name="permdesc_writeContacts">"Allows an application to modify the contact (address) data stored on your phone. Malicious applications can use this to erase or modify your contact data."</string>
- <string name="permlab_writeOwnerData">"write owner data"</string>
- <string name="permdesc_writeOwnerData">"Allows an application to modify the phone owner data stored on your phone. Malicious applications can use this to erase or modify owner data."</string>
- <string name="permlab_readOwnerData">"read owner data"</string>
- <string name="permdesc_readOwnerData">"Allows an application read the phone owner data stored on your phone. Malicious applications can use this to read phone owner data."</string>
- <string name="permlab_readCalendar">"read calendar data"</string>
- <string name="permdesc_readCalendar">"Allows an application to read all of the calendar events stored on your phone. Malicious applications can use this to send your calendar events to other people."</string>
- <string name="permlab_writeCalendar">"write calendar data"</string>
- <string name="permdesc_writeCalendar">"Allows an application to modify the calendar events stored on your phone. Malicious applications can use this to erase or modify your calendar data."</string>
- <string name="permlab_accessMockLocation">"mock location sources for testing"</string>
- <string name="permdesc_accessMockLocation">"Create mock location sources for testing. Malicious applications can use this to override the location and/or status returned by real location sources such as GPS or Network providers."</string>
- <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
- <skip />
- <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
- <skip />
- <string name="permlab_accessFineLocation">"fine (GPS) location"</string>
- <string name="permdesc_accessFineLocation">"Access fine location sources such as the Global Positioning System on the phone, where available. Malicious applications can use this to determine where you are, and may consume additional battery power."</string>
- <string name="permlab_accessCoarseLocation">"coarse (network-based) location"</string>
- <string name="permdesc_accessCoarseLocation">"Access coarse location sources such as the cellular network database to determine an approximate phone location, where available. Malicious applications can use this to determine approximately where you are."</string>
- <string name="permlab_accessSurfaceFlinger">"access SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger">"Allows application to use SurfaceFlinger low-level features."</string>
- <string name="permlab_readFrameBuffer">"read frame buffer"</string>
- <string name="permdesc_readFrameBuffer">"Allows application to read the content of the frame buffer."</string>
- <string name="permlab_modifyAudioSettings">"change your audio settings"</string>
- <string name="permdesc_modifyAudioSettings">"Allows application to modify global audio settings such as volume and routing."</string>
- <string name="permlab_recordAudio">"record audio"</string>
- <string name="permdesc_recordAudio">"Allows application to access the audio record path."</string>
- <string name="permlab_camera">"take pictures"</string>
- <string name="permdesc_camera">"Allows application to take pictures with the camera. This allows the application at any time to collect images the camera is seeing."</string>
- <string name="permlab_brick">"permanently disable phone"</string>
- <string name="permdesc_brick">"Allows the application to disable the entire phone permanently. This is very dangerous."</string>
- <!-- no translation found for permlab_reboot (8844650672567077423) -->
- <skip />
- <!-- no translation found for permdesc_reboot (4704919552870918328) -->
- <skip />
- <string name="permlab_mount_unmount_filesystems">"mount and unmount filesystems"</string>
- <string name="permdesc_mount_unmount_filesystems">"Allows the application to mount and unmount filesystems for removable storage."</string>
- <string name="permlab_vibrate">"control vibrator"</string>
- <string name="permdesc_vibrate">"Allows the application to control the vibrator."</string>
- <string name="permlab_flashlight">"control flashlight"</string>
- <string name="permdesc_flashlight">"Allows the application to control the flashlight."</string>
- <string name="permlab_hardware_test">"test hardware"</string>
- <string name="permdesc_hardware_test">"Allows the application to control various peripherals for the purpose of hardware testing."</string>
- <string name="permlab_callPhone">"directly call phone numbers"</string>
- <string name="permdesc_callPhone">"Allows the application to call phone numbers without your intervention. Malicious applications may cause unexpected calls on your phone bill. Note that this does not allow the application to call emergency numbers."</string>
- <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
- <skip />
- <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
- <skip />
- <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
- <skip />
- <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
- <skip />
- <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
- <skip />
- <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
- <skip />
- <string name="permlab_modifyPhoneState">"modify phone state"</string>
- <string name="permdesc_modifyPhoneState">"Allows the application to control the phone features of the device. An application with this permission can switch networks, turn the phone radio on and off and the like without ever notifying you."</string>
- <string name="permlab_readPhoneState">"read phone state"</string>
- <string name="permdesc_readPhoneState">"Allows the application to access the phone features of the device. An application with this permission can determine the phone number of this phone, whether a call is active, the number that call is connected to and the like."</string>
- <string name="permlab_wakeLock">"prevent phone from sleeping"</string>
- <string name="permdesc_wakeLock">"Allows an application to prevent the phone from going to sleep."</string>
- <string name="permlab_devicePower">"power phone on or off"</string>
- <string name="permdesc_devicePower">"Allows the application to turn the phone on or off."</string>
- <string name="permlab_factoryTest">"run in factory test mode"</string>
- <string name="permdesc_factoryTest">"Run as a low-level manufacturer test, allowing complete access to the phone hardware. Only available when a phone is running in manufacturer test mode."</string>
- <string name="permlab_setWallpaper">"set wallpaper"</string>
- <string name="permdesc_setWallpaper">"Allows the application to set the system wallpaper."</string>
- <string name="permlab_setWallpaperHints">"set wallpaper size hints"</string>
- <string name="permdesc_setWallpaperHints">"Allows the application to set the system wallpaper size hints."</string>
- <string name="permlab_masterClear">"reset system to factory defaults"</string>
- <string name="permdesc_masterClear">"Allows an application to completely reset the system to its factory settings, erasing all data, configuration, and installed applications."</string>
- <string name="permlab_setTimeZone">"set time zone"</string>
- <string name="permdesc_setTimeZone">"Allows an application to change the phones time zone."</string>
- <string name="permlab_getAccounts">"discover known accounts"</string>
- <string name="permdesc_getAccounts">"Allows an application to get the list of accounts known by the phone."</string>
- <string name="permlab_accessNetworkState">"view network state"</string>
- <string name="permdesc_accessNetworkState">"Allows an application to view the state of all networks."</string>
- <string name="permlab_createNetworkSockets">"full Internet access"</string>
- <string name="permdesc_createNetworkSockets">"Allows an application to create network sockets."</string>
- <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
- <skip />
- <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
- <skip />
- <string name="permlab_changeNetworkState">"change network connectivity"</string>
- <string name="permdesc_changeNetworkState">"Allows an application to change the state network connectivity."</string>
- <string name="permlab_accessWifiState">"view Wi-Fi state"</string>
- <string name="permdesc_accessWifiState">"Allows an application to view the information about the state of Wi-Fi."</string>
- <string name="permlab_changeWifiState">"change Wi-Fi state"</string>
- <string name="permdesc_changeWifiState">"Allows an application to connect to and disconnect from Wi-Fi access points, and to make changes to configured Wi-Fi networks."</string>
- <string name="permlab_bluetoothAdmin">"bluetooth administration"</string>
- <string name="permdesc_bluetoothAdmin">"Allows an application to configure the local Bluetooth phone, and to discover and pair with remote devices."</string>
- <string name="permlab_bluetooth">"create Bluetooth connections"</string>
- <string name="permdesc_bluetooth">"Allows an application to view configuration of the local Bluetooth phone, and to make and accept connections with paired devices."</string>
- <string name="permlab_disableKeyguard">"disable keylock"</string>
- <string name="permdesc_disableKeyguard">"Allows an application to disable the keylock and any associated password security. A legitimate example of this is the phone disabling the keylock when receiving an incoming phone call, then re-enabling the keylock when the call is finished."</string>
- <string name="permlab_readSyncSettings">"read sync settings"</string>
- <string name="permdesc_readSyncSettings">"Allows an application to read the sync settings, such as whether sync is enabled for Contacts."</string>
- <string name="permlab_writeSyncSettings">"write sync settings"</string>
- <string name="permdesc_writeSyncSettings">"Allows an application to modify the sync settings, such as whether sync is enabled for Contacts."</string>
- <string name="permlab_readSyncStats">"read sync statistics"</string>
- <string name="permdesc_readSyncStats">"Allows an application to reafocusd the sync stats; e.g., the history of syncs that have occurred."</string>
- <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
- <skip />
- <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
- <skip />
- <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
- <skip />
- <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
- <skip />
- <!-- no translation found for phoneTypes:0 (6070018634209800981) -->
- <!-- no translation found for phoneTypes:1 (1514509689885965711) -->
- <!-- no translation found for phoneTypes:2 (497473201754095234) -->
- <!-- no translation found for phoneTypes:3 (5554432614281047787) -->
- <!-- no translation found for phoneTypes:4 (2222084401110150993) -->
- <!-- no translation found for phoneTypes:5 (2290007103906353121) -->
- <!-- no translation found for phoneTypes:6 (6930783706213719251) -->
- <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
- <!-- no translation found for emailAddressTypes:0 (1540640638077615417) -->
- <!-- no translation found for emailAddressTypes:1 (4252853367575831977) -->
- <!-- no translation found for emailAddressTypes:2 (7158046581744435718) -->
- <!-- no translation found for emailAddressTypes:3 (3625034471181268169) -->
- <!-- no translation found for postalAddressTypes:0 (5732960259696659380) -->
- <!-- no translation found for postalAddressTypes:1 (7132240704786130285) -->
- <!-- no translation found for postalAddressTypes:2 (1317604357745852817) -->
- <!-- no translation found for postalAddressTypes:3 (1582953598462826702) -->
- <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
- <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
- <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
- <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
- <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
- <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
- <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
- <!-- no translation found for imProtocols:0 (3318725788774688043) -->
- <!-- no translation found for imProtocols:1 (1787713387022932886) -->
- <!-- no translation found for imProtocols:2 (6751174158442316516) -->
- <!-- no translation found for imProtocols:3 (1151283347465052653) -->
- <!-- no translation found for imProtocols:4 (2157980008878817934) -->
- <!-- no translation found for imProtocols:5 (7836237460308230767) -->
- <!-- no translation found for imProtocols:6 (1180789904462172516) -->
- <!-- no translation found for imProtocols:7 (21955111672779862) -->
- <string name="keyguard_password_enter_pin_code">"Enter PIN code:"</string>
- <string name="keyguard_password_wrong_pin_code">"Incorrect PIN code!"</string>
- <string name="keyguard_label_text">"To unlock, press Menu then 0."</string>
- <string name="emergency_call_dialog_number_for_display">"Emergency number"</string>
- <string name="lockscreen_carrier_default">"(No service)"</string>
- <string name="lockscreen_screen_locked">"Screen locked"</string>
- <string name="lockscreen_instructions_when_pattern_enabled">"Press Menu to unlock or place emergency call."</string>
- <string name="lockscreen_instructions_when_pattern_disabled">"Press Menu to unlock."</string>
- <string name="lockscreen_pattern_instructions">"Draw pattern to unlock:"</string>
- <string name="lockscreen_emergency_call">"Emergency call"</string>
- <string name="lockscreen_pattern_correct">"Correct!"</string>
- <string name="lockscreen_pattern_wrong">"Sorry, try again:"</string>
- <string name="lockscreen_plugged_in">"Charging (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
- <string name="lockscreen_low_battery">"Connect your charger."</string>
- <string name="lockscreen_missing_sim_message_short">"No SIM card."</string>
- <string name="lockscreen_missing_sim_message">"No SIM card in phone."</string>
- <string name="lockscreen_missing_sim_instructions">"Please insert a SIM card."</string>
- <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
- <skip />
- <string name="lockscreen_sim_puk_locked_message">"SIM card is PUK-locked."</string>
- <string name="lockscreen_sim_puk_locked_instructions">"Please contact Customer Care."</string>
- <string name="lockscreen_sim_locked_message">"SIM card is locked."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message">"Unlocking SIM card…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="lockscreen_failed_attempts_almost_glogin">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown">"Try again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
- <string name="lockscreen_forgot_pattern_button_text">"Forgot pattern?"</string>
- <string name="lockscreen_glogin_too_many_attempts">"Too many pattern attempts!"</string>
- <string name="lockscreen_glogin_instructions">"To unlock,"\n"sign in with your Google account:"</string>
- <string name="lockscreen_glogin_username_hint">"Username (email)"</string>
- <string name="lockscreen_glogin_password_hint">"Password"</string>
- <string name="lockscreen_glogin_submit_button">"Sign in"</string>
- <string name="lockscreen_glogin_invalid_input">"Invalid username or password."</string>
- <!-- unknown placeholder FORMAT in status_bar_time_format -->
- <skip />
- <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
- <skip />
- <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
- <skip />
- <!-- no translation found for hour_ampm (7665432130905376251) -->
- <skip />
- <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
- <skip />
- <string name="status_bar_clear_all_button">"Clear notifications"</string>
- <string name="status_bar_no_notifications_title">"No notifications"</string>
- <string name="status_bar_ongoing_events_title">"Ongoing"</string>
- <string name="status_bar_latest_events_title">"Notifications"</string>
- <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g>"</string>
- <string name="battery_status_charging">"Charging…"</string>
- <string name="battery_low_title">"Please connect charger"</string>
- <string name="battery_low_subtitle">"The battery is getting low:"</string>
- <string name="battery_low_percent_format">"less than <xliff:g id="NUMBER">%d%%</xliff:g> remaining."</string>
- <string name="factorytest_failed">"Factory test failed"</string>
- <string name="factorytest_not_system">"The FACTORY_TEST action is only supported for packages installed in /system/app."</string>
- <string name="factorytest_no_action">"No package was found that provides the FACTORY_TEST action."</string>
- <string name="factorytest_reboot">"Reboot"</string>
- <string name="save_password_label">"Confirm"</string>
- <string name="save_password_message">"Do you want the browser to remember this password?"</string>
- <string name="save_password_notnow">"Not now"</string>
- <string name="save_password_remember">"Remember"</string>
- <string name="save_password_never">"Never"</string>
- <string name="open_permission_deny">"You do not have permission to open this page."</string>
- <string name="text_copied">"Text copied to clipboard."</string>
- <string name="more_item_label">"More"</string>
- <string name="prepend_shortcut_label">"Menu+"</string>
- <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
- <skip />
- <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
- <skip />
- <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
- <skip />
- <string name="search_go">"Search"</string>
- <string name="today">"Today"</string>
- <string name="yesterday">"Yesterday"</string>
- <string name="tomorrow">"Tomorrow"</string>
- <string name="oneMonthDurationPast">"1 month ago"</string>
- <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
- <skip />
- <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
- <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
- <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
- <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
- <!-- no translation found for num_hours_ago:one (853404611989669641) -->
- <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
- <!-- no translation found for num_days_ago:one (4222479980812128212) -->
- <!-- no translation found for num_days_ago:other (5445701370433601703) -->
- <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
- <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
- <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
- <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
- <!-- no translation found for in_num_hours:one (6501470863235186391) -->
- <!-- no translation found for in_num_hours:other (4415358752953289251) -->
- <!-- no translation found for in_num_days:one (5608475533104443893) -->
- <!-- no translation found for in_num_days:other (3827193006163842267) -->
- <string name="preposition_for_date">"on %s"</string>
- <string name="preposition_for_time">"at %s"</string>
- <string name="preposition_for_year">"in %s"</string>
- <string name="day">"day"</string>
- <string name="days">"days"</string>
- <string name="hour">"hour"</string>
- <string name="hours">"hours"</string>
- <string name="minute">"min"</string>
- <string name="minutes">"mins"</string>
- <string name="second">"sec"</string>
- <string name="seconds">"secs"</string>
- <string name="week">"week"</string>
- <string name="weeks">"weeks"</string>
- <string name="year">"year"</string>
- <string name="years">"years"</string>
- <string name="sunday">"Sunday"</string>
- <string name="monday">"Monday"</string>
- <string name="tuesday">"Tuesday"</string>
- <string name="wednesday">"Wednesday"</string>
- <string name="thursday">"Thursday"</string>
- <string name="friday">"Friday"</string>
- <string name="saturday">"Saturday"</string>
- <string name="every_weekday">"Every weekday (Mon–Fri)"</string>
- <string name="daily">"Daily"</string>
- <string name="weekly">"Weekly on <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly">"Monthly"</string>
- <string name="yearly">"Yearly"</string>
- <string name="VideoView_error_title">"Cannot play video"</string>
- <string name="VideoView_error_text_unknown">"Sorry, this video cannot be played."</string>
- <string name="VideoView_error_button">"OK"</string>
- <string name="am">"AM"</string>
- <string name="pm">"PM"</string>
- <!-- unknown placeholder FORMAT in numeric_date -->
- <skip />
- <!-- unknown placeholder FORMAT in wday1_date1_time1_wday2_date2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in wday1_date1_wday2_date2 -->
- <skip />
- <!-- unknown placeholder FORMAT in date1_time1_date2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in date1_date2 -->
- <skip />
- <!-- unknown placeholder FORMAT in time1_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in time_wday_date -->
- <skip />
- <!-- unknown placeholder FORMAT in wday_date -->
- <skip />
- <!-- unknown placeholder FORMAT in time_date -->
- <skip />
- <!-- unknown placeholder FORMAT in time_wday -->
- <skip />
- <!-- no translation found for full_date_month_first (6011143962222283357) -->
- <skip />
- <!-- no translation found for full_date_day_first (8621594762705478189) -->
- <skip />
- <!-- no translation found for medium_date_month_first (48990963718825728) -->
- <skip />
- <!-- no translation found for medium_date_day_first (2898992016440387123) -->
- <skip />
- <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
- <skip />
- <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
- <skip />
- <string name="noon">"noon"</string>
- <string name="Noon">"Noon"</string>
- <string name="midnight">"midnight"</string>
- <string name="Midnight">"Midnight"</string>
- <!-- unknown placeholder FORMAT in month_day -->
- <skip />
- <!-- unknown placeholder FORMAT in month -->
- <skip />
- <!-- unknown placeholder FORMAT in month_day_year -->
- <skip />
- <!-- unknown placeholder FORMAT in month_year -->
- <skip />
- <!-- no translation found for time_of_day (8375993139317154157) -->
- <skip />
- <!-- no translation found for date_and_time (9197690194373107109) -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_md1_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_md1_wday2_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_mdy1_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_wday2_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_md1_time1_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_md1_time1_wday2_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_mdy1_time1_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_time1_wday2_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_md1_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_md1_wday2_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_mdy1_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_wday2_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_md1_time1_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_md1_time1_wday2_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_mdy1_time1_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_time1_wday2_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_md1_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_md1_wday2_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_mdy1_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_wday2_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_md1_time1_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_md1_time1_wday2_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_mdy1_time1_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_time1_wday2_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month_day_year -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month_year -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month_day -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month -->
- <skip />
- <string name="day_of_week_long_sunday">"Sunday"</string>
- <string name="day_of_week_long_monday">"Monday"</string>
- <string name="day_of_week_long_tuesday">"Tuesday"</string>
- <string name="day_of_week_long_wednesday">"Wednesday"</string>
- <string name="day_of_week_long_thursday">"Thursday"</string>
- <string name="day_of_week_long_friday">"Friday"</string>
- <string name="day_of_week_long_saturday">"Saturday"</string>
- <string name="day_of_week_medium_sunday">"Sun"</string>
- <string name="day_of_week_medium_monday">"Mon"</string>
- <string name="day_of_week_medium_tuesday">"Tue"</string>
- <string name="day_of_week_medium_wednesday">"Wed"</string>
- <string name="day_of_week_medium_thursday">"Thu"</string>
- <string name="day_of_week_medium_friday">"Fri"</string>
- <string name="day_of_week_medium_saturday">"Sat"</string>
- <string name="day_of_week_short_sunday">"Su"</string>
- <string name="day_of_week_short_monday">"Mo"</string>
- <string name="day_of_week_short_tuesday">"Tu"</string>
- <string name="day_of_week_short_wednesday">"We"</string>
- <string name="day_of_week_short_thursday">"Th"</string>
- <string name="day_of_week_short_friday">"Fr"</string>
- <string name="day_of_week_short_saturday">"Sa"</string>
- <string name="day_of_week_shorter_sunday">"Su"</string>
- <string name="day_of_week_shorter_monday">"M"</string>
- <string name="day_of_week_shorter_tuesday">"Tu"</string>
- <string name="day_of_week_shorter_wednesday">"W"</string>
- <string name="day_of_week_shorter_thursday">"Th"</string>
- <string name="day_of_week_shorter_friday">"F"</string>
- <string name="day_of_week_shorter_saturday">"Sa"</string>
- <string name="day_of_week_shortest_sunday">"S"</string>
- <string name="day_of_week_shortest_monday">"M"</string>
- <string name="day_of_week_shortest_tuesday">"T"</string>
- <string name="day_of_week_shortest_wednesday">"W"</string>
- <string name="day_of_week_shortest_thursday">"T"</string>
- <string name="day_of_week_shortest_friday">"F"</string>
- <string name="day_of_week_shortest_saturday">"S"</string>
- <string name="month_long_january">"January"</string>
- <string name="month_long_february">"February"</string>
- <string name="month_long_march">"March"</string>
- <string name="month_long_april">"April"</string>
- <string name="month_long_may">"May"</string>
- <string name="month_long_june">"June"</string>
- <string name="month_long_july">"July"</string>
- <string name="month_long_august">"August"</string>
- <string name="month_long_september">"September"</string>
- <string name="month_long_october">"October"</string>
- <string name="month_long_november">"November"</string>
- <string name="month_long_december">"December"</string>
- <string name="month_medium_january">"Jan"</string>
- <string name="month_medium_february">"Feb"</string>
- <string name="month_medium_march">"Mar"</string>
- <string name="month_medium_april">"Apr"</string>
- <string name="month_medium_may">"May"</string>
- <string name="month_medium_june">"Jun"</string>
- <string name="month_medium_july">"Jul"</string>
- <string name="month_medium_august">"Aug"</string>
- <string name="month_medium_september">"Sep"</string>
- <string name="month_medium_october">"Oct"</string>
- <string name="month_medium_november">"Nov"</string>
- <string name="month_medium_december">"Dec"</string>
- <string name="month_shortest_january">"J"</string>
- <string name="month_shortest_february">"F"</string>
- <string name="month_shortest_march">"M"</string>
- <string name="month_shortest_april">"A"</string>
- <string name="month_shortest_may">"M"</string>
- <string name="month_shortest_june">"J"</string>
- <string name="month_shortest_july">"J"</string>
- <string name="month_shortest_august">"A"</string>
- <string name="month_shortest_september">"S"</string>
- <string name="month_shortest_october">"O"</string>
- <string name="month_shortest_november">"N"</string>
- <string name="month_shortest_december">"D"</string>
- <!-- unknown placeholder FORMAT in elapsed_time_short_format_mm_ss -->
- <skip />
- <!-- unknown placeholder FORMAT in elapsed_time_short_format_h_mm_ss -->
- <skip />
- <string name="selectAll">"Select all"</string>
- <string name="cut">"Cut"</string>
- <string name="cutAll">"Cut all"</string>
- <string name="copy">"Copy"</string>
- <string name="copyAll">"Copy all"</string>
- <string name="paste">"Paste"</string>
- <string name="copyUrl">"Copy URL"</string>
- <!-- no translation found for inputMethod (7911866729148111492) -->
- <skip />
- <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
- <skip />
- <string name="low_internal_storage_view_title">"Low on space"</string>
- <string name="low_internal_storage_view_text">"Your phone is running low on internal storage space."</string>
- <string name="ok">"OK"</string>
- <string name="cancel">"Cancel"</string>
- <string name="yes">"OK"</string>
- <string name="no">"Cancel"</string>
- <string name="capital_on">"ON"</string>
- <string name="capital_off">"OFF"</string>
- <string name="whichApplication">"Complete action using"</string>
- <string name="alwaysUse">"Use by default for this action."</string>
- <string name="clearDefaultHintMsg">"Clear default in Home Settings &gt; Applications &gt; Manage applications."</string>
- <string name="chooseActivity">"Select an action"</string>
- <string name="noApplications">"No applications can perform this action."</string>
- <string name="aerr_title">"Sorry!"</string>
- <string name="aerr_application">"The application <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has stopped unexpectedly. Please try again."</string>
- <string name="aerr_process">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has stopped unexpectedly. Please try again."</string>
- <string name="anr_title">"Application unresponsive"</string>
- <string name="anr_activity_application">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in application <xliff:g id="APPLICATION">%2$s</xliff:g>) is not responding."</string>
- <string name="anr_activity_process">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
- <string name="anr_application_process">"Application <xliff:g id="APPLICATION">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
- <string name="anr_process">"Process <xliff:g id="PROCESS">%1$s</xliff:g> is not responding."</string>
- <string name="force_close">"Force close"</string>
- <string name="wait">"Wait"</string>
- <string name="debug">"Debug"</string>
- <string name="sendText">"Select an action for text"</string>
- <string name="volume_ringtone">"Ringer volume"</string>
- <string name="volume_music">"Music/video volume"</string>
- <string name="volume_call">"In-call volume"</string>
- <string name="volume_alarm">"Alarm volume"</string>
- <string name="volume_unknown">"Volume"</string>
- <string name="ringtone_default">"Default ringtone"</string>
- <string name="ringtone_default_with_actual">"Default ringtone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent">"Silent"</string>
- <string name="ringtone_picker_title">"Select a ringtone"</string>
- <string name="ringtone_unknown">"Unknown ringtone"</string>
- <!-- no translation found for wifi_available:one (8168012881468888470) -->
- <!-- no translation found for wifi_available:other (4666122955807117718) -->
- <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
- <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
- <string name="select_character">"Select character to insert"</string>
- <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
- <skip />
- <string name="sms_control_title">"Sending SMS messages"</string>
- <string name="sms_control_message">"A large number of SMS messages are being sent. Select \"OK\" to continue, or \"Cancel\" to stop sending."</string>
- <string name="sms_control_yes">"OK"</string>
- <string name="sms_control_no">"Cancel"</string>
- <string name="date_time_set">"Set"</string>
- <string name="default_permission_group">"Default"</string>
- <string name="no_permissions">"No permissions required"</string>
- <!-- no translation found for perms_hide (4145325555929151849) -->
- <skip />
- <!-- no translation found for perms_show_all (6040194843455403173) -->
- <skip />
- <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
- <skip />
- <!-- no translation found for usb_storage_title (8699631567051394409) -->
- <skip />
- <!-- no translation found for usb_storage_message (5344039189213308733) -->
- <skip />
- <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
- <skip />
- <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
- <skip />
- <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
- <skip />
- <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
- <skip />
- <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
- <skip />
- <!-- no translation found for select_input_method (2658280517827502015) -->
- <skip />
- <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
- <skip />
- <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
- <skip />
- <!-- no translation found for candidates_style (7738463880139922176) -->
- <skip />
+ <string name="byteShort">B</string>
</resources>
diff --git a/core/res/res/values-en-rSG/arrays.xml b/core/res/res/values-en-rSG/arrays.xml
new file mode 100644
index 0000000..ee1e64b
--- /dev/null
+++ b/core/res/res/values-en-rSG/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2006, Google Inc.
+**
+** 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.
+*/
+-->
+<resources>
+
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_lat_lng">
+ <item>1333333</item>
+ <item>103875000</item>
+ </integer-array>
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_zoom">
+ <item>4</item>
+ </integer-array>
+
+</resources>
diff --git a/core/res/res/values-en-rSG/strings.xml b/core/res/res/values-en-rSG/strings.xml
index b9df983..6850a5d 100644
--- a/core/res/res/values-en-rSG/strings.xml
+++ b/core/res/res/values-en-rSG/strings.xml
@@ -710,7 +710,7 @@
<!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
<skip />
<!-- no translation found for status_bar_time_format (2168573805413119180) -->
- <skip />
+ <string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<!-- no translation found for hour_minute_ampm (1850330605794978742) -->
<skip />
<!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
@@ -861,34 +861,35 @@
<skip />
<!-- no translation found for pm (7206933220587555766) -->
<skip />
- <!-- no translation found for numeric_date (5120078478872821100) -->
- <skip />
+ <!-- copied from values-de/strings.xml with the crazyness of the . removed-->
<!-- no translation found for wday1_date1_time1_wday2_date2_time2 (7066878981949584861) -->
- <skip />
+ <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
<!-- no translation found for wday1_date1_wday2_date2 (8671068747172261907) -->
- <skip />
+ <string name="wday1_date1_wday2_date2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>"</string>
+ <!-- no translation found for numeric_date (5537215108967329745) -->
+ <string name="numeric_date">"<xliff:g id="DAY">%d</xliff:g>/<xliff:g id="MONTH">%m</xliff:g>/<xliff:g id="YEAR">%Y</xliff:g>"</string>
<!-- no translation found for date1_time1_date2_time2 (3645498975775629615) -->
- <skip />
+ <string name="date1_time1_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
<!-- no translation found for date1_date2 (377057563556488062) -->
- <skip />
+ <string name="date1_date2">"<xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>"</string>
<!-- no translation found for time1_time2 (3173474242109288305) -->
- <skip />
+ <string name="time1_time2">"<xliff:g id="TIME1">%1$s</xliff:g> – <xliff:g id="TIME2">%2$s</xliff:g>"</string>
<!-- no translation found for time_wday_date (8928955562064570313) -->
- <skip />
+ <string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<!-- no translation found for wday_date (8794741400546136975) -->
- <skip />
+ <string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<!-- no translation found for time_date (1922644512833014496) -->
- <skip />
+ <string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<!-- no translation found for time_wday (1422050241301754712) -->
- <skip />
+ <string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
<!-- no translation found for full_date_month_first (6011143962222283357) -->
<skip />
<!-- no translation found for full_date_day_first (8621594762705478189) -->
- <skip />
+ <string name="full_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
<!-- no translation found for medium_date_month_first (48990963718825728) -->
<skip />
<!-- no translation found for medium_date_day_first (2898992016440387123) -->
- <skip />
+ <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
<!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
<skip />
<!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
@@ -902,71 +903,71 @@
<!-- no translation found for Midnight (1260172107848123187) -->
<skip />
<!-- no translation found for month_day (3356633704511426364) -->
- <skip />
+ <string name="month_day">"<xliff:g id="day" example="9">%-d</xliff:g> <xliff:g id="month" example="October">%B</xliff:g>"</string>
<!-- no translation found for month (3017405760734206414) -->
<skip />
<!-- no translation found for month_day_year (2435948225709176752) -->
- <skip />
+ <string name="month_day_year">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
<!-- no translation found for month_year (6228414124777343135) -->
<skip />
<!-- no translation found for time_of_day (8375993139317154157) -->
- <skip />
+ <string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<!-- no translation found for date_and_time (9197690194373107109) -->
- <skip />
+ <string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
<!-- no translation found for same_year_md1_md2 (9199324363135981317) -->
- <skip />
+ <string name="same_year_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<!-- no translation found for same_year_wday1_md1_wday2_md2 (6006392413355305178) -->
- <skip />
+ <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<!-- no translation found for same_year_mdy1_mdy2 (1576657593937827090) -->
- <skip />
+ <string name="same_year_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR">%9$s</xliff:g>"</string>
<!-- no translation found for same_year_wday1_mdy1_wday2_mdy2 (9135935796468891580) -->
- <skip />
+ <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR">%9$s</xliff:g>"</string>
<!-- no translation found for same_year_md1_time1_md2_time2 (2172964106375558081) -->
<skip />
<!-- no translation found for same_year_wday1_md1_time1_wday2_md2_time2 (1702879534101786310) -->
- <skip />
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_year_mdy1_time1_mdy2_time2 (2476443311723358767) -->
- <skip />
+ <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_year_wday1_mdy1_time1_wday2_mdy2_time2 (1564837340334069879) -->
- <skip />
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for numeric_md1_md2 (8908376522875100300) -->
- <skip />
+ <string name="numeric_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<!-- no translation found for numeric_wday1_md1_wday2_md2 (3239690882018292077) -->
- <skip />
+ <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<!-- no translation found for numeric_mdy1_mdy2 (8883797176939233525) -->
- <skip />
+ <string name="numeric_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
<!-- no translation found for numeric_wday1_mdy1_wday2_mdy2 (4150475769255828954) -->
- <skip />
+ <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
<!-- no translation found for numeric_md1_time1_md2_time2 (3624746590607741419) -->
- <skip />
+ <string name="numeric_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for numeric_wday1_md1_time1_wday2_md2_time2 (4258040955467298134) -->
- <skip />
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for numeric_mdy1_time1_mdy2_time2 (3598215409314517987) -->
- <skip />
+ <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for numeric_wday1_mdy1_time1_wday2_mdy2_time2 (264076937155877259) -->
- <skip />
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_month_md1_md2 (2393563617438036111) -->
- <skip />
+ <string name="same_month_md1_md2">"<xliff:g id="DAY1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="DAY2" example="3">%8$s</xliff:g> <xliff:g id="MONTH1" example="Oct">%2$s</xliff:g>"</string>
<!-- no translation found for same_month_wday1_md1_wday2_md2 (1208946773794057819) -->
- <skip />
+ <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<!-- no translation found for same_month_mdy1_mdy2 (3713236637869030492) -->
- <skip />
+ <string name="same_month_mdy1_mdy2">"<xliff:g id="DAY1" example="31">%3$s</xliff:g> \u2013 <xliff:g id="DAY2" example="3">%8$s</xliff:g> <xliff:g id="MONTH1" example="Oct">%2$s</xliff:g> <xliff:g id="YEAR2" example="2007">%9$s</xliff:g>"</string>
<!-- no translation found for same_month_wday1_mdy1_wday2_mdy2 (389638922479870472) -->
- <skip />
+ <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
<!-- no translation found for same_month_md1_time1_md2_time2 (7477075526337542685) -->
- <skip />
+ <string name="same_month_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_month_wday1_md1_time1_wday2_md2_time2 (3516978303779391173) -->
- <skip />
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_month_mdy1_time1_mdy2_time2 (7320410992514057310) -->
- <skip />
+ <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for same_month_wday1_mdy1_time1_wday2_mdy2_time2 (1332950588774239228) -->
- <skip />
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<!-- no translation found for abbrev_month_day_year (5767271534015320250) -->
- <skip />
+ <string name="abbrev_month_day_year">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%b</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
<!-- no translation found for abbrev_month_year (8058929633673942490) -->
<skip />
<!-- no translation found for abbrev_month_day (458867920693482757) -->
- <skip />
+ <string name="abbrev_month_day">"<xliff:g id="day" example="31">%-d</xliff:g> <xliff:g id="month" example="Oct">%b</xliff:g>"</string>
<!-- no translation found for abbrev_month (1674509986330181349) -->
<skip />
<!-- no translation found for day_of_week_long_sunday (9057662850446501884) -->
@@ -1112,9 +1113,9 @@
<!-- no translation found for month_shortest_december (6213739417171334040) -->
<skip />
<!-- no translation found for elapsed_time_short_format_mm_ss (1294409362352514646) -->
- <skip />
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<!-- no translation found for elapsed_time_short_format_h_mm_ss (2997059666628785039) -->
- <skip />
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<!-- no translation found for selectAll (691691810023908884) -->
<skip />
<!-- no translation found for cut (5845613239192595662) -->
diff --git a/core/res/res/values-es-rES/arrays.xml b/core/res/res/values-es-rES/arrays.xml
new file mode 100644
index 0000000..7f5667c
--- /dev/null
+++ b/core/res/res/values-es-rES/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2006, Google Inc.
+**
+** 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.
+*/
+-->
+<resources>
+
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_lat_lng">
+ <item>40413496</item>
+ <item>-3713379</item>
+ </integer-array>
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_zoom">
+ <item>6</item>
+ </integer-array>
+
+</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
deleted file mode 100644
index a2fd8d5..0000000
--- a/core/res/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,904 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort">"b"</string>
- <string name="kilobyteShort">"Kb"</string>
- <string name="megabyteShort">"Mb"</string>
- <string name="gigabyteShort">"Gb"</string>
- <string name="terabyteShort">"Tb"</string>
- <string name="petabyteShort">"Pb"</string>
- <string name="untitled">"&lt;sin título&gt;"</string>
- <string name="ellipsis">"…"</string>
- <string name="emptyPhoneNumber">"(ningún número de teléfono)"</string>
- <string name="unknownName">"(desconocido)"</string>
- <string name="defaultVoiceMailAlphaTag">"Correo de voz"</string>
- <string name="defaultMsisdnAlphaTag">"Msisdn1"</string>
- <string name="mmiError">"Error de red o código MMI no válido."</string>
- <string name="serviceEnabled">"Servicio habilitado"</string>
- <string name="serviceEnabledFor">"Servicio habilitado para:"</string>
- <string name="serviceDisabled">"Servicio deshabilitado"</string>
- <string name="serviceRegistered">"Registro completado"</string>
- <string name="serviceErased">"Borrado completado"</string>
- <string name="passwordIncorrect">"Contraseña incorrecta"</string>
- <string name="mmiComplete">"MMI completo"</string>
- <!-- no translation found for badPin (5103184589972647739) -->
- <skip />
- <!-- no translation found for badPuk (2200634943393540609) -->
- <skip />
- <!-- no translation found for mismatchPin (5055729703806180857) -->
- <skip />
- <!-- no translation found for invalidPin (6201854814319326475) -->
- <skip />
- <!-- no translation found for needPuk (4788728144863892764) -->
- <skip />
- <!-- no translation found for needPuk2 (7056908944942451033) -->
- <skip />
- <string name="ClipMmi">"ID de llamada entrante"</string>
- <string name="ClirMmi">"ID de llamada saliente"</string>
- <string name="CfMmi">"Desvío de llamadas"</string>
- <string name="CwMmi">"Llamada en espera"</string>
- <string name="BaMmi">"Bloqueo de llamadas"</string>
- <string name="PwdMmi">"Cambio de contraseña"</string>
- <string name="PinMmi">"Cambio de PIN"</string>
- <string name="CLIRDefaultOnNextCallOn">"El valor predeterminado de la restricción de ID es restringida. Próxima llamada: restringida"</string>
- <string name="CLIRDefaultOnNextCallOff">"El valor predeterminado de la restricción de ID es restringida. Próxima llamada: no restringida"</string>
- <string name="CLIRDefaultOffNextCallOn">"El valor predeterminado de la restricción de ID es no restringida. Próxima llamada: restringida"</string>
- <string name="CLIRDefaultOffNextCallOff">"El valor predeterminado de la restricción de ID es no restringida. Próxima llamada: no restringida"</string>
- <string name="serviceNotProvisioned">"Servicio no previsto."</string>
- <string name="CLIRPermanent">"Restricción de ID prevista en el modo permanente."</string>
- <string name="serviceClassVoice">"Voz"</string>
- <string name="serviceClassData">"Datos"</string>
- <string name="serviceClassFAX">"FAX"</string>
- <string name="serviceClassSMS">"SMS"</string>
- <string name="serviceClassDataAsync">"Asíncrono"</string>
- <string name="serviceClassDataSync">"Sincronizar"</string>
- <string name="serviceClassPacket">"Paquete"</string>
- <string name="serviceClassPAD">"PAD"</string>
- <string name="cfTemplateNotForwarded">"{0}: No desviada"</string>
- <string name="cfTemplateForwarded">"{0}: {1}"</string>
- <string name="cfTemplateForwardedTime">"{0}: {1} después de {2} segundos"</string>
- <string name="cfTemplateRegistered">"{0}: No desviada ({1})"</string>
- <string name="cfTemplateRegisteredTime">"{0}: No desviada ({1} después de {2} segundos)"</string>
- <string name="httpErrorOk">"Aceptar"</string>
- <string name="httpError">"Error desconocido"</string>
- <string name="httpErrorLookup">"Host desconocido"</string>
- <string name="httpErrorUnsupportedAuthScheme">"Esquema de autenticación no compatible. Fallo al autenticar."</string>
- <string name="httpErrorAuth">"Error de autenticación"</string>
- <string name="httpErrorProxyAuth">"Error de autenticación de servidor proxy"</string>
- <string name="httpErrorConnect">"Fallo al conectar con el servidor"</string>
- <string name="httpErrorIO">"Fallo al leer o escribir en el servidor"</string>
- <string name="httpErrorTimeout">"Agotado el tiempo de espera de conexión con el servidor"</string>
- <string name="httpErrorRedirectLoop">"Demasiadas redirecciones de servidor"</string>
- <string name="httpErrorUnsupportedScheme">"Protocolo no compatible"</string>
- <string name="httpErrorFailedSslHandshake">"Fallo al realizar SSL mutuo"</string>
- <string name="httpErrorBadUrl">"URL no válida"</string>
- <string name="httpErrorFile">"Error en el archivo"</string>
- <string name="httpErrorFileNotFound">"Archivo no encontrado"</string>
- <!-- no translation found for httpErrorTooManyRequests (3764334538393544875) -->
- <skip />
- <string name="contentServiceSync">"Sincronizar"</string>
- <string name="contentServiceSyncNotificationTitle">"Sincronizar"</string>
- <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8477597194404210723) -->
- <skip />
- <!-- no translation found for low_memory (4191592786596642367) -->
- <skip />
- <!-- no translation found for me (4616693653158602117) -->
- <skip />
- <string name="power_dialog">"Opciones de energía"</string>
- <string name="silent_mode">"Modo silencioso"</string>
- <string name="turn_on_radio">"Encender radio"</string>
- <string name="turn_off_radio">"Apagar radio"</string>
- <string name="screen_lock">"Bloquear"</string>
- <string name="power_off">"Apagado"</string>
- <!-- no translation found for shutdown_progress (3735034517335251808) -->
- <skip />
- <!-- no translation found for shutdown_confirm (699224922526414097) -->
- <skip />
- <string name="no_recent_tasks">"Ninguna aplicación reciente"</string>
- <string name="global_actions">"Acciones globales"</string>
- <string name="global_action_lock">"Bloquear"</string>
- <string name="global_action_power_off">"Apagado"</string>
- <string name="global_action_toggle_silent_mode">"Modo silencioso"</string>
- <string name="global_action_silent_mode_on_status">"El sonido está desactivado"</string>
- <string name="global_action_silent_mode_off_status">"El sonido está activado"</string>
- <string name="safeMode">"Modo seguro"</string>
- <!-- no translation found for permgrouplab_costMoney (904087853776533085) -->
- <skip />
- <!-- no translation found for permgroupdesc_costMoney (4662370555643969515) -->
- <skip />
- <!-- no translation found for permgrouplab_messages (2984053976424233925) -->
- <skip />
- <!-- no translation found for permgroupdesc_messages (2129093134354989379) -->
- <skip />
- <!-- no translation found for permgrouplab_personalInfo (4548406335021507392) -->
- <skip />
- <!-- no translation found for permgroupdesc_personalInfo (8499310823817958034) -->
- <skip />
- <!-- no translation found for permgrouplab_location (8535677827151907069) -->
- <skip />
- <!-- no translation found for permgroupdesc_location (2341662219604651887) -->
- <skip />
- <!-- no translation found for permgrouplab_network (3597781730625751831) -->
- <skip />
- <!-- no translation found for permgroupdesc_network (8332572695347918340) -->
- <skip />
- <!-- no translation found for permgrouplab_accounts (8631201594657951893) -->
- <skip />
- <!-- no translation found for permgroupdesc_accounts (443982868906396781) -->
- <skip />
- <!-- no translation found for permgrouplab_hardwareControls (5074512938567152139) -->
- <skip />
- <!-- no translation found for permgroupdesc_hardwareControls (8772503144945278440) -->
- <skip />
- <!-- no translation found for permgrouplab_phoneCalls (7096448531266882376) -->
- <skip />
- <!-- no translation found for permgroupdesc_phoneCalls (6703873478653366233) -->
- <skip />
- <!-- no translation found for permgrouplab_systemTools (1840847965111633430) -->
- <skip />
- <!-- no translation found for permgroupdesc_systemTools (2810337951496685271) -->
- <skip />
- <!-- no translation found for permgrouplab_developmentTools (692844635256963358) -->
- <skip />
- <!-- no translation found for permgroupdesc_developmentTools (5253915519857796400) -->
- <skip />
- <string name="permlab_statusBar">"Controlar la barra de estado"</string>
- <string name="permdesc_statusBar">"Permite a las aplicaciones abrir, cerrar o deshabilitar la barra de estado y sus iconos."</string>
- <!-- no translation found for permlab_expandStatusBar (6382500803293284173) -->
- <skip />
- <!-- no translation found for permdesc_expandStatusBar (90953162060681436) -->
- <skip />
- <!-- no translation found for permlab_processOutgoingCalls (786316295241100144) -->
- <skip />
- <!-- no translation found for permdesc_processOutgoingCalls (1655242138991854396) -->
- <skip />
- <string name="permlab_receiveSms">"Recibir mensajes SMS"</string>
- <string name="permdesc_receiveSms">"Permite que la aplicación reciba y procese mensajes de texto. Una aplicación maliciosa puede controlar sus mensajes o eliminarlos sin que usted los vea."</string>
- <string name="permlab_receiveMms">"Recibir mensajes MMS"</string>
- <string name="permdesc_receiveMms">"Permite que la aplicación reciba y procese mensajes multimedia. Una aplicación maliciosa puede controlar sus mensajes o eliminarlos sin que usted los vea."</string>
- <string name="permlab_sendSms">"Enviar mensajes SMS"</string>
- <string name="permdesc_sendSms">"Permite a la aplicación enviar mensajes de texto. Una aplicación maliciosa puede hacerle gastar dinero enviando mensajes sin su confirmación."</string>
- <string name="permlab_readSms">"Leer mensajes SMS/MMS"</string>
- <string name="permdesc_readSms">"Permite que la aplicación lea los mensajes SMS almacenados en su teléfono o tarjeta SIM. Una aplicación maliciosa puede leer sus mensajes confidenciales."</string>
- <string name="permlab_writeSms">"Escribir mensajes SMS/MMS"</string>
- <string name="permdesc_writeSms">"Permite a la aplicación escribir mensajes SMS almacenados en su teléfono o tarjeta SIM. Una aplicación maliciosa puede eliminar sus mensajes."</string>
- <string name="permlab_receiveWapPush">"Recibir mensajes WAP"</string>
- <string name="permdesc_receiveWapPush">"Permite que la aplicación reciba y procese mensajes WAP. Una aplicación maliciosa puede controlar sus mensajes o eliminarlos sin que usted los vea."</string>
- <string name="permlab_getTasks">"Obtener información de tareas"</string>
- <string name="permdesc_getTasks">"Permite a la aplicación recuperar información sobre tareas que se acaban de ejecutar y tareas que se están ejecutando actualmente. Puede permitir que una aplicación maliciosa descubra información privada sobre otras aplicaciones."</string>
- <string name="permlab_reorderTasks">"Reordenar tareas"</string>
- <string name="permdesc_reorderTasks">"Permite que una aplicación mueva las tareas a primer plano y a segundo plano. Una aplicación maliciosa puede aparecer en primer plano sin su control."</string>
- <string name="permlab_setDebugApp">"Establecer aplicación de depuración"</string>
- <string name="permdesc_setDebugApp">"Permite a una aplicación activar la depuración para otra aplicación. Una aplicación maliciosa puede usar esta función para acabar con otras aplicaciones."</string>
- <string name="permlab_changeConfiguration">"Cambiar configuración"</string>
- <string name="permdesc_changeConfiguration">"Permite que una aplicación cambie la configuración actual, como la hora local o el tamaño general de la fuente."</string>
- <!-- no translation found for permlab_restartPackages (5836367540766044606) -->
- <skip />
- <!-- no translation found for permdesc_restartPackages (1764965996765573321) -->
- <skip />
- <!-- no translation found for permlab_setProcessForeground (4860990420780868638) -->
- <skip />
- <!-- no translation found for permdesc_setProcessForeground (3795477299954784360) -->
- <skip />
- <string name="permlab_forceBack">"Restablecer"</string>
- <string name="permdesc_forceBack">"Permite a la aplicación hacer que cualquier actividad que esté en primer plano se cierre y pase a segundo plano. Esta función no debería ser necesaria para las aplicaciones normales."</string>
- <string name="permlab_dump">"Volcar estado del sistema"</string>
- <string name="permdesc_dump">"Permite a la aplicación recuperar el estado interno del sistema. Una aplicación maliciosa puede recuperar una gran variedad de información privada y segura que normalmente no debería necesitar nunca."</string>
- <string name="permlab_addSystemService">"Agregar servicio del sistema"</string>
- <string name="permdesc_addSystemService">"Permite que la aplicación publique sus propios servicios de sistema de bajo nivel. Una aplicación maliciosa puede apropiarse del sistema y robar o dañar cualquier dato."</string>
- <string name="permlab_runSetActivityWatcher">"Establecer vigilante de actividades"</string>
- <string name="permdesc_runSetActivityWatcher">"Permite que una aplicación controle y supervise el modo en que el sistema inicia las actividades. Una aplicación maliciosa puede comprometer todo el sistema. Este permiso sólo es necesario para el desarrollo, nunca para el uso normal del dispositivo."</string>
- <string name="permlab_broadcastPackageRemoved">"Paquete de emisión eliminado"</string>
- <string name="permdesc_broadcastPackageRemoved">"Permite que una aplicación emita una notificación de que se ha eliminado un paquete de la aplicación. Una aplicación maliciosa puede usar esta función para acabar con cualquier otra aplicación que se esté ejecutando."</string>
- <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
- <skip />
- <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
- <skip />
- <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
- <skip />
- <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
- <skip />
- <string name="permlab_setProcessLimit">"Establecer límite de procesos"</string>
- <string name="permdesc_setProcessLimit">"Permite a una aplicación controle el número máximo de procesos que se ejecutarán. Esta función no es necesaria para las aplicaciones normales."</string>
- <string name="permlab_setAlwaysFinish">"Establecer finalizar siempre"</string>
- <string name="permdesc_setAlwaysFinish">"Permite a una aplicación controlar si las actividades han acabado en cuanto pasan a segundo plano. Esta función no es necesaria para las aplicaciones normales."</string>
- <string name="permlab_fotaUpdate">"Instalación de actualización del sistema"</string>
- <string name="permdesc_fotaUpdate">"Permite a una aplicación recibir notifications about pending system updates and trigger their su instalación. Una aplicación maliciosa puede usar esta función para corromper el sistema con actualizaciones no autorizadas o interferir en el proceso de actualización."</string>
- <!-- no translation found for permlab_batteryStats (1598947993704535568) -->
- <skip />
- <!-- no translation found for permdesc_batteryStats (6247598531831307989) -->
- <skip />
- <string name="permlab_internalSystemWindow">"Ventana de sistema interno"</string>
- <string name="permdesc_internalSystemWindow">"Permite la creación de ventanas destinadas a ser usadas por la interfaz de usuario del sistema interno. No está destinada al uso por aplicaciones normales."</string>
- <string name="permlab_systemAlertWindow">"Ventana de alerta del sistema"</string>
- <string name="permdesc_systemAlertWindow">"Permite a una aplicación mostrar ventanas de alerta del sistema. Una aplicación maliciosa puede controlar toda la pantalla del dispositivo."</string>
- <string name="permlab_setAnimationScale">"Establecer escala de animación"</string>
- <string name="permdesc_setAnimationScale">"Permite que una aplicación cambie la velocidad de animación global (animaciones más rápidas o más lentas) en cualquier momento."</string>
- <string name="permlab_manageAppTokens">"Administrar credenciales de aplicación"</string>
- <string name="permdesc_manageAppTokens">"Permite a las aplicaciones crear y gestionar sus propios credenciales, saltándose su orden Z normal. Esta función no debería ser necesaria para las aplicaciones normales."</string>
- <string name="permlab_injectEvents">"Introducir eventos de entrada"</string>
- <string name="permdesc_injectEvents">"Permite a una aplicación ofrecer sus propios eventos de entrada (pulsaciones de teclas, etc.) a otras aplicaciones. Una aplicación maliciosa puede usar esta función para controlar el dispositivo."</string>
- <string name="permlab_readInputState">"Leer estado de entrada"</string>
- <string name="permdesc_readInputState">"Permite que las aplicaciones vigilen las teclas que pulsa incluso cuando interactúe con otra aplicación (como al introducir una contraseña). Esta función no debería ser necesaria para las aplicaciones normales."</string>
- <string name="permlab_setOrientation">"Establecer orientación"</string>
- <string name="permdesc_setOrientation">"Permite que una aplicación cambie la rotación de la pantalla en cualquier momento. No debería ser necesaria en aplicaciones normales."</string>
- <string name="permlab_signalPersistentProcesses">"Señalar procesos persistentes"</string>
- <string name="permdesc_signalPersistentProcesses">"Permite a la aplicación solicitar que la señal suministrada se envíe a todos los procesos persistentes."</string>
- <string name="permlab_persistentActivity">"Actividades persistentes"</string>
- <string name="permdesc_persistentActivity">"Permite que una aplicación convierta partes de sí misma en persistentes, de forma que el sistema no pueda usarlas para otras aplicaciones."</string>
- <string name="permlab_deletePackages">"Borrar paquetes"</string>
- <string name="permdesc_deletePackages">"Permite que una aplicación elimine paquetes Android. Una aplicación maliciosa puede usar esta función para eliminar importantes aplicaciones."</string>
- <!-- no translation found for permlab_clearAppUserData (3858185484601410171) -->
- <skip />
- <!-- no translation found for permdesc_clearAppUserData (7233537744753081136) -->
- <skip />
- <string name="permlab_deleteCacheFiles">"Borrar archivos de caché"</string>
- <string name="permdesc_deleteCacheFiles">"Permite que una aplicación elimine archivos de la caché."</string>
- <!-- no translation found for permlab_getPackageSize (6743556676630447973) -->
- <skip />
- <!-- no translation found for permdesc_getPackageSize (2893996655828539776) -->
- <skip />
- <string name="permlab_installPackages">"Instalar paquetes"</string>
- <string name="permdesc_installPackages">"Permite a una aplicación instalar paquetes Android nuevos o actualizados. Una aplicación maliciosa puede usar esta función para agregar nuevas aplicaciones con permisos arbitrariamente poderosos."</string>
- <string name="permlab_clearAppCache">"Borrar datos de la caché de la aplicación"</string>
- <string name="permdesc_clearAppCache">"Permite que una aplicación libere memoria de almacenamiento del dispositivo eliminando archivos del directorio caché de la aplicación. El acceso suele estar muy restringido al proceso del sistema."</string>
- <!-- no translation found for permlab_readLogs (6653488552442991707) -->
- <skip />
- <!-- no translation found for permdesc_readLogs (356352685800884319) -->
- <skip />
- <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
- <skip />
- <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
- <skip />
- <string name="permlab_changeComponentState">"Habilitar o deshabilitar componentes de la aplicación"</string>
- <string name="permdesc_changeComponentState">"Permite que una aplicación cambie si un componente de otra aplicación está habilitado o no. Una aplicación maliciosa puede usar esta función para deshabilitar importantes capacidades del dispositivo. Se debe tener cuidado con el permiso, ya que los componentes de la aplicación se pueden volver inestables o inconsistentes."</string>
- <string name="permlab_setPreferredApplications">"Establecer aplicaciones preferidas"</string>
- <string name="permdesc_setPreferredApplications">"Permite que una aplicación modifique sus aplicaciones preferidas. Esta función puede permitir que una aplicación maliciosa cambie silenciosamente las aplicaciones que se están ejecutando y haga que las aplicaciones existentes recopilen datos privados."</string>
- <string name="permlab_writeSettings">"Escribir configuración del sistema"</string>
- <string name="permdesc_writeSettings">"Permite a una aplicación modificar los datos de configuración del sistema. Una aplicación maliciosa puede corromper la configuración del sistema."</string>
- <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
- <skip />
- <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
- <skip />
- <!-- no translation found for permlab_writeGservices (296370685945777755) -->
- <skip />
- <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
- <skip />
- <string name="permlab_receiveBootCompleted">"Ejecutar al arrancar"</string>
- <string name="permdesc_receiveBootCompleted">"Permite que una aplicación se inicie en cuanto el sistema haya terminado de arrancar. Esto puede hacer que el dispositivo tarde más en iniciarse y que la aplicación ralentice todo el dispositivo al ejecutarse siempre."</string>
- <string name="permlab_broadcastSticky">"Intento de emisión permanente"</string>
- <string name="permdesc_broadcastSticky">"Permite que una aplicación envíe emisiones continuas, que permanecen una vez que termina la emisión. Una aplicación maliciosa puede hacer que el dispositivo sea lento o inestable y use demasiada memoria."</string>
- <string name="permlab_readContacts">"Leer datos de contacto"</string>
- <string name="permdesc_readContacts">"Permite que una aplicación lea todos los datos (de dirección) de contacto almacenados en su dispositivo. Una aplicación maliciosa puede usar esta función para enviar sus datos a otras personas."</string>
- <string name="permlab_writeContacts">"Escribir datos de contactos"</string>
- <string name="permdesc_writeContacts">"Permite a una aplicación modificar los datos (de dirección) de contacto almacenados en su dispositivo. Una aplicación maliciosa puede usar esta función para borrar o modificar sus datos de contacto."</string>
- <!-- no translation found for permlab_writeOwnerData (8036840529708535113) -->
- <skip />
- <!-- no translation found for permdesc_writeOwnerData (5873447528845878348) -->
- <skip />
- <!-- no translation found for permlab_readOwnerData (1847040178513733757) -->
- <skip />
- <!-- no translation found for permdesc_readOwnerData (7563299529149214764) -->
- <skip />
- <!-- no translation found for permlab_readCalendar (2111238731453410895) -->
- <skip />
- <!-- no translation found for permdesc_readCalendar (4408253940601239114) -->
- <skip />
- <!-- no translation found for permlab_writeCalendar (7518052789370653396) -->
- <skip />
- <!-- no translation found for permdesc_writeCalendar (8057304232140147596) -->
- <skip />
- <!-- no translation found for permlab_accessMockLocation (321094551062270213) -->
- <skip />
- <!-- no translation found for permdesc_accessMockLocation (3651565866471419739) -->
- <skip />
- <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
- <skip />
- <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
- <skip />
- <string name="permlab_accessFineLocation">"Acceder a ubicación de GPS"</string>
- <string name="permdesc_accessFineLocation">"Acceda al sistema de posicionamiento global (GPS) del dispositivo, en caso de que esté disponible. Una aplicación maliciosa puede usar esta función para determinar dónde está y puede consumir batería adicional."</string>
- <string name="permlab_accessCoarseLocation">"Acceder a ubicación de red"</string>
- <string name="permdesc_accessCoarseLocation">"Utilice la base de datos de la red para determinar una ubicación aproximada del dispositivo, en caso de que esté disponible. Una aplicación maliciosa puede usar esta opción para determinar aproximadamente dónde está."</string>
- <string name="permlab_accessSurfaceFlinger">"Acceder a SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger">"Permite que la aplicación use las características de bajo nivel de SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer">"Leer búfer de trama"</string>
- <string name="permdesc_readFrameBuffer">"Permite que la aplicación lea el contenido del búfer de trama."</string>
- <string name="permlab_modifyAudioSettings">"Modificar configuración de audio"</string>
- <string name="permdesc_modifyAudioSettings">"Permite que la aplicación modifique la configuración de audio global, como el volumen y el enrutamiento."</string>
- <string name="permlab_recordAudio">"Grabar audio"</string>
- <string name="permdesc_recordAudio">"Permite que la aplicación acceda a la ruta de grabación de audio."</string>
- <string name="permlab_camera">"Cámara"</string>
- <string name="permdesc_camera">"Permite que la aplicación saque fotos con la cámara. Esto permite que la aplicación capture en cualquier momento imágenes que la cámara esté viendo."</string>
- <string name="permlab_brick">"Deshabilitar dispositivo"</string>
- <string name="permdesc_brick">"Permite que la aplicación deshabilite de forma permanente todo el dispositivo. Esto es muy peligroso."</string>
- <!-- no translation found for permlab_reboot (8844650672567077423) -->
- <skip />
- <!-- no translation found for permdesc_reboot (4704919552870918328) -->
- <skip />
- <string name="permlab_mount_unmount_filesystems">"Montar y desmontar archivos del sistema"</string>
- <string name="permdesc_mount_unmount_filesystems">"Permite que la aplicación monte y desmonte archivos del sistema para el almacenamiento extraíble."</string>
- <string name="permlab_vibrate">"Vibrador"</string>
- <string name="permdesc_vibrate">"Permite a la aplicación controlar el vibrador."</string>
- <string name="permlab_flashlight">"Linterna"</string>
- <string name="permdesc_flashlight">"Permite a la aplicación controlar la linterna."</string>
- <string name="permlab_hardware_test">"Prueba de hardware"</string>
- <string name="permdesc_hardware_test">"Permite a la aplicación controlar distintos periféricos para realizar una prueba de hardware."</string>
- <string name="permlab_callPhone">"Llamar a números de teléfono"</string>
- <string name="permdesc_callPhone">"Permite que la aplicación llame a los números de teléfono sin que usted intervenga. Una aplicación maliciosa puede hacer que aparezcan llamadas inesperadas en su factura del teléfono."</string>
- <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
- <skip />
- <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
- <skip />
- <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
- <skip />
- <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
- <skip />
- <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
- <skip />
- <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
- <skip />
- <!-- no translation found for permlab_modifyPhoneState (7791696535097912313) -->
- <skip />
- <!-- no translation found for permdesc_modifyPhoneState (6352405226410454770) -->
- <skip />
- <!-- no translation found for permlab_readPhoneState (7320082586621086653) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (8004450067066407969) -->
- <skip />
- <!-- no translation found for permlab_wakeLock (1591164750935072136) -->
- <skip />
- <!-- no translation found for permdesc_wakeLock (160471538196734936) -->
- <skip />
- <string name="permlab_devicePower">"Alimentación del dispositivo"</string>
- <string name="permdesc_devicePower">"Permite a la aplicación encender o apagar el dispositivo o mantenerlo encendido."</string>
- <string name="permlab_factoryTest">"Prueba de fábrica"</string>
- <string name="permdesc_factoryTest">"Se ejecuta como una prueba de fabricante de bajo nivel, permitiendo el acceso completo al hardware del dispositivo. Sólo disponible cuando un dispositivo se ejecuta en el modo de prueba del fabricante."</string>
- <string name="permlab_setWallpaper">"Establecer fondo de escritorio"</string>
- <string name="permdesc_setWallpaper">"Permite a la aplicación establecer el fondo de escritorio del sistema."</string>
- <!-- no translation found for permlab_setWallpaperHints (4192438316932517807) -->
- <skip />
- <!-- no translation found for permdesc_setWallpaperHints (738757439960921674) -->
- <skip />
- <string name="permlab_masterClear">"Restablecimiento de todo el sistema"</string>
- <string name="permdesc_masterClear">"Permite que una aplicación restablezca por completo los valores de fábrica del sistema, borrando todos los datos, la configuración y las aplicaciones instaladas."</string>
- <!-- no translation found for permlab_setTimeZone (477196167239548690) -->
- <skip />
- <!-- no translation found for permdesc_setTimeZone (8564892020460841198) -->
- <skip />
- <!-- no translation found for permlab_getAccounts (2764070033402295170) -->
- <skip />
- <!-- no translation found for permdesc_getAccounts (1203491378748649898) -->
- <skip />
- <!-- no translation found for permlab_accessNetworkState (2032916924886010827) -->
- <skip />
- <!-- no translation found for permdesc_accessNetworkState (7081329402551195933) -->
- <skip />
- <!-- no translation found for permlab_createNetworkSockets (4706698319966917864) -->
- <skip />
- <!-- no translation found for permdesc_createNetworkSockets (2580337178778551792) -->
- <skip />
- <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
- <skip />
- <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
- <skip />
- <!-- no translation found for permlab_changeNetworkState (2710779001260856872) -->
- <skip />
- <!-- no translation found for permdesc_changeNetworkState (8076109230787022270) -->
- <skip />
- <!-- no translation found for permlab_accessWifiState (3613679494230374297) -->
- <skip />
- <!-- no translation found for permdesc_accessWifiState (8226508433563326925) -->
- <skip />
- <!-- no translation found for permlab_changeWifiState (6043889338995432957) -->
- <skip />
- <!-- no translation found for permdesc_changeWifiState (7829372845909567994) -->
- <skip />
- <!-- no translation found for permlab_bluetoothAdmin (5513286736585647334) -->
- <skip />
- <!-- no translation found for permdesc_bluetoothAdmin (1838208497914347365) -->
- <skip />
- <!-- no translation found for permlab_bluetooth (6378797624765639115) -->
- <skip />
- <!-- no translation found for permdesc_bluetooth (8592386018922265273) -->
- <skip />
- <!-- no translation found for permlab_disableKeyguard (4574886811903233903) -->
- <skip />
- <!-- no translation found for permdesc_disableKeyguard (815972646344251271) -->
- <skip />
- <!-- no translation found for permlab_readSyncSettings (8818819977141505127) -->
- <skip />
- <!-- no translation found for permdesc_readSyncSettings (8454705401908767847) -->
- <skip />
- <!-- no translation found for permlab_writeSyncSettings (4514911143753152941) -->
- <skip />
- <!-- no translation found for permdesc_writeSyncSettings (7630627689635091836) -->
- <skip />
- <!-- no translation found for permlab_readSyncStats (5748337739678952863) -->
- <skip />
- <!-- no translation found for permdesc_readSyncStats (582551457321957183) -->
- <skip />
- <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
- <skip />
- <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
- <skip />
- <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
- <skip />
- <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
- <skip />
- <!-- no translation found for phoneTypes:0 (6070018634209800981) -->
- <!-- no translation found for phoneTypes:1 (1514509689885965711) -->
- <!-- no translation found for phoneTypes:2 (497473201754095234) -->
- <!-- no translation found for phoneTypes:3 (5554432614281047787) -->
- <!-- no translation found for phoneTypes:4 (2222084401110150993) -->
- <!-- no translation found for phoneTypes:5 (2290007103906353121) -->
- <!-- no translation found for phoneTypes:6 (6930783706213719251) -->
- <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
- <!-- no translation found for emailAddressTypes:0 (1540640638077615417) -->
- <!-- no translation found for emailAddressTypes:1 (4252853367575831977) -->
- <!-- no translation found for emailAddressTypes:2 (7158046581744435718) -->
- <!-- no translation found for emailAddressTypes:3 (3625034471181268169) -->
- <!-- no translation found for postalAddressTypes:0 (5732960259696659380) -->
- <!-- no translation found for postalAddressTypes:1 (7132240704786130285) -->
- <!-- no translation found for postalAddressTypes:2 (1317604357745852817) -->
- <!-- no translation found for postalAddressTypes:3 (1582953598462826702) -->
- <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
- <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
- <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
- <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
- <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
- <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
- <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
- <!-- no translation found for imProtocols:0 (3318725788774688043) -->
- <!-- no translation found for imProtocols:1 (1787713387022932886) -->
- <!-- no translation found for imProtocols:2 (6751174158442316516) -->
- <!-- no translation found for imProtocols:3 (1151283347465052653) -->
- <!-- no translation found for imProtocols:4 (2157980008878817934) -->
- <!-- no translation found for imProtocols:5 (7836237460308230767) -->
- <!-- no translation found for imProtocols:6 (1180789904462172516) -->
- <!-- no translation found for imProtocols:7 (21955111672779862) -->
- <string name="keyguard_password_enter_pin_code">"Introducir código PIN"</string>
- <string name="keyguard_password_wrong_pin_code">"¡Código PIN incorrecto!"</string>
- <string name="keyguard_label_text">"Para desbloquear, pulse Menú y luego 0."</string>
- <string name="emergency_call_dialog_number_for_display">"Número de emergencia"</string>
- <string name="lockscreen_carrier_default">"(Fuera de servicio)"</string>
- <string name="lockscreen_screen_locked">"Pantalla bloqueada"</string>
- <string name="lockscreen_instructions_when_pattern_enabled">"Pulse Menú para desbloquear o realice una llamada de emergencia"</string>
- <string name="lockscreen_instructions_when_pattern_disabled">"Pulse Menú para desbloquear"</string>
- <string name="lockscreen_pattern_instructions">"Trazar patrón de desbloqueo"</string>
- <string name="lockscreen_emergency_call">"Llamada de emergencia"</string>
- <string name="lockscreen_pattern_correct">"¡Correcto!"</string>
- <string name="lockscreen_pattern_wrong">"¡Patrón incorrecto! Inténtelo de nuevo"</string>
- <string name="lockscreen_plugged_in">"Cargando (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
- <string name="lockscreen_low_battery">"Conectar cargador"</string>
- <!-- no translation found for lockscreen_missing_sim_message_short (5051192587315492957) -->
- <skip />
- <string name="lockscreen_missing_sim_message">"No hay ninguna tarjeta SIM en el dispositivo"</string>
- <string name="lockscreen_missing_sim_instructions">"Inserte una tarjeta SIM"</string>
- <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
- <skip />
- <!-- no translation found for lockscreen_sim_puk_locked_message (1005803622871256359) -->
- <skip />
- <!-- no translation found for lockscreen_sim_puk_locked_instructions (5033160098036646955) -->
- <skip />
- <!-- no translation found for lockscreen_sim_locked_message (7398401200962556379) -->
- <skip />
- <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (5939537246164692076) -->
- <skip />
- <!-- unknown placeholder BREAK in lockscreen_too_many_failed_attempts_dialog_message -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_almost_glogin (1569017295989454551) -->
- <skip />
- <string name="lockscreen_too_many_failed_attempts_countdown">"Inténtelo de nuevo en <xliff:g id="NUMBER">%d</xliff:g> segundos"</string>
- <!-- no translation found for lockscreen_forgot_pattern_button_text (4219994639843985488) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_too_many_attempts (7504679498838839295) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_instructions (6542400673357252011) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_username_hint (6378418320242015111) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_password_hint (3224230234042131153) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_submit_button (5562051040043760034) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
- <skip />
- <!-- unknown placeholder FORMAT in status_bar_time_format -->
- <skip />
- <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
- <skip />
- <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
- <skip />
- <!-- no translation found for hour_ampm (7665432130905376251) -->
- <skip />
- <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
- <skip />
- <!-- no translation found for status_bar_clear_all_button (2202004591253243750) -->
- <skip />
- <string name="status_bar_no_notifications_title">"Notificaciones"</string>
- <string name="status_bar_ongoing_events_title">"En curso"</string>
- <string name="status_bar_latest_events_title">"Últimos eventos"</string>
- <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g>"</string>
- <string name="battery_status_charging">"Cargando…"</string>
- <string name="battery_low_title">"Conectar cargador"</string>
- <string name="battery_low_subtitle">"Batería baja"</string>
- <string name="battery_low_percent_format">"Menos de <xliff:g id="NUMBER">%d%%</xliff:g> restantes"</string>
- <string name="factorytest_failed">"Fallo al realizar la prueba de fábrica"</string>
- <string name="factorytest_not_system">"La acción FACTORY_TEST sólo es compatible con los paquetes instalados en /system/app."</string>
- <string name="factorytest_no_action">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST."</string>
- <string name="factorytest_reboot">"Reiniciar"</string>
- <string name="save_password_label">"Confirmar"</string>
- <string name="save_password_message">"¿Quiere que el explorador recuerde esta contraseña?"</string>
- <string name="save_password_notnow">"Ahora no"</string>
- <string name="save_password_remember">"Recordar"</string>
- <string name="save_password_never">"Nunca"</string>
- <string name="open_permission_deny">"No tiene permiso para abrir esta página."</string>
- <!-- no translation found for text_copied (6106873823411904723) -->
- <skip />
- <string name="more_item_label">"Más"</string>
- <string name="prepend_shortcut_label">"Menú+"</string>
- <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
- <skip />
- <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
- <skip />
- <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
- <skip />
- <string name="search_go">"IR"</string>
- <string name="today">"Hoy"</string>
- <string name="yesterday">"Ayer"</string>
- <string name="tomorrow">"Mañana"</string>
- <!-- no translation found for oneMonthDurationPast (3402179395240209557) -->
- <skip />
- <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
- <skip />
- <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
- <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
- <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
- <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
- <!-- no translation found for num_hours_ago:one (853404611989669641) -->
- <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
- <!-- no translation found for num_days_ago:one (4222479980812128212) -->
- <!-- no translation found for num_days_ago:other (5445701370433601703) -->
- <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
- <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
- <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
- <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
- <!-- no translation found for in_num_hours:one (6501470863235186391) -->
- <!-- no translation found for in_num_hours:other (4415358752953289251) -->
- <!-- no translation found for in_num_days:one (5608475533104443893) -->
- <!-- no translation found for in_num_days:other (3827193006163842267) -->
- <string name="preposition_for_date">"en %s"</string>
- <string name="preposition_for_time">"en %s"</string>
- <string name="preposition_for_year">"en %s"</string>
- <string name="day">"día"</string>
- <string name="days">"días"</string>
- <string name="hour">"hora"</string>
- <string name="hours">"horas"</string>
- <string name="minute">"minuto"</string>
- <string name="minutes">"minutos"</string>
- <string name="second">"segundo"</string>
- <string name="seconds">"segundos"</string>
- <string name="week">"semana"</string>
- <string name="weeks">"semanas"</string>
- <!-- no translation found for year (8024790425994085153) -->
- <skip />
- <!-- no translation found for years (8592090054773244417) -->
- <skip />
- <string name="sunday">"Domingo"</string>
- <string name="monday">"Lunes"</string>
- <string name="tuesday">"Martes"</string>
- <string name="wednesday">"Miércoles"</string>
- <string name="thursday">"Jueves"</string>
- <string name="friday">"Viernes"</string>
- <string name="saturday">"Sábado"</string>
- <string name="every_weekday">"Todos los días laborables (Lun–Vie)"</string>
- <string name="daily">"Diario"</string>
- <string name="weekly">"Semanal en <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly">"Mensual"</string>
- <string name="yearly">"Anual"</string>
- <string name="VideoView_error_title">"Error de reproducción del vídeo"</string>
- <string name="VideoView_error_text_unknown">"Se ha producido un error al reproducir el vídeo seleccionado."</string>
- <string name="VideoView_error_button">"Aceptar"</string>
- <string name="am">"AM"</string>
- <string name="pm">"PM"</string>
- <!-- unknown placeholder FORMAT in numeric_date -->
- <skip />
- <!-- unknown placeholder FORMAT in wday1_date1_time1_wday2_date2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in wday1_date1_wday2_date2 -->
- <skip />
- <!-- unknown placeholder FORMAT in date1_time1_date2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in date1_date2 -->
- <skip />
- <!-- unknown placeholder FORMAT in time1_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in time_wday_date -->
- <skip />
- <!-- unknown placeholder FORMAT in wday_date -->
- <skip />
- <!-- unknown placeholder FORMAT in time_date -->
- <skip />
- <!-- unknown placeholder FORMAT in time_wday -->
- <skip />
- <!-- no translation found for full_date_month_first (6011143962222283357) -->
- <skip />
- <!-- no translation found for full_date_day_first (8621594762705478189) -->
- <skip />
- <!-- no translation found for medium_date_month_first (48990963718825728) -->
- <skip />
- <!-- no translation found for medium_date_day_first (2898992016440387123) -->
- <skip />
- <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
- <skip />
- <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
- <skip />
- <string name="noon">"mediodía"</string>
- <string name="Noon">"Mediodía"</string>
- <string name="midnight">"media noche"</string>
- <string name="Midnight">"Media noche"</string>
- <!-- unknown placeholder FORMAT in month_day -->
- <skip />
- <!-- unknown placeholder FORMAT in month -->
- <skip />
- <!-- unknown placeholder FORMAT in month_day_year -->
- <skip />
- <!-- unknown placeholder FORMAT in month_year -->
- <skip />
- <!-- no translation found for time_of_day (8375993139317154157) -->
- <skip />
- <!-- no translation found for date_and_time (9197690194373107109) -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_md1_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_md1_wday2_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_mdy1_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_wday2_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_md1_time1_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_md1_time1_wday2_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_mdy1_time1_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_time1_wday2_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_md1_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_md1_wday2_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_mdy1_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_wday2_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_md1_time1_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_md1_time1_wday2_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_mdy1_time1_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_time1_wday2_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_md1_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_md1_wday2_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_mdy1_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_wday2_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_md1_time1_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_md1_time1_wday2_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_mdy1_time1_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_time1_wday2_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month_day_year -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month_year -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month_day -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month -->
- <skip />
- <string name="day_of_week_long_sunday">"Domingo"</string>
- <string name="day_of_week_long_monday">"Lunes"</string>
- <string name="day_of_week_long_tuesday">"Martes"</string>
- <string name="day_of_week_long_wednesday">"Miércoles"</string>
- <string name="day_of_week_long_thursday">"Jueves"</string>
- <string name="day_of_week_long_friday">"Viernes"</string>
- <string name="day_of_week_long_saturday">"Sábado"</string>
- <string name="day_of_week_medium_sunday">"Dom"</string>
- <string name="day_of_week_medium_monday">"Lun"</string>
- <string name="day_of_week_medium_tuesday">"Mar"</string>
- <string name="day_of_week_medium_wednesday">"Mié"</string>
- <string name="day_of_week_medium_thursday">"Jue"</string>
- <string name="day_of_week_medium_friday">"Vie"</string>
- <string name="day_of_week_medium_saturday">"Sáb"</string>
- <string name="day_of_week_short_sunday">"Do"</string>
- <string name="day_of_week_short_monday">"Lu"</string>
- <string name="day_of_week_short_tuesday">"Ma"</string>
- <string name="day_of_week_short_wednesday">"Mi"</string>
- <string name="day_of_week_short_thursday">"Ju"</string>
- <string name="day_of_week_short_friday">"Vi"</string>
- <string name="day_of_week_short_saturday">"Sá"</string>
- <string name="day_of_week_shorter_sunday">"D"</string>
- <string name="day_of_week_shorter_monday">"L"</string>
- <string name="day_of_week_shorter_tuesday">"M"</string>
- <string name="day_of_week_shorter_wednesday">"X"</string>
- <string name="day_of_week_shorter_thursday">"J"</string>
- <string name="day_of_week_shorter_friday">"V"</string>
- <string name="day_of_week_shorter_saturday">"S"</string>
- <string name="day_of_week_shortest_sunday">"D"</string>
- <string name="day_of_week_shortest_monday">"L"</string>
- <string name="day_of_week_shortest_tuesday">"M"</string>
- <string name="day_of_week_shortest_wednesday">"X"</string>
- <string name="day_of_week_shortest_thursday">"J"</string>
- <string name="day_of_week_shortest_friday">"V"</string>
- <string name="day_of_week_shortest_saturday">"S"</string>
- <string name="month_long_january">"Enero"</string>
- <string name="month_long_february">"Febrero"</string>
- <string name="month_long_march">"Marzo"</string>
- <string name="month_long_april">"Abril"</string>
- <string name="month_long_may">"Mayo"</string>
- <string name="month_long_june">"Junio"</string>
- <string name="month_long_july">"Julio"</string>
- <string name="month_long_august">"Agosto"</string>
- <string name="month_long_september">"Septiembre"</string>
- <string name="month_long_october">"Octubre"</string>
- <string name="month_long_november">"Noviembre"</string>
- <string name="month_long_december">"Diciembre"</string>
- <string name="month_medium_january">"Ene"</string>
- <string name="month_medium_february">"Feb"</string>
- <string name="month_medium_march">"Mar"</string>
- <string name="month_medium_april">"Abr"</string>
- <string name="month_medium_may">"May"</string>
- <string name="month_medium_june">"Jun"</string>
- <string name="month_medium_july">"Jul"</string>
- <string name="month_medium_august">"Ago"</string>
- <string name="month_medium_september">"Sep"</string>
- <string name="month_medium_october">"Oct"</string>
- <string name="month_medium_november">"Nov"</string>
- <string name="month_medium_december">"Dic"</string>
- <string name="month_shortest_january">"E"</string>
- <string name="month_shortest_february">"F"</string>
- <string name="month_shortest_march">"M"</string>
- <string name="month_shortest_april">"A"</string>
- <string name="month_shortest_may">"M"</string>
- <string name="month_shortest_june">"E"</string>
- <string name="month_shortest_july">"E"</string>
- <string name="month_shortest_august">"A"</string>
- <string name="month_shortest_september">"S"</string>
- <string name="month_shortest_october">"O"</string>
- <string name="month_shortest_november">"N"</string>
- <string name="month_shortest_december">"D"</string>
- <!-- unknown placeholder FORMAT in elapsed_time_short_format_mm_ss -->
- <skip />
- <!-- unknown placeholder FORMAT in elapsed_time_short_format_h_mm_ss -->
- <skip />
- <string name="selectAll">"Seleccionar todo"</string>
- <string name="cut">"Cortar"</string>
- <!-- no translation found for cutAll (4474519683293791451) -->
- <skip />
- <string name="copy">"Copiar"</string>
- <!-- no translation found for copyAll (4777548804630476932) -->
- <skip />
- <string name="paste">"Pegar"</string>
- <string name="copyUrl">"Copiar URL"</string>
- <!-- no translation found for inputMethod (7911866729148111492) -->
- <skip />
- <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
- <skip />
- <string name="low_internal_storage_view_title">"Espacio de almacenamiento interno bajo"</string>
- <string name="low_internal_storage_view_text">"El dispositivo se está quedando sin espacio de almacenamiento interno"</string>
- <string name="ok">"Aceptar"</string>
- <string name="cancel">"Cancelar"</string>
- <string name="yes">"Aceptar"</string>
- <string name="no">"Cancelar"</string>
- <string name="capital_on">"Activar"</string>
- <string name="capital_off">"Desactivar"</string>
- <string name="whichApplication">"¿Qué aplicación desea usar?"</string>
- <string name="alwaysUse">"Usar siempre esta aplicación para esta actividad"</string>
- <!-- no translation found for clearDefaultHintMsg (5742432113023174321) -->
- <skip />
- <string name="chooseActivity">"Seleccionar una acción"</string>
- <string name="noApplications">"No hay ninguna aplicación disponible para llevar a cabo la acción"</string>
- <!-- no translation found for aerr_title (2654390351574026098) -->
- <skip />
- <!-- no translation found for aerr_application (4917288809565116720) -->
- <skip />
- <!-- no translation found for aerr_process (1273819861108073461) -->
- <skip />
- <!-- no translation found for anr_title (3305935690891435915) -->
- <skip />
- <!-- no translation found for anr_activity_application (1653036325679156678) -->
- <skip />
- <!-- no translation found for anr_activity_process (2674027618362070465) -->
- <skip />
- <!-- no translation found for anr_application_process (2163656674970221928) -->
- <skip />
- <!-- no translation found for anr_process (7747550780123472160) -->
- <skip />
- <!-- no translation found for force_close (9020954128872810669) -->
- <skip />
- <!-- no translation found for wait (7973775702304037058) -->
- <skip />
- <!-- no translation found for debug (857932504764728770) -->
- <skip />
- <string name="sendText">"Seleccionar qué hacer con el texto"</string>
- <!-- no translation found for volume_ringtone (4121694816346562058) -->
- <skip />
- <!-- no translation found for volume_music (4869950240104717493) -->
- <skip />
- <!-- no translation found for volume_call (5723421277753250395) -->
- <skip />
- <!-- no translation found for volume_alarm (2752102730973081294) -->
- <skip />
- <!-- no translation found for volume_unknown (6908187627672375742) -->
- <skip />
- <!-- no translation found for ringtone_default (2873893375149093475) -->
- <skip />
- <!-- no translation found for ringtone_default_with_actual (5474076151665761913) -->
- <skip />
- <!-- no translation found for ringtone_silent (7477159279081654685) -->
- <skip />
- <!-- no translation found for ringtone_picker_title (7055241890764367884) -->
- <skip />
- <!-- no translation found for ringtone_unknown (6888219771401173795) -->
- <skip />
- <!-- no translation found for wifi_available:one (8168012881468888470) -->
- <!-- no translation found for wifi_available:other (4666122955807117718) -->
- <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
- <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
- <!-- no translation found for select_character (3735110139249491726) -->
- <skip />
- <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
- <skip />
- <!-- no translation found for sms_control_title (2742400596989418394) -->
- <skip />
- <!-- no translation found for sms_control_message (3447126217666595989) -->
- <skip />
- <!-- no translation found for sms_control_yes (8839660939359273650) -->
- <skip />
- <!-- no translation found for sms_control_no (909756849988183801) -->
- <skip />
- <!-- no translation found for date_time_set (2495199891239480952) -->
- <skip />
- <!-- no translation found for default_permission_group (7742780381379652409) -->
- <skip />
- <!-- no translation found for no_permissions (85461124044682315) -->
- <skip />
- <!-- no translation found for perms_hide (4145325555929151849) -->
- <skip />
- <!-- no translation found for perms_show_all (6040194843455403173) -->
- <skip />
- <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
- <skip />
- <!-- no translation found for usb_storage_title (8699631567051394409) -->
- <skip />
- <!-- no translation found for usb_storage_message (5344039189213308733) -->
- <skip />
- <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
- <skip />
- <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
- <skip />
- <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
- <skip />
- <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
- <skip />
- <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
- <skip />
- <!-- no translation found for select_input_method (2658280517827502015) -->
- <skip />
- <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
- <skip />
- <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
- <skip />
- <!-- no translation found for candidates_style (7738463880139922176) -->
- <skip />
-</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 2ceea2c..495f8aa 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -101,9 +101,17 @@
<string name="global_action_lock">"Bloqueo de pantalla"</string>
<string name="global_action_power_off">"Apagar"</string>
<string name="global_action_toggle_silent_mode">"Modo silencio"</string>
- <string name="global_action_silent_mode_on_status">"El sonido está desactivado."</string>
- <string name="global_action_silent_mode_off_status">"El sonido está activado."</string>
+ <string name="global_action_silent_mode_on_status">"El sonido está desactivado. Activar."</string>
+ <string name="global_action_silent_mode_off_status">"El sonido está activado. Desactivar."</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
<string name="safeMode">"Modo seguro"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
<string name="permgrouplab_costMoney">"Servicios por los que tienes que pagar"</string>
<string name="permgroupdesc_costMoney">"Permite que las aplicaciones realicen acciones por las que puede que tengas que pagar."</string>
<string name="permgrouplab_messages">"Tus mensajes"</string>
@@ -149,7 +157,7 @@
<string name="permlab_setDebugApp">"habilitar depuración de aplicación"</string>
<string name="permdesc_setDebugApp">"Permite que una aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden utilizar este permiso para desactivar otras aplicaciones."</string>
<string name="permlab_changeConfiguration">"cambiar la configuración de la interfaz de usuario"</string>
- <string name="permdesc_changeConfiguration">"Permite que una aplicación cambie la configuración actual como, por ejemplo, la configuración regional o el tamaño de fuente general."</string>
+ <string name="permdesc_changeConfiguration">"Permite que una aplicación cambie la configuración actual como, por ejemplo, la configuración local o el tamaño de fuente general."</string>
<string name="permlab_restartPackages">"reiniciar otras aplicaciones"</string>
<string name="permdesc_restartPackages">"Permite que una aplicación reinicie de forma forzosa otras aplicaciones."</string>
<string name="permlab_setProcessForeground">"impedir su interrupción"</string>
@@ -260,8 +268,10 @@
<string name="permdesc_brick">"Permite que la aplicación inhabilite todas las funciones del teléfono de forma permanente. Este permiso es muy peligroso."</string>
<string name="permlab_reboot">"forzar reinicio del teléfono"</string>
<string name="permdesc_reboot">"Permite que la aplicación fuerce al teléfono a reiniciarse."</string>
- <string name="permlab_mount_unmount_filesystems">"montar y desmontar sistemas de archivos"</string>
- <string name="permdesc_mount_unmount_filesystems">"Permite que las aplicaciones monten y desmonten sistemas de archivos para un almacenamiento extraíble."</string>
+ <string name="permlab_mount_unmount_filesystems">"activar y desactivar sistemas de archivos"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Permite que las aplicaciones activen y desactiven sistemas de archivos para un almacenamiento extraíble."</string>
+ <string name="permlab_mount_format_filesystems">"formatear almacenamiento externo"</string>
+ <string name="permdesc_mount_format_filesystems">"Permite a la aplicación formatear un almacenamiento extraíble."</string>
<string name="permlab_vibrate">"controlar vibración"</string>
<string name="permdesc_vibrate">"Permite que la aplicación controle la función de vibración."</string>
<string name="permlab_flashlight">"controlar linterna"</string>
@@ -273,11 +283,13 @@
<string name="permlab_callPrivileged">"llamar directamente a cualquier número de teléfono"</string>
<string name="permdesc_callPrivileged">"Permite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin que el usuario intervenga. Las aplicaciones malintencionadas pueden realizar llamadas innecesarias e ilícitas a los servicios de emergencias."</string>
<string name="permlab_locationUpdates">"controlar las notificaciones de actualización de la ubicación"</string>
- <string name="permdesc_locationUpdates">"Permite habilitar/inhabilitar las notificaciones de actualización de la ubicación de la radio. No está destinado al uso por parte de aplicaciones normales."</string>
+ <string name="permdesc_locationUpdates">"Permite habilitar/inhabilitar las notificaciones de actualización de la señal móvil. No está destinado al uso por parte de aplicaciones normales."</string>
<string name="permlab_checkinProperties">"acceder a propiedades de registro"</string>
<string name="permdesc_checkinProperties">"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."</string>
+ <string name="permlab_bindGadget">"seleccionar gadgets"</string>
+ <string name="permdesc_bindGadget">"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."</string>
<string name="permlab_modifyPhoneState">"modificar estado del teléfono"</string>
- <string name="permdesc_modifyPhoneState">"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 radio, etc., sin necesidad de notificar al usuario."</string>
+ <string name="permdesc_modifyPhoneState">"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."</string>
<string name="permlab_readPhoneState">"leer el estado del teléfono"</string>
<string name="permdesc_readPhoneState">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. Una aplicación con este permiso puede determinar el número de teléfono de este teléfono, si una llamada está activa, el número al que está vinculado esa llamada, etc."</string>
<string name="permlab_wakeLock">"impedir que el teléfono entre en modo de suspensión"</string>
@@ -304,6 +316,8 @@
<string name="permdesc_writeApnSettings">"Permite que una aplicación modifique los valores de configuración de un APN como, por ejemplo, el proxy y el puerto de cualquier APN."</string>
<string name="permlab_changeNetworkState">"cambiar la conectividad de red"</string>
<string name="permdesc_changeNetworkState">"Permite que una aplicación cambie la conectividad de red de estado."</string>
+ <string name="permlab_changeBackgroundDataSetting">"cambiar configuración de uso de datos de referencia"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Permite a una aplicación cambiar la configuración de uso de los datos de referencia."</string>
<string name="permlab_accessWifiState">"ver estado de la conectividad Wi-Fi"</string>
<string name="permdesc_accessWifiState">"Permite que una aplicación vea la información sobre el estado de la conectividad Wi-Fi."</string>
<string name="permlab_changeWifiState">"cambiar estado de Wi-Fi"</string>
@@ -324,14 +338,10 @@
<string name="permdesc_subscribedFeedsRead">"Permite que una aplicación obtenga detalles sobre los feeds sincronizados en este momento."</string>
<string name="permlab_subscribedFeedsWrite">"escribir feeds a los que está suscrito el usuario"</string>
<string name="permdesc_subscribedFeedsWrite">"Permite que una aplicación modifique los feeds sincronizados actualmente. Este permiso podría provocar que una aplicación malintencionada cambie los feeds sincronizados."</string>
- <!-- no translation found for permlab_readDictionary (432535716804748781) -->
- <skip />
- <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
- <skip />
- <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
- <skip />
- <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
- <skip />
+ <string name="permlab_readDictionary">"leer diccionario definido por el usuario"</string>
+ <string name="permdesc_readDictionary">"Permite a una aplicación leer cualquier frase, palabra o nombre privado que el usuario haya almacenado en su diccionario."</string>
+ <string name="permlab_writeDictionary">"escribir en el diccionario definido por el usuario"</string>
+ <string name="permdesc_writeDictionary">"Permite a una aplicación escribir palabras nuevas en el diccionario del usuario."</string>
<string-array name="phoneTypes">
<item>"Casa"</item>
<item>"Móvil"</item>
@@ -343,7 +353,7 @@
<item>"Personalizar"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item>"Casa"</item>
+ <item>"Personal"</item>
<item>"Trabajo"</item>
<item>"Otra"</item>
<item>"Personalizar"</item>
@@ -377,19 +387,20 @@
</string-array>
<string name="keyguard_password_enter_pin_code">"Introduce el código PIN"</string>
<string name="keyguard_password_wrong_pin_code">"El código PIN es incorrecto."</string>
- <string name="keyguard_label_text">"Para desbloquear el teléfono, pulsa \"Menú\" y, a continuación, pulsa 0."</string>
+ <string name="keyguard_label_text">"Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0."</string>
<string name="emergency_call_dialog_number_for_display">"Número de emergencia"</string>
- <string name="lockscreen_carrier_default">"(Sin servicio)"</string>
- <string name="lockscreen_screen_locked">"Pantalla bloqueada."</string>
- <string name="lockscreen_instructions_when_pattern_enabled">"Pulsa \"Menú\" para desbloquear el teléfono o realizar una llamada de emergencia."</string>
- <string name="lockscreen_instructions_when_pattern_disabled">"Pulsa \"Menú\" para desbloquear el teléfono."</string>
- <string name="lockscreen_pattern_instructions">"Crear patrón para desbloquear"</string>
+ <string name="lockscreen_carrier_default">"(Sin cobertura)"</string>
+ <string name="lockscreen_screen_locked">"Pantalla bloqueada"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Pulsa la tecla de menú para desbloquear la pantalla."</string>
+ <string name="lockscreen_pattern_instructions">"Dibujar patrón de desbloqueo"</string>
<string name="lockscreen_emergency_call">"Llamada de emergencia"</string>
<string name="lockscreen_pattern_correct">"Correcto"</string>
<string name="lockscreen_pattern_wrong">"Inténtalo de nuevo"</string>
- <string name="lockscreen_plugged_in">"Cargando (<xliff:g id="NUMBER">%d%%</xliff:g>)..."</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
<string name="lockscreen_low_battery">"Conecta el cargador"</string>
- <string name="lockscreen_missing_sim_message_short">"No hay ninguna tarjeta SIM."</string>
+ <string name="lockscreen_missing_sim_message_short">"Falta la tarjeta SIM"</string>
<string name="lockscreen_missing_sim_message">"No se ha insertado ninguna tarjeta SIM en el teléfono."</string>
<string name="lockscreen_missing_sim_instructions">"Inserta una tarjeta SIM."</string>
<string name="lockscreen_network_locked_message">"Bloqueada para la red"</string>
@@ -410,30 +421,27 @@
<string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
<string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <!-- no translation found for hour_ampm (7618670480400517084) -->
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
<skip />
- <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
<skip />
<string name="status_bar_clear_all_button">"Cerrar notificaciones"</string>
- <string name="status_bar_no_notifications_title">"Ninguna notificación"</string>
+ <string name="status_bar_no_notifications_title">"No tienes notificaciones"</string>
<string name="status_bar_ongoing_events_title">"Entrante"</string>
<string name="status_bar_latest_events_title">"Notificaciones"</string>
- <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
<skip />
<string name="battery_status_charging">"Cargando..."</string>
<string name="battery_low_title">"Conecta el cargador"</string>
<string name="battery_low_subtitle">"Se está agotando la batería:"</string>
- <string name="battery_low_percent_format">"menos de <xliff:g id="NUMBER">%d%%</xliff:g> disponible."</string>
+ <string name="battery_low_percent_format">"menos del <xliff:g id="NUMBER">%d%%</xliff:g> disponible."</string>
<string name="factorytest_failed">"Fallo en la prueba de fábrica"</string>
<string name="factorytest_not_system">"La acción FACTORY_TEST sólo es compatible con los paquetes instalados en /system/app."</string>
<string name="factorytest_no_action">"No se ha encontrado ningún paquete que proporcione la acción FACTORY_TEST."</string>
<string name="factorytest_reboot">"Reiniciar"</string>
- <!-- no translation found for js_dialog_title (8143918455087008109) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
- <skip />
+ <string name="js_dialog_title">"La página \"<xliff:g id="TITLE">%s</xliff:g>\" dice:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"¿Quieres salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona \"Aceptar\" para continuar o \"Cancelar\" para permanecer en la página actual."</string>
<string name="save_password_label">"Confirmar"</string>
<string name="save_password_message">"¿Deseas que el navegador recuerde esta contraseña?"</string>
<string name="save_password_notnow">"Ahora no"</string>
@@ -442,7 +450,7 @@
<string name="open_permission_deny">"No dispones de permiso para abrir esta página."</string>
<string name="text_copied">"Texto copiado al portapapeles."</string>
<string name="more_item_label">"Más"</string>
- <string name="prepend_shortcut_label">"\"Menú\"+"</string>
+ <string name="prepend_shortcut_label">"MENU+"</string>
<string name="menu_space_shortcut_label">"espacio"</string>
<string name="menu_enter_shortcut_label">"intro"</string>
<string name="menu_delete_shortcut_label">"suprimir"</string>
@@ -484,22 +492,38 @@
<item quantity="one">"mañana"</item>
<item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"hace 1 segundo"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"hace 1 minuto"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"hace 1 hora"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"ayer"</item>
+ <item quantity="other">"hace <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"dentro de 1 segundo"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> segundos"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"dentro de 1 minuto"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> minutos"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"dentro de 1 hora"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> horas"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"mañana"</item>
+ <item quantity="other">"dentro de <xliff:g id="COUNT">%d</xliff:g> días"</item>
+ </plurals>
<string name="preposition_for_date">"el %s"</string>
<string name="preposition_for_time">"a las %s"</string>
<string name="preposition_for_year">"en %s"</string>
@@ -532,7 +556,7 @@
<string name="VideoView_error_button">"Aceptar"</string>
<string name="am">"a.m."</string>
<string name="pm">"p.m."</string>
- <string name="numeric_date">"<xliff:g id="MONTH">%m</xliff:g>/<xliff:g id="DAY">%d</xliff:g>/<xliff:g id="YEAR">%Y</xliff:g>"</string>
+ <string name="numeric_date">"<xliff:g id="DAY">%d</xliff:g>/<xliff:g id="MONTH">%m</xliff:g>/<xliff:g id="YEAR">%Y</xliff:g>"</string>
<string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
<string name="wday1_date1_wday2_date2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>"</string>
<string name="date1_time1_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
@@ -541,60 +565,58 @@
<string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
- <!-- no translation found for date_time (6104442718633642836) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
- <string name="full_date_month_first">"<xliff:g id="DAY">dd</xliff:g> de <xliff:g id="MONTH">MMMM</xliff:g> de <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="full_date_day_first">"<xliff:g id="MONTH">MMMM</xliff:g> de <xliff:g id="DAY">dd</xliff:g> de <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_month_first">"<xliff:g id="DAY">dd</xliff:g> de <xliff:g id="MONTH">MMM</xliff:g> de <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMM</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
- <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="DAY">d</xliff:g>' de '<xliff:g id="MONTH">MMMM</xliff:g>' de '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' de '<xliff:g id="MONTH">MMMM</xliff:g>' de '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="DAY">d</xliff:g>' de '<xliff:g id="MONTH">MMM</xliff:g>' de '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMM</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
<string name="noon">"mediodía"</string>
<string name="Noon">"Mediodía"</string>
<string name="midnight">"medianoche"</string>
<string name="Midnight">"Medianoche"</string>
- <!-- no translation found for month_day (5565829181417740906) -->
+ <!-- no translation found for month_day (3693060561170538204) -->
<skip />
- <!-- no translation found for month (7026169712234774086) -->
+ <!-- no translation found for month (1976700695144952053) -->
<skip />
- <string name="month_day_year">"<xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for month_year (9219019380312413367) -->
+ <string name="month_day_year">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
+ <!-- no translation found for month_year (2106203387378728384) -->
<skip />
<string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <string name="same_year_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>"</string>
- <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>"</string>
- <string name="same_year_mdy1_mdy2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR">%9$s</xliff:g>"</string>
+ <string name="same_year_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+ <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+ <string name="same_year_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="YEAR">%9$s</xliff:g>"</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR">%9$s</xliff:g>"</string>
- <string name="same_year_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> de <xliff:g id="MONTH1">%2$s</xliff:g> de <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> de <xliff:g id="MONTH2">%7$s</xliff:g> de <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_year_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> de <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> de <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> de <xliff:g id="MONTH1">%2$s</xliff:g> de <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> de <xliff:g id="MONTH2">%7$s</xliff:g> de <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="numeric_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>"</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>"</string>
- <string name="numeric_mdy1_mdy2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+ <string name="numeric_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
<string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
- <string name="numeric_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_month_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>"</string>
+ <string name="numeric_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>"</string>
<string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>"</string>
- <string name="same_month_mdy1_mdy2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+ <string name="same_month_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
<string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> de <xliff:g id="MONTH1">%2$s</xliff:g> de <xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> de <xliff:g id="MONTH2">%7$s</xliff:g> de <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
- <string name="same_month_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="abbrev_month_day_year">"<xliff:g id="DAY">%-d</xliff:g> de <xliff:g id="MONTH">%b</xliff:g> de <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
<skip />
- <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
<skip />
- <!-- no translation found for abbrev_month (3131032032850777433) -->
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
<skip />
<string name="day_of_week_long_sunday">"Domingo"</string>
<string name="day_of_week_long_monday">"Lunes"</string>
@@ -679,6 +701,7 @@
<string name="paste">"Pegar"</string>
<string name="copyUrl">"Copiar URL"</string>
<string name="inputMethod">"Método de introducción de texto"</string>
+ <string name="addToDictionary">"Añadir \"%s\" al diccionario"</string>
<string name="editTextMenuTitle">"Editar texto"</string>
<string name="low_internal_storage_view_title">"Poco espacio"</string>
<string name="low_internal_storage_view_text">"Se está agotando el espacio de almacenamiento del teléfono."</string>
@@ -686,11 +709,12 @@
<string name="cancel">"Cancelar"</string>
<string name="yes">"Aceptar"</string>
<string name="no">"Cancelar"</string>
+ <string name="dialog_alert_title">"Atención"</string>
<string name="capital_on">"Activado"</string>
<string name="capital_off">"Desconectado"</string>
<string name="whichApplication">"Completar acción utilizando"</string>
<string name="alwaysUse">"Utilizar de forma predeterminada para esta acción"</string>
- <string name="clearDefaultHintMsg">"Borrar valores predeterminados en \"Página principal &gt; menú de configuración &gt; Aplicaciones &gt; Administrar aplicaciones\"."</string>
+ <string name="clearDefaultHintMsg">"Borrar valores predeterminados en la página de configuración de la pantalla de inicio del teléfono &gt; Aplicaciones &gt; Administrar aplicaciones\"."</string>
<string name="chooseActivity">"Seleccionar una acción"</string>
<string name="noApplications">"Ninguna aplicación puede realizar esta acción."</string>
<string name="aerr_title">"Lo sentimos."</string>
@@ -704,12 +728,12 @@
<string name="force_close">"Forzar cierre"</string>
<string name="wait">"Esperar"</string>
<string name="debug">"Depurar"</string>
- <string name="sendText">"Seleccionar una acción para el texto"</string>
+ <string name="sendText">"Seleccionar la opción para compartir"</string>
<string name="volume_ringtone">"Volumen del timbre"</string>
<string name="volume_music">"Volumen multimedia"</string>
<string name="volume_music_hint_playing_through_bluetooth">"Reproduciendo a través de Bluetooth"</string>
<string name="volume_call">"Volumen de la llamada"</string>
- <string name="volume_call_hint_playing_through_bluetooth">"Reproduciendo a través de Bluetooth"</string>
+ <string name="volume_bluetooth_call">"Volumen de la llamada de Bluetooth"</string>
<string name="volume_alarm">"Volumen de alarma"</string>
<string name="volume_notification">"Volumen de notificaciones"</string>
<string name="volume_unknown">"Volumen"</string>
@@ -739,14 +763,53 @@
<string name="perms_show_all"><b>"Mostrar todos"</b></string>
<string name="googlewebcontenthelper_loading">"Cargando..."</string>
<string name="usb_storage_title">"Conectado por USB"</string>
- <string name="usb_storage_message">"Has conectado el teléfono al equipo mediante USB. Selecciona \"Montar\" si deseas copiar archivos entre el equipo y la tarjeta SD del teléfono."</string>
- <string name="usb_storage_button_mount">"Montar"</string>
- <string name="usb_storage_button_unmount">"No montar"</string>
+ <string name="usb_storage_message">"Has conectado el teléfono al equipo mediante USB. Selecciona \"Activar\" si deseas copiar archivos entre el equipo y la tarjeta SD del teléfono."</string>
+ <string name="usb_storage_button_mount">"Activar"</string>
+ <string name="usb_storage_button_unmount">"No activar"</string>
<string name="usb_storage_error_message">"Se ha producido un problema al intentar utilizar la tarjeta SD para el almacenamiento USB."</string>
<string name="usb_storage_notification_title">"Conectado por USB"</string>
<string name="usb_storage_notification_message">"Seleccionar para copiar archivos al/desde el equipo"</string>
+ <string name="usb_storage_stop_notification_title">"Desactivar almacenar en USB"</string>
+ <string name="usb_storage_stop_notification_message">"Seleccionar para desactivar USB."</string>
+ <string name="usb_storage_stop_title">"Desactivar almacenamiento USB"</string>
+ <string name="usb_storage_stop_message">"Antes de desactivar el almacenamiento USB, asegúrate de haber desactivado el host USB. Selecciona \"Desactivar\" para desactivar el almacenamiento USB."</string>
+ <string name="usb_storage_stop_button_mount">"Desactivar"</string>
+ <string name="usb_storage_stop_button_unmount">"Cancelar"</string>
+ <string name="usb_storage_stop_error_message">"Se ha producido un problema al desactivar el almacenamiento USB. Asegúrate de que has desactivado el host USB e inténtalo de nuevo."</string>
+ <string name="extmedia_format_title">"Formatear tarjeta SD"</string>
+ <string name="extmedia_format_message">"¿Estás seguro de que quieres formatear la tarjeta SD? Se perderán todos los datos de la tarjeta."</string>
+ <string name="extmedia_format_button_format">"Formato"</string>
<string name="select_input_method">"Seleccionar método de introducción de texto"</string>
- <string name="fast_scroll_alphabet">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style"><font fgcolor="#ff000000" bgcolor="#ff8080ff"><u>"candidatos"</u>"u&gt;"</font></string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidatos"</u></string>
+ <string name="ext_media_checking_notification_title">"Preparando tarjeta SD"</string>
+ <string name="ext_media_checking_notification_message">"Comprobando errores"</string>
+ <string name="ext_media_nofs_notification_title">"Tarjeta SD vacía"</string>
+ <string name="ext_media_nofs_notification_message">"La tarjeta SD está vacía o utiliza un sistema de archivos incompatible."</string>
+ <string name="ext_media_unmountable_notification_title">"Tarjeta SD dañada"</string>
+ <string name="ext_media_unmountable_notification_message">"La tarjeta SD está dañada. Es posible que sea necesario volver a formatearla."</string>
+ <string name="ext_media_badremoval_notification_title">"La tarjeta SD se ha extraído inesperadamente."</string>
+ <string name="ext_media_badremoval_notification_message">"Desactiva la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Es seguro extraer la tarjeta SD."</string>
+ <string name="ext_media_safe_unmount_notification_message">"Ya puedes extraer la tarjeta SD."</string>
+ <string name="ext_media_nomedia_notification_title">"Tarjeta SD extraída"</string>
+ <string name="ext_media_nomedia_notification_message">"La tarjeta SD se ha extraído. Inserta una nueva tarjeta SD para aumentar la capacidad de almacenamiento de tu dispositivo."</string>
+ <string name="activity_list_empty">"No se ha encontrado ninguna actividad coincidente."</string>
+ <string name="permlab_pkgUsageStats">"actualizar estadísticas de uso de componentes"</string>
+ <string name="permdesc_pkgUsageStats">"Permite la modificación de estadísticas recopiladas sobre el uso de componentes. No está destinado al uso por parte de aplicaciones normales."</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr-rFR/arrays.xml b/core/res/res/values-fr-rFR/arrays.xml
new file mode 100644
index 0000000..504ab0f
--- /dev/null
+++ b/core/res/res/values-fr-rFR/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2006, Google Inc.
+**
+** 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.
+*/
+-->
+<resources>
+
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_lat_lng">
+ <item>48850258</item>
+ <item>2351074</item>
+ </integer-array>
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_zoom">
+ <item>6</item>
+ </integer-array>
+
+</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index ef826cb..8bd064d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -38,7 +38,7 @@
<string name="badPin">"L\'ancien code PIN saisi est incorrect."</string>
<string name="badPuk">"Le code PUK saisi est incorrect."</string>
<string name="mismatchPin">"Les codes PIN saisis ne correspondent pas."</string>
- <string name="invalidPin">"Saisissez un code PIN comptant 4 à 8 chiffres."</string>
+ <string name="invalidPin">"Le code PIN doit compter de 4 à 8 chiffres."</string>
<string name="needPuk">"Votre carte SIM est verrouillée par code PUK. Saisissez le code PUK pour la déverrouiller."</string>
<string name="needPuk2">"Saisissez le code PUK2 pour débloquer la carte SIM."</string>
<string name="ClipMmi">"Identifiant d\'appelant entrant"</string>
@@ -58,8 +58,8 @@
<string name="serviceClassData">"Données"</string>
<string name="serviceClassFAX">"Télécopie"</string>
<string name="serviceClassSMS">"SMS"</string>
- <string name="serviceClassDataAsync">"Asynchronisées"</string>
- <string name="serviceClassDataSync">"Synchroniser"</string>
+ <string name="serviceClassDataAsync">"Asynchrones"</string>
+ <string name="serviceClassDataSync">"Synchrones"</string>
<string name="serviceClassPacket">"Paquet"</string>
<string name="serviceClassPAD">"PAD"</string>
<string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
@@ -84,7 +84,7 @@
<string name="httpErrorFileNotFound">"Le fichier demandé est introuvable."</string>
<string name="httpErrorTooManyRequests">"Trop de requêtes sont en cours de traitement. Veuillez réessayer ultérieurement."</string>
<string name="contentServiceSync">"Synchroniser"</string>
- <string name="contentServiceSyncNotificationTitle">"Synchroniser"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synchronisation"</string>
<string name="contentServiceTooManyDeletesNotificationDesc">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
<string name="low_memory">"La mémoire du téléphone est pleine ! Supprimez des fichiers pour libérer de l\'espace."</string>
<string name="me">"Moi"</string>
@@ -95,7 +95,7 @@
<string name="screen_lock">"Verrouillage de l\'écran"</string>
<string name="power_off">"Éteindre"</string>
<string name="shutdown_progress">"Arrêt en cours..."</string>
- <string name="shutdown_confirm">"Votre téléphone va s\'éteindra."</string>
+ <string name="shutdown_confirm">"Votre téléphone va s\'éteindre."</string>
<string name="no_recent_tasks">"Aucune application récente"</string>
<string name="global_actions">"Options du téléphone"</string>
<string name="global_action_lock">"Verrouillage de l\'écran"</string>
@@ -103,20 +103,28 @@
<string name="global_action_toggle_silent_mode">"Mode silencieux"</string>
<string name="global_action_silent_mode_on_status">"Le son est désactivé."</string>
<string name="global_action_silent_mode_off_status">"Le son est activé."</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
<string name="safeMode">"Mode sécurisé"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
<string name="permgrouplab_costMoney">"Services payants"</string>
<string name="permgroupdesc_costMoney">"Permet aux applications d\'effectuer des opérations payantes."</string>
<string name="permgrouplab_messages">"Vos messages"</string>
<string name="permgroupdesc_messages">"Permet de lire et rédiger vos SMS, e-mails et autres messages."</string>
<string name="permgrouplab_personalInfo">"Vos informations personnelles"</string>
- <string name="permgroupdesc_personalInfo">"Accédez directement aux contacts et au calendrier enregistrés sur votre téléphone."</string>
- <string name="permgrouplab_location">"Votre position géographique"</string>
+ <string name="permgroupdesc_personalInfo">"Accédez directement aux contacts et à l\'agenda enregistrés sur votre téléphone."</string>
+ <string name="permgrouplab_location">"Votre position"</string>
<string name="permgroupdesc_location">"Suivre votre position géographique"</string>
<string name="permgrouplab_network">"Communications réseau"</string>
<string name="permgroupdesc_network">"Permet à des applications d\'accéder à différentes fonctionnalités du réseau."</string>
<string name="permgrouplab_accounts">"Vos comptes Google"</string>
<string name="permgroupdesc_accounts">"Accédez aux comptes Google disponibles."</string>
- <string name="permgrouplab_hardwareControls">"Contrôles du matériel"</string>
+ <string name="permgrouplab_hardwareControls">"Commandes du matériel"</string>
<string name="permgroupdesc_hardwareControls">"Permet d\'accéder directement au matériel de l\'appareil."</string>
<string name="permgrouplab_phoneCalls">"Appels"</string>
<string name="permgroupdesc_phoneCalls">"Suivre, enregistrer et traiter les appels téléphoniques"</string>
@@ -124,216 +132,218 @@
<string name="permgroupdesc_systemTools">"Accès et contrôle de faible niveau du système."</string>
<string name="permgrouplab_developmentTools">"Outils de développement"</string>
<string name="permgroupdesc_developmentTools">"Ces fonctionnalités sont réservées aux développeurs d\'applications."</string>
- <string name="permlab_statusBar">"Désactiver ou modifier la barre d\'état"</string>
+ <string name="permlab_statusBar">"Désactivation ou modification de la barre d\'état"</string>
<string name="permdesc_statusBar">"Permet à une application de désactiver la barre d\'état ou d\'ajouter/supprimer des icônes système."</string>
<string name="permlab_expandStatusBar">"Agrandir/réduire la barre d\'état"</string>
<string name="permdesc_expandStatusBar">"Permet à l\'application de réduire ou d\'agrandir la barre d\'état."</string>
- <string name="permlab_processOutgoingCalls">"Intercepter les appels sortants"</string>
+ <string name="permlab_processOutgoingCalls">"Interception d\'appels sortants"</string>
<string name="permdesc_processOutgoingCalls">"Permet à l\'application de traiter des appels en cours et de modifier le numéro à composer. Des applications malveillantes peuvent suivre, rediriger ou empêcher des appels sortants."</string>
- <string name="permlab_receiveSms">"Recevoir SMS"</string>
- <string name="permdesc_receiveSms">"Permet à une application de recevoir et traiter des messages SMS. Des applications malveillantes peuvent surveiller vos messages ou les effacer sans que vous en ayez pris connaissance."</string>
- <string name="permlab_receiveMms">"recevoir des MMS"</string>
- <string name="permdesc_receiveMms">"Permet à une application de recevoir et traiter des messages MMS. Des applications malveillantes peuvent utiliser cette fonctionnalité pour surveiller vos messages ou les effacer sans que vous en ayez pris connaissance."</string>
- <string name="permlab_sendSms">"Envoyer des messages SMS"</string>
+ <string name="permlab_receiveSms">"Réception de SMS"</string>
+ <string name="permdesc_receiveSms">"Permet à une application de recevoir et traiter des messages SMS. Des applications malveillantes peuvent surveiller ou effacer vos messages sans que vous les ayez lus."</string>
+ <string name="permlab_receiveMms">"Réception des MMS"</string>
+ <string name="permdesc_receiveMms">"Permet à une application de recevoir et traiter des messages MMS. Des applications malveillantes peuvent utiliser cette fonctionnalité pour surveiller ou effacer vos messages sans que vous les ayez lus."</string>
+ <string name="permlab_sendSms">"Envoi de messages SMS"</string>
<string name="permdesc_sendSms">"Permet aux applications d\'envoyer des messages SMS. Des applications malveillantes peuvent entraîner des frais en envoyant des messages sans vous en demander la confirmation."</string>
- <string name="permlab_readSms">"Lire les SMS ou MMS"</string>
- <string name="permdesc_readSms">"Permet à l\'application de lire les messages SMS enregistrés dans la mémoire de votre téléphone ou sur votre carte SD. Des applications malveillantes peuvent lire vos messages confidentiels."</string>
- <string name="permlab_writeSms">"Modifier un SMS ou un MMS"</string>
- <string name="permdesc_writeSms">"Permet à une application d\'éditer des messages SMS enregistrés sur votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent ainsi supprimer vos messages."</string>
- <string name="permlab_receiveWapPush">"Recevoir WAP"</string>
+ <string name="permlab_readSms">"Lecture des SMS ou MMS"</string>
+ <string name="permdesc_readSms">"Permet à l\'application de lire les SMS enregistrés dans la mémoire de votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent lire vos messages confidentiels."</string>
+ <string name="permlab_writeSms">"Modification de SMS ou de MMS"</string>
+ <string name="permdesc_writeSms">"Permet à une application de modifier des messages SMS enregistrés sur votre téléphone ou sur votre carte SIM. Des applications malveillantes peuvent ainsi supprimer vos messages."</string>
+ <string name="permlab_receiveWapPush">"Réception de WAP"</string>
<string name="permdesc_receiveWapPush">"Permet à l\'application de recevoir et de traiter des messages WAP. Des applications malveillantes peuvent ainsi surveiller vos messages ou les effacer sans que vous en ayez pris connaissance."</string>
- <string name="permlab_getTasks">"Récupérer les applications en cours d\'exécution"</string>
+ <string name="permlab_getTasks">"Récupération des applications en cours d\'exécution"</string>
<string name="permdesc_getTasks">"Permet à l\'application de récupérer des informations sur des tâches en cours d\'exécution ou récemment utilisées. Des applications malveillantes peuvent ainsi obtenir des informations d\'ordre privé concernant d\'autres applications."</string>
- <string name="permlab_reorderTasks">"Réorganiser les applications en cours d\'exécution"</string>
+ <string name="permlab_reorderTasks">"Réorganisation des applications en cours d\'exécution"</string>
<string name="permdesc_reorderTasks">"Permet à une application de placer des tâches au premier plan ou en arrière-plan. Des applications malveillantes peuvent se placer inopinément au premier plan sans votre autorisation."</string>
- <string name="permlab_setDebugApp">"Activer le débogage de l\'application"</string>
+ <string name="permlab_setDebugApp">"Activation du débogage de l\'application"</string>
<string name="permdesc_setDebugApp">"Permet à une application d\'activer le mode de débogage d\'une autre application. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interrompre d\'autres applications de façon inopinée."</string>
- <string name="permlab_changeConfiguration">"Modifier les paramètres de l\'IU"</string>
+ <string name="permlab_changeConfiguration">"Modification des paramètres de l\'IU"</string>
<string name="permdesc_changeConfiguration">"Permet à une application de modifier la configuration actuelle (par ex. : la taille de la police générale ou des paramètres régionaux)."</string>
- <string name="permlab_restartPackages">"Relancer d\'autres applications"</string>
+ <string name="permlab_restartPackages">"Démarrage d\'autres applications"</string>
<string name="permdesc_restartPackages">"Permet à une application de forcer le lancement d\'autres applications."</string>
- <string name="permlab_setProcessForeground">"Empêcher l\'interruption"</string>
+ <string name="permlab_setProcessForeground">"Non-possibilité d\'interruption"</string>
<string name="permdesc_setProcessForeground">"Permet à une application d\'exécuter tout processus au premier plan afin qu\'il ne puisse pas être interrompu. Les applications normales ne devraient jamais nécessiter cette fonctionnalité."</string>
- <string name="permlab_forceBack">"Obliger l\'application à se fermer"</string>
+ <string name="permlab_forceBack">"Fermeture forcée de l\'application"</string>
<string name="permdesc_forceBack">"Permet à une application de forcer une autre application exécutée au premier plan à se fermer et à passer en arrière-plan. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_dump">"Récupérer l\'état interne du système"</string>
+ <string name="permlab_dump">"Vérification de l\'état interne du système"</string>
<string name="permdesc_dump">"Permet à l\'application de récupérer l\'état interne du système. Des applications malveillantes peuvent obtenir de nombreuses informations personnelles et sécurisées auxquelles elles ne devraient pas avoir accès."</string>
<string name="permlab_addSystemService">"Éditer des services à faible niveau"</string>
- <string name="permdesc_addSystemService">"Permet à l\'application de publier ses propres services de système de niveau inférieur. Des applications malveillantes peuvent prendre le contrôle du système et voler ou corrompre les données qu\'il contient."</string>
- <string name="permlab_runSetActivityWatcher">"Surveiller et contrôler tout lancement d\'application"</string>
+ <string name="permdesc_addSystemService">"Permet à l\'application de publier ses propres services de système de niveau inférieur. Des applications malveillantes peuvent prendre le contrôle du système et subtiliser ou endommager ses données."</string>
+ <string name="permlab_runSetActivityWatcher">"Contrôle du lancement des applications"</string>
<string name="permdesc_runSetActivityWatcher">"Permet à une application de suivre et de contrôler la façon dont le système lance des activités. Des applications malveillantes peuvent entièrement déstabiliser le système. Cette autorisation est uniquement nécessaire au développement et non pour l\'utilisation normale du téléphone."</string>
<string name="permlab_broadcastPackageRemoved">"Envoyer une diffusion sans paquet"</string>
<string name="permdesc_broadcastPackageRemoved">"Permet à une application de diffuser une notification lorsqu\'un paquet d\'application a été supprimé. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interrompre d\'autres applications en cours d\'exécution."</string>
<string name="permlab_broadcastSmsReceived">"Envoyer une diffusion reçue par SMS"</string>
<string name="permdesc_broadcastSmsReceived">"Permet à une application de diffuser une notification lors de la réception d\'un message SMS. Des applications malveillantes peuvent utiliser cette fonctionnalité pour falsifier des messages SMS entrants."</string>
- <string name="permlab_broadcastWapPush">"Envoyer une diffusion de réception de WAP PUSH"</string>
- <string name="permdesc_broadcastWapPush">"Permet à une application d\'envoyer une notification lors de la réception d\'un message WAP PUSH. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux accusés de réception de MMS ou remplacer le contenu de toute page Internet par des données malveillantes."</string>
- <string name="permlab_setProcessLimit">"Limiter le nombre de processus en cours d\'exécution"</string>
+ <string name="permlab_broadcastWapPush">"Envoi de diffusion de réception de WAP PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Permet à une application d\'envoyer une notification lors de la réception d\'un message WAP PUSH. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux accusés de réception de MMS ou remplacer le contenu de toute page Web par des données malveillantes."</string>
+ <string name="permlab_setProcessLimit">"Nombre maximal de processus en cours d\'exécution"</string>
<string name="permdesc_setProcessLimit">"Permet à une application de contrôler le nombre de processus maximal exécutés en même temps. Les applications normales n\'ont jamais recours à cette fonctionnalité."</string>
- <string name="permlab_setAlwaysFinish">"Fermer toutes les applications en tâche de fond"</string>
+ <string name="permlab_setAlwaysFinish">"Fermeture de toutes les applications en tâche de fond"</string>
<string name="permdesc_setAlwaysFinish">"Permet à une application de vérifier si des activités sont systématiquement interrompues lorsqu\'elles sont placées en tâche de fond. Cette fonctionnalité n\'est jamais utilisée par les applications normales."</string>
- <string name="permlab_fotaUpdate">"Installer automatiquement les mises à jour du système"</string>
- <string name="permdesc_fotaUpdate">"Permet à une application de recevoir des notifications concernant des mises à jour système en cours et de lancer leur installation. Des applications malveillantes peuvent utiliser cette fonctionnalité pour corrompre le système avec des mises à jour non autorisées ou plus généralement, pour interférer avec le processus de mise à jour."</string>
- <string name="permlab_batteryStats">"Modifier les statistiques de la batterie"</string>
+ <string name="permlab_fotaUpdate">"Installation des mises à jour du système"</string>
+ <string name="permdesc_fotaUpdate">"Permet à une application de recevoir des notifications sur des mises à jour système en cours et de lancer leur installation. Des applications malveillantes peuvent utiliser cette fonctionnalité pour endommager le système avec des mises à jour non autorisées ou interférer avec le processus de mise à jour."</string>
+ <string name="permlab_batteryStats">"Modification des statistiques de la batterie"</string>
<string name="permdesc_batteryStats">"Autoriser la modification des statistiques de la batterie. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_internalSystemWindow">"Afficher les fenêtres non autorisées"</string>
+ <string name="permlab_internalSystemWindow">"Affichage de fenêtres non autorisées"</string>
<string name="permdesc_internalSystemWindow">"Permet de créer des fenêtres conçues pour l\'interface utilisateur du système interne. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_systemAlertWindow">"Afficher les alertes au niveau du système"</string>
+ <string name="permlab_systemAlertWindow">"Affichage d\'alertes système"</string>
<string name="permdesc_systemAlertWindow">"Permet à une application d\'afficher des fenêtres d\'alerte système. Des applications malveillantes peuvent masquer la totalité de l\'écran du téléphone."</string>
- <string name="permlab_setAnimationScale">"Modifier la vitesse générale des animations"</string>
- <string name="permdesc_setAnimationScale">"Permet à une application de modifier à tout moment la vitesse globale des animations (pour les rendre plus lentes ou plus rapides)."</string>
- <string name="permlab_manageAppTokens">"Gérer les repères des applications"</string>
+ <string name="permlab_setAnimationScale">"Réglage de la vitesse des animations"</string>
+ <string name="permdesc_setAnimationScale">"Permet à une application de modifier à tout moment la vitesse générale des animations (pour les rendre plus lentes ou plus rapides)."</string>
+ <string name="permlab_manageAppTokens">"Gestion des repères des applications"</string>
<string name="permdesc_manageAppTokens">"Permet à des applications de créer et gérer leurs propres jetons en ignorant leur ordre de plan normal. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_injectEvents">"Appuyer sur des touches ou contrôler des commandes"</string>
+ <string name="permlab_injectEvents">"Utilisation des touches ou contrôle des commandes"</string>
<string name="permdesc_injectEvents">"Permet à une application de fournir ses propres commandes (touches enfoncées, etc.) à d\'autres applications. Des applications malveillantes peuvent utiliser cette fonctionnalité pour prendre le contrôle de votre téléphone."</string>
<string name="permlab_readInputState">"Enregistrer le texte saisi et les actions effectuées"</string>
<string name="permdesc_readInputState">"Permet à des applications d\'identifier les touches sur lesquelles vous appuyez même lorsque vous utilisez une autre application (lors de la saisie d\'un mot de passe, par exemple). Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_bindInputMethod">"connecter à un mode de saisie"</string>
+ <string name="permlab_bindInputMethod">"Association à un mode de saisie"</string>
<string name="permdesc_bindInputMethod">"Permet au support de se connecter à l\'interface de plus haut niveau d\'un mode de saisie. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_setOrientation">"Changer l\'orientation de l\'écran"</string>
+ <string name="permlab_setOrientation">"Changement d\'orientation de l\'écran"</string>
<string name="permdesc_setOrientation">"Permet à une application de modifier la rotation de l\'écran à tout moment. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
- <string name="permlab_signalPersistentProcesses">"Envoyer des signaux Linux aux applications"</string>
+ <string name="permlab_signalPersistentProcesses">"Envoi de signaux Linux aux applications"</string>
<string name="permdesc_signalPersistentProcesses">"Permet à une application de demander que le signal fourni soit envoyé à tous les processus persistants."</string>
- <string name="permlab_persistentActivity">"Exécuter l\'application en continu"</string>
+ <string name="permlab_persistentActivity">"Exécution de l\'application en continu"</string>
<string name="permdesc_persistentActivity">"Permet à une application de perdurer en partie afin que le système ne puisse pas l\'utiliser pour d\'autres applications."</string>
<string name="permlab_deletePackages">"Supprimer des applications"</string>
<string name="permdesc_deletePackages">"Permet à une application de supprimer des paquets de données Android. Des applications malveillantes peuvent utiliser cette fonctionnalité pour supprimer des applications importantes."</string>
- <string name="permlab_clearAppUserData">"Supprimer les données d\'autres applications"</string>
+ <string name="permlab_clearAppUserData">"Suppression des données d\'autres applications"</string>
<string name="permdesc_clearAppUserData">"Permet à une application d\'effacer les données de l\'utilisateur."</string>
- <string name="permlab_deleteCacheFiles">"Supprimer le cache d\'autres applications"</string>
+ <string name="permlab_deleteCacheFiles">"Suppression du cache d\'autres applications"</string>
<string name="permdesc_deleteCacheFiles">"Permet à une application de supprimer des fichiers du cache."</string>
- <string name="permlab_getPackageSize">"Évaluer l\'espace de stockage de l\'application"</string>
+ <string name="permlab_getPackageSize">"Évaluation de l\'espace de stockage de l\'application"</string>
<string name="permdesc_getPackageSize">"Permet à une application de récupérer la taille de son code, de ses données et de son cache."</string>
- <string name="permlab_installPackages">"Installer directement les applications"</string>
+ <string name="permlab_installPackages">"Installation directe d\'applications"</string>
<string name="permdesc_installPackages">"Permet à une application d\'installer des nouveaux paquets de données ou des mises à jour Android. Des applications malveillantes peuvent utiliser cette fonctionnalité pour ajouter de nouvelles applications disposant d\'autorisations anormalement élevées."</string>
- <string name="permlab_clearAppCache">"Effacer les données du cache de toutes les applications"</string>
+ <string name="permlab_clearAppCache">"Suppression des données du cache de toutes les applications"</string>
<string name="permdesc_clearAppCache">"Permet à une application de libérer de l\'espace dans la mémoire du téléphone en supprimant des fichiers du répertoire du cache des applications. Cet accès est en général limité aux processus système."</string>
- <string name="permlab_readLogs">"Lire les fichiers journaux du système"</string>
+ <string name="permlab_readLogs">"Lecture des fichiers journaux du système"</string>
<string name="permdesc_readLogs">"Permet à une application de lire les différents fichiers journaux du système afin d\'obtenir des informations générales sur la façon dont vous utilisez votre téléphone, sans pour autant récupérer des informations d\'ordre personnel ou privé."</string>
- <string name="permlab_diagnostic">"Lire/écrire dans les ressources appartenant aux diagnostics"</string>
+ <string name="permlab_diagnostic">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
<string name="permdesc_diagnostic">"Permet à une application de lire et d\'éditer toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers in/dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
<string name="permlab_changeComponentState">"Activer ou désactiver des éléments de l\'application"</string>
- <string name="permdesc_changeComponentState">"Permet à une application de modifier l\'état d\'activation/désactivation d\'un élément d\'une autre application. Des applications malveillantes peuvent utiliser cette fonctionnalité pour désactiver des options importantes du téléphone. Soyez prudent en utilisant cette autorisation, car il est possible que certains éléments deviennent instables, incohérents ou inutilisables."</string>
- <string name="permlab_setPreferredApplications">"Définir les applications préférées"</string>
+ <string name="permdesc_changeComponentState">"Permet à une application d\'envoyer une notification lors de la réception d\'un message WAP PUSH. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux accusés de réception de MMS ou remplacer le contenu de toute page Web par des données malveillantes."</string>
+ <string name="permlab_setPreferredApplications">"Définition des applications préférées"</string>
<string name="permdesc_setPreferredApplications">"Permet à une application de modifier vos applications préférées. Des applications malveillantes peuvent utiliser cette fonctionnalité pour modifier discrètement les applications en cours d\'exécution, en imitant vos applications existantes afin de récupérer des données personnelles vous concernant."</string>
- <string name="permlab_writeSettings">"Modifier les paramètres généraux du système"</string>
- <string name="permdesc_writeSettings">"Permet à une application de modifier les données des paramètres du système. Des applications malveillantes peuvent utiliser cette fonctionnalité pour corrompre la configuration de votre système."</string>
+ <string name="permlab_writeSettings">"Modification des paramètres généraux du système"</string>
+ <string name="permdesc_writeSettings">"Permet à une application de modifier les données des paramètres système. Des applications malveillantes peuvent utiliser cette fonctionnalité pour endommager la configuration de votre système."</string>
<string name="permlab_writeSecureSettings">"Modifier les paramètres de sécurité du système"</string>
<string name="permdesc_writeSecureSettings">"Permet à une application de modifier les données des paramètres de sécurité du système. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_writeGservices">"Modifier la carte des services Google"</string>
+ <string name="permlab_writeGservices">"Modification de la carte des services Google"</string>
<string name="permdesc_writeGservices">"Permet à une application de modifier la carte des services Google. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
- <string name="permlab_receiveBootCompleted">"Lancer automatiquement au démarrage"</string>
- <string name="permdesc_receiveBootCompleted">"Permet à une application de se lancer dès la fin du démarrage du système. Ceci peut rallonger le temps de démarrage requis par le téléphone. L\'application étant alors constamment en cours d\'exécution, le fonctionnement général du téléphone risque d\'être ralenti."</string>
- <string name="permlab_broadcastSticky">"Envoyer une diffusion persistante"</string>
+ <string name="permlab_receiveBootCompleted">"Lancement automatique au démarrage"</string>
+ <string name="permdesc_receiveBootCompleted">"Permet à une application de se lancer dès la fin du démarrage du système. Cela peut rallonger le temps de démarrage requis par le téléphone. L\'application étant alors constamment en cours d\'exécution, le fonctionnement général du téléphone risque d\'être ralenti."</string>
+ <string name="permlab_broadcastSticky">"Envoi d\'une diffusion persistante"</string>
<string name="permdesc_broadcastSticky">"Permet à une application d\'envoyer des diffusions \"persistantes\", qui perdurent après la fin de la diffusion. Des applications malveillantes peuvent ainsi ralentir le téléphone ou le rendre instable en l\'obligeant à utiliser trop de mémoire."</string>
- <string name="permlab_readContacts">"Lire les données des contacts"</string>
+ <string name="permlab_readContacts">"Accès aux données des contacts"</string>
<string name="permdesc_readContacts">"Permet à une application de lire toutes les données des contacts (adresses) enregistrées sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer vos données à d\'autres personnes."</string>
- <string name="permlab_writeContacts">"Éditer les données d\'un contact"</string>
+ <string name="permlab_writeContacts">"Édition des données d\'un contact"</string>
<string name="permdesc_writeContacts">"Permet à une application de modifier toutes les données de contact (adresses) enregistrées sur le téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier vos données de contact."</string>
- <string name="permlab_writeOwnerData">"Éditer les données du propriétaire"</string>
+ <string name="permlab_writeOwnerData">"Édition les données du propriétaire"</string>
<string name="permdesc_writeOwnerData">"Permet à une application de modifier les données du propriétaire du téléphone enregistrées sur votre appareil. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier ces données."</string>
- <string name="permlab_readOwnerData">"Lire des données du propriétaire"</string>
+ <string name="permlab_readOwnerData">"Lecture des données du propriétaire"</string>
<string name="permdesc_readOwnerData">"Permet à une application de lire les données du propriétaire du téléphone enregistrées sur votre appareil. Des applications malveillantes peuvent utiliser cette fonctionnalité pour lire ces données."</string>
- <string name="permlab_readCalendar">"Lire les données du calendrier"</string>
- <string name="permdesc_readCalendar">"Permet à une application de lire tous les événements du calendrier enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer les événements de votre calendrier à d\'autres personnes."</string>
- <string name="permlab_writeCalendar">"Écrire les données du calendrier"</string>
- <string name="permdesc_writeCalendar">"Permet à une application de modifier les événements du calendrier enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier les données de votre calendrier."</string>
- <string name="permlab_accessMockLocation">"Créer des sources géographiques fictives à des fins de test"</string>
+ <string name="permlab_readCalendar">"Lecture des données de l\'agenda"</string>
+ <string name="permdesc_readCalendar">"Permet à une application de lire tous les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer les événements de votre agenda à d\'autres personnes."</string>
+ <string name="permlab_writeCalendar">"Écriture des données de l\'agenda"</string>
+ <string name="permdesc_writeCalendar">"Permet à une application de modifier les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier les données de votre agenda."</string>
+ <string name="permlab_accessMockLocation">"Création de sources géographiques fictives à des fins de test"</string>
<string name="permdesc_accessMockLocation">"Permet de créer des sources de position géographique fictives à des fins de test. Des applications malveillantes peuvent utiliser cette fonctionnalité pour remplacer la position géographique et/ou l\'état fournis par des sources réelles comme le GPS ou les fournisseurs d\'accès."</string>
- <string name="permlab_accessLocationExtraCommands">"Accéder à des commandes de fournisseur de position géographique supplémentaires"</string>
+ <string name="permlab_accessLocationExtraCommands">"Accès aux commandes de fournisseur de position géographique supplémentaires"</string>
<string name="permdesc_accessLocationExtraCommands">"Permet d\'accéder à des commandes de fournisseur de position géographique supplémentaires. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interférer avec l\'utilisation du GPS ou d\'autres sources de positionnement géographique."</string>
- <string name="permlab_accessFineLocation">"Position géographique précise (GPS)"</string>
+ <string name="permlab_accessFineLocation">"Localisation OK (GPS)"</string>
<string name="permdesc_accessFineLocation">"Permet d\'accéder à des sources de positionnement géographique précises comme le Global Positioning System (GPS) sur le téléphone, lorsque ces services sont disponibles. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer l\'endroit où vous vous trouvez et augmenter la consommation de la batterie de votre téléphone."</string>
- <string name="permlab_accessCoarseLocation">"Position géographique approximative (selon le réseau)"</string>
- <string name="permdesc_accessCoarseLocation">"Accéder à des sources de positionnement géographique approximatif (par ex. des bases de données de réseaux mobiles) pour déterminer la position géographique du téléphone, lorsque cette option est disponible. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer approximativement l\'endroit où vous vous trouvez."</string>
- <string name="permlab_accessSurfaceFlinger">"Accéder à SurfaceFlinger"</string>
+ <string name="permlab_accessCoarseLocation">"Position géo. approximative (selon le réseau)"</string>
+ <string name="permdesc_accessCoarseLocation">"Accès à des sources de positionnement approximatif (par ex. des bases de données de réseaux mobiles) pour déterminer la position géographique du téléphone, lorsque cette option est disponible. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer approximativement l\'endroit où vous vous trouvez."</string>
+ <string name="permlab_accessSurfaceFlinger">"Accès à SurfaceFlinger"</string>
<string name="permdesc_accessSurfaceFlinger">"Permet à certaines applications d\'utiliser les fonctionnalités SurfaceFlinger de bas niveau."</string>
- <string name="permlab_readFrameBuffer">"Lire la mémoire tampon graphique"</string>
+ <string name="permlab_readFrameBuffer">"Lecture de la mémoire tampon graphique"</string>
<string name="permdesc_readFrameBuffer">"Permet aux applications de lire/utiliser le contenu de la mémoire tampon graphique."</string>
- <string name="permlab_modifyAudioSettings">"Modifier vos paramètres audio"</string>
+ <string name="permlab_modifyAudioSettings">"Modification de vos paramètres audio"</string>
<string name="permdesc_modifyAudioSettings">"Permet à l\'application de modifier les paramètres audio généraux (p. ex. le volume et le routage)."</string>
- <string name="permlab_recordAudio">"Enregistrer un fichier audio"</string>
+ <string name="permlab_recordAudio">"Enregistrement de fichier audio"</string>
<string name="permdesc_recordAudio">"Permet à l\'application d\'accéder au chemin de l\'enregistrement audio."</string>
- <string name="permlab_camera">"Prendre des photos"</string>
+ <string name="permlab_camera">"Prise de photos"</string>
<string name="permdesc_camera">"Permet à l\'application de prendre des clichés avec l\'appareil photo. Cette fonctionnalité permet à l\'application de récupérer à tout moment les images perçues par l\'appareil."</string>
- <string name="permlab_brick">"Désactiver définitivement le téléphone"</string>
+ <string name="permlab_brick">"Désactivation définitive du téléphone"</string>
<string name="permdesc_brick">"Permet à l\'application de désactiver définitivement le téléphone. Cette fonctionnalité est très dangereuse."</string>
- <string name="permlab_reboot">"Forcer le redémarrage du téléphone"</string>
+ <string name="permlab_reboot">"Redémarrage forcé du téléphone"</string>
<string name="permdesc_reboot">"Permet à l\'application de forcer le redémarrage du téléphone."</string>
<string name="permlab_mount_unmount_filesystems">"Monter et démonter des systèmes de fichiers"</string>
<string name="permdesc_mount_unmount_filesystems">"Permet à l\'application de monter et démonter des systèmes de fichiers pour des périphériques de stockage amovibles."</string>
- <string name="permlab_vibrate">"Contrôler le vibreur"</string>
+ <string name="permlab_mount_format_filesystems">"Formatage du périphérique de stockage externe"</string>
+ <string name="permdesc_mount_format_filesystems">"Permet à l\'application de formater le périphérique de stockage amovible."</string>
+ <string name="permlab_vibrate">"Contrôle du vibreur"</string>
<string name="permdesc_vibrate">"Permet à l\'application de contrôler le vibreur."</string>
- <string name="permlab_flashlight">"Contrôler la lampe de poche"</string>
+ <string name="permlab_flashlight">"Contrôle de la lampe de poche"</string>
<string name="permdesc_flashlight">"Permet à l\'application de contrôler la lampe de poche."</string>
- <string name="permlab_hardware_test">"Tester le matériel"</string>
+ <string name="permlab_hardware_test">"Tests du matériel"</string>
<string name="permdesc_hardware_test">"Permet à l\'application de contrôler différents périphériques à des fins de test matériel."</string>
- <string name="permlab_callPhone">"Appeler directement des numéros de téléphone"</string>
- <string name="permdesc_callPhone">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Des applications malveillantes peuvent ainsi passer appels non désirés , qui s\'ajoutent à votre facture téléphonique. Sachez que cette fonctionnalité ne permet pas à l\'application d\'appeler des numéros d\'urgence."</string>
- <string name="permlab_callPrivileged">"Appeler directement tout numéro de téléphone"</string>
+ <string name="permlab_callPhone">"Appel direct des numéros de téléphone"</string>
+ <string name="permdesc_callPhone">"Permet à l\'application d\'appeler des numéros sans votre intervention. Des applications malveillantes peuvent ainsi passer des appels à votre insu qui s\'ajoutent à votre facture téléphonique. Cette fonctionnalité ne permet pas à l\'application d\'appeler des numéros d\'urgence."</string>
+ <string name="permlab_callPrivileged">"Appel direct de tout numéro de téléphone"</string>
<string name="permdesc_callPrivileged">"Permet à une application d\'appeler tout numéro de téléphone (y compris les numéros d\'urgence) sans votre intervention. Des applications malveillantes peuvent passer des appels non nécessaires ou illégitimes à des services d\'urgence."</string>
- <string name="permlab_locationUpdates">"Contrôler les notifications de mise à jour de position géographique"</string>
+ <string name="permlab_locationUpdates">"Contrôle des notifications de mise à jour de position géo."</string>
<string name="permdesc_locationUpdates">"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é."</string>
- <string name="permlab_checkinProperties">"Accéder aux propriétés d\'enregistrement"</string>
+ <string name="permlab_checkinProperties">"Accès aux propriétés d\'enregistrement"</string>
<string name="permdesc_checkinProperties">"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é."</string>
- <string name="permlab_modifyPhoneState">"Modifier l\'état du téléphone"</string>
- <string name="permdesc_modifyPhoneState">"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 notifier."</string>
- <string name="permlab_readPhoneState">"Lire l\'état du téléphone"</string>
+ <string name="permlab_bindGadget">"choisir les gadgets"</string>
+ <string name="permdesc_bindGadget">"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."</string>
+ <string name="permlab_modifyPhoneState">"Modification de l\'état du téléphone"</string>
+ <string name="permdesc_modifyPhoneState">"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."</string>
+ <string name="permlab_readPhoneState">"Lecture de l\'état du téléphone"</string>
<string name="permdesc_readPhoneState">"Permet à l\'application d\'accéder aux fonctionnalités d\'appel du téléphone. L\'application peut alors déterminer le numéro de téléphone de l\'appareil, savoir si un appel est en cours, identifier le numéro appelé, etc."</string>
- <string name="permlab_wakeLock">"Empêcher le téléphone de passer en mode veille"</string>
+ <string name="permlab_wakeLock">"Arrêt du mode veille sur le téléphone"</string>
<string name="permdesc_wakeLock">"Permet à une application d\'empêcher votre téléphone de passer en mode veille."</string>
<string name="permlab_devicePower">"Éteindre ou allumer le téléphone"</string>
<string name="permdesc_devicePower">"Permet à l\'application d\'éteindre et d\'allumer le téléphone."</string>
- <string name="permlab_factoryTest">"Exécuter en mode Test d\'usine"</string>
+ <string name="permlab_factoryTest">"Exécution en mode Test d\'usine"</string>
<string name="permdesc_factoryTest">"Permet d\'exécuter en tant que test fabricant de faible niveau en autorisant l\'accès au matériel du téléphone. Cette fonctionnalité est uniquement disponible lorsque le téléphone est en mode de test fabricant."</string>
- <string name="permlab_setWallpaper">"Configurer le fond d\'écran"</string>
- <string name="permdesc_setWallpaper">"Permet à une application de définir le fond d\'écran du système."</string>
- <string name="permlab_setWallpaperHints">"Définir les informations relatives à la taille du fond d\'écran"</string>
- <string name="permdesc_setWallpaperHints">"Permet à une application de définir les informations relatives à la taille du fond d\'écran du système."</string>
- <string name="permlab_masterClear">"Réinitialiser le système à ses paramètres d\'usine"</string>
- <string name="permdesc_masterClear">"Permet à une application de réinitialiser entièrement le système afin qu\'il récupère ses valeurs d\'usine et d\'effacer toutes les données, configurations et applications installées."</string>
- <string name="permlab_setTimeZone">"Définir le fuseau horaire"</string>
+ <string name="permlab_setWallpaper">"Configuration du fond d\'écran"</string>
+ <string name="permdesc_setWallpaper">"Permet à une application de définir l\'arrière-plan du système."</string>
+ <string name="permlab_setWallpaperHints">"Sélection de la la taille du fond d\'écran"</string>
+ <string name="permdesc_setWallpaperHints">"Permet à une application de définir la taille d\'arrière-plan du système."</string>
+ <string name="permlab_masterClear">"Réinitialisation du système à ses paramètres d\'usine"</string>
+ <string name="permdesc_masterClear">"Permet à une application de réinitialiser entièrement le système afin de rétablir ses valeurs d\'usine et d\'effacer toutes les données, configurations et applications installées."</string>
+ <string name="permlab_setTimeZone">"Sélection du fuseau horaire"</string>
<string name="permdesc_setTimeZone">"Permet à l\'application de modifier le fuseau horaire du téléphone."</string>
- <string name="permlab_getAccounts">"Identifier des comptes connus"</string>
+ <string name="permlab_getAccounts">"Identification des comptes connus"</string>
<string name="permdesc_getAccounts">"Permet à une application d\'obtenir la liste des comptes connus du téléphone."</string>
- <string name="permlab_accessNetworkState">"Afficher l\'état du réseau"</string>
+ <string name="permlab_accessNetworkState">"Affichage de l\'état du réseau"</string>
<string name="permdesc_accessNetworkState">"Permet à une application d\'afficher l\'état de tous les réseaux."</string>
<string name="permlab_createNetworkSockets">"Accès Internet complet"</string>
<string name="permdesc_createNetworkSockets">"Permet à une application de créer des connecteurs réseau."</string>
- <string name="permlab_writeApnSettings">"Écrire les paramètres de Nom des points d\'accès"</string>
+ <string name="permlab_writeApnSettings">"Écriture des paramètres \"Nom des points d\'accès\""</string>
<string name="permdesc_writeApnSettings">"Permet à une application de modifier les paramètres APN (Nom des points d\'accès), comme le proxy ou le port de tout APN."</string>
- <string name="permlab_changeNetworkState">"Modifier la connectivité du réseau"</string>
+ <string name="permlab_changeNetworkState">"Modification de la connectivité du réseau"</string>
<string name="permdesc_changeNetworkState">"Permet à une application de modifier la connectivité du réseau."</string>
- <string name="permlab_accessWifiState">"Afficher l\'état du Wi-Fi"</string>
+ <string name="permlab_changeBackgroundDataSetting">"modifier le paramètre d\'utilisation des données en arrière-plan"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Permet à une application de modifier le paramètre d\'utilisation des données en arrière-plan."</string>
+ <string name="permlab_accessWifiState">"Affichage de l\'état du Wi-Fi"</string>
<string name="permdesc_accessWifiState">"Permet à une application d\'afficher des informations concernant l\'état du Wi-Fi."</string>
<string name="permlab_changeWifiState">"Modifier l\'état du Wi-Fi"</string>
<string name="permdesc_changeWifiState">"Permet à une application de se connecter à des points d\'accès Wi-Fi, de s\'en déconnecter et de modifier des réseaux Wi-Fi configurés."</string>
<string name="permlab_bluetoothAdmin">"Gestion Bluetooth"</string>
<string name="permdesc_bluetoothAdmin">"Permet à une application de configurer le téléphone Bluetooth local, d\'identifier des périphériques distants et de les associer au téléphone."</string>
- <string name="permlab_bluetooth">"Créer des connexions Bluetooth"</string>
+ <string name="permlab_bluetooth">"Création de connexions Bluetooth"</string>
<string name="permdesc_bluetooth">"Permet à une application d\'obtenir la configuration du téléphone Bluetooth local et de créer et accepter des connexions à des appareils associés."</string>
- <string name="permlab_disableKeyguard">"Désactiver le verrouillage des touches"</string>
+ <string name="permlab_disableKeyguard">"Désactivation du verrouillage des touches"</string>
<string name="permdesc_disableKeyguard">"Permet à une application de désactiver le verrouillage des touches et toute sécurité par mot de passe. Exemple : Votre téléphone désactive le verrouillage du clavier lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
- <string name="permlab_readSyncSettings">"Lire les paramètres de synchronisation"</string>
+ <string name="permlab_readSyncSettings">"Lecture des paramètres de synchronisation"</string>
<string name="permdesc_readSyncSettings">"Permet à une application de lire les paramètres de synchronisation (par ex. savoir si la synchronisation est activée pour les Contacts)."</string>
- <string name="permlab_writeSyncSettings">"Écrire les paramètres de synchronisation"</string>
+ <string name="permlab_writeSyncSettings">"Écriture des paramètres de synchronisation"</string>
<string name="permdesc_writeSyncSettings">"Permet à une application de modifier les paramètres de synchronisation (p. ex. si la synchronisation est activée pour les contacts)."</string>
- <string name="permlab_readSyncStats">"Lire les statistiques de synchronisation"</string>
+ <string name="permlab_readSyncStats">"Lecture des statistiques de synchronisation"</string>
<string name="permdesc_readSyncStats">"Permet à une application de lire les statistiques de synchronisation (par ex. l\'historique des synchronisations effectuées)."</string>
- <string name="permlab_subscribedFeedsRead">"Lire les flux auxquels vous êtes abonné"</string>
+ <string name="permlab_subscribedFeedsRead">"Lecture des flux auxquels vous êtes abonné"</string>
<string name="permdesc_subscribedFeedsRead">"Permet à une application d\'obtenir des informations sur les flux récemment synchronisés."</string>
- <string name="permlab_subscribedFeedsWrite">"Écrire les flux auxquels vous êtes abonné"</string>
+ <string name="permlab_subscribedFeedsWrite">"Écriture des flux auxquels vous êtes abonné"</string>
<string name="permdesc_subscribedFeedsWrite">"Permet à une application de modifier vos flux synchronisés actuels. Cette fonctionnalité peut permettre à des applications malveillantes de modifier vos flux synchronisés."</string>
- <!-- no translation found for permlab_readDictionary (432535716804748781) -->
- <skip />
- <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
- <skip />
- <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
- <skip />
- <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
- <skip />
+ <string name="permlab_readDictionary">"Lecture du dictionnaire défini par l\'utilisateur"</string>
+ <string name="permdesc_readDictionary">"Permet à une application de lire tous les mots, noms et expressions que l\'utilisateur a pu enregistrer dans son dictionnaire personnel."</string>
+ <string name="permlab_writeDictionary">"Enregistrement dans le dictionnaire défini par l\'utilisateur"</string>
+ <string name="permdesc_writeDictionary">"Permet à une application d\'enregistrer de nouveaux mots dans le dictionnaire personnel de l\'utilisateur."</string>
<string-array name="phoneTypes">
- <item>"Accueil"</item>
+ <item>"Domicile"</item>
<item>"Mobile"</item>
<item>"Bureau"</item>
<item>"Télécopie bureau"</item>
@@ -343,19 +353,19 @@
<item>"Personnalisé"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item>"Accueil"</item>
+ <item>"Domicile"</item>
<item>"Bureau"</item>
<item>"Autre"</item>
<item>"Personnalisée"</item>
</string-array>
<string-array name="postalAddressTypes">
- <item>"Accueil"</item>
+ <item>"Domicile"</item>
<item>"Bureau"</item>
<item>"Autre"</item>
<item>"Personnalisée"</item>
</string-array>
<string-array name="imAddressTypes">
- <item>"Accueil"</item>
+ <item>"Domicile"</item>
<item>"Bureau"</item>
<item>"Autre"</item>
<item>"Personnalisé"</item>
@@ -375,19 +385,20 @@
<item>"ICQ"</item>
<item>"Jabber"</item>
</string-array>
- <string name="keyguard_password_enter_pin_code">"Saisir le code PIN"</string>
+ <string name="keyguard_password_enter_pin_code">"Saisissez le code PIN"</string>
<string name="keyguard_password_wrong_pin_code">"Le code PIN est incorrect !"</string>
- <string name="keyguard_label_text">"Pour débloquer le clavier, appuyez sur Menu puis sur 0."</string>
+ <string name="keyguard_label_text">"Pour débloquer le clavier, appuyez sur \"Menu\" puis sur 0."</string>
<string name="emergency_call_dialog_number_for_display">"Numéro d\'urgence"</string>
<string name="lockscreen_carrier_default">"(Aucun service)"</string>
<string name="lockscreen_screen_locked">"Écran verrouillé"</string>
- <string name="lockscreen_instructions_when_pattern_enabled">"Appuyez sur Menu pour débloquer le téléphone ou appeler un numéro d\'urgence"</string>
- <string name="lockscreen_instructions_when_pattern_disabled">"Appuyez sur Menu pour déverrouiller le téléphone."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Appuyez sur \"Menu\" pour déverrouiller le téléphone."</string>
<string name="lockscreen_pattern_instructions">"Dessinez un motif pour déverrouiller le téléphone"</string>
<string name="lockscreen_emergency_call">"Appel d\'urgence"</string>
<string name="lockscreen_pattern_correct">"Combinaison correcte !"</string>
- <string name="lockscreen_pattern_wrong">"Désolé. Merci de réessayer"</string>
- <string name="lockscreen_plugged_in">"Chargement (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+ <string name="lockscreen_pattern_wrong">"Désolé. Merci de réessayer."</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
<string name="lockscreen_low_battery">"Branchez votre chargeur."</string>
<string name="lockscreen_missing_sim_message_short">"Aucune carte SIM n\'a été trouvée."</string>
<string name="lockscreen_missing_sim_message">"Aucune carte SIM n\'est insérée dans le téléphone."</string>
@@ -402,7 +413,7 @@
<string name="lockscreen_too_many_failed_attempts_countdown">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
<string name="lockscreen_forgot_pattern_button_text">"Motif oublié ?"</string>
<string name="lockscreen_glogin_too_many_attempts">"Trop de tentatives de motif !"</string>
- <string name="lockscreen_glogin_instructions">"Pour débloquer votre téléphone,"\n"connectez-vous à votre compte Google"</string>
+ <string name="lockscreen_glogin_instructions">"Pour débloquer votre téléphone,"\n"connectez-vous à l\'aide de votre compte Google"</string>
<string name="lockscreen_glogin_username_hint">"Nom d\'utilisateur (e-mail)"</string>
<string name="lockscreen_glogin_password_hint">"Mot de passe"</string>
<string name="lockscreen_glogin_submit_button">"Se connecter"</string>
@@ -410,30 +421,26 @@
<string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
<string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <!-- no translation found for hour_ampm (7618670480400517084) -->
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
<skip />
- <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
<skip />
<string name="status_bar_clear_all_button">"Effacer les notifications"</string>
<string name="status_bar_no_notifications_title">"Aucune notification"</string>
<string name="status_bar_ongoing_events_title">"En cours"</string>
<string name="status_bar_latest_events_title">"Notifications"</string>
- <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
- <skip />
+ <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="battery_status_charging">"Chargement..."</string>
<string name="battery_low_title">"Branchez le chargeur"</string>
- <string name="battery_low_subtitle">"La batterie commence à faiblir :"</string>
- <string name="battery_low_percent_format">"Batterie restante : <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_subtitle">"Le niveau de la batterie est bas :"</string>
+ <string name="battery_low_percent_format">"Batterie restante inférieure à <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
<string name="factorytest_failed">"Échec du test usine"</string>
<string name="factorytest_not_system">"L\'action FACTORY_TEST est uniquement prise en charge pour les paquets de données installés dans in/system/app."</string>
<string name="factorytest_no_action">"Impossible de trouver un paquet proposant l\'action FACTORY_TEST."</string>
<string name="factorytest_reboot">"Redémarrer"</string>
- <!-- no translation found for js_dialog_title (8143918455087008109) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
- <skip />
+ <string name="js_dialog_title">"La page \"<xliff:g id="TITLE">%s</xliff:g>\" affirme :"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Vous souhaitez quitter cette page ?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Sélectionnez OK pour continuer ou Annuler pour rester sur la page actuelle."</string>
<string name="save_password_label">"Confirmer"</string>
<string name="save_password_message">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
<string name="save_password_notnow">"Pas maintenant"</string>
@@ -484,22 +491,38 @@
<item quantity="one">"demain"</item>
<item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
</plurals>
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"il y a 1 seconde"</item>
+ <item quantity="other">"il y a <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"il y a 1 minute"</item>
+ <item quantity="other">"il y a <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"il y a 1 heure"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> heures"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"hier"</item>
+ <item quantity="other">"Il y a <xliff:g id="COUNT">%d</xliff:g> jours"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"dans 1 seconde"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> secondes"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"dans 1 minute"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> minutes"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"dans 1 heure"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> heures"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"demain"</item>
+ <item quantity="other">"dans <xliff:g id="COUNT">%d</xliff:g> jours"</item>
+ </plurals>
<string name="preposition_for_date">"%s"</string>
<string name="preposition_for_time">"à %s"</string>
<string name="preposition_for_year">"en %s"</string>
@@ -533,7 +556,7 @@
<string name="am">"AM"</string>
<string name="pm">"PM"</string>
<string name="numeric_date">"<xliff:g id="DAY">%d</xliff:g>/<xliff:g id="MONTH">%m</xliff:g>/<xliff:g id="YEAR">%Y</xliff:g>"</string>
- <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g> <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g> <xliff:g id="TIME2">%6$s</xliff:g>"</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g> <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
<string name="wday1_date1_wday2_date2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="DATE2">%5$s</xliff:g>"</string>
<string name="date1_time1_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
<string name="date1_date2">"<xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>"</string>
@@ -541,32 +564,29 @@
<string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
- <!-- no translation found for date_time (6104442718633642836) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
- <string name="full_date_month_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="full_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_month_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
- <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
<string name="noon">"midi"</string>
<string name="Noon">"Midi"</string>
<string name="midnight">"minuit"</string>
<string name="Midnight">"Minuit"</string>
- <!-- no translation found for month_day (5565829181417740906) -->
- <skip />
- <!-- no translation found for month (7026169712234774086) -->
+ <string name="month_day">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g>"</string>
+ <!-- no translation found for month (1976700695144952053) -->
<skip />
<string name="month_day_year">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for month_year (9219019380312413367) -->
+ <!-- no translation found for month_year (2106203387378728384) -->
<skip />
<string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
<string name="same_year_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
- <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+ <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<string name="same_year_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR">%9$s</xliff:g>"</string>
<string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR">%9$s</xliff:g>"</string>
<string name="same_year_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
@@ -574,27 +594,26 @@
<string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="numeric_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>"</string>
- <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+ <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<string name="numeric_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
<string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
<string name="numeric_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>"</string>
<string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
<string name="same_month_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
- <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
<string name="same_month_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="abbrev_month_day_year">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%b</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
<skip />
- <!-- no translation found for abbrev_month_day (5028815883653985933) -->
- <skip />
- <!-- no translation found for abbrev_month (3131032032850777433) -->
+ <string name="abbrev_month_day">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%b</xliff:g>"</string>
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
<skip />
<string name="day_of_week_long_sunday">"dimanche"</string>
<string name="day_of_week_long_monday">"lundi"</string>
@@ -604,33 +623,33 @@
<string name="day_of_week_long_friday">"vendredi"</string>
<string name="day_of_week_long_saturday">"samedi"</string>
<string name="day_of_week_medium_sunday">"dim."</string>
- <string name="day_of_week_medium_monday">"lun."</string>
- <string name="day_of_week_medium_tuesday">"mar."</string>
- <string name="day_of_week_medium_wednesday">"mer."</string>
- <string name="day_of_week_medium_thursday">"jeu."</string>
- <string name="day_of_week_medium_friday">"ven."</string>
- <string name="day_of_week_medium_saturday">"sam."</string>
- <string name="day_of_week_short_sunday">"dim."</string>
- <string name="day_of_week_short_monday">"lun."</string>
- <string name="day_of_week_short_tuesday">"mar."</string>
- <string name="day_of_week_short_wednesday">"mer."</string>
- <string name="day_of_week_short_thursday">"jeu."</string>
- <string name="day_of_week_short_friday">"ven."</string>
- <string name="day_of_week_short_saturday">"sam."</string>
- <string name="day_of_week_shorter_sunday">"dim."</string>
- <string name="day_of_week_shorter_monday">"lun."</string>
- <string name="day_of_week_shorter_tuesday">"mar."</string>
- <string name="day_of_week_shorter_wednesday">"mer."</string>
- <string name="day_of_week_shorter_thursday">"jeu."</string>
- <string name="day_of_week_shorter_friday">"ven."</string>
+ <string name="day_of_week_medium_monday">"Lun"</string>
+ <string name="day_of_week_medium_tuesday">"Mar"</string>
+ <string name="day_of_week_medium_wednesday">"Mer"</string>
+ <string name="day_of_week_medium_thursday">"Jeu"</string>
+ <string name="day_of_week_medium_friday">"Ven"</string>
+ <string name="day_of_week_medium_saturday">"Sam"</string>
+ <string name="day_of_week_short_sunday">"Dim"</string>
+ <string name="day_of_week_short_monday">"Lun"</string>
+ <string name="day_of_week_short_tuesday">"Mar"</string>
+ <string name="day_of_week_short_wednesday">"Mer"</string>
+ <string name="day_of_week_short_thursday">"Jeu"</string>
+ <string name="day_of_week_short_friday">"Ven"</string>
+ <string name="day_of_week_short_saturday">"Sam"</string>
+ <string name="day_of_week_shorter_sunday">"Dim"</string>
+ <string name="day_of_week_shorter_monday">"Lun"</string>
+ <string name="day_of_week_shorter_tuesday">"Mar"</string>
+ <string name="day_of_week_shorter_wednesday">"Mer"</string>
+ <string name="day_of_week_shorter_thursday">"Jeu"</string>
+ <string name="day_of_week_shorter_friday">"Ven"</string>
<string name="day_of_week_shorter_saturday">"sam."</string>
- <string name="day_of_week_shortest_sunday">"dim."</string>
- <string name="day_of_week_shortest_monday">"lun."</string>
- <string name="day_of_week_shortest_tuesday">"Mar."</string>
- <string name="day_of_week_shortest_wednesday">"mer."</string>
- <string name="day_of_week_shortest_thursday">"jeu."</string>
- <string name="day_of_week_shortest_friday">"ven."</string>
- <string name="day_of_week_shortest_saturday">"sam."</string>
+ <string name="day_of_week_shortest_sunday">"Dim"</string>
+ <string name="day_of_week_shortest_monday">"Lun"</string>
+ <string name="day_of_week_shortest_tuesday">"Mar"</string>
+ <string name="day_of_week_shortest_wednesday">"Mer"</string>
+ <string name="day_of_week_shortest_thursday">"Jeu"</string>
+ <string name="day_of_week_shortest_friday">"Ven"</string>
+ <string name="day_of_week_shortest_saturday">"Sam"</string>
<string name="month_long_january">"janvier"</string>
<string name="month_long_february">"février"</string>
<string name="month_long_march">"mars"</string>
@@ -656,7 +675,7 @@
<string name="month_medium_november">"nov."</string>
<string name="month_medium_december">"déc."</string>
<string name="month_shortest_january">"jan."</string>
- <string name="month_shortest_february">"ven."</string>
+ <string name="month_shortest_february">"Ven"</string>
<string name="month_shortest_march">"mars"</string>
<string name="month_shortest_april">"avr."</string>
<string name="month_shortest_may">"mai"</string>
@@ -671,7 +690,7 @@
<string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll">"Tout sélectionner"</string>
<string name="selectText">"Sélectionner le texte"</string>
- <string name="stopSelectingText">"Arrêter de sélectionner du texte"</string>
+ <string name="stopSelectingText">"Arrêter sélection de texte"</string>
<string name="cut">"Couper"</string>
<string name="cutAll">"Tout couper"</string>
<string name="copy">"Copier"</string>
@@ -679,6 +698,7 @@
<string name="paste">"Coller"</string>
<string name="copyUrl">"Copier l\'URL"</string>
<string name="inputMethod">"Mode de saisie"</string>
+ <string name="addToDictionary">"Ajouter \"%s\" au dictionnaire"</string>
<string name="editTextMenuTitle">"Modifier le texte"</string>
<string name="low_internal_storage_view_title">"Espace disponible faible"</string>
<string name="low_internal_storage_view_text">"La mémoire du téléphone commence à être pleine."</string>
@@ -686,15 +706,16 @@
<string name="cancel">"Annuler"</string>
<string name="yes">"OK"</string>
<string name="no">"Annuler"</string>
+ <string name="dialog_alert_title">"Attention"</string>
<string name="capital_on">"ON"</string>
<string name="capital_off">"OFF"</string>
- <string name="whichApplication">"Terminer l\'action avec"</string>
- <string name="alwaysUse">"Utiliser cette application par défaut pour cette action."</string>
- <string name="clearDefaultHintMsg">"Effacez les paramètres par défaut dans les Paramètres d\'accueil &gt; Applications &gt; Gérer les applications."</string>
+ <string name="whichApplication">"Continuer avec"</string>
+ <string name="alwaysUse">"Utiliser cette application par défaut pour cette action"</string>
+ <string name="clearDefaultHintMsg">"Effacer les paramètres par défaut dans les Paramètres de page d\'accueil &gt; Applications &gt; Gérer les applications."</string>
<string name="chooseActivity">"Sélectionner une action"</string>
<string name="noApplications">"Aucune application ne peut effectuer cette action."</string>
<string name="aerr_title">"Désolé !"</string>
- <string name="aerr_application">"L\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>) s\'est interrompue inopinément. Merci de réessayer."</string>
+ <string name="aerr_application">"Fermeture soudaine de l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>). Merci de réessayer."</string>
<string name="aerr_process">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> s\'est interrompu de façon inopinée. Merci de réessayer."</string>
<string name="anr_title">"Désolé !"</string>
<string name="anr_activity_application">"L\'activité <xliff:g id="ACTIVITY">%1$s</xliff:g> (de l\'application <xliff:g id="APPLICATION">%2$s</xliff:g>) ne répond pas."</string>
@@ -706,11 +727,11 @@
<string name="debug">"Débogage"</string>
<string name="sendText">"Sélectionner une action pour le texte"</string>
<string name="volume_ringtone">"Volume de la sonnerie"</string>
- <string name="volume_music">"Volume des médias"</string>
+ <string name="volume_music">"Volume"</string>
<string name="volume_music_hint_playing_through_bluetooth">"Lecture via Bluetooth"</string>
<string name="volume_call">"Volume des appels entrants"</string>
- <string name="volume_call_hint_playing_through_bluetooth">"Lecture via Bluetooth"</string>
- <string name="volume_alarm">"Volume de l\'alarme"</string>
+ <string name="volume_bluetooth_call">"Volume d\'appels entrants sur Bluetooth"</string>
+ <string name="volume_alarm">"Volume"</string>
<string name="volume_notification">"Volume des notifications"</string>
<string name="volume_unknown">"Volume"</string>
<string name="ringtone_default">"Sonnerie par défaut"</string>
@@ -744,9 +765,47 @@
<string name="usb_storage_button_unmount">"Ne pas monter"</string>
<string name="usb_storage_error_message">"Un problème est survenu lors de l\'utilisation de votre carte SD en tant que périphérique de stockage USB."</string>
<string name="usb_storage_notification_title">"Connecté avec un câble USB"</string>
- <string name="usb_storage_notification_message">"Sélectionnez cette option pour copier des fichiers vers/à partir de votre ordinateur."</string>
+ <string name="usb_storage_notification_message">"Activez pour copier des fichiers vers/de votre ordinateur."</string>
+ <string name="usb_storage_stop_notification_title">"Éteindre le périphérique de stockage USB"</string>
+ <string name="usb_storage_stop_notification_message">"Sélectionner pour éteindre le périphérique de stockage USB"</string>
+ <string name="usb_storage_stop_title">"Éteindre le périphérique de stockage USB"</string>
+ <string name="usb_storage_stop_message">"Avant d\'éteindre le périphérique de stockage USB, assurez-vous d\'avoir désactivé l\'hôte USB. Sélectionnez \"Éteindre\" pour éteindre le périphérique de stockage USB."</string>
+ <string name="usb_storage_stop_button_mount">"Éteindre"</string>
+ <string name="usb_storage_stop_button_unmount">"Annuler"</string>
+ <string name="usb_storage_stop_error_message">"Un problème est survenu lors de la mise hors tension du périphérique de stockage USB. Assurez-vous que l\'hôte USB a bien été désactivé, puis essayez à nouveau."</string>
+ <string name="extmedia_format_title">"Formater la carte SD"</string>
+ <string name="extmedia_format_message">"Voulez-vous vraiment formater la carte SD ? Toutes les données de cette carte seront perdues."</string>
+ <string name="extmedia_format_button_format">"Format"</string>
<string name="select_input_method">"Sélectionner un mode de saisie"</string>
- <string name="fast_scroll_alphabet">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style"><font fgcolor="#ff000000" bgcolor="#ff8080ff"><u>"candidats"</u>"u&gt;"</font></string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidats"</u></string>
+ <string name="ext_media_checking_notification_title">"Préparation de la carte SD"</string>
+ <string name="ext_media_checking_notification_message">"Recherche d\'erreurs"</string>
+ <string name="ext_media_nofs_notification_title">"Carte SD vide"</string>
+ <string name="ext_media_nofs_notification_message">"La carte SD est vide ou utilise un système de fichiers non pris en charge."</string>
+ <string name="ext_media_unmountable_notification_title">"Carte SD endommagée"</string>
+ <string name="ext_media_unmountable_notification_message">"La carte SD est endommagée. Vous devrez peut-être reformater votre carte."</string>
+ <string name="ext_media_badremoval_notification_title">"Carte SD retirée inopinément"</string>
+ <string name="ext_media_badremoval_notification_message">"Désactiver la carte SD avant de la retirer pour éviter toute perte de données."</string>
+ <string name="ext_media_safe_unmount_notification_title">"La carte SD peut être retirée en toute sécurité"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Vous pouvez désormais retirer la carte SD en toute sécurité."</string>
+ <string name="ext_media_nomedia_notification_title">"Carte SD manquante"</string>
+ <string name="ext_media_nomedia_notification_message">"La carte SD a été retirée. Insérez une autre carte pour augmenter la capacité de stockage de votre appareil."</string>
+ <string name="activity_list_empty">"Aucune activité correspondante trouvée"</string>
+ <string name="permlab_pkgUsageStats">"mettre à jour les données statistiques du composant"</string>
+ <string name="permdesc_pkgUsageStats">"Permet de modifier les données statistiques collectées du composant. Cette option n\'est pas utilisée par les applications standard."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">"Tapez deux fois pour le zoom"</string>
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-it-rIT/arrays.xml b/core/res/res/values-it-rIT/arrays.xml
new file mode 100644
index 0000000..92e5260
--- /dev/null
+++ b/core/res/res/values-it-rIT/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2006, Google Inc.
+**
+** 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.
+*/
+-->
+<resources>
+
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_lat_lng">
+ <item>41795888</item>
+ <item>12480469</item>
+ </integer-array>
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_zoom">
+ <item>6</item>
+ </integer-array>
+
+</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index caf63c7..b4cf458 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -103,7 +103,15 @@
<string name="global_action_toggle_silent_mode">"Modalità silenziosa"</string>
<string name="global_action_silent_mode_on_status">"Audio non attivo"</string>
<string name="global_action_silent_mode_off_status">"Audio attivo"</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
<string name="safeMode">"Modalità provvisoria"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
<string name="permgrouplab_costMoney">"Servizi che prevedono un costo"</string>
<string name="permgroupdesc_costMoney">"Consentono alle applicazioni di svolgere operazioni che possono comportare un costo."</string>
<string name="permgrouplab_messages">"I tuoi messaggi"</string>
@@ -126,244 +134,246 @@
<string name="permgroupdesc_developmentTools">"Funzionalità necessarie soltanto agli sviluppatori di applicazioni."</string>
<string name="permlab_statusBar">"disattivare o modificare la barra di stato"</string>
<string name="permdesc_statusBar">"Consente all\'applicazione di disattivare la barra di stato o di aggiungere e rimuovere icone di sistema."</string>
- <string name="permlab_expandStatusBar">"espandere/comprimere la barra di stato"</string>
+ <string name="permlab_expandStatusBar">"espansione/compressione barra di stato"</string>
<string name="permdesc_expandStatusBar">"Consente all\'applicazione di espandere o comprimere la barra di stato."</string>
- <string name="permlab_processOutgoingCalls">"intercettare chiamate in uscita"</string>
+ <string name="permlab_processOutgoingCalls">"intercettazione chiamate in uscita"</string>
<string name="permdesc_processOutgoingCalls">"Consente all\'applicazione di elaborare le chiamate in uscita e di modificare il numero da comporre. Le applicazioni dannose potrebbero monitorare, deviare o impedire le chiamate in uscita."</string>
- <string name="permlab_receiveSms">"ricevere SMS"</string>
+ <string name="permlab_receiveSms">"ricezione SMS"</string>
<string name="permdesc_receiveSms">"Consente il ricevimento e l\'elaborazione di SMS da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
- <string name="permlab_receiveMms">"ricevere MMS"</string>
+ <string name="permlab_receiveMms">"ricezione MMS"</string>
<string name="permdesc_receiveMms">"Consente il ricevimento e l\'elaborazione di MMS da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
- <string name="permlab_sendSms">"inviare SMS"</string>
+ <string name="permlab_sendSms">"invio SMS"</string>
<string name="permdesc_sendSms">"Consente all\'applicazione di inviare messaggi SMS. Le applicazioni dannose potrebbero inviare messaggi a tua insaputa facendoti sostenere dei costi."</string>
- <string name="permlab_readSms">"leggere SMS o MMS"</string>
+ <string name="permlab_readSms">"lettura SMS o MMS"</string>
<string name="permdesc_readSms">"Consente all\'applicazione di leggere SMS memorizzati sul telefono o sulla SIM. Le applicazioni dannose potrebbero leggere messaggi riservati."</string>
- <string name="permlab_writeSms">"modificare SMS o MMS"</string>
+ <string name="permlab_writeSms">"modifica SMS o MMS"</string>
<string name="permdesc_writeSms">"Consente all\'applicazione di rispondere a SMS memorizzati sul telefono o sulla SIM. Le applicazioni dannose potrebbero eliminare i messaggi."</string>
- <string name="permlab_receiveWapPush">"ricevere WAP"</string>
+ <string name="permlab_receiveWapPush">"ricezione WAP"</string>
<string name="permdesc_receiveWapPush">"Consente il ricevimento e l\'elaborazione di messaggi WAP da parte dell\'applicazione. Le applicazioni dannose potrebbero monitorare i messaggi o eliminarli senza visualizzarli."</string>
- <string name="permlab_getTasks">"recuperare applicazioni in esecuzione"</string>
+ <string name="permlab_getTasks">"recupero applicazioni in esecuzione"</string>
<string name="permdesc_getTasks">"Consente all\'applicazione di recuperare informazioni sulle attività in esecuzione ed eseguite di recente. Le applicazioni dannose potrebbero essere in grado di scoprire informazioni riservate su altre applicazioni."</string>
- <string name="permlab_reorderTasks">"ridisporre applicazioni in esecuzione"</string>
+ <string name="permlab_reorderTasks">"riordinamento applicazioni in esecuz."</string>
<string name="permdesc_reorderTasks">"Consente a un\'applicazione di spostare attività in primo e secondo piano. Le applicazioni dannose possono imporsi ponendosi automaticamente in primo piano."</string>
- <string name="permlab_setDebugApp">"attivare il debug delle applicazioni"</string>
+ <string name="permlab_setDebugApp">"attivazione debug delle applicazioni"</string>
<string name="permdesc_setDebugApp">"Consente a un\'applicazione di attivare il debug per un\'altra applicazione. Le applicazioni dannose possono sfruttare questa possibilità per interrompere altre applicazioni."</string>
- <string name="permlab_changeConfiguration">"cambiare le impostazioni della UI"</string>
+ <string name="permlab_changeConfiguration">"modifica impostazioni UI"</string>
<string name="permdesc_changeConfiguration">"Consente a un\'applicazione di modificare la configurazione corrente, come le dimensioni dei caratteri locali o complessive."</string>
- <string name="permlab_restartPackages">"riavviare altre applicazioni"</string>
+ <string name="permlab_restartPackages">"riavvio altre applicazioni"</string>
<string name="permdesc_restartPackages">"Consente a un\'applicazione di riavviare forzatamente altre applicazioni."</string>
<string name="permlab_setProcessForeground">"impedire l\'interruzione"</string>
<string name="permdesc_setProcessForeground">"Consente a un\'applicazione di eseguire i processi in primo piano in modo che non possano essere interrotti. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_forceBack">"forzare la chiusura delle applicazioni"</string>
+ <string name="permlab_forceBack">"chiusura forzata dell\'applicazione"</string>
<string name="permdesc_forceBack">"Consente a un\'applicazione di forzare la chiusura di attività in primo piano. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_dump">"recuperare lo stato interno del sistema"</string>
+ <string name="permlab_dump">"recupero stato interno del sistema"</string>
<string name="permdesc_dump">"Consente all\'applicazione di recuperare lo stato interno del sistema. Le applicazioni dannose potrebbero recuperare molte informazioni riservate e protette di cui non dovrebbero avere mai bisogno."</string>
- <string name="permlab_addSystemService">"pubblicare servizi di basso livello"</string>
+ <string name="permlab_addSystemService">"pubblicaz. servizi di basso livello"</string>
<string name="permdesc_addSystemService">"Consente a un\'applicazione di pubblicare i suoi servizi di sistema di basso livello. Le applicazioni dannose potrebbero assumere il controllo del sistema e impossessarsi di dati o danneggiarli."</string>
- <string name="permlab_runSetActivityWatcher">"monitorare e controllare l\'avvio di tutte le applicazioni"</string>
+ <string name="permlab_runSetActivityWatcher">"monitoraggio e controllo avvio applicazioni"</string>
<string name="permdesc_runSetActivityWatcher">"Consente a un\'applicazione di monitorare e controllare la modalità di avvio delle attività nel sistema. Le applicazioni dannose potrebbero compromettere totalmente il sistema. Questa autorizzazione è necessaria soltanto per lo sviluppo, mai per il normale utilizzo del telefono."</string>
- <string name="permlab_broadcastPackageRemoved">"inviare broadcast rimossi dal pacchetto"</string>
+ <string name="permlab_broadcastPackageRemoved">"invio broadcast rimossi dal pacchetto"</string>
<string name="permdesc_broadcastPackageRemoved">"Consente a un\'applicazione di trasmettere una notifica di rimozione del pacchetto di un\'applicazione. Le applicazioni dannose potrebbero sfruttare questa possibilità per interrompere ogni altra applicazione in esecuzione."</string>
- <string name="permlab_broadcastSmsReceived">"inviare broadcast ricevuti tramite SMS"</string>
+ <string name="permlab_broadcastSmsReceived">"invio broadcast ricevuti tramite SMS"</string>
<string name="permdesc_broadcastSmsReceived">"Consente a un\'applicazione di trasmettere una notifica di ricevimento di un SMS. Le applicazioni dannose potrebbero sfruttare questa possibilità per far credere che siano stati ricevuti SMS."</string>
- <string name="permlab_broadcastWapPush">"inviare broadcast ricevuti tramite WAP-PUSH"</string>
- <string name="permdesc_broadcastWapPush">"Consente a un\'applicazione di trasmettere una notifica di ricevimento di un messaggio WAP PUSH. Le applicazioni dannose potrebbero sfruttare questa possibilità per far credere che sia stato ricevuto un MMS o per sostituire automaticamente il contenuto di pagine web con varianti dannose."</string>
+ <string name="permlab_broadcastWapPush">"invio broadcast ricevuti tramite WAP-PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Consente a un\'applicazione di trasmettere una notifica di ricevimento di un messaggio WAP PUSH. Le applicazioni dannose potrebbero sfruttare questa possibilità per far credere che sia stato ricevuto un MMS o per sostituire automaticamente contenuti di pagine web con varianti dannose."</string>
<string name="permlab_setProcessLimit">"numero limite di processi in esecuzione"</string>
<string name="permdesc_setProcessLimit">"Consente a un\'applicazione di stabilire il numero massimo di processi in esecuzione. Mai necessario per le normali applicazioni."</string>
- <string name="permlab_setAlwaysFinish">"chiudere tutte le applicazioni in background"</string>
+ <string name="permlab_setAlwaysFinish">"chiusura applicazioni in background"</string>
<string name="permdesc_setAlwaysFinish">"Consente a un\'applicazione di controllare se le attività sono sempre completate quando vengono messe in secondo piano. Mai necessario per le normali applicazioni."</string>
- <string name="permlab_fotaUpdate">"installare automaticamente aggiornamenti di sistema"</string>
+ <string name="permlab_fotaUpdate">"installazione autom. aggiornamenti di sistema"</string>
<string name="permdesc_fotaUpdate">"Consente a un\'applicazione di ricevere notifiche sugli aggiornamenti del sistema in sospeso e di attivarne l\'installazione. Le applicazioni dannose possono sfruttare questa possibilità per danneggiare il sistema con aggiornamenti non autorizzati, o interferire con il processo di aggiornamento."</string>
- <string name="permlab_batteryStats">"modificare le statistiche della batteria"</string>
+ <string name="permlab_batteryStats">"modifica statistiche batteria"</string>
<string name="permdesc_batteryStats">"Consente la modifica delle statistiche sulla batteria raccolte. Da non usare per normali applicazioni."</string>
- <string name="permlab_internalSystemWindow">"visualizzare finestre non autorizzate"</string>
+ <string name="permlab_internalSystemWindow">"visualizzazione finestre non autorizzate"</string>
<string name="permdesc_internalSystemWindow">"Consente la creazione di finestre destinate all\'uso nell\'interfaccia utente di sistema interna. Da non usare per normali applicazioni."</string>
- <string name="permlab_systemAlertWindow">"visualizzare avvisi a livello di sistema"</string>
+ <string name="permlab_systemAlertWindow">"visualizzazione avvisi di sistema"</string>
<string name="permdesc_systemAlertWindow">"Consente a un\'applicazione di visualizzare finestre di avviso del sistema. Le applicazioni dannose possono sfruttare questa opzione per riempire lo schermo del telefono di messaggi."</string>
- <string name="permlab_setAnimationScale">"modificare velocità di animazione globali"</string>
+ <string name="permlab_setAnimationScale">"modifica velocità di animazione globale"</string>
<string name="permdesc_setAnimationScale">"Consente a un\'applicazione di modificare la velocità di animazione globale (animazioni più veloci o più lente) in qualsiasi momento."</string>
- <string name="permlab_manageAppTokens">"gestire i token delle applicazioni"</string>
+ <string name="permlab_manageAppTokens">"gestione token applicazioni"</string>
<string name="permdesc_manageAppTokens">"Consente alle applicazioni di creare e gestire i propri token, ignorando il normale ordinamento Z. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_injectEvents">"premere tasti e pulsanti di controllo"</string>
+ <string name="permlab_injectEvents">"uso tasti e pulsanti di controllo"</string>
<string name="permdesc_injectEvents">"Consente a un\'applicazione di offrire i suoi eventi di input (pressioni di tasti etc.) ad altre applicazioni. Le applicazioni dannose possono sfruttare questa possibilità per assumere il controllo del telefono."</string>
- <string name="permlab_readInputState">"registrare il testo digitato e le azioni effettuate"</string>
+ <string name="permlab_readInputState">"registrazione testo digitato e azioni eseguite"</string>
<string name="permdesc_readInputState">"Consente il rilevamento da parte delle applicazioni dei tasti premuti anche durante l\'interazione con un\'altra applicazione (come nel caso di inserimento di una password). Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_bindInputMethod">"associare a un metodo di inserimento"</string>
+ <string name="permlab_bindInputMethod">"associaz. a un metodo di inserimento"</string>
<string name="permdesc_bindInputMethod">"Consente l\'associazione all\'interfaccia principale di un metodo di inserimento. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_setOrientation">"cambiare l\'orientamento dello schermo"</string>
+ <string name="permlab_setOrientation">"modifica orientamento dello schermo"</string>
<string name="permdesc_setOrientation">"Consente a un\'applicazione di cambiare la rotazione dello schermo in qualsiasi momento. Non dovrebbe essere mai necessario per le normali applicazioni."</string>
- <string name="permlab_signalPersistentProcesses">"inviare segnali Linux alle applicazioni"</string>
+ <string name="permlab_signalPersistentProcesses">"invio segnali Linuz alle applicazioni"</string>
<string name="permdesc_signalPersistentProcesses">"Consente all\'applicazione di richiedere l\'invio del segnale fornito a tutti i processi persistenti."</string>
- <string name="permlab_persistentActivity">"lasciare sempre in esecuzione le applicazioni"</string>
+ <string name="permlab_persistentActivity">"esecuzione permanente delle applicazioni"</string>
<string name="permdesc_persistentActivity">"Consente a un\'applicazione di rendere delle sue parti costanti in modo che il sistema non possa usarla per altre applicazioni."</string>
- <string name="permlab_deletePackages">"eliminare applicazioni"</string>
+ <string name="permlab_deletePackages">"eliminazione applicazioni"</string>
<string name="permdesc_deletePackages">"Consente a un\'applicazione di eliminare pacchetti Android. Le applicazioni dannose possono sfruttare questa possibilità per eliminare importanti applicazioni."</string>
- <string name="permlab_clearAppUserData">"eliminare dati di altre applicazioni"</string>
+ <string name="permlab_clearAppUserData">"eliminazione dati di altre applicazioni"</string>
<string name="permdesc_clearAppUserData">"Consente a un\'applicazione di cancellare dati dell\'utente."</string>
- <string name="permlab_deleteCacheFiles">"eliminare le cache di altre applicazioni"</string>
+ <string name="permlab_deleteCacheFiles">"eliminazione cache altre applicazioni"</string>
<string name="permdesc_deleteCacheFiles">"Consente a un\'applicazione di eliminare file della cache."</string>
- <string name="permlab_getPackageSize">"stabilire lo spazio di archiviazione delle applicazioni"</string>
+ <string name="permlab_getPackageSize">"calcolo spazio di archiviazione applicazioni"</string>
<string name="permdesc_getPackageSize">"Consente a un\'applicazione di recuperare i suoi codici, dati e dimensioni della cache"</string>
- <string name="permlab_installPackages">"installare direttamente applicazioni"</string>
+ <string name="permlab_installPackages">"installazione diretta di applicazioni"</string>
<string name="permdesc_installPackages">"Consente a un\'applicazione di installare nuovi pacchetti Android o aggiornamenti. Le applicazioni dannose possono sfruttare questa possibilità per aggiungere nuove applicazioni con potenti autorizzazioni arbitrarie."</string>
- <string name="permlab_clearAppCache">"eliminare tutti i dati della cache delle applicazioni"</string>
+ <string name="permlab_clearAppCache">"eliminazione dati della cache applicazioni"</string>
<string name="permdesc_clearAppCache">"Consente a un\'applicazione di liberare spazio sul telefono eliminando file nella directory della cache dell\'applicazione. L\'accesso è generalmente limitato a processi di sistema."</string>
- <string name="permlab_readLogs">"leggere file di registro di sistema"</string>
+ <string name="permlab_readLogs">"lettura file di registro sistema"</string>
<string name="permdesc_readLogs">"Consente a un\'applicazione di leggere vari file di registro del sistema per trovare informazioni generali sulle operazioni effettuate con il telefono. Tali file non dovrebbero contenere informazioni personali o riservate."</string>
- <string name="permlab_diagnostic">"leggere/scrivere a risorse di proprietà di diag"</string>
+ <string name="permlab_diagnostic">"lettura/scrittura risorse di proprietà di diag"</string>
<string name="permdesc_diagnostic">"Consente a un\'applicazione di leggere le risorse del gruppo diag e scrivere a esse, per esempio i file in /dev. Questa capacità potrebbe influire sulla stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
- <string name="permlab_changeComponentState">"attivare o disattivare componenti delle applicazioni"</string>
+ <string name="permlab_changeComponentState">"attivazione/disattivazione componenti applicazioni"</string>
<string name="permdesc_changeComponentState">"Consente a un\'applicazione di attivare o disattivare un componente di un\'altra applicazione. Le applicazioni dannose possono sfruttare questa possibilità per disattivare importanti funzionalità del telefono. Prestare attenzione con questa autorizzazione perché è possibile rendere inutilizzabili, incoerenti o instabili i componenti delle applicazioni."</string>
- <string name="permlab_setPreferredApplications">"impostare le applicazioni preferite"</string>
+ <string name="permlab_setPreferredApplications">"impostazione applicazioni preferite"</string>
<string name="permdesc_setPreferredApplications">"Consente la modifica da parte di un\'applicazione delle applicazioni preferite. Le applicazioni dannose potrebbero essere in grado di modificare automaticamente le applicazioni in esecuzione, effettuando lo spoofing delle applicazioni esistenti per raccogliere dati riservati."</string>
- <string name="permlab_writeSettings">"modificare le impostazioni di sistema globali"</string>
+ <string name="permlab_writeSettings">"modifica impostazioni di sistema globali"</string>
<string name="permdesc_writeSettings">"Consente la modifica in un\'applicazione dei dati delle impostazioni del sistema. Le applicazioni dannose possono danneggiare la configurazione del sistema."</string>
<string name="permlab_writeSecureSettings">"modificare le impostazioni di protezione del sistema"</string>
<string name="permdesc_writeSecureSettings">"Consente a un\'applicazione di modificare i dati delle impostazioni di protezione del sistema. Da non usare per normali applicazioni."</string>
- <string name="permlab_writeGservices">"modificare la mappa dei servizi Google"</string>
+ <string name="permlab_writeGservices">"modifica mappa servizi Google"</string>
<string name="permdesc_writeGservices">"Consente a un\'applicazione di modificare la mappa dei servizi Google. Da non usare per normali applicazioni."</string>
- <string name="permlab_receiveBootCompleted">"aprire automaticamente all\'avvio"</string>
+ <string name="permlab_receiveBootCompleted">"apertura automatica all\'avvio"</string>
<string name="permdesc_receiveBootCompleted">"Consente a un\'applicazione di aprirsi automaticamente al termine dell\'avvio del sistema. Potrebbe essere necessario più tempo per l\'avvio del telefono e l\'applicazione potrebbe rallentare tutte le funzioni del telefono rimanendo sempre in esecuzione."</string>
- <string name="permlab_broadcastSticky">"inviare broadcast permanenti"</string>
+ <string name="permlab_broadcastSticky">"invio broadcast permanenti"</string>
<string name="permdesc_broadcastSticky">"Consente a un\'applicazione di inviare broadcast permanenti, che permangono anche al termine del broadcast. Le applicazioni dannose possono rendere il telefono lento o instabile tramite un uso eccessivo della memoria."</string>
- <string name="permlab_readContacts">"leggere dati di contatto"</string>
+ <string name="permlab_readContacts">"lettura dati di contatto"</string>
<string name="permdesc_readContacts">"Consente la lettura da parte di un\'applicazione di tutti i dati (gli indirizzi) di contatto memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per inviare i dati ad altre persone."</string>
- <string name="permlab_writeContacts">"scrivere dati di contatto"</string>
+ <string name="permlab_writeContacts">"scrittura dati di contatto"</string>
<string name="permdesc_writeContacts">"Consente a un\'applicazione di modificare i dati (gli indirizzi) di contatto memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati di contatto."</string>
- <string name="permlab_writeOwnerData">"scrivere dati del proprietario"</string>
+ <string name="permlab_writeOwnerData">"scrittura dati proprietario"</string>
<string name="permdesc_writeOwnerData">"Consente a un\'applicazione di modificare i dati del proprietario del telefono memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare tali dati."</string>
- <string name="permlab_readOwnerData">"leggere dati del proprietario"</string>
+ <string name="permlab_readOwnerData">"lettura dati proprietario"</string>
<string name="permdesc_readOwnerData">"Consente a un\'applicazione di leggere i dati del proprietario del telefono memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per leggere tali dati."</string>
- <string name="permlab_readCalendar">"leggere dati di calendario"</string>
+ <string name="permlab_readCalendar">"lettura dati di calendario"</string>
<string name="permdesc_readCalendar">"Consente la lettura da parte di un\'applicazione di tutti gli eventi di calendario memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per inviare i tuoi eventi di calendario ad altre persone."</string>
- <string name="permlab_writeCalendar">"scrivere dati di calendario"</string>
+ <string name="permlab_writeCalendar">"scrittura dati di calendario"</string>
<string name="permdesc_writeCalendar">"Consente a un\'applicazione di modificare gli eventi di calendario memorizzati sul telefono. Le applicazioni dannose possono sfruttare questa possibilità per cancellare o modificare i dati del calendario."</string>
<string name="permlab_accessMockLocation">"fonti di localizzazione fittizie per test"</string>
<string name="permdesc_accessMockLocation">"Creare fonti di localizzazione fittizie per test. Le applicazioni dannose possono sfruttare questa possibilità per sostituire la posizione e/o lo stato restituito da reali fonti di localizzazione come GPS o provider di rete."</string>
- <string name="permlab_accessLocationExtraCommands">"accedere a comandi aggiuntivi del provider di localizzazione"</string>
+ <string name="permlab_accessLocationExtraCommands">"accesso a comandi aggiuntivi del provider di localizz."</string>
<string name="permdesc_accessLocationExtraCommands">"Accedere a comandi aggiuntivi del provider di localizzazione. Le applicazioni dannose possono sfruttare questa possibilità per interferire con il funzionamento del GPS o di altre fonti di localizzazione."</string>
<string name="permlab_accessFineLocation">"localizzazione precisa (GPS)"</string>
<string name="permdesc_accessFineLocation">"Consente l\'accesso a fonti di localizzazione precisa, come il sistema GPS del telefono, se disponibile. Le applicazioni dannose possono sfruttare questa possibilità per determinare la tua posizione e, nel farlo, far esaurire più in fretta la batteria."</string>
<string name="permlab_accessCoarseLocation">"localizzazione approssimativa (basata sulla rete)"</string>
<string name="permdesc_accessCoarseLocation">"Consente l\'accesso a fonti di localizzazione geografica non puntuale (come il database della rete cellulare) per determinare una posizione approssimativa del telefono, quando possibile. Le applicazioni dannose possono sfruttare questa possibilità per determinare approssimativamente dove ti trovi."</string>
- <string name="permlab_accessSurfaceFlinger">"accedere a SurfaceFlinger"</string>
+ <string name="permlab_accessSurfaceFlinger">"accesso a SurfaceFlinger"</string>
<string name="permdesc_accessSurfaceFlinger">"Consente l\'utilizzo dell\'applicazione di funzioni di basso livello SurfaceFlinger."</string>
- <string name="permlab_readFrameBuffer">"leggere il buffer di frame"</string>
+ <string name="permlab_readFrameBuffer">"lettura buffer di frame"</string>
<string name="permdesc_readFrameBuffer">"Consente la lettura da parte dell\'applicazione dei contenuti del buffer di frame."</string>
- <string name="permlab_modifyAudioSettings">"cambiare le impostazioni audio"</string>
+ <string name="permlab_modifyAudioSettings">"modifica impostazioni audio"</string>
<string name="permdesc_modifyAudioSettings">"Consente all\'applicazione di modificare impostazioni audio globali come volume e routing."</string>
- <string name="permlab_recordAudio">"registrare audio"</string>
+ <string name="permlab_recordAudio">"registrazione audio"</string>
<string name="permdesc_recordAudio">"Consente l\'accesso dell\'applicazione al percorso di registrazione dell\'audio."</string>
- <string name="permlab_camera">"scattare foto"</string>
+ <string name="permlab_camera">"acquisizione foto"</string>
<string name="permdesc_camera">"Consente di scattare foto nell\'applicazione con la fotocamera. L\'applicazione può acquisire in qualsiasi momento le immagini rilevate dalla fotocamera."</string>
- <string name="permlab_brick">"disattivare definitivamente il telefono"</string>
+ <string name="permlab_brick">"disattivazione telefono"</string>
<string name="permdesc_brick">"Consente all\'applicazione di disattivare l\'intero telefono in modo definitivo. Questa autorizzazione è molto pericolosa."</string>
- <string name="permlab_reboot">"imporre il riavvio del telefono"</string>
+ <string name="permlab_reboot">"riavvio forzato del telefono"</string>
<string name="permdesc_reboot">"Consente all\'applicazione di imporre il riavvio del telefono."</string>
- <string name="permlab_mount_unmount_filesystems">"montare e smontare filesystem"</string>
+ <string name="permlab_mount_unmount_filesystems">"installazione/disinstallazione filesystem"</string>
<string name="permdesc_mount_unmount_filesystems">"Consente montaggio e smontaggio da parte dell\'applicazione dei filesystem degli archivi rimovibili."</string>
- <string name="permlab_vibrate">"controllare la vibrazione"</string>
+ <string name="permlab_mount_format_filesystems">"formattazione archivio esterno"</string>
+ <string name="permdesc_mount_format_filesystems">"Consente all\'applicazione di formattare l\'archivio rimovibile."</string>
+ <string name="permlab_vibrate">"controllo vibrazione"</string>
<string name="permdesc_vibrate">"Consente all\'applicazione di controllare la vibrazione."</string>
- <string name="permlab_flashlight">"controllare il flash"</string>
+ <string name="permlab_flashlight">"controllo flash"</string>
<string name="permdesc_flashlight">"Consente all\'applicazione di controllare il flash."</string>
- <string name="permlab_hardware_test">"testare l\'hardware"</string>
+ <string name="permlab_hardware_test">"esecuzione test hardware"</string>
<string name="permdesc_hardware_test">"Consente all\'applicazione di controllare varie periferiche per il test dell\'hardware."</string>
- <string name="permlab_callPhone">"chiamare direttamente i numeri di telefono"</string>
+ <string name="permlab_callPhone">"chiamata diretta n. telefono"</string>
<string name="permdesc_callPhone">"Consente all\'applicazione di chiamare numeri automaticamente. Le applicazioni dannose potrebbero far risultare chiamate impreviste sulla bolletta telefonica. Questa autorizzazione non consente all\'applicazione di chiamare numeri di emergenza."</string>
- <string name="permlab_callPrivileged">"chiamare direttamente tutti i numeri di telefono"</string>
+ <string name="permlab_callPrivileged">"chiamata diretta di tutti i n. telefono"</string>
<string name="permdesc_callPrivileged">"Consente all\'applicazione di chiamare qualsiasi numero, compresi quelli di emergenza, automaticamente. Le applicazioni dannose potrebbero effettuare chiamate non necessarie e illegali a servizi di emergenza."</string>
- <string name="permlab_locationUpdates">"controllare le notifiche di aggiornamento della posizione"</string>
- <string name="permdesc_locationUpdates">"Consente l\'attivazione/disattivazione delle notifiche di aggiornamento della posizione. Da non usare per normali applicazioni."</string>
- <string name="permlab_checkinProperties">"accedere a proprietà di archiviazione"</string>
+ <string name="permlab_locationUpdates">"controllo notifiche aggiornamento posizione"</string>
+ <string name="permdesc_locationUpdates">"Consente l\'attivazione/disattivazione delle notifiche di aggiornamento della posizione dal segnale cellulare. Da non usare per normali applicazioni."</string>
+ <string name="permlab_checkinProperties">"accesso a proprietà di archiviazione"</string>
<string name="permdesc_checkinProperties">"Consente l\'accesso di lettura/scrittura alle proprietà caricate dal servizio di archiviazione. Da non usare per normali applicazioni."</string>
- <string name="permlab_modifyPhoneState">"modificare lo stato del telefono"</string>
- <string name="permdesc_modifyPhoneState">"Consente all\'applicazione di controllare le funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può cambiare rete, accendere e spegnere il modulo radio del telefono e così via, il tutto automaticamente."</string>
- <string name="permlab_readPhoneState">"leggere lo stato del telefono"</string>
+ <string name="permlab_bindGadget">"scegliere gadget"</string>
+ <string name="permdesc_bindGadget">"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."</string>
+ <string name="permlab_modifyPhoneState">"modifica stato del telefono"</string>
+ <string name="permdesc_modifyPhoneState">"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."</string>
+ <string name="permlab_readPhoneState">"lettura stato del telefono"</string>
<string name="permdesc_readPhoneState">"Consente l\'accesso dell\'applicazione alle funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può determinare il numero del telefono in uso, se una chiamata è attiva o meno, il numero a cui è collegata la chiamata e simili."</string>
- <string name="permlab_wakeLock">"impedire la sospensione del telefono"</string>
- <string name="permdesc_wakeLock">"Consente a un\'applicazione di impedire la sospensione del telefono."</string>
- <string name="permlab_devicePower">"accendere o spegnere il telefono"</string>
+ <string name="permlab_wakeLock">"disattivazione stand-by del telefono"</string>
+ <string name="permdesc_wakeLock">"Consente a un\'applicazione di impedire lo stand-by del telefono."</string>
+ <string name="permlab_devicePower">"accensione o spegnimento del telefono"</string>
<string name="permdesc_devicePower">"Consente all\'applicazione di accendere o spegnere il telefono."</string>
- <string name="permlab_factoryTest">"eseguire in modalità test di fabbrica"</string>
+ <string name="permlab_factoryTest">"esecuzione in modalità test di fabbrica"</string>
<string name="permdesc_factoryTest">"In esecuzione come test del produttore di basso livello, consentendo l\'accesso completo all\'hardware del telefono. Disponibile soltanto quando il telefono è in esecuzione in modalità test del produttore."</string>
- <string name="permlab_setWallpaper">"impostare lo sfondo"</string>
+ <string name="permlab_setWallpaper">"impostazione sfondo"</string>
<string name="permdesc_setWallpaper">"Consente all\'applicazione di impostare lo sfondo del sistema."</string>
- <string name="permlab_setWallpaperHints">"impostare suggerimenti per le dimensioni dello sfondo"</string>
+ <string name="permlab_setWallpaperHints">"impostaz. suggerimenti dimensioni sfondo"</string>
<string name="permdesc_setWallpaperHints">"Consente all\'applicazione di impostare i suggerimenti per le dimensioni dello sfondo del sistema."</string>
- <string name="permlab_masterClear">"ripristinare impostazioni predefinite di fabbrica"</string>
+ <string name="permlab_masterClear">"ripristino impostazioni predef. di fabbrica"</string>
<string name="permdesc_masterClear">"Consente a un\'applicazione di ripristinare le impostazioni di fabbrica del sistema, eliminando tutti i dati, le configurazioni e le applicazioni installate."</string>
- <string name="permlab_setTimeZone">"impostare il fuso orario"</string>
+ <string name="permlab_setTimeZone">"impostazione fuso orario"</string>
<string name="permdesc_setTimeZone">"Consente a un\'applicazione di modificare il fuso orario del telefono."</string>
- <string name="permlab_getAccounts">"trovare account noti"</string>
+ <string name="permlab_getAccounts">"rilevamento account noti"</string>
<string name="permdesc_getAccounts">"Consente a un\'applicazione di recuperare l\'elenco di account memorizzati sul telefono."</string>
- <string name="permlab_accessNetworkState">"visualizzare lo stato della rete"</string>
+ <string name="permlab_accessNetworkState">"visualizzazione stato della rete"</string>
<string name="permdesc_accessNetworkState">"Consente a un\'applicazione di visualizzare lo stato di tutte le reti."</string>
<string name="permlab_createNetworkSockets">"accesso completo a Internet"</string>
<string name="permdesc_createNetworkSockets">"Consente a un\'applicazione di creare socket di rete."</string>
- <string name="permlab_writeApnSettings">"scrivere impostazioni di nomi di punti di accesso"</string>
+ <string name="permlab_writeApnSettings">"scrittura impostazioni APN"</string>
<string name="permdesc_writeApnSettings">"Consente a un\'applicazione di modificare le impostazioni APN, come proxy e porta di qualsiasi APN."</string>
- <string name="permlab_changeNetworkState">"cambiare connettività di rete"</string>
+ <string name="permlab_changeNetworkState">"modifica connettività di rete"</string>
<string name="permdesc_changeNetworkState">"Consente a un\'applicazione di modificare lo stato di connettività di rete."</string>
- <string name="permlab_accessWifiState">"visualizzare lo stato Wi-Fi"</string>
+ <string name="permlab_changeBackgroundDataSetting">"cambiare l\'impostazione di utilizzo dei dati in background"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Consente a un\'applicazione di cambiare l\'impostazione di utilizzo dei dati in background."</string>
+ <string name="permlab_accessWifiState">"visualizzazione stato Wi-Fi"</string>
<string name="permdesc_accessWifiState">"Consente a un\'applicazione di visualizzare le informazioni relative allo stato della connessione Wi-Fi."</string>
- <string name="permlab_changeWifiState">"cambiare stato Wi-Fi"</string>
+ <string name="permlab_changeWifiState">"modifica stato Wi-Fi"</string>
<string name="permdesc_changeWifiState">"Consente a un\'applicazione di connettersi/disconnettersi da punti di accesso Wi-Fi e di apportare modifiche alle reti Wi-Fi configurate."</string>
<string name="permlab_bluetoothAdmin">"gestione Bluetooth"</string>
<string name="permdesc_bluetoothAdmin">"Consente a un\'applicazione di configurare il telefono Bluetooth locale e di rilevare e abbinare dispositivi remoti."</string>
- <string name="permlab_bluetooth">"creare connessioni Bluetooth"</string>
+ <string name="permlab_bluetooth">"creazione connessioni Bluetooth"</string>
<string name="permdesc_bluetooth">"Consente a un\'applicazione di visualizzare la configurazione del telefono Bluetooth locale e di stabilire e accettare connessioni con dispositivi associati."</string>
- <string name="permlab_disableKeyguard">"disattivare blocco tastiera"</string>
+ <string name="permlab_disableKeyguard">"disattivazione blocco tastiera"</string>
<string name="permdesc_disableKeyguard">"Consente la disattivazione da parte di un\'applicazione del blocco tastiera e di eventuali protezioni tramite password associate. Un valido esempio è la disattivazione da parte del telefono del blocco tastiera quando riceve una telefonata in entrata, e la successiva riattivazione del blocco al termine della chiamata."</string>
- <string name="permlab_readSyncSettings">"leggere impostazioni di sincronizzazione"</string>
+ <string name="permlab_readSyncSettings">"lettura impostazioni di sincronizz."</string>
<string name="permdesc_readSyncSettings">"Consente a un\'applicazione di leggere le impostazioni di sincronizzazione, come l\'attivazione o meno della sincronizzazione per Contatti."</string>
- <string name="permlab_writeSyncSettings">"scrivere impostazioni di sincronizzazione"</string>
+ <string name="permlab_writeSyncSettings">"scrittura impostazioni di sincronizz."</string>
<string name="permdesc_writeSyncSettings">"Consente a un\'applicazione di modificare le impostazioni di sincronizzazione, come l\'attivazione o meno della sincronizzazione per Contatti."</string>
- <string name="permlab_readSyncStats">"leggere statistiche di sincronizzazione"</string>
+ <string name="permlab_readSyncStats">"lettura statistiche di sincronizz."</string>
<string name="permdesc_readSyncStats">"Consente a un\'applicazione di leggere le statistiche di sincronizzazione, per esempio la cronologia delle sincronizzazioni effettuate."</string>
- <string name="permlab_subscribedFeedsRead">"leggere feed sottoscritti"</string>
+ <string name="permlab_subscribedFeedsRead">"lettura feed sottoscritti"</string>
<string name="permdesc_subscribedFeedsRead">"Consente a un\'applicazione di ottenere dettagli sui feed attualmente sincronizzati."</string>
- <string name="permlab_subscribedFeedsWrite">"scrivere feed sottoscritti"</string>
+ <string name="permlab_subscribedFeedsWrite">"scrittura feed sottoscritti"</string>
<string name="permdesc_subscribedFeedsWrite">"Consente la modifica da parte di un\'applicazione dei feed attualmente sincronizzati. Le applicazioni dannose potrebbero essere in grado di modificare i feed sincronizzati."</string>
- <!-- no translation found for permlab_readDictionary (432535716804748781) -->
- <skip />
- <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
- <skip />
- <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
- <skip />
- <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
- <skip />
+ <string name="permlab_readDictionary">"lettura dizionario definito dall\'utente"</string>
+ <string name="permdesc_readDictionary">"Consente a un\'applicazione di leggere parole, nomi e frasi private che l\'utente potrebbe aver memorizzato nel dizionario utente."</string>
+ <string name="permlab_writeDictionary">"scrittura nel dizionario definito dall\'utente"</string>
+ <string name="permdesc_writeDictionary">"Consente a un\'applicazione di scrivere nuove parole nel dizionario utente."</string>
<string-array name="phoneTypes">
<item>"Casa"</item>
<item>"Cellulare"</item>
- <item>"Lavoro"</item>
- <item>"Fax lavoro"</item>
- <item>"Fax abitazione"</item>
+ <item>"Ufficio"</item>
+ <item>"Fax ufficio"</item>
+ <item>"Fax casa"</item>
<item>"Cercapersone"</item>
<item>"Altro"</item>
- <item>"Personale"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="emailAddressTypes">
<item>"Casa"</item>
- <item>"Lavoro"</item>
+ <item>"Ufficio"</item>
<item>"Altro"</item>
- <item>"Personale"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="postalAddressTypes">
<item>"Casa"</item>
- <item>"Lavoro"</item>
+ <item>"Ufficio"</item>
<item>"Altro"</item>
- <item>"Personale"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="imAddressTypes">
<item>"Casa"</item>
- <item>"Lavoro"</item>
+ <item>"Uffico"</item>
<item>"Altro"</item>
- <item>"Personale"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="organizationTypes">
- <item>"Lavoro"</item>
+ <item>"Ufficio"</item>
<item>"Altro"</item>
- <item>"Personale"</item>
+ <item>"Personalizzato"</item>
</string-array>
<string-array name="imProtocols">
<item>"AIM"</item>
@@ -387,8 +397,9 @@
<string name="lockscreen_emergency_call">"Chiamata di emergenza"</string>
<string name="lockscreen_pattern_correct">"Corretta."</string>
<string name="lockscreen_pattern_wrong">"Riprova"</string>
- <string name="lockscreen_plugged_in">"In carica (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
- <string name="lockscreen_low_battery">"Collega il caricabatterie."</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Collegare il caricabatterie."</string>
<string name="lockscreen_missing_sim_message_short">"Nessuna SIM presente."</string>
<string name="lockscreen_missing_sim_message">"Nessuna SIM presente nel telefono."</string>
<string name="lockscreen_missing_sim_instructions">"Inserisci una SIM."</string>
@@ -410,30 +421,27 @@
<string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
<string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <!-- no translation found for hour_ampm (7618670480400517084) -->
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
<skip />
- <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
<skip />
<string name="status_bar_clear_all_button">"Cancella notifiche"</string>
<string name="status_bar_no_notifications_title">"Nessuna notifica"</string>
<string name="status_bar_ongoing_events_title">"In corso"</string>
<string name="status_bar_latest_events_title">"Notifiche"</string>
- <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
<skip />
<string name="battery_status_charging">"In carica..."</string>
- <string name="battery_low_title">"Collega il caricabatterie"</string>
+ <string name="battery_low_title">"Collegare il caricabatterie"</string>
<string name="battery_low_subtitle">"Batteria quasi scarica:"</string>
- <string name="battery_low_percent_format">"meno di <xliff:g id="NUMBER">%d%%</xliff:g> rimanenti."</string>
+ <string name="battery_low_percent_format">"energia residua inferiore a <xliff:g id="NUMBER">%d%%</xliff:g>."</string>
<string name="factorytest_failed">"Test di fabbrica non riuscito"</string>
<string name="factorytest_not_system">"L\'azione FACTORY_TEST è supportata soltanto per i pacchetti installati in /system/app."</string>
<string name="factorytest_no_action">"Nessun pacchetto trovato che fornisca l\'azione FACTORY_TEST."</string>
<string name="factorytest_reboot">"Riavvia"</string>
- <!-- no translation found for js_dialog_title (8143918455087008109) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
- <skip />
+ <string name="js_dialog_title">"La pagina all\'indirizzo <xliff:g id="TITLE">%s</xliff:g> indica:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Uscire da questa pagina?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Seleziona OK per continuare o Annulla per rimanere nella pagina corrente."</string>
<string name="save_password_label">"Conferma"</string>
<string name="save_password_message">"Memorizzare la password nel browser?"</string>
<string name="save_password_notnow">"Non ora"</string>
@@ -484,22 +492,38 @@
<item quantity="one">"domani"</item>
<item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
</plurals>
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"1 sec fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> sec fa"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"1 min fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> min fa"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"1 ora fa"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> ore fa"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"ieri"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> giorni fa"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"tra 1 sec"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> sec"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"tra 1 min"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"tra 1 ora"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> ore"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"domani"</item>
+ <item quantity="other">"tra <xliff:g id="COUNT">%d</xliff:g> giorni"</item>
+ </plurals>
<string name="preposition_for_date">"il %s"</string>
<string name="preposition_for_time">"alle %s"</string>
<string name="preposition_for_year">"nel %s"</string>
@@ -541,27 +565,25 @@
<string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
- <!-- no translation found for date_time (6104442718633642836) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
- <string name="full_date_month_first">"<xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="DAY">dd</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="full_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_month_first">"<xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="DAY">dd</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
- <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
<string name="noon">"mezzogiorno"</string>
<string name="Noon">"Mezzogiorno"</string>
<string name="midnight">"mezzanotte"</string>
<string name="Midnight">"Mezzanotte"</string>
- <!-- no translation found for month_day (5565829181417740906) -->
+ <!-- no translation found for month_day (3693060561170538204) -->
<skip />
- <!-- no translation found for month (7026169712234774086) -->
+ <!-- no translation found for month (1976700695144952053) -->
<skip />
- <string name="month_day_year">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for month_year (9219019380312413367) -->
+ <string name="month_day_year">"<xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
+ <!-- no translation found for month_year (2106203387378728384) -->
<skip />
<string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
@@ -590,11 +612,11 @@
<string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="abbrev_month_day_year">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%b</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
<skip />
- <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
<skip />
- <!-- no translation found for abbrev_month (3131032032850777433) -->
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
<skip />
<string name="day_of_week_long_sunday">"Domenica"</string>
<string name="day_of_week_long_monday">"Lunedì"</string>
@@ -679,6 +701,7 @@
<string name="paste">"Incolla"</string>
<string name="copyUrl">"Copia URL"</string>
<string name="inputMethod">"Metodo inserimento"</string>
+ <string name="addToDictionary">"Aggiungi \"%s\" al dizionario"</string>
<string name="editTextMenuTitle">"Modifica testo"</string>
<string name="low_internal_storage_view_title">"Spazio in esaurimento"</string>
<string name="low_internal_storage_view_text">"Spazio di archiviazione del telefono in esaurimento."</string>
@@ -686,6 +709,7 @@
<string name="cancel">"Annulla"</string>
<string name="yes">"OK"</string>
<string name="no">"Annulla"</string>
+ <string name="dialog_alert_title">"Attenzione"</string>
<string name="capital_on">"ON"</string>
<string name="capital_off">"OFF"</string>
<string name="whichApplication">"Completa l\'azione con"</string>
@@ -706,10 +730,10 @@
<string name="debug">"Debug"</string>
<string name="sendText">"Seleziona un\'azione per il testo"</string>
<string name="volume_ringtone">"Volume suoneria"</string>
- <string name="volume_music">"Volume media"</string>
+ <string name="volume_music">"Volume app. multimediali"</string>
<string name="volume_music_hint_playing_through_bluetooth">"Riproduzione tramite Bluetooth"</string>
<string name="volume_call">"Volume chiamate"</string>
- <string name="volume_call_hint_playing_through_bluetooth">"Riproduzione tramite Bluetooth"</string>
+ <string name="volume_bluetooth_call">"Volume chiamate Bluetooth"</string>
<string name="volume_alarm">"Volume allarme"</string>
<string name="volume_notification">"Volume notifiche"</string>
<string name="volume_unknown">"Volume"</string>
@@ -744,9 +768,48 @@
<string name="usb_storage_button_unmount">"Non collegare"</string>
<string name="usb_storage_error_message">"Problema di utilizzo della scheda SD per l\'archiviazione USB."</string>
<string name="usb_storage_notification_title">"USB collegata"</string>
- <string name="usb_storage_notification_message">"Seleziona per copiare file sul/dal computer in uso."</string>
+ <string name="usb_storage_notification_message">"Seleziona per copiare file sul/dal tuo computer."</string>
+ <string name="usb_storage_stop_notification_title">"Disattiva archivio USB"</string>
+ <string name="usb_storage_stop_notification_message">"Seleziona per disattivare archivio USB."</string>
+ <string name="usb_storage_stop_title">"Disattiva archivio USB"</string>
+ <string name="usb_storage_stop_message">"Prima di disattivare l\'archivio USB, verifica di aver smontato l\'host USB. A tale scopo, seleziona \"Disattiva\"."</string>
+ <string name="usb_storage_stop_button_mount">"Disattiva"</string>
+ <string name="usb_storage_stop_button_unmount">"Annulla"</string>
+ <string name="usb_storage_stop_error_message">"Abbiamo riscontrato un problema disattivando l\'archivio USB. Verifica di aver smontato l\'host USB e riprova."</string>
+ <string name="extmedia_format_title">"Formatta scheda SD"</string>
+ <string name="extmedia_format_message">"Formattare la scheda SD? Tutti i dati sulla scheda verranno persi."</string>
+ <string name="extmedia_format_button_format">"Formatta"</string>
<string name="select_input_method">"Seleziona metodo di inserimento"</string>
- <string name="fast_scroll_alphabet">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style"><font fgcolor="#ff000000" bgcolor="#ff8080ff"><u>"candidati"</u>"u&gt;"</font></string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"candidati"</u></string>
+ <string name="ext_media_checking_notification_title">"Preparazione scheda SD"</string>
+ <string name="ext_media_checking_notification_message">"Ricerca errori"</string>
+ <string name="ext_media_nofs_notification_title">"Scheda SD vuota"</string>
+ <string name="ext_media_nofs_notification_message">"La scheda SD è vuota o utilizza un file system non supportato."</string>
+ <string name="ext_media_unmountable_notification_title">"Scheda SD danneggiata"</string>
+ <string name="ext_media_unmountable_notification_message">"La scheda SD è danneggiata. Potrebbe essere necessario riformattarla."</string>
+ <string name="ext_media_badremoval_notification_title">"Rimozione imprevista della scheda SD"</string>
+ <string name="ext_media_badremoval_notification_message">"Smonta scheda SD prima della rimozione per evitare la perdita di dati."</string>
+ <string name="ext_media_safe_unmount_notification_title">"È possibile rimuovere la scheda SD"</string>
+ <string name="ext_media_safe_unmount_notification_message">"È ora possibile rimuovere la scheda SD in modo sicuro."</string>
+ <string name="ext_media_nomedia_notification_title">"Scheda SD rimossa"</string>
+ <string name="ext_media_nomedia_notification_message">"Inserisci una nuova scheda SD per aumentare la memoria del dispositivo."</string>
+ <string name="activity_list_empty">"Nessuna attività corrispondente trovata"</string>
+ <string name="permlab_pkgUsageStats">"aggiornare le statistiche di utilizzo dei componenti"</string>
+ <string name="permdesc_pkgUsageStats">"Consente la modifica delle statistiche di utilizzo dei componenti raccolte. Da non usare per normali applicazioni."</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ja-rJP/arrays.xml b/core/res/res/values-ja-rJP/arrays.xml
new file mode 100644
index 0000000..74e8a59
--- /dev/null
+++ b/core/res/res/values-ja-rJP/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2009, Google Inc.
+**
+** 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.
+*/
+-->
+<resources>
+
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_lat_lng">
+ <item>35666667</item>
+ <item>139750000</item>
+ </integer-array>
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_zoom">
+ <item>5</item>
+ </integer-array>
+
+</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 055a8b1..2a21bd3 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -21,10 +21,10 @@
<string name="gigabyteShort">"GB"</string>
<string name="terabyteShort">"TB"</string>
<string name="petabyteShort">"PB"</string>
- <string name="untitled">"&lt;無題&gt;"</string>
+ <string name="untitled">"&lt;新規&gt;"</string>
<string name="ellipsis">"..."</string>
- <string name="emptyPhoneNumber">"(電話番号なし)"</string>
- <string name="unknownName">"(不明)"</string>
+ <string name="emptyPhoneNumber">"(電話番号なし)"</string>
+ <string name="unknownName">"(名前)"</string>
<string name="defaultVoiceMailAlphaTag">"ボイスメール"</string>
<string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
<string name="mmiError">"接続に問題があるか、MMIコードが正しくありません。"</string>
@@ -48,11 +48,11 @@
<string name="BaMmi">"発信制限"</string>
<string name="PwdMmi">"パスワードの変更"</string>
<string name="PinMmi">"PINの変更"</string>
- <string name="CLIRDefaultOnNextCallOn">"デフォルトでは発信者番号は非通知です。次の通話でも非通知です。"</string>
- <string name="CLIRDefaultOnNextCallOff">"デフォルトでは発信者番号は非通知ですが、次の通話では通知されます。"</string>
- <string name="CLIRDefaultOffNextCallOn">"デフォルトでは発信者番号は通知されますが、次の通話では非通知です。"</string>
- <string name="CLIRDefaultOffNextCallOff">"デフォルトでは発信者番号は通知されます。次の通話でも通知されます。"</string>
- <string name="serviceNotProvisioned">"サービスは提供されません。"</string>
+ <string name="CLIRDefaultOnNextCallOn">"既定: 発信者番号非通知、次の発信: 非通知"</string>
+ <string name="CLIRDefaultOnNextCallOff">"既定: 発信者番号非通知、次の発信: 通知"</string>
+ <string name="CLIRDefaultOffNextCallOn">"既定: 発信者番号通知、次の発信: 非通知"</string>
+ <string name="CLIRDefaultOffNextCallOff">"既定: 発信者番号通知、次の発信: 通知"</string>
+ <string name="serviceNotProvisioned">"提供可能なサービスがありません。"</string>
<string name="CLIRPermanent">"発信者番号の設定は変更できません。"</string>
<string name="serviceClassVoice">"音声"</string>
<string name="serviceClassData">"データ"</string>
@@ -90,46 +90,54 @@
<string name="me">"自分"</string>
<string name="power_dialog">"携帯電話オプション"</string>
<string name="silent_mode">"マナーモード"</string>
- <string name="turn_on_radio">"ワイヤレスをオン"</string>
- <string name="turn_off_radio">"ワイヤレスオフ"</string>
+ <string name="turn_on_radio">"ワイヤレス接続をONにする"</string>
+ <string name="turn_off_radio">"ワイヤレス接続をOFFにする"</string>
<string name="screen_lock">"画面をロック"</string>
<string name="power_off">"電源オフ"</string>
<string name="shutdown_progress">"シャットダウン中..."</string>
<string name="shutdown_confirm">"携帯電話の電源をオフにします。"</string>
<string name="no_recent_tasks">"最近使ったアプリケーションはありません。"</string>
<string name="global_actions">"携帯電話オプション"</string>
- <string name="global_action_lock">"画面をロック"</string>
+ <string name="global_action_lock">"画面ロック"</string>
<string name="global_action_power_off">"電源オフ"</string>
<string name="global_action_toggle_silent_mode">"マナーモード"</string>
<string name="global_action_silent_mode_on_status">"音声オフ"</string>
<string name="global_action_silent_mode_off_status">"サウンド:オン"</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
<string name="safeMode">"セーフモード"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
<string name="permgrouplab_costMoney">"料金の発生するサービス"</string>
<string name="permgroupdesc_costMoney">"料金の発生する操作をアプリケーションに許可します。"</string>
<string name="permgrouplab_messages">"送受信したメッセージ"</string>
<string name="permgroupdesc_messages">"SMS、メールなどのメッセージの読み書き"</string>
<string name="permgrouplab_personalInfo">"個人情報"</string>
- <string name="permgroupdesc_personalInfo">"携帯電話に保存した連絡先とカレンダーに直接アクセス"</string>
+ <string name="permgroupdesc_personalInfo">"端末の連絡先とカレンダーに直接アクセス"</string>
<string name="permgrouplab_location">"現在地"</string>
- <string name="permgroupdesc_location">"現在地を監視"</string>
+ <string name="permgroupdesc_location">"現在地を追跡"</string>
<string name="permgrouplab_network">"ネットワーク通信"</string>
<string name="permgroupdesc_network">"ネットワークのさまざまな機能へのアクセスをアプリケーションに許可します。"</string>
<string name="permgrouplab_accounts">"Googleアカウント"</string>
<string name="permgroupdesc_accounts">"利用可能なGoogleアカウントへのアクセス"</string>
<string name="permgrouplab_hardwareControls">"ハードウェアの制御"</string>
<string name="permgroupdesc_hardwareControls">"携帯電話のハードウェアに直接アクセスします。"</string>
- <string name="permgrouplab_phoneCalls">"電話の発信"</string>
+ <string name="permgrouplab_phoneCalls">"電話/通話"</string>
<string name="permgroupdesc_phoneCalls">"通話の監視、記録、処理"</string>
<string name="permgrouplab_systemTools">"システムツール"</string>
<string name="permgroupdesc_systemTools">"システムの低レベルのアクセスと制御"</string>
<string name="permgrouplab_developmentTools">"開発ツール"</string>
<string name="permgroupdesc_developmentTools">"アプリケーションのデベロッパーにのみ必要な機能です。"</string>
- <string name="permlab_statusBar">"ステータスバーを無効にしたり変更する"</string>
- <string name="permdesc_statusBar">"ステータスバーの無効化や、システムアイコンの追加や削除をアプリケーションに許可します。"</string>
+ <string name="permlab_statusBar">"ステータスバーの無効化や変更"</string>
+ <string name="permdesc_statusBar">"ステータスバーの無効化やシステムアイコンの追加や削除をアプリケーションに許可します。"</string>
<string name="permlab_expandStatusBar">"ステータスバーの拡大/縮小"</string>
<string name="permdesc_expandStatusBar">"ステータスバーの拡大や縮小をアプリケーションに許可します。"</string>
<string name="permlab_processOutgoingCalls">"発信の傍受"</string>
- <string name="permdesc_processOutgoingCalls">"発信を処理して、ダイヤルする番号を変更することをアプリケーションに許可します。悪意のあるアプリケーションが発信を監視、転送、阻止する恐れがあります。"</string>
+ <string name="permdesc_processOutgoingCalls">"通話の発信とダイヤルする番号の変更とをアプリケーションに許可します。悪意のあるアプリケーションが発信を監視、転送、阻止する恐れがあります。"</string>
<string name="permlab_receiveSms">"SMSの受信"</string>
<string name="permdesc_receiveSms">"SMSメッセージの受信と処理をアプリケーションに許可します。悪意のあるアプリケーションがメッセージを監視したり、表示せずに削除する恐れがあります。"</string>
<string name="permlab_receiveMms">"MMSの受信"</string>
@@ -137,7 +145,7 @@
<string name="permlab_sendSms">"SMSメッセージの送信"</string>
<string name="permdesc_sendSms">"SMSメッセージの送信をアプリケーションに許可します。悪意のあるアプリケーションが確認なしでメッセージを送信し、料金が発生する恐れがあります。"</string>
<string name="permlab_readSms">"SMSやMMSの読み取り"</string>
- <string name="permdesc_readSms">"携帯電話またはSIMカードに保存したSMSメッセージの読み取りをアプリケーションに許可します。悪意のあるアプリケーションが機密メッセージを読み取る恐れがあります。"</string>
+ <string name="permdesc_readSms">"携帯電話やSIMカードに保存したSMSメッセージの読み取りをアプリケーションに許可します。悪意のあるアプリケーションが機密メッセージを読み取る恐れがあります。"</string>
<string name="permlab_writeSms">"SMSやMMSの編集"</string>
<string name="permdesc_writeSms">"携帯電話やSIMカードに保存したSMSメッセージへの書き込みをアプリケーションに許可します。悪意のあるアプリケーションがメッセージを削除する恐れがあります。"</string>
<string name="permlab_receiveWapPush">"WAPの受信"</string>
@@ -147,9 +155,9 @@
<string name="permlab_reorderTasks">"実行中のアプリケーションの順序の変更"</string>
<string name="permdesc_reorderTasks">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリケーションに許可します。悪意のあるアプリケーションが優先されて、コントロールできなくなる恐れがあります。"</string>
<string name="permlab_setDebugApp">"アプリケーションのデバッグを有効にする"</string>
- <string name="permdesc_setDebugApp">"別のアプリケーションをデバッグモードにすることをアプリケーションに許可します。これにより悪意のあるアプリケーションが、別のアプリケーションを終了させる恐れがあります。"</string>
+ <string name="permdesc_setDebugApp">"別のアプリケーションをデバッグモードにすることをアプリケーションに許可します。悪意のあるアプリケーションが別のアプリケーションを終了させる恐れがあります。"</string>
<string name="permlab_changeConfiguration">"UI設定の変更"</string>
- <string name="permdesc_changeConfiguration">"ロケールや全体のフォントのサイズなど、現在の設定の変更をアプリケーションに許可します。"</string>
+ <string name="permdesc_changeConfiguration">"地域/言語やフォントのサイズなど、現在の設定の変更をアプリケーションに許可します。"</string>
<string name="permlab_restartPackages">"他のアプリケーションの再起動"</string>
<string name="permdesc_restartPackages">"他のアプリケーションの強制的な再起動をアプリケーションに許可します。"</string>
<string name="permlab_setProcessForeground">"停止の阻止"</string>
@@ -157,47 +165,47 @@
<string name="permlab_forceBack">"アプリケーションの強制終了"</string>
<string name="permdesc_forceBack">"フォアグラウンドで実行されている操作を強制終了して戻ることをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
<string name="permlab_dump">"システムの内部状態の取得"</string>
- <string name="permdesc_dump">"システムの内部状態の取得をアプリケーションに許可します。悪意のあるアプリケーションが、通常は必要のない、広範囲にわたる非公開の機密情報を取得する恐れがあります。"</string>
+ <string name="permdesc_dump">"システムの内部状態の取得をアプリケーションに許可します。悪意のあるアプリケーションが、通常は必要としない広範囲にわたる非公開の機密情報を取得する恐れがあります。"</string>
<string name="permlab_addSystemService">"低レベルサービスの公開"</string>
<string name="permdesc_addSystemService">"独自の低レベルのシステムサービスを公開することをアプリケーションに許可します。悪意のあるアプリケーションがシステムを乗っ取って、データの盗用や破壊をする恐れがあります。"</string>
<string name="permlab_runSetActivityWatcher">"起動中のすべてのアプリケーションの監視と制御"</string>
<string name="permdesc_runSetActivityWatcher">"システムが起動する操作の監視と制御をアプリケーションに許可します。悪意のあるアプリケーションがシステムを完全に破壊する恐れがあります。この許可は開発にのみ必要で、携帯電話の通常の使用にはまったく必要ありません。"</string>
<string name="permlab_broadcastPackageRemoved">"パッケージ削除ブロードキャストの送信"</string>
- <string name="permdesc_broadcastPackageRemoved">"アプリケーションパッケージの削除通知を配信することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、他の実行中のアプリケーションを強制終了する恐れがあります。"</string>
+ <string name="permdesc_broadcastPackageRemoved">"アプリケーションパッケージの削除の通知を配信することをアプリケーションに許可します。悪意のあるアプリケーションが他の実行中のアプリケーションを強制終了する恐れがあります。"</string>
<string name="permlab_broadcastSmsReceived">"SMS受信ブロードキャストの送信"</string>
- <string name="permdesc_broadcastSmsReceived">"SMSメッセージの受信通知の配信をアプリケーションに許可します。これにより悪意のあるアプリケーションが、受信SMSメッセージを偽造する恐れがあります。"</string>
+ <string name="permdesc_broadcastSmsReceived">"SMSメッセージの受信通知の配信をアプリケーションに許可します。悪意のあるアプリケーションが受信SMSメッセージを偽造する恐れがあります。"</string>
<string name="permlab_broadcastWapPush">"WAP-PUSH受信ブロードキャストの送信"</string>
- <string name="permdesc_broadcastWapPush">"WAP PUSHメッセージの受信通知を配信することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、MMS受信メッセージを偽造したり、ウェブページのコンテンツを密かに改ざんしたりする恐れがあります。"</string>
+ <string name="permdesc_broadcastWapPush">"WAP PUSHメッセージの受信の通知を配信することをアプリケーションに許可します。悪意のあるアプリケーションがMMS受信メッセージを偽造したり、ウェブページのコンテンツを密かに改ざんする恐れがあります。"</string>
<string name="permlab_setProcessLimit">"実行中のプロセスの数を制限"</string>
<string name="permdesc_setProcessLimit">"実行するプロセス数の上限の制御をアプリケーションに許可します。通常のアプリケーションにはまったく必要ありません。"</string>
<string name="permlab_setAlwaysFinish">"バックグラウンドアプリケーションをすべて終了する"</string>
<string name="permdesc_setAlwaysFinish">"バックグラウンドになり次第必ず操作を終了させるかどうかの制御をアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
<string name="permlab_fotaUpdate">"システムアップデートの自動インストール"</string>
- <string name="permdesc_fotaUpdate">"保留中のシステムアップデートに関する通知を受信してインストールを開始することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、許可なく更新を行ってシステムを破壊したり、更新処理を妨害する恐れがあります。"</string>
- <string name="permlab_batteryStats">"バッテリ統計の変更"</string>
- <string name="permdesc_batteryStats">"収集されたバッテリの統計の変更を許可します。通常のアプリケーションでは使用しません。"</string>
+ <string name="permdesc_fotaUpdate">"保留中のシステムアップデートに関する通知の受信とインストールの開始をアプリケーションに許可します。悪意のあるアプリケーションが許可なく更新を行ってシステムを破壊したり、更新処理を妨害する恐れがあります。"</string>
+ <string name="permlab_batteryStats">"電池統計情報の変国"</string>
+ <string name="permdesc_batteryStats">"収集した電池統計情報の変更を許可します。通常のアプリケーションでは使用しません。"</string>
<string name="permlab_internalSystemWindow">"未許可のウィンドウの表示"</string>
<string name="permdesc_internalSystemWindow">"内部システムのユーザーインターフェースで使用するためのウィンドウ作成を許可します。通常のアプリケーションでは使用しません。"</string>
<string name="permlab_systemAlertWindow">"システムレベルの警告の表示"</string>
- <string name="permdesc_systemAlertWindow">"システムの警告ウィンドウをアプリケーションで表示できるようにします。悪意のあるアプリケーションが携帯電話の画面全体を偽装する恐れがあります。"</string>
- <string name="permlab_setAnimationScale">"アニメーション全般の速度の変更"</string>
+ <string name="permdesc_systemAlertWindow">"システムの警告ウィンドウの表示をアプリケーションに許可します。悪意のあるアプリケーションが携帯電話の画面全体を偽装する恐れがあります。"</string>
+ <string name="permlab_setAnimationScale">"アニメーションのプリセット速度の変更"</string>
<string name="permdesc_setAnimationScale">"いつでもアニメーション全般の速度を変更する (アニメーションを速くまたは遅くする) ことをアプリケーションに許可します。"</string>
<string name="permlab_manageAppTokens">"アプリケーショントークンの管理"</string>
<string name="permdesc_manageAppTokens">"通常のZ-orderingを回避して、独自のトークンを作成、管理することをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
<string name="permlab_injectEvents">"キーを押してボタンをコントロール"</string>
<string name="permdesc_injectEvents">"入力イベント (キーを押すなど) を別のアプリケーションに伝えることをアプリケーションに許可します。これにより悪意のあるアプリケーションが、携帯電話を乗っ取る恐れがあります。"</string>
<string name="permlab_readInputState">"入力や操作の記録"</string>
- <string name="permdesc_readInputState">"別のアプリケーションへの入力 (パスワードなど) でもキー入力を監視することをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
+ <string name="permdesc_readInputState">"別のアプリケーションへの入力(パスワードなど)でもキー入力を監視することをアプリケーションに許可します。通常のアプリケーションではまったく必要ありません。"</string>
<string name="permlab_bindInputMethod">"入力方法に関連付ける"</string>
<string name="permdesc_bindInputMethod">"入力方法のトップレベルインターフェースに関連付けることを所有者に許可します。通常のアプリケーションにはまったく必要ありません。"</string>
<string name="permlab_setOrientation">"画面の向きの変更"</string>
<string name="permdesc_setOrientation">"いつでも画面の回転を変更することをアプリケーションに許可します。通常のアプリケーションにはまったく必要ありません。"</string>
<string name="permlab_signalPersistentProcesses">"Linuxのシグナルをアプリケーションに送信"</string>
- <string name="permdesc_signalPersistentProcesses">"すべての永続プロセスに特定の信号を送信するリクエストをアプリケーションに許可します。"</string>
+ <string name="permdesc_signalPersistentProcesses">"受信した電波を継続プロセスに送信することをアプリケーションに許可します。"</string>
<string name="permlab_persistentActivity">"アプリケーションを常に実行する"</string>
<string name="permdesc_persistentActivity">"自身を部分的に永続させて、他のアプリケーション用にはその領域をシステムに使わせないようにすることをアプリケーションに許可します。"</string>
<string name="permlab_deletePackages">"アプリケーションの削除"</string>
- <string name="permdesc_deletePackages">"Androidパッケージの削除をアプリケーションに許可します。これにより悪意のあるアプリケーションが、重要なアプリケーションを削除する恐れがあります。"</string>
+ <string name="permdesc_deletePackages">"Androidパッケージの削除をアプリケーションに許可します。悪意のあるアプリケーションが、重要なアプリケーションを削除する恐れがあります。"</string>
<string name="permlab_clearAppUserData">"他のアプリケーションのデータを削除"</string>
<string name="permdesc_clearAppUserData">"ユーザーデータの消去をアプリケーションに許可します。"</string>
<string name="permlab_deleteCacheFiles">"他のアプリケーションのキャッシュを削除"</string>
@@ -205,46 +213,46 @@
<string name="permlab_getPackageSize">"アプリケーションのメモリ容量の計測"</string>
<string name="permdesc_getPackageSize">"アプリケーションのコード、データ、キャッシュのサイズを取得することを許可します。"</string>
<string name="permlab_installPackages">"アプリケーションを直接インストール"</string>
- <string name="permdesc_installPackages">"Androidパッケージを新たにインストールまたは更新することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、勝手に強力な権限を持つ新しいアプリケーションを追加する恐れがあります。"</string>
+ <string name="permdesc_installPackages">"Androidパッケージのインストール/更新をアプリケーションに許可します。悪意のあるアプリケーションが、勝手に強力な権限を持つ新しいアプリケーションを追加する恐れがあります。"</string>
<string name="permlab_clearAppCache">"アプリケーションキャッシュデータの削除"</string>
<string name="permdesc_clearAppCache">"アプリケーションのキャッシュディレクトリからファイルを削除して携帯電話のメモリを解放することをアプリケーションに許可します。通常、アクセスはシステムプロセスのみに制限されます。"</string>
<string name="permlab_readLogs">"システムログファイルの読み取り"</string>
<string name="permdesc_readLogs">"システムのさまざまなログファイルの読み取りをアプリケーションに許可します。これにより携帯電話の使用状況に関する全般情報が取得されますが、個人情報や非公開情報が含まれることはありません。"</string>
<string name="permlab_diagnostic">"diagが所有するリソースの読み書き"</string>
- <string name="permdesc_diagnostic">"diagグループが所有するリソース (/dev内のファイルなど) への読み書きをアプリケーションに許可します。これはシステムの安定性とセキュリティに影響する恐れがあります。メーカーまたはオペレータによるハードウェア固有の診断以外には使用しないでください。"</string>
+ <string name="permdesc_diagnostic">"diagグループが所有するリソース(例:/dev内のファイル)への読み書きをアプリケーションに許可します。システムの安定性とセキュリティに影響する恐れがあります。メーカー/オペレーターによるハードウェア固有の診断以外には使用しないでください。"</string>
<string name="permlab_changeComponentState">"アプリケーションのコンポーネントを有効/無効にする"</string>
<string name="permdesc_changeComponentState">"別アプリケーションのコンポーネントの有効/無効を変更することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、携帯電話の重要な機能を無効にする恐れがあります。アプリケーションコンポーネントが利用できない、整合性が取れない、または不安定な状態になる恐れがあるので、許可には注意が必要です。"</string>
<string name="permlab_setPreferredApplications">"優先アプリケーションの設定"</string>
- <string name="permdesc_setPreferredApplications">"優先アプリケーションを変更することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、実行中のアプリケーションを密かに変更し、既存のアプリケーションになりすまして、非公開データを収集する恐れがあります。"</string>
- <string name="permlab_writeSettings">"システム全般の設定の変更"</string>
+ <string name="permdesc_setPreferredApplications">"優先アプリケーションを変更することをアプリケーションに許可します。悪意のあるアプリケーションが実行中のアプリケーションを密かに変更し、既存のアプリケーションになりすまして非公開データを収集する恐れがあります。"</string>
+ <string name="permlab_writeSettings">"システムの全般設定の変更"</string>
<string name="permdesc_writeSettings">"システム設定データの変更をアプリケーションに許可します。悪意のあるアプリケーションがシステム設定を破壊する恐れがあります。"</string>
<string name="permlab_writeSecureSettings">"システムのセキュリティ設定の変更"</string>
<string name="permdesc_writeSecureSettings">"システムのセキュリティ設定の変更をアプリケーションに許可します。通常のアプリケーションでは使用しません。"</string>
<string name="permlab_writeGservices">"Googleサービスの地図の変更"</string>
<string name="permdesc_writeGservices">"Googleサービスマップの変更をアプリケーションに許可します。通常のアプリケーションでは使用しません。"</string>
<string name="permlab_receiveBootCompleted">"起動時に自動的に開始"</string>
- <string name="permdesc_receiveBootCompleted">"システムの起動直後に自動的に起動することをアプリケーションに許可します。これにより携帯電話の起動に時間がかかるようになります。また、アプリケーションが常に実行中となるため、携帯電話の全体的な動作が遅くなります。"</string>
+ <string name="permdesc_receiveBootCompleted">"システムの起動後に自動的に起動することをアプリケーションに許可します。携帯電話の起動に時間がかかるようになり、アプリケーションが常に実行されるために携帯電話の全体的な動作が遅くなります。"</string>
<string name="permlab_broadcastSticky">"stickyブロードキャストの配信"</string>
<string name="permdesc_broadcastSticky">"配信が終了してもメモリに残るようなstickyブロードキャストをアプリケーションに許可します。悪意のあるアプリケーションがメモリを使いすぎて、携帯電話の動作が遅くなったり、不安定になる恐れがあります。"</string>
<string name="permlab_readContacts">"連絡先データの読み取り"</string>
- <string name="permdesc_readContacts">"携帯電話に保存した連絡先 (アドレス) データをアプリケーションですべて読み取れるようにします。これにより悪意のあるアプリケーションが、そのデータを他人に送信する恐れがあります。"</string>
+ <string name="permdesc_readContacts">"端末に保存した連絡先(アドレス)データの読み取りをアプリケーションに許可します。悪意のあるアプリケーションがデータを他人に送信する恐れがあります。"</string>
<string name="permlab_writeContacts">"連絡先データの書き込み"</string>
- <string name="permdesc_writeContacts">"携帯電話に保存した連絡先 (アドレス) データの変更をアプリケーションに許可します。これにより悪意のあるアプリケーションが、連絡先データを消去や変更する恐れがあります。"</string>
+ <string name="permdesc_writeContacts">"端末に保存した連絡先(アドレス)データの変更をアプリケーションに許可します。悪意のあるアプリケーションが連絡先データを消去/変更する恐れがあります。"</string>
<string name="permlab_writeOwnerData">"所有者データの書き込み"</string>
- <string name="permdesc_writeOwnerData">"携帯電話に保存した所有者のデータの変更をアプリケーションに許可します。これにより悪意のあるアプリケーションが、所有者のデータを消去または変更する恐れがあります。"</string>
+ <string name="permdesc_writeOwnerData">"端末に保存した所有者のデータの変更をアプリケーションに許可します。悪意のあるアプリケーションが所有者のデータを消去/変更する恐れがあります。"</string>
<string name="permlab_readOwnerData">"所有者データの読み取り"</string>
- <string name="permdesc_readOwnerData">"携帯電話に保存した所有者データの読み取りをアプリケーションに許可します。これにより悪意のあるアプリケーションが、所有者データを読み取る恐れがあります。"</string>
+ <string name="permdesc_readOwnerData">"携帯電話に保存した所有者データの読み取りをアプリケーションに許可します。悪意のあるアプリケーションが所有者データを読み取る恐れがあります。"</string>
<string name="permlab_readCalendar">"カレンダーデータの読み取り"</string>
- <string name="permdesc_readCalendar">"携帯電話に保存したカレンダーのイベントをアプリケーションですべて読み取れるようにします。悪意のあるアプリケーションではこれを利用して、カレンダーのイベントを他人に送信できます。"</string>
+ <string name="permdesc_readCalendar">"端末に保存したカレンダーの予定の読み取りをアプリケーションに許可します。悪意のあるアプリケーションがカレンダーの予定を他人に送信する恐れがあります。"</string>
<string name="permlab_writeCalendar">"カレンダーデータの書き込み"</string>
- <string name="permdesc_writeCalendar">"携帯電話に保存したカレンダーイベントの変更をアプリケーションに許可します。これにより悪意のあるアプリケーションが、カレンダーデータを消去や変更する恐れがあります。"</string>
+ <string name="permdesc_writeCalendar">"端末に保存したカレンダーの予定の変更をアプリケーションに許可します。悪意のあるアプリケーションが、カレンダーデータを消去/変更する恐れがあります。"</string>
<string name="permlab_accessMockLocation">"仮の位置情報でテスト"</string>
<string name="permdesc_accessMockLocation">"テスト用に仮の位置情報源を作成します。これにより悪意のあるアプリケーションが、GPS、ネットワークプロバイダなどから返される本当の位置情報や状況を改ざんする恐れがあります。"</string>
<string name="permlab_accessLocationExtraCommands">"位置情報プロバイダのその他のコマンドへのアクセス"</string>
- <string name="permdesc_accessLocationExtraCommands">"位置情報プロバイダのその他のコマンドにアクセスします。これにより悪意のあるアプリケーションが、GPSなどの位置情報源の動作を妨害する恐れがあります。"</string>
- <string name="permlab_accessFineLocation">"正確な (GPS) 位置"</string>
- <string name="permdesc_accessFineLocation">"GPSなど、携帯電話の正確な位置情報源に、可能な場合アクセスします。これにより悪意のあるアプリケーションが、ユーザーの現在地を特定したり、バッテリの消費を増やしたりする恐れがあります。"</string>
- <string name="permlab_accessCoarseLocation">"おおよその (ネットワーク情報による) 位置"</string>
+ <string name="permdesc_accessLocationExtraCommands">"位置情報提供元の追加コマンドにアクセスします。悪意のあるアプリケーションがGPSなどの位置提供の動作を妨害する恐れがあります。"</string>
+ <string name="permlab_accessFineLocation">"精細な位置情報(GPS)"</string>
+ <string name="permdesc_accessFineLocation">"GPSなど携帯電話の位置情報にアクセスします(可能な場合)。今いる場所が悪意のあるアプリケーションに検出されたり、バッテリーの消費が増える恐れがあります。"</string>
+ <string name="permlab_accessCoarseLocation">"おおよその位置情報(ネットワーク基地局)"</string>
<string name="permdesc_accessCoarseLocation">"セルラーネットワークデータベースなど、携帯電話のおおよその位置を特定する情報源が利用可能な場合にアクセスします。これにより悪意のあるアプリケーションが、ユーザーのおおよその位置を特定できる恐れがあります。"</string>
<string name="permlab_accessSurfaceFlinger">"SurfaceFlingerへのアクセス"</string>
<string name="permdesc_accessSurfaceFlinger">"SurfaceFlingerの低レベルの機能の使用をアプリケーションに許可します。"</string>
@@ -255,33 +263,37 @@
<string name="permlab_recordAudio">"録音"</string>
<string name="permdesc_recordAudio">"オーディオ録音パスへのアクセスをアプリケーションに許可します。"</string>
<string name="permlab_camera">"写真の撮影"</string>
- <string name="permdesc_camera">"カメラで写真を撮ることをアプリケーションに許可します。これによりアプリケーションは、カメラに写る画像をいつでも収集できます。"</string>
- <string name="permlab_brick">"携帯電話を永久に使用できなくする"</string>
+ <string name="permdesc_camera">"カメラでの写真撮影をアプリケーションに許可します。アプリケーションはカメラから画像をいつでも収集できます。"</string>
+ <string name="permlab_brick">"端末を永続的に無効にする"</string>
<string name="permdesc_brick">"携帯電話全体を永続的に無効にすることをアプリケーションに許可します。この許可は非常に危険です。"</string>
- <string name="permlab_reboot">"携帯電話の再起動"</string>
- <string name="permdesc_reboot">"携帯電話の強制的な再起動をアプリケーションに許可します。"</string>
+ <string name="permlab_reboot">"端末の再起動"</string>
+ <string name="permdesc_reboot">"端末の強制的な再起動をアプリケーションに許可します。"</string>
<string name="permlab_mount_unmount_filesystems">"ファイルシステムのマウントとマウント解除"</string>
<string name="permdesc_mount_unmount_filesystems">"リムーバブルメモリのファイルシステムのマウントとマウント解除をアプリケーションに許可します。"</string>
- <string name="permlab_vibrate">"バイブレータの制御"</string>
- <string name="permdesc_vibrate">"バイブレータのコントロールをアプリケーションに許可します。"</string>
+ <string name="permlab_mount_format_filesystems">"外部ストレージのフォーマット"</string>
+ <string name="permdesc_mount_format_filesystems">"アプリケーションがリムーバブルストレージをフォーマットすることを許可します。"</string>
+ <string name="permlab_vibrate">"バイブレーション制御"</string>
+ <string name="permdesc_vibrate">"バイブレーションの制御をアプリケーションに許可します。"</string>
<string name="permlab_flashlight">"ライトのコントロール"</string>
<string name="permdesc_flashlight">"ライトの制御をアプリケーションに許可します。"</string>
<string name="permlab_hardware_test">"ハードウェアのテスト"</string>
<string name="permdesc_hardware_test">"ハードウェアのテストのためにさまざまな周辺機器を制御することをアプリケーションに許可します。"</string>
- <string name="permlab_callPhone">"電話番号に直接発信"</string>
- <string name="permdesc_callPhone">"電話を自動でかけることをアプリケーションに許可します。悪意のあるアプリケーションが予想外の電話をかけて、料金が発生する恐れがあります。緊急電話番号への通話は許可しません。"</string>
- <string name="permlab_callPrivileged">"あらゆる電話番号に直接発信"</string>
- <string name="permdesc_callPrivileged">"緊急電話を含めてあらゆる電話番号に自動発信することをアプリケーションに許可します。悪意のあるアプリケーションが緊急サービスに不要かつ不正な通話をする恐れがあります。"</string>
- <string name="permlab_locationUpdates">"位置の更新通知の制御"</string>
+ <string name="permlab_callPhone">"電話番号発信"</string>
+ <string name="permdesc_callPhone">"アプリケーションが電話を自動発信することを許可します。悪意のあるアプリケーションが意図しない電話をかけて料金が発生する恐れがあります。緊急呼への発信は許可しません。"</string>
+ <string name="permlab_callPrivileged">"電話番号発信"</string>
+ <string name="permdesc_callPrivileged">"緊急呼を含めあらゆる電話番号に自動発信することをアプリケーションに許可します。悪意のあるアプリケーションが緊急サービスに不正な通報をする恐れがあります。"</string>
+ <string name="permlab_locationUpdates">"位置情報の更新通知"</string>
<string name="permdesc_locationUpdates">"無線通信からの位置更新通知を有効/無効にすることを許可します。通常のアプリケーションでは使用しません。"</string>
<string name="permlab_checkinProperties">"チェックインプロパティへのアクセス"</string>
<string name="permdesc_checkinProperties">"チェックインサービスがアップロードしたプロパティへの読み書きを許可します。通常のアプリケーションでは使用しません。"</string>
- <string name="permlab_modifyPhoneState">"携帯電話の状態の変更"</string>
- <string name="permdesc_modifyPhoneState">"携帯端末の電話機能のコントロールをアプリケーションに許可します。この許可を受けたアプリケーションは、ネットワークの切り替え、携帯電話の無線通信のオン/オフなどを通知せずに行うことができます。"</string>
- <string name="permlab_readPhoneState">"携帯電話の状態の読み取り"</string>
- <string name="permdesc_readPhoneState">"携帯端末の電話機能へのアクセスをアプリケーションに許可します。これを許可されたアプリケーションは、この携帯電話の電話番号、通話中かどうか、通話相手の電話番号などを特定できます。"</string>
- <string name="permlab_wakeLock">"携帯電話をスリープ状態にしない"</string>
- <string name="permdesc_wakeLock">"携帯電話をスリープ状態にしないようにすることをアプリケーションに許可します。"</string>
+ <string name="permlab_bindGadget">"ガジェットの選択"</string>
+ <string name="permdesc_bindGadget">"特定のアプリケーションで使用可能なガジェットをシステムに指定することをアプリケーションに許可します。この許可を受けたアプリケーションは、他のアプリケーションに個人データへのアクセスを許可することができます。通常のアプリケーションでは使用しません。"</string>
+ <string name="permlab_modifyPhoneState">"端末ステータスの変更"</string>
+ <string name="permdesc_modifyPhoneState">"端末の電話機能のコントロールをアプリケーションに許可します。アプリケーションは、ネットワークの切り替え、携帯電話の無線通信のオン/オフなどを通知せずに行うことができます。"</string>
+ <string name="permlab_readPhoneState">"端末ステータスの読み取り"</string>
+ <string name="permdesc_readPhoneState">"端末の電話機能へのアクセスをアプリケーションに許可します。アプリケーションは、この携帯電話の電話番号、通話中かどうか、通話相手の電話番号などを特定できます。"</string>
+ <string name="permlab_wakeLock">"端末のスリープを無効にする"</string>
+ <string name="permdesc_wakeLock">"端末のスリープを無効にすることをアプリケーションに許可します。"</string>
<string name="permlab_devicePower">"携帯電話の電源のオン/オフ"</string>
<string name="permdesc_devicePower">"携帯電話の電源のオン/オフをアプリケーションに許可します。"</string>
<string name="permlab_factoryTest">"出荷時試験モードでの実行"</string>
@@ -290,78 +302,76 @@
<string name="permdesc_setWallpaper">"システムの壁紙の設定をアプリケーションに許可します。"</string>
<string name="permlab_setWallpaperHints">"壁紙サイズのヒントの設定"</string>
<string name="permdesc_setWallpaperHints">"システムの壁紙サイズのヒントの設定をアプリケーションに許可します。"</string>
- <string name="permlab_masterClear">"システムを出荷時のデフォルトにリセット"</string>
+ <string name="permlab_masterClear">"システムを出荷時設定にリセット"</string>
<string name="permdesc_masterClear">"データ、設定、インストールしたアプリケーションをすべて消去して、完全に出荷時の設定にシステムをリセットすることをアプリケーションに許可します。"</string>
<string name="permlab_setTimeZone">"タイムゾーンの設定"</string>
- <string name="permdesc_setTimeZone">"携帯電話のタイムゾーンの変更をアプリケーションに許可します。"</string>
+ <string name="permdesc_setTimeZone">"端末のタイムゾーンの変更をアプリケーションに許可します。"</string>
<string name="permlab_getAccounts">"既知のアカウントの取得"</string>
- <string name="permdesc_getAccounts">"携帯端末内にあるアカウントのリストの取得をアプリケーションに許可します。"</string>
+ <string name="permdesc_getAccounts">"端末内にあるアカウントのリストの取得をアプリケーションに許可します。"</string>
<string name="permlab_accessNetworkState">"ネットワーク状態の表示"</string>
<string name="permdesc_accessNetworkState">"すべてのネットワーク状態の表示をアプリケーションに許可します。"</string>
- <string name="permlab_createNetworkSockets">"インターネットへの完全なアクセス権"</string>
+ <string name="permlab_createNetworkSockets">"完全なインターネットアクセス"</string>
<string name="permdesc_createNetworkSockets">"ネットワークソケットの作成をアプリケーションに許可します。"</string>
<string name="permlab_writeApnSettings">"アクセスポイント名設定の書き込み"</string>
<string name="permdesc_writeApnSettings">"APNのプロキシやポートなどのAPN設定の変更をアプリケーションに許可します。"</string>
<string name="permlab_changeNetworkState">"ネットワーク接続の変更"</string>
<string name="permdesc_changeNetworkState">"ネットワークの接続状態の変更をアプリケーションに許可します。"</string>
+ <string name="permlab_changeBackgroundDataSetting">"バックグラウンドデータ使用の設定の変更"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"バックグラウンドデータ使用の設定の変更をアプリケーションに許可します。"</string>
<string name="permlab_accessWifiState">"Wi-Fi状態の表示"</string>
<string name="permdesc_accessWifiState">"Wi-Fi状態に関する情報の表示をアプリケーションに許可します。"</string>
<string name="permlab_changeWifiState">"Wi-Fi状態の変更"</string>
<string name="permdesc_changeWifiState">"Wi-Fiアクセスポイントへの接続や接続の切断、設定されたWi-Fiネットワークの変更をアプリケーションに許可します。"</string>
<string name="permlab_bluetoothAdmin">"Bluetoothの管理"</string>
- <string name="permdesc_bluetoothAdmin">"ローカルのBluetooth電話を設定し、リモートデバイスを検出してペアに設定することをアプリケーションに許可します。"</string>
+ <string name="permdesc_bluetoothAdmin">"このBluetooth端末の設定、およびリモート端末を検出してペアに設定することをアプリケーションに許可します。"</string>
<string name="permlab_bluetooth">"Bluetooth接続の作成"</string>
- <string name="permdesc_bluetooth">"ローカルBluetooth電話の設定を表示し、デバイスをペアとして設定して接続を承認することをアプリケーションに許可します。"</string>
+ <string name="permdesc_bluetooth">"このBluetooth端末の設定表示、および別の端末をペアとして設定し接続を承認することをアプリケーションに許可します。"</string>
<string name="permlab_disableKeyguard">"キーロックを無効にする"</string>
<string name="permdesc_disableKeyguard">"キーロックや関連するパスワードセキュリティを無効にすることをアプリケーションに許可します。正当な利用の例では、かかってきた電話を受信する際にキーロックを無効にし、通話の終了時にキーロックを有効にし直します。"</string>
<string name="permlab_readSyncSettings">"同期設定の読み取り"</string>
- <string name="permdesc_readSyncSettings">"連絡先の同期が有効かどうかなど、同期設定の読み取りをアプリケーションに許可します。"</string>
+ <string name="permdesc_readSyncSettings">"連絡先の同期の有効/無効など、同期設定の読み取りをアプリケーションに許可します。"</string>
<string name="permlab_writeSyncSettings">"同期設定の書き込み"</string>
- <string name="permdesc_writeSyncSettings">"連絡先の同期が有効かどうかなど、同期設定の変更をアプリケーションに許可します。"</string>
+ <string name="permdesc_writeSyncSettings">"連絡先の同期の有効/無効など、同期設定の変更をアプリケーションに許可します。"</string>
<string name="permlab_readSyncStats">"同期統計の読み取り"</string>
- <string name="permdesc_readSyncStats">"同期状態 (同期履歴など) の読み取りをアプリケーションに許可します。"</string>
+ <string name="permdesc_readSyncStats">"同期状態(同期履歴など)の読み取りをアプリケーションに許可します。"</string>
<string name="permlab_subscribedFeedsRead">"登録したフィードの読み取り"</string>
<string name="permdesc_subscribedFeedsRead">"現在同期しているフィードの詳細の取得をアプリケーションに許可します。"</string>
<string name="permlab_subscribedFeedsWrite">"登録したフィードの書き込み"</string>
<string name="permdesc_subscribedFeedsWrite">"現在同期しているフィードの変更をアプリケーションに許可します。悪意のあるアプリケーションが同期フィードを変更する恐れがあります。"</string>
- <!-- no translation found for permlab_readDictionary (432535716804748781) -->
- <skip />
- <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
- <skip />
- <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
- <skip />
- <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
- <skip />
+ <string name="permlab_readDictionary">"ユーザー定義辞書の読み込み"</string>
+ <string name="permdesc_readDictionary">"アプリケーションがユーザー辞書に登録されている個人的な語句や名前を読み込むことを許可します。"</string>
+ <string name="permlab_writeDictionary">"ユーザー定義辞書への書き込み"</string>
+ <string name="permdesc_writeDictionary">"アプリケーションがユーザー辞書に新しい語句を書き込むことを許可します。"</string>
<string-array name="phoneTypes">
<item>"自宅"</item>
<item>"携帯"</item>
- <item>"勤務先"</item>
- <item>"勤務先FAX"</item>
- <item>"自宅FAX"</item>
+ <item>"仕事"</item>
+ <item>"FAX(仕事)"</item>
+ <item>"FAX(自宅)"</item>
<item>"ポケベル"</item>
<item>"その他"</item>
<item>"カスタム"</item>
</string-array>
<string-array name="emailAddressTypes">
<item>"自宅"</item>
- <item>"勤務先"</item>
+ <item>"仕事"</item>
<item>"その他"</item>
<item>"カスタム"</item>
</string-array>
<string-array name="postalAddressTypes">
<item>"自宅"</item>
- <item>"勤務先"</item>
+ <item>"仕事"</item>
<item>"その他"</item>
<item>"カスタム"</item>
</string-array>
<string-array name="imAddressTypes">
<item>"自宅"</item>
- <item>"勤務先"</item>
+ <item>"仕事"</item>
<item>"その他"</item>
<item>"カスタム"</item>
</string-array>
<string-array name="organizationTypes">
- <item>"勤務先"</item>
+ <item>"仕事"</item>
<item>"その他"</item>
<item>"カスタム"</item>
</string-array>
@@ -377,31 +387,32 @@
</string-array>
<string name="keyguard_password_enter_pin_code">"PINコードを入力"</string>
<string name="keyguard_password_wrong_pin_code">"PINコードが正しくありません。"</string>
- <string name="keyguard_label_text">"ロックを解除するには、Menu、0キーの順に押します。"</string>
- <string name="emergency_call_dialog_number_for_display">"緊急電話番号"</string>
- <string name="lockscreen_carrier_default">"(サービスなし)"</string>
- <string name="lockscreen_screen_locked">"画面がロックされています。"</string>
- <string name="lockscreen_instructions_when_pattern_enabled">"Menuキーを押してロックを解除するか、緊急電話をかけます。"</string>
- <string name="lockscreen_instructions_when_pattern_disabled">"ロックを解除するにはMenuキーを押します。"</string>
+ <string name="keyguard_label_text">"ロックを解除するにはMENU、0キーの順に押します。"</string>
+ <string name="emergency_call_dialog_number_for_display">"緊急呼番号"</string>
+ <string name="lockscreen_carrier_default">"(サービス登録なし)"</string>
+ <string name="lockscreen_screen_locked">"画面ロック中"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"MENUキーでロック解除(または緊急呼)"</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"MENUキーでロック解除"</string>
<string name="lockscreen_pattern_instructions">"ロックを解除するパターンを入力"</string>
- <string name="lockscreen_emergency_call">"緊急電話"</string>
+ <string name="lockscreen_emergency_call">"緊急呼"</string>
<string name="lockscreen_pattern_correct">"一致しました"</string>
- <string name="lockscreen_pattern_wrong">"もう一度試してください"</string>
- <string name="lockscreen_plugged_in">"充電中 (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+ <string name="lockscreen_pattern_wrong">"やり直してください"</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
<string name="lockscreen_low_battery">"充電してください。"</string>
- <string name="lockscreen_missing_sim_message_short">"SIMカードがありません。"</string>
- <string name="lockscreen_missing_sim_message">"SIMカードが携帯電話に挿入されていません。"</string>
+ <string name="lockscreen_missing_sim_message_short">"SIMカードが挿入されていません"</string>
+ <string name="lockscreen_missing_sim_message">"SIMカードが挿入されていません"</string>
<string name="lockscreen_missing_sim_instructions">"SIMカードを挿入してください。"</string>
<string name="lockscreen_network_locked_message">"ネットワークがロックされました"</string>
<string name="lockscreen_sim_puk_locked_message">"SIMカードはPUKでロックされています。"</string>
<string name="lockscreen_sim_puk_locked_instructions">"お客様サポートにお問い合わせください。"</string>
<string name="lockscreen_sim_locked_message">"SIMカードはロックされています。"</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message">"SIMカードのロックを解除中..."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIMカードのロック解除中..."</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message">"ロック解除のパターンは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しく指定されていません。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度指定してください。"</string>
<string name="lockscreen_failed_attempts_almost_glogin">"指定したパターンは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しくありません。あと<xliff:g id="NUMBER_1">%d</xliff:g>回指定に失敗すると、携帯電話のロックの解除にGoogleへのログインが必要になります。"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度指定してください。"</string>
- <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g>秒後にもう一度試してください。"</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g>秒後にやり直してください。"</string>
<string name="lockscreen_forgot_pattern_button_text">"パターンを忘れた場合"</string>
- <string name="lockscreen_glogin_too_many_attempts">"パターンの指定回数が多すぎる"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"パターンのエラーが多すぎます"</string>
<string name="lockscreen_glogin_instructions">"ロックを解除するには、"\n"Googleアカウントでログインしてください。"</string>
<string name="lockscreen_glogin_username_hint">"ユーザー名 (メール)"</string>
<string name="lockscreen_glogin_password_hint">"パスワード"</string>
@@ -410,39 +421,36 @@
<string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
<string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <!-- no translation found for hour_ampm (7618670480400517084) -->
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
<skip />
- <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
<skip />
<string name="status_bar_clear_all_button">"通知を消去"</string>
<string name="status_bar_no_notifications_title">"通知なし"</string>
<string name="status_bar_ongoing_events_title">"継続中"</string>
<string name="status_bar_latest_events_title">"通知"</string>
- <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
<skip />
<string name="battery_status_charging">"充電中..."</string>
<string name="battery_low_title">"充電してください"</string>
- <string name="battery_low_subtitle">"バッテリの残量が少なくなっています。"</string>
+ <string name="battery_low_subtitle">"電池が残り少なくなっています:"</string>
<string name="battery_low_percent_format">"残り<xliff:g id="NUMBER">%d%%</xliff:g>未満"</string>
<string name="factorytest_failed">"出荷時試験が失敗"</string>
<string name="factorytest_not_system">"FACTORY_TEST操作は、/system/appにインストールされたパッケージのみが対象です。"</string>
<string name="factorytest_no_action">"FACTORY_TEST操作を行うパッケージは見つかりませんでした。"</string>
<string name="factorytest_reboot">"再起動"</string>
- <!-- no translation found for js_dialog_title (8143918455087008109) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
- <skip />
+ <string name="js_dialog_title">"ページ「<xliff:g id="TITLE">%s</xliff:g>」の記述:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"このページから移動しますか?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"続行する場合は[OK]、今のページに残る場合は[キャンセル]を選択してください。"</string>
<string name="save_password_label">"確認"</string>
<string name="save_password_message">"このパスワードをブラウザで保存しますか?"</string>
<string name="save_password_notnow">"今は保存しない"</string>
<string name="save_password_remember">"保存"</string>
<string name="save_password_never">"保存しない"</string>
<string name="open_permission_deny">"このページへのアクセスは許可されていません。"</string>
- <string name="text_copied">"テキストがクリップボードにコピーされました。"</string>
+ <string name="text_copied">"テキストをクリップボードにコピーしました。"</string>
<string name="more_item_label">"その他"</string>
- <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="prepend_shortcut_label">"MENU+"</string>
<string name="menu_space_shortcut_label">"Space"</string>
<string name="menu_enter_shortcut_label">"Enter"</string>
<string name="menu_delete_shortcut_label">"Del"</string>
@@ -484,22 +492,38 @@
<item quantity="one">"明日"</item>
<item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
</plurals>
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"1秒前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒前"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"1分前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"1時間前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間前"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"昨日"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>日前"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"1秒後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>秒後"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"1分後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>分後"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"1時間後"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>時間後"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"明日"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>日後"</item>
+ </plurals>
<string name="preposition_for_date">"%s"</string>
<string name="preposition_for_time">"%s"</string>
<string name="preposition_for_year">"%s年"</string>
@@ -515,14 +539,14 @@
<string name="weeks">"週間"</string>
<string name="year">"年"</string>
<string name="years">"年"</string>
- <string name="sunday">"日曜"</string>
- <string name="monday">"月曜"</string>
- <string name="tuesday">"火曜"</string>
- <string name="wednesday">"水曜"</string>
- <string name="thursday">"木曜"</string>
- <string name="friday">"金曜"</string>
- <string name="saturday">"土曜"</string>
- <string name="every_weekday">"平日の毎日 (月~金)"</string>
+ <string name="sunday">"日曜日"</string>
+ <string name="monday">"月曜日"</string>
+ <string name="tuesday">"火曜日"</string>
+ <string name="wednesday">"水曜日"</string>
+ <string name="thursday">"木曜日"</string>
+ <string name="friday">"金曜日"</string>
+ <string name="saturday">"土曜日"</string>
+ <string name="every_weekday">"平日(月~金)"</string>
<string name="daily">"毎日"</string>
<string name="weekly">"毎週<xliff:g id="DAY">%s</xliff:g>"</string>
<string name="monthly">"毎月"</string>
@@ -533,97 +557,95 @@
<string name="am">"AM"</string>
<string name="pm">"PM"</string>
<string name="numeric_date">"<xliff:g id="YEAR">%Y</xliff:g>/<xliff:g id="MONTH">%m</xliff:g>/<xliff:g id="DAY">%d</xliff:g>"</string>
- <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%3$s</xliff:g>~<xliff:g id="DATE2">%5$s</xliff:g> (<xliff:g id="WEEKDAY2">%4$s</xliff:g>) <xliff:g id="TIME2">%6$s</xliff:g>"</string>
- <string name="wday1_date1_wday2_date2">"<xliff:g id="DATE1">%2$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="DATE2">%5$s</xliff:g> (<xliff:g id="WEEKDAY2">%4$s</xliff:g>)"</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g><xliff:g id="TIME1">%3$s</xliff:g>~<xliff:g id="DATE2">%5$s</xliff:g><xliff:g id="WEEKDAY2">%4$s</xliff:g><xliff:g id="TIME2">%6$s</xliff:g>"</string>
+ <string name="wday1_date1_wday2_date2">"<xliff:g id="DATE1">%2$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g>~<xliff:g id="DATE2">%5$s</xliff:g><xliff:g id="WEEKDAY2">%4$s</xliff:g>"</string>
<string name="date1_time1_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g> <xliff:g id="TIME1">%3$s</xliff:g>~<xliff:g id="DATE2">%5$s</xliff:g> <xliff:g id="TIME2">%6$s</xliff:g>"</string>
<string name="date1_date2">"<xliff:g id="DATE1">%2$s</xliff:g>~<xliff:g id="DATE2">%5$s</xliff:g>"</string>
<string name="time1_time2">"<xliff:g id="TIME1">%1$s</xliff:g>~<xliff:g id="TIME2">%2$s</xliff:g>"</string>
- <string name="time_wday_date">"<xliff:g id="DATE">%3$s</xliff:g> (<xliff:g id="WEEKDAY">%2$s</xliff:g>) <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
- <string name="wday_date">"<xliff:g id="DATE">%3$s</xliff:g> (<xliff:g id="WEEKDAY">%2$s</xliff:g>)"</string>
+ <string name="time_wday_date">"<xliff:g id="DATE">%3$s</xliff:g><xliff:g id="WEEKDAY">%2$s</xliff:g><xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="wday_date">"<xliff:g id="DATE">%3$s</xliff:g><xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
<string name="time_date">"<xliff:g id="DATE">%3$s</xliff:g>、<xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
- <!-- no translation found for date_time (6104442718633642836) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>、<xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>、<xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="time_wday">"<xliff:g id="WEEKDAY">%2$s</xliff:g>、<xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
- <string name="full_date_month_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMMM</xliff:g><xliff:g id="DAY">dd</xliff:g>\'日\'"</string>
- <string name="full_date_day_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMMM</xliff:g><xliff:g id="DAY">dd</xliff:g>\'日\'"</string>
- <string name="medium_date_month_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMM</xliff:g><xliff:g id="DAY">dd</xliff:g>\'日\'"</string>
- <string name="medium_date_day_first">"<xliff:g id="YEAR">yyyy</xliff:g>\'年\'<xliff:g id="MONTH">MMM</xliff:g><xliff:g id="DAY">dd</xliff:g>\'日\'"</string>
- <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
- <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="YEAR">yyyy</xliff:g>'/'<xliff:g id="MONTH">MMMM</xliff:g>'/'<xliff:g id="DAY">d</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="YEAR">yyyy</xliff:g>'年'<xliff:g id="MONTH">MMMM</xliff:g>'月'<xliff:g id="DAY">d</xliff:g>'日'"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="MONTH">MMM</xliff:g>'/'<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>'年'"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>'/'<xliff:g id="MONTH">MMM</xliff:g>'/'<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
<string name="noon">"正午"</string>
<string name="Noon">"正午"</string>
<string name="midnight">"午前0時"</string>
<string name="Midnight">"午前0時"</string>
- <!-- no translation found for month_day (5565829181417740906) -->
+ <!-- no translation found for month_day (3693060561170538204) -->
<skip />
- <!-- no translation found for month (7026169712234774086) -->
+ <!-- no translation found for month (1976700695144952053) -->
<skip />
<string name="month_day_year">"<xliff:g id="YEAR">%Y</xliff:g>年<xliff:g id="MONTH">%B</xliff:g><xliff:g id="DAY">%-d</xliff:g>日"</string>
- <!-- no translation found for month_year (9219019380312413367) -->
+ <!-- no translation found for month_year (2106203387378728384) -->
<skip />
<string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
- <string name="date_and_time">"<xliff:g id="YEAR">%Y</xliff:g>年<xliff:g id="MONTH">%B</xliff:g><xliff:g id="DAY">%-d</xliff:g>日<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
- <string name="same_year_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日"</string>
- <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
- <string name="same_year_mdy1_mdy2">"<xliff:g id="YEAR">%9$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日"</string>
- <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR">%9$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
- <string name="same_year_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日<xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日<xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日<xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日<xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="date_and_time">"<xliff:g id="YEAR">%Y</xliff:g>/<xliff:g id="MONTH">%B</xliff:g>/<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
+ <string name="same_year_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>月<xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="MONTH2">%7$s</xliff:g>月<xliff:g id="DAY2">%8$s</xliff:g>日"</string>
+ <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
+ <string name="same_year_mdy1_mdy2">"<xliff:g id="YEAR">%9$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g>月<xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="MONTH2">%7$s</xliff:g>月<xliff:g id="DAY2">%8$s</xliff:g>日"</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR">%9$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
+ <string name="same_year_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>月<xliff:g id="DAY1">%3$s</xliff:g>日<xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>月<xliff:g id="DAY2">%8$s</xliff:g>日<xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g><xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g><xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g>月<xliff:g id="DAY1">%3$s</xliff:g>日 <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH2">%7$s</xliff:g>月<xliff:g id="DAY2">%8$s</xliff:g>日 <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g><xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g><xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="numeric_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>"</string>
- <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g> (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
+ <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
<string name="numeric_mdy1_mdy2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>"</string>
- <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g> (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
<string name="numeric_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g> (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g><xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g><xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g> (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g> (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_month_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="DAY2">%8$s</xliff:g>日"</string>
- <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
- <string name="same_month_mdy1_mdy2">"<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="DAY2">%8$s</xliff:g>日"</string>
- <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR1">%4$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>)~<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>)"</string>
- <string name="same_month_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日<xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日<xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1">%3$s</xliff:g>日<xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2">%8$s</xliff:g>日<xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g><xliff:g id="DAY1_0">%3$s</xliff:g>日 (<xliff:g id="WEEKDAY1">%1$s</xliff:g>) <xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH2">%7$s</xliff:g><xliff:g id="DAY2_1">%8$s</xliff:g>日 (<xliff:g id="WEEKDAY2">%6$s</xliff:g>) <xliff:g id="TIME2">%10$s</xliff:g>"</string>
- <string name="abbrev_month_day_year">"<xliff:g id="YEAR">%Y</xliff:g>年<xliff:g id="MONTH">%b</xliff:g><xliff:g id="DAY">%-d</xliff:g>日"</string>
- <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g><xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g><xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>月<xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="DAY2">%8$s</xliff:g>日"</string>
+ <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
+ <string name="same_month_mdy1_mdy2">"<xliff:g id="YEAR2">%9$s</xliff:g>年<xliff:g id="MONTH1">%2$s</xliff:g>月<xliff:g id="DAY1">%3$s</xliff:g>日~<xliff:g id="DAY2">%8$s</xliff:g>日"</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
+ <string name="same_month_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g><xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g><xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g><xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g><xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g><xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g><xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g><xliff:g id="WEEKDAY1">%1$s</xliff:g><xliff:g id="TIME1">%5$s</xliff:g>~<xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g><xliff:g id="WEEKDAY2">%6$s</xliff:g><xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="abbrev_month_day_year">"<xliff:g id="YEAR">%Y</xliff:g>/<xliff:g id="MONTH">%b</xliff:g>/<xliff:g id="DAY">%-d</xliff:g>"</string>
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
<skip />
- <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
<skip />
- <!-- no translation found for abbrev_month (3131032032850777433) -->
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
<skip />
- <string name="day_of_week_long_sunday">"日曜"</string>
- <string name="day_of_week_long_monday">"月曜"</string>
- <string name="day_of_week_long_tuesday">"火曜"</string>
- <string name="day_of_week_long_wednesday">"水曜"</string>
- <string name="day_of_week_long_thursday">"木曜"</string>
- <string name="day_of_week_long_friday">"金曜"</string>
- <string name="day_of_week_long_saturday">"土曜"</string>
- <string name="day_of_week_medium_sunday">"日"</string>
- <string name="day_of_week_medium_monday">"月"</string>
- <string name="day_of_week_medium_tuesday">"火"</string>
- <string name="day_of_week_medium_wednesday">"水"</string>
- <string name="day_of_week_medium_thursday">"木"</string>
- <string name="day_of_week_medium_friday">"金"</string>
- <string name="day_of_week_medium_saturday">"土"</string>
- <string name="day_of_week_short_sunday">"日"</string>
- <string name="day_of_week_short_monday">"月"</string>
- <string name="day_of_week_short_tuesday">"火"</string>
- <string name="day_of_week_short_wednesday">"水"</string>
- <string name="day_of_week_short_thursday">"木"</string>
- <string name="day_of_week_short_friday">"金"</string>
- <string name="day_of_week_short_saturday">"土"</string>
- <string name="day_of_week_shorter_sunday">"日"</string>
+ <string name="day_of_week_long_sunday">"日曜日"</string>
+ <string name="day_of_week_long_monday">"月曜日"</string>
+ <string name="day_of_week_long_tuesday">"火曜日"</string>
+ <string name="day_of_week_long_wednesday">"水曜日"</string>
+ <string name="day_of_week_long_thursday">"木曜日"</string>
+ <string name="day_of_week_long_friday">"金曜日"</string>
+ <string name="day_of_week_long_saturday">"土曜日"</string>
+ <string name="day_of_week_medium_sunday">"(日)"</string>
+ <string name="day_of_week_medium_monday">"(月)"</string>
+ <string name="day_of_week_medium_tuesday">"(火)"</string>
+ <string name="day_of_week_medium_wednesday">"(水)"</string>
+ <string name="day_of_week_medium_thursday">"(木)"</string>
+ <string name="day_of_week_medium_friday">"(金)"</string>
+ <string name="day_of_week_medium_saturday">"(土)"</string>
+ <string name="day_of_week_short_sunday">"(日)"</string>
+ <string name="day_of_week_short_monday">"(月)"</string>
+ <string name="day_of_week_short_tuesday">"(火)"</string>
+ <string name="day_of_week_short_wednesday">"(水)"</string>
+ <string name="day_of_week_short_thursday">"(木)"</string>
+ <string name="day_of_week_short_friday">"(金)"</string>
+ <string name="day_of_week_short_saturday">"(土)"</string>
+ <string name="day_of_week_shorter_sunday">"(日)"</string>
<string name="day_of_week_shorter_monday">"月"</string>
- <string name="day_of_week_shorter_tuesday">"火"</string>
+ <string name="day_of_week_shorter_tuesday">"(火)"</string>
<string name="day_of_week_shorter_wednesday">"水"</string>
- <string name="day_of_week_shorter_thursday">"木"</string>
+ <string name="day_of_week_shorter_thursday">"(木)"</string>
<string name="day_of_week_shorter_friday">"金"</string>
- <string name="day_of_week_shorter_saturday">"土"</string>
+ <string name="day_of_week_shorter_saturday">"(土)"</string>
<string name="day_of_week_shortest_sunday">"日"</string>
<string name="day_of_week_shortest_monday">"月"</string>
<string name="day_of_week_shortest_tuesday">"火"</string>
@@ -657,7 +679,7 @@
<string name="month_medium_december">"12月"</string>
<string name="month_shortest_january">"1"</string>
<string name="month_shortest_february">"2"</string>
- <string name="month_shortest_march">"月"</string>
+ <string name="month_shortest_march">"3"</string>
<string name="month_shortest_april">"4"</string>
<string name="month_shortest_may">"5"</string>
<string name="month_shortest_june">"6"</string>
@@ -679,6 +701,7 @@
<string name="paste">"貼り付け"</string>
<string name="copyUrl">"URLをコピー"</string>
<string name="inputMethod">"入力方法"</string>
+ <string name="addToDictionary">"辞書に「%s」を追加"</string>
<string name="editTextMenuTitle">"テキストを編集"</string>
<string name="low_internal_storage_view_title">"空き容量低下"</string>
<string name="low_internal_storage_view_text">"携帯電話の空き容量が少なくなっています。"</string>
@@ -686,41 +709,42 @@
<string name="cancel">"キャンセル"</string>
<string name="yes">"OK"</string>
<string name="no">"キャンセル"</string>
+ <string name="dialog_alert_title">"注意"</string>
<string name="capital_on">"オン"</string>
<string name="capital_off">"オフ"</string>
<string name="whichApplication">"操作の完了に使用"</string>
- <string name="alwaysUse">"この操作にデフォルトで使用します。"</string>
- <string name="clearDefaultHintMsg">"ホームの[設定]&gt;[アプリケーション]&gt;[アプリケーションを管理]で、デフォルトをクリアします。"</string>
+ <string name="alwaysUse">"常にこの操作で使用する"</string>
+ <string name="clearDefaultHintMsg">"ホームの[設定]&gt;[アプリケーション]&gt;[アプリケーションの管理]でデフォルト設定をクリアします。"</string>
<string name="chooseActivity">"操作の選択"</string>
<string name="noApplications">"この操作を実行できるアプリケーションはありません。"</string>
<string name="aerr_title">"エラー"</string>
- <string name="aerr_application">"アプリケーション<xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>プロセス) が予期せず停止しました。もう一度試してください。"</string>
- <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>プロセスが予期せず停止しました。もう一度試してください。"</string>
+ <string name="aerr_application">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)が予期せず停止しました。やり直してください。"</string>
+ <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>が予期せず停止しました。やり直してください。"</string>
<string name="anr_title">"エラー"</string>
- <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g>操作 (アプリケーション<xliff:g id="APPLICATION">%2$s</xliff:g>) は応答していません。"</string>
- <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g>操作 (プロセス:<xliff:g id="PROCESS">%2$s</xliff:g>) は応答していません。"</string>
- <string name="anr_application_process">"アプリケーション<xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g>プロセス) は応答していません。"</string>
- <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>プロセスは応答していません。"</string>
+ <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g>(<xliff:g id="APPLICATION">%2$s</xliff:g>)は応答していません。"</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g>(プロセス: <xliff:g id="PROCESS">%2$s</xliff:g>)は応答していません。"</string>
+ <string name="anr_application_process">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)は応答していません。"</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g>は応答していません。"</string>
<string name="force_close">"強制終了"</string>
<string name="wait">"待機"</string>
<string name="debug">"デバッグ"</string>
- <string name="sendText">"テキストの操作の選択"</string>
+ <string name="sendText">"テキストの操作"</string>
<string name="volume_ringtone">"着信音の音量"</string>
<string name="volume_music">"メディアの音量"</string>
<string name="volume_music_hint_playing_through_bluetooth">"Bluetooth経由で再生中です"</string>
<string name="volume_call">"着信音の音量"</string>
- <string name="volume_call_hint_playing_through_bluetooth">"Bluetooth経由で再生中です"</string>
+ <string name="volume_bluetooth_call">"Bluetooth着信音の音量"</string>
<string name="volume_alarm">"アラームの音量"</string>
<string name="volume_notification">"通知音の音量"</string>
<string name="volume_unknown">"音量"</string>
<string name="ringtone_default">"デフォルトの着信音"</string>
- <string name="ringtone_default_with_actual">"デフォルトの着信音 (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_default_with_actual">"端末既定の着信音(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent">"無音"</string>
<string name="ringtone_picker_title">"着信音"</string>
- <string name="ringtone_unknown">"不明時着信音"</string>
+ <string name="ringtone_unknown">"不明な着信音"</string>
<plurals name="wifi_available">
- <item quantity="one">"Wi-Fiネットワークが利用可能"</item>
- <item quantity="other">"Wi-Fiネットワークが利用可能"</item>
+ <item quantity="one">"Wi-Fiを利用できます"</item>
+ <item quantity="other">"Wi-Fiを利用できます"</item>
</plurals>
<plurals name="wifi_available_detailed">
<item quantity="one">"Wi-Fiオープンネットワークが利用できます"</item>
@@ -729,12 +753,12 @@
<string name="select_character">"文字を挿入"</string>
<string name="sms_control_default_app_name">"不明なアプリケーション"</string>
<string name="sms_control_title">"SMSメッセージの送信中"</string>
- <string name="sms_control_message">"大量のSMSメッセージが送信されます。送信するには[OK]、中止するには[キャンセル]を選択します。"</string>
+ <string name="sms_control_message">"大量のSMSメッセージを送信しようとしています。[OK]で送信、[キャンセル]で中止します。"</string>
<string name="sms_control_yes">"OK"</string>
<string name="sms_control_no">"キャンセル"</string>
<string name="date_time_set">"設定"</string>
- <string name="default_permission_group">"デフォルト"</string>
- <string name="no_permissions">"許可は必要ありません"</string>
+ <string name="default_permission_group">"端末既定"</string>
+ <string name="no_permissions">"権限付与の必要はありません"</string>
<string name="perms_hide"><b>"隠す"</b></string>
<string name="perms_show_all"><b>"すべて表示"</b></string>
<string name="googlewebcontenthelper_loading">"読み込み中..."</string>
@@ -745,8 +769,47 @@
<string name="usb_storage_error_message">"USBメモリにSDカードを使用する際に問題が発生しました。"</string>
<string name="usb_storage_notification_title">"USB接続"</string>
<string name="usb_storage_notification_message">"パソコンとの間でファイルをコピーします。"</string>
+ <string name="usb_storage_stop_notification_title">"USBストレージをOFFにする"</string>
+ <string name="usb_storage_stop_notification_message">"USBストレージをOFFにする場合に選択します。"</string>
+ <string name="usb_storage_stop_title">"USBストレージをOFFにする"</string>
+ <string name="usb_storage_stop_message">"USBストレージをOFFにする前にUSBホストのマウントを解除したことを確認してください。USBストレージをOFFにするには[OFF]を選択します。"</string>
+ <string name="usb_storage_stop_button_mount">"OFF"</string>
+ <string name="usb_storage_stop_button_unmount">"キャンセル"</string>
+ <string name="usb_storage_stop_error_message">"USBストレージをOFFにする際に問題が発生しました。USBホストのマウントが解除されていることを確認してからもう一度お試しください。"</string>
+ <string name="extmedia_format_title">"SDカードをフォーマット"</string>
+ <string name="extmedia_format_message">"SDカードをフォーマットしてもよろしいですか?カード内のすべてのデータが失われます。"</string>
+ <string name="extmedia_format_button_format">"フォーマット"</string>
<string name="select_input_method">"入力方法の選択"</string>
- <string name="fast_scroll_alphabet">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style"><font fgcolor="#ff000000" bgcolor="#ff8080ff"><u>"候補"</u></font></string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"候補"</u></string>
+ <string name="ext_media_checking_notification_title">"SDカードの準備中"</string>
+ <string name="ext_media_checking_notification_message">"エラーを確認中"</string>
+ <string name="ext_media_nofs_notification_title">"空のSDカード"</string>
+ <string name="ext_media_nofs_notification_message">"SDカードが空か、サポート対象外のファイルシステムを使用しています。"</string>
+ <string name="ext_media_unmountable_notification_title">"破損したSDカード"</string>
+ <string name="ext_media_unmountable_notification_message">"SDカードが破損しています。カードのフォーマットが必要な可能性があります。"</string>
+ <string name="ext_media_badremoval_notification_title">"SDカードが予期せず取り外されました"</string>
+ <string name="ext_media_badremoval_notification_message">"データの喪失を防ぐためSDカードを取り外す前にマウントを解除してください。"</string>
+ <string name="ext_media_safe_unmount_notification_title">"SDカードを安全に取り外しました"</string>
+ <string name="ext_media_safe_unmount_notification_message">"SDカードを安全に取り外せます。"</string>
+ <string name="ext_media_nomedia_notification_title">"SDカードが取り外されています"</string>
+ <string name="ext_media_nomedia_notification_message">"SDカードが取り外されました。新しいSDカードを挿入して端末のメモリを増やしてください。"</string>
+ <string name="activity_list_empty">"一致するアクティビティが見つかりません"</string>
+ <string name="permlab_pkgUsageStats">"コンポーネント使用状況に関する統計情報の更新"</string>
+ <string name="permdesc_pkgUsageStats">"収集されたコンポーネント使用状況に関する統計情報の変更を許可します。通常のアプリケーションでは使用しません。"</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
new file mode 100644
index 0000000..8fc7d12
--- /dev/null
+++ b/core/res/res/values-ko/strings.xml
@@ -0,0 +1,815 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"KB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="untitled">"&lt;제목없음&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(전화번호 없음)"</string>
+ <string name="unknownName">"(알 수 없음)"</string>
+ <string name="defaultVoiceMailAlphaTag">"음성메일"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"연결에 문제가 있거나 MMI 코드가 잘못되었습니다."</string>
+ <string name="serviceEnabled">"서비스가 활성화되었습니다."</string>
+ <string name="serviceEnabledFor">"사용 설정된 서비스 목록:"</string>
+ <string name="serviceDisabled">"서비스가 비활성화되었습니다."</string>
+ <string name="serviceRegistered">"등록이 완료되었습니다."</string>
+ <string name="serviceErased">"지웠습니다."</string>
+ <string name="passwordIncorrect">"비밀번호가 잘못되었습니다."</string>
+ <string name="mmiComplete">"MMI 완료"</string>
+ <string name="badPin">"이전 PIN이 올바르지 않습니다."</string>
+ <string name="badPuk">"입력한 PUK가 올바르지 않습니다."</string>
+ <string name="mismatchPin">"입력한 PIN이 일치하지 않습니다."</string>
+ <string name="invalidPin">"4~8자리 숫자로 된 PIN을 입력하세요."</string>
+ <string name="needPuk">"SIM 카드의 PUK가 잠겨 있습니다. 잠금해제하려면 PUK 코드를 입력하세요."</string>
+ <string name="needPuk2">"SIM 카드 잠금을 해제하려면 PUK2를 입력하세요."</string>
+ <string name="ClipMmi">"수신 발신자 번호"</string>
+ <string name="ClirMmi">"발신 발신자 번호"</string>
+ <string name="CfMmi">"착신전환"</string>
+ <string name="CwMmi">"통화중 대기"</string>
+ <string name="BaMmi">"착발신 제한"</string>
+ <string name="PwdMmi">"비밀번호 변경"</string>
+ <string name="PinMmi">"PIN 변경"</string>
+ <string name="CLIRDefaultOnNextCallOn">"발신자 번호가 기본적으로 제한됨으로 설정됩니다. 다음 통화: 제한됨"</string>
+ <string name="CLIRDefaultOnNextCallOff">"발신자 번호가 기본적으로 제한됨으로 설정됩니다. 다음 통화: 제한되지 않음"</string>
+ <string name="CLIRDefaultOffNextCallOn">"발신자 번호가 기본적으로 제한되지 않음으로 설정됩니다. 다음 통화: 제한됨"</string>
+ <string name="CLIRDefaultOffNextCallOff">"발신자 번호가 기본적으로 제한되지 않음으로 설정됩니다. 다음 통화: 제한되지 않음"</string>
+ <string name="serviceNotProvisioned">"서비스가 준비되지 않았습니다."</string>
+ <string name="CLIRPermanent">"발신자 번호 설정을 변경할 수 없습니다."</string>
+ <string name="serviceClassVoice">"음성"</string>
+ <string name="serviceClassData">"데이터"</string>
+ <string name="serviceClassFAX">"팩스"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"비동기"</string>
+ <string name="serviceClassDataSync">"동기화"</string>
+ <string name="serviceClassPacket">"패킷"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안 됨"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g>초 후 <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안 됨"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안 됨"</string>
+ <string name="httpErrorOk">"확인"</string>
+ <string name="httpError">"웹페이지에 오류가 있습니다."</string>
+ <string name="httpErrorLookup">"URL을 찾을 수 없습니다."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"사이트 인증 스키마가 지원되지 않습니다."</string>
+ <string name="httpErrorAuth">"인증에 실패했습니다."</string>
+ <string name="httpErrorProxyAuth">"프록시 서버를 통한 인증에 실패했습니다."</string>
+ <string name="httpErrorConnect">"서버에 연결하지 못했습니다."</string>
+ <string name="httpErrorIO">"서버와 통신할 수 없습니다. 나중에 다시 시도하세요."</string>
+ <string name="httpErrorTimeout">"서버 연결 제한시간이 초과되었습니다."</string>
+ <string name="httpErrorRedirectLoop">"페이지에 서버 리디렉션이 너무 많이 포함되어 있습니다."</string>
+ <string name="httpErrorUnsupportedScheme">"지원되지 않는 프로토콜입니다."</string>
+ <string name="httpErrorFailedSslHandshake">"보안 연결을 설정하지 못했습니다."</string>
+ <string name="httpErrorBadUrl">"URL이 올바르지 않아 페이지를 열 수 없습니다."</string>
+ <string name="httpErrorFile">"파일에 액세스할 수 없습니다."</string>
+ <string name="httpErrorFileNotFound">"요청한 파일을 찾을 수 없습니다."</string>
+ <string name="httpErrorTooManyRequests">"처리 중인 요청이 너무 많습니다. 잠시 후에 다시 시도하세요."</string>
+ <string name="contentServiceSync">"동기화"</string>
+ <string name="contentServiceSyncNotificationTitle">"동기화"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> 삭제가 너무 많습니다."</string>
+ <string name="low_memory">"전화기 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장 여유 공간을 늘리세요."</string>
+ <string name="me">"나"</string>
+ <string name="power_dialog">"전화기 옵션"</string>
+ <string name="silent_mode">"무음 모드"</string>
+ <string name="turn_on_radio">"무선 켜기"</string>
+ <string name="turn_off_radio">"무선 끄기"</string>
+ <string name="screen_lock">"화면 잠금"</string>
+ <string name="power_off">"끄기"</string>
+ <string name="shutdown_progress">"종료 중..."</string>
+ <string name="shutdown_confirm">"전화기가 종료됩니다."</string>
+ <string name="no_recent_tasks">"최신 응용프로그램이 아닙니다."</string>
+ <string name="global_actions">"전화기 옵션"</string>
+ <string name="global_action_lock">"화면 잠금"</string>
+ <string name="global_action_power_off">"끄기"</string>
+ <string name="global_action_toggle_silent_mode">"무음 모드"</string>
+ <string name="global_action_silent_mode_on_status">"소리 꺼짐"</string>
+ <string name="global_action_silent_mode_off_status">"소리 켜짐"</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
+ <string name="safeMode">"안전 모드"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
+ <string name="permgrouplab_costMoney">"요금이 부과되는 서비스"</string>
+ <string name="permgroupdesc_costMoney">"응용프로그램이 요금이 부과될 수 있는 작업을 할 수 있습니다."</string>
+ <string name="permgrouplab_messages">"메시지"</string>
+ <string name="permgroupdesc_messages">"SMS, 이메일 및 기타 메시지를 읽고 씁니다."</string>
+ <string name="permgrouplab_personalInfo">"개인 정보"</string>
+ <string name="permgroupdesc_personalInfo">"전화기에 저장된 연락처 및 캘린더에 직접 액세스합니다."</string>
+ <string name="permgrouplab_location">"위치"</string>
+ <string name="permgroupdesc_location">"물리적 위치 모니터링"</string>
+ <string name="permgrouplab_network">"네트워크 통신"</string>
+ <string name="permgroupdesc_network">"응용프로그램이 다양한 네트워크 기능에 액세스할 수 있습니다."</string>
+ <string name="permgrouplab_accounts">"Google 계정"</string>
+ <string name="permgroupdesc_accounts">"사용가능한 Google 계정에 액세스합니다."</string>
+ <string name="permgrouplab_hardwareControls">"하드웨어 제어"</string>
+ <string name="permgroupdesc_hardwareControls">"핸드셋의 하드웨어에 직접 액세스합니다."</string>
+ <string name="permgrouplab_phoneCalls">"전화 통화"</string>
+ <string name="permgroupdesc_phoneCalls">"전화 통화를 모니터링, 기록 및 처리합니다."</string>
+ <string name="permgrouplab_systemTools">"시스템 도구"</string>
+ <string name="permgroupdesc_systemTools">"하위 수준의 액세스 및 시스템 제어"</string>
+ <string name="permgrouplab_developmentTools">"개발도구"</string>
+ <string name="permgroupdesc_developmentTools">"응용프로그램 개발자에게만 필요한 기능입니다."</string>
+ <string name="permlab_statusBar">"상태 표시줄 사용 안 함 또는 수정"</string>
+ <string name="permdesc_statusBar">"응용프로그램이 상태 표시줄을 비활성화하거나 시스템 아이콘을 추가 및 제거할 수 있습니다."</string>
+ <string name="permlab_expandStatusBar">"상태 표시줄 확장/축소"</string>
+ <string name="permdesc_expandStatusBar">"응용프로그램이 상태 표시줄을 확장하거나 축소할 수 있습니다."</string>
+ <string name="permlab_processOutgoingCalls">"발신전화 가로채기"</string>
+ <string name="permdesc_processOutgoingCalls">"응용프로그램이 발신전화를 처리하고 전화를 걸 번호를 변경할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 발신전화를 모니터링하거나, 다른 방향으로 돌리거나, 중단시킬 수 있습니다."</string>
+ <string name="permlab_receiveSms">"SMS 받기"</string>
+ <string name="permdesc_receiveSms">"응용프로그램이 SMS 메시지를 받고 처리할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
+ <string name="permlab_receiveMms">"MMS 받기"</string>
+ <string name="permdesc_receiveMms">"응용프로그램이 MMS 메시지를 받고 처리할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
+ <string name="permlab_sendSms">"SMS 메시지 보내기"</string>
+ <string name="permdesc_sendSms">"응용프로그램이 SMS 메시지를 보낼 수 있습니다. 악성 응용프로그램은 사용자의 확인 없이 메시지를 전송하여 요금을 부과할 수 있습니다."</string>
+ <string name="permlab_readSms">"SMS 또는 MMS 읽기"</string>
+ <string name="permdesc_readSms">"응용프로그램이 전화기 또는 SIM 카드에 저장된 SMS 메시지를 읽을 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 기밀 메시지를 읽을 수 있습니다."</string>
+ <string name="permlab_writeSms">"SMS 또는 MMS 편집"</string>
+ <string name="permdesc_writeSms">"응용프로그램이 전화기 또는 SIM 카드에 저장된 SMS 메시지에 쓸 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 메시지를 삭제할 수 있습니다."</string>
+ <string name="permlab_receiveWapPush">"WAP 받기"</string>
+ <string name="permdesc_receiveWapPush">"응용프로그램이 WAP 메시지를 받고 처리할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
+ <string name="permlab_getTasks">"실행 중인 응용프로그램 검색"</string>
+ <string name="permdesc_getTasks">"응용프로그램이 현재 실행 중이거나 최근에 실행된 작업에 대한 정보를 검색할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 다른 응용프로그램에 대한 개인 정보를 검색할 수 있습니다."</string>
+ <string name="permlab_reorderTasks">"실행 중인 응용프로그램 순서 재지정"</string>
+ <string name="permdesc_reorderTasks">"응용프로그램이 작업을 포그라운드나 백그라운드로 이동할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 사용자의 조작 없이 작업을 강제로 앞으로 이동할 수 있습니다."</string>
+ <string name="permlab_setDebugApp">"응용프로그램 디버깅 사용"</string>
+ <string name="permdesc_setDebugApp">"응용프로그램이 다른 응용프로그램에 대한 디버깅을 설정할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 다른 응용프로그램을 중지시킬 수 있습니다."</string>
+ <string name="permlab_changeConfiguration">"UI 설정 변경"</string>
+ <string name="permdesc_changeConfiguration">"응용프로그램이 로케일 또는 전체 글꼴 크기 같은 현재 구성을 변경할 수 있습니다."</string>
+ <string name="permlab_restartPackages">"다른 응용프로그램 다시 시작"</string>
+ <string name="permdesc_restartPackages">"응용프로그램이 다른 응용프로그램을 강제로 다시 시작할 수 있습니다."</string>
+ <string name="permlab_setProcessForeground">"중지되지 않도록 하기"</string>
+ <string name="permdesc_setProcessForeground">"응용프로그램이 프로세스를 포그라운드에서 실행되도록 하여 프로세스를 중지할 수 있습니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_forceBack">"강제로 응용프로그램 닫기"</string>
+ <string name="permdesc_forceBack">"응용프로그램이 포그라운드에 있는 활동을 강제로 닫을 수 있습니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_dump">"시스템 내부 상태 검색"</string>
+ <string name="permdesc_dump">"응용프로그램이 시스템의 내부 상태를 검색할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 일반적으로 필요하지 않은 다양한 개인 정보와 보안 정보를 검색할 수 있습니다."</string>
+ <string name="permlab_addSystemService">"하위 수준 서비스 게시"</string>
+ <string name="permdesc_addSystemService">"응용프로그램이 자체 하위 수준 시스템 서비스를 게시할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 시스템을 하이재킹하거나 시스템의 데이터를 도용 또는 손상시킬 수 있습니다."</string>
+ <string name="permlab_runSetActivityWatcher">"실행 중인 모든 응용프로그램 모니터링 및 제어"</string>
+ <string name="permdesc_runSetActivityWatcher">"응용프로그램이 시스템에서 활동이 시작되는 방식을 모니터링하고 제어할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 시스템을 완전히 손상시킬 수 있습니다. 이 권한은 개발 과정에만 필요하며 일반 전화기 사용 시에는 필요하지 않습니다."</string>
+ <string name="permlab_broadcastPackageRemoved">"패키지 제거 브로드캐스트 보내기"</string>
+ <string name="permdesc_broadcastPackageRemoved">"응용프로그램이 응용프로그램 패키지가 제거되었다는 알림을 브로드캐스트할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 실행 중인 다른 응용프로그램을 중지시킬 수 있습니다."</string>
+ <string name="permlab_broadcastSmsReceived">"SMS 수신 브로드캐스트 보내기"</string>
+ <string name="permdesc_broadcastSmsReceived">"응용프로그램이 SMS 메시지를 받았다는 알림을 브로드캐스트할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 들어오는 SMS 메시지처럼 위장할 수 있습니다."</string>
+ <string name="permlab_broadcastWapPush">"WAP-PUSH-수신 브로드캐스트 보내기"</string>
+ <string name="permdesc_broadcastWapPush">"응용프로그램이 WAP PUSH 메시지를 받았다는 알림을 브로드캐스트할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 MMS 메시지를 받은 것처럼 위장하거나 웹페이지의 콘텐츠를 악성 변종으로 바꿀 수 있습니다."</string>
+ <string name="permlab_setProcessLimit">"실행 중인 프로세스 수 제한"</string>
+ <string name="permdesc_setProcessLimit">"응용프로그램이 실행할 최대 프로세스 수를 제어할 수 있습니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_setAlwaysFinish">"모든 백그라운드 응용프로그램이 닫히도록 하기"</string>
+ <string name="permdesc_setAlwaysFinish">"응용프로그램이 백그라운드로 이동한 활동을 항상 바로 마칠지 여부를 제어할 수 있습니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_fotaUpdate">"시스템 업데이트 자동으로 설치"</string>
+ <string name="permdesc_fotaUpdate">"응용프로그램이 대기 중인 시스템 업데이트에 대한 알림을 받고 설치를 트리거할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 인증되지 않은 업데이트로 시스템을 손상시키거나 업데이트 절차를 방해할 수 있습니다."</string>
+ <string name="permlab_batteryStats">"배터리 통계 수정"</string>
+ <string name="permdesc_batteryStats">"수집된 배터리 통계를 수정할 수 있습니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+ <string name="permlab_internalSystemWindow">"인증되지 않은 창 표시"</string>
+ <string name="permdesc_internalSystemWindow">"내부 시스템 사용자 인터페이스에서 사용하는 창을 만들 수 있습니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+ <string name="permlab_systemAlertWindow">"시스템 수준 경고 표시"</string>
+ <string name="permdesc_systemAlertWindow">"응용프로그램이 시스템 경고 창을 표시할 수 있습니다. 악성 응용프로그램은 전화기 화면 전체를 차지할 수 있습니다."</string>
+ <string name="permlab_setAnimationScale">"전체 애니메이션 속도 수정"</string>
+ <string name="permdesc_setAnimationScale">"응용프로그램이 언제든지 전체 애니메이션 속도를 빠르게 또는 느리게 변경할 수 있습니다."</string>
+ <string name="permlab_manageAppTokens">"응용프로그램 토큰 관리"</string>
+ <string name="permdesc_manageAppTokens">"응용프로그램이 일반적인 Z-순서를 무시하여 자체 토큰을 만들고 관리할 수 있습니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_injectEvents">"키 및 컨트롤 버튼 누르기"</string>
+ <string name="permdesc_injectEvents">"응용프로그램이 입력 이벤트(예: 키 누름)를 다른 응용프로그램에 전달할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 전화기를 완전히 제어할 수 있습니다."</string>
+ <string name="permlab_readInputState">"사용자가 입력한 내용 및 수행한 작업 기록"</string>
+ <string name="permdesc_readInputState">"응용프로그램이 다른 응용프로그램과 상호작용할 때에도 사용자가 누르는 키(예: 비밀번호 입력)를 볼 수 있습니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_bindInputMethod">"입력 방법에 고정"</string>
+ <string name="permdesc_bindInputMethod">"보유자가 입력 방법의 최상위 인터페이스에 고정할 수 있습니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_setOrientation">"화면 방향 변경"</string>
+ <string name="permdesc_setOrientation">"응용프로그램이 언제든지 화면 회전을 변경할 수 있습니다. 일반 응용프로그램에는 필요하지 않습니다."</string>
+ <string name="permlab_signalPersistentProcesses">"응용프로그램에 Linux 신호 보내기"</string>
+ <string name="permdesc_signalPersistentProcesses">"응용프로그램이 제공된 신호를 모든 영구 프로세스로 보내도록 요청할 수 있습니다."</string>
+ <string name="permlab_persistentActivity">"응용프로그램이 항상 실행되도록 설정"</string>
+ <string name="permdesc_persistentActivity">"응용프로그램이 연결된 일부 구성요소를 지속하여 다른 응용프로그램에 사용할 수 없도록 합니다."</string>
+ <string name="permlab_deletePackages">"응용프로그램 삭제"</string>
+ <string name="permdesc_deletePackages">"응용프로그램이 Android 패키지를 삭제할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 중요한 응용프로그램을 삭제할 수 있습니다."</string>
+ <string name="permlab_clearAppUserData">"다른 응용프로그램의 데이터 삭제"</string>
+ <string name="permdesc_clearAppUserData">"응용프로그램이 사용자 데이터를 지울 수 있습니다."</string>
+ <string name="permlab_deleteCacheFiles">"다른 응용프로그램의 캐시 삭제"</string>
+ <string name="permdesc_deleteCacheFiles">"응용프로그램이 캐시 파일을 삭제할 수 있습니다."</string>
+ <string name="permlab_getPackageSize">"응용프로그램 저장공간 계산"</string>
+ <string name="permdesc_getPackageSize">"응용프로그램이 해당 코드, 데이터 및 캐시 크기를 검색할 수 있습니다."</string>
+ <string name="permlab_installPackages">"응용프로그램 직접 설치"</string>
+ <string name="permdesc_installPackages">"응용프로그램이 새로운 또는 업데이트된 Android 패키지를 설치할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 임의의 강력한 권한으로 새 응용프로그램을 추가할 수 있습니다."</string>
+ <string name="permlab_clearAppCache">"모든 응용프로그램 캐시 데이터 삭제"</string>
+ <string name="permdesc_clearAppCache">"응용프로그램이 응용프로그램 캐시 디렉토리에 있는 파일을 삭제하여 전화기의 저장공간을 늘릴 수 있습니다. 액세스는 일반적으로 시스템 프로세스로 제한됩니다."</string>
+ <string name="permlab_readLogs">"시스템 로그 파일 읽기"</string>
+ <string name="permdesc_readLogs">"응용프로그램이 시스템의 다양한 로그 파일을 읽을 수 있습니다. 이 경우 응용프로그램은 사용자가 전화기로 수행하는 작업에 대한 일반적인 정보를 검색할 수 있지만 여기에 개인 정보는 포함되어서는 안 됩니다."</string>
+ <string name="permlab_diagnostic">"진단 그룹 소유의 리소스 읽기/작성"</string>
+ <string name="permdesc_diagnostic">"응용프로그램이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있습니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로, 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
+ <string name="permlab_changeComponentState">"응용프로그램 구성요소 사용 또는 사용 안 함"</string>
+ <string name="permdesc_changeComponentState">"응용프로그램이 다른 응용프로그램 구성요소의 사용 여부를 변경할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 중요한 전화기 기능을 사용하지 않도록 설정할 수 있습니다. 응용프로그램 구성요소가 쓸모없게 되거나, 일관성이 없어지거나, 불안정해질 수 있으므로 이 권한을 설정할 때는 주의해야 합니다."</string>
+ <string name="permlab_setPreferredApplications">"기본 응용프로그램 설정"</string>
+ <string name="permdesc_setPreferredApplications">"응용프로그램이 기본 응용프로그램을 수정할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 기존 응용프로그램이 사용자의 개인 데이터를 수집하도록 스푸핑하여 실행되는 응용프로그램을 변경할 수 있습니다."</string>
+ <string name="permlab_writeSettings">"전체 시스템 설정 수정"</string>
+ <string name="permdesc_writeSettings">"응용프로그램이 시스템의 설정 데이터를 수정할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 시스템 구성을 손상시킬 수 있습니다."</string>
+ <string name="permlab_writeSecureSettings">"보안 시스템 설정 수정"</string>
+ <string name="permdesc_writeSecureSettings">"응용프로그램이 시스템 보안 설정값 데이터를 수정할 수 있습니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+ <string name="permlab_writeGservices">"Google 서비스 지도 수정"</string>
+ <string name="permdesc_writeGservices">"응용프로그램이 Google 서비스 지도를 수정할 수 있습니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+ <string name="permlab_receiveBootCompleted">"부팅할 때 자동 시작"</string>
+ <string name="permdesc_receiveBootCompleted">"응용프로그램이 시스템 부팅이 끝난 후 바로 시작할 수 있습니다. 이 경우 전화기가 시작하는 데 시간이 오래 걸리고 응용프로그램이 항상 실행되어 전체 전화기 속도가 느려질 수 있습니다."</string>
+ <string name="permlab_broadcastSticky">"남은 브로드캐스트 보내기"</string>
+ <string name="permdesc_broadcastSticky">"응용프로그램이 브로드캐스트가 끝난 후에 남은 브로드캐스트를 보낼 수 있습니다. 악성 응용프로그램은 전화기가 메모리를 너무 많이 사용하도록 하여 속도를 저하시키거나 불안정하게 만들 수 있습니다."</string>
+ <string name="permlab_readContacts">"연락처 데이터 읽기"</string>
+ <string name="permdesc_readContacts">"응용프로그램이 전화기에 저장된 모든 연락처(주소) 데이터를 읽을 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 데이터를 다른 사람에게 보낼 수 있습니다."</string>
+ <string name="permlab_writeContacts">"연락처 데이터 작성"</string>
+ <string name="permdesc_writeContacts">"응용프로그램이 전화기에 저장된 연락처(주소) 데이터를 수정할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 연락처 데이터를 지우거나 수정할 수 있습니다."</string>
+ <string name="permlab_writeOwnerData">"소유자 데이터 작성"</string>
+ <string name="permdesc_writeOwnerData">"응용프로그램이 전화기에 저장된 전화기 소유자 데이터를 수정할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 소유자 데이터를 지우거나 수정할 수 있습니다."</string>
+ <string name="permlab_readOwnerData">"소유자 데이터 읽기"</string>
+ <string name="permdesc_readOwnerData">"응용프로그램이 전화기에 저장된 전화기 소유자 데이터를 읽을 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 전화기 소유자 데이터를 읽을 수 있습니다."</string>
+ <string name="permlab_readCalendar">"캘린더 데이터 읽기"</string>
+ <string name="permdesc_readCalendar">"응용프로그램이 전화기에 저장된 모든 캘린더 일정을 읽을 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 캘린더 일정을 다른 사람에게 보낼 수 있습니다."</string>
+ <string name="permlab_writeCalendar">"캘린더 데이터 작성"</string>
+ <string name="permdesc_writeCalendar">"응용프로그램이 전화기에 저장된 캘린더 일정을 수정할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 캘린더 데이터를 지우거나 수정할 수 있습니다."</string>
+ <string name="permlab_accessMockLocation">"테스트를 위해 위치 소스로 가장"</string>
+ <string name="permdesc_accessMockLocation">"테스트용 가짜 위치 소스를 만듭니다. 악성 응용프로그램은 이 기능을 이용하여 GPS, 네트워크 제공업체 같은 실제 위치 소스에서 반환한 위치 및/또는 상태를 덮어쓸 수 있습니다."</string>
+ <string name="permlab_accessLocationExtraCommands">"추가 위치 제공업체 명령 액세스"</string>
+ <string name="permdesc_accessLocationExtraCommands">"추가 위치 제공업체 명령에 액세스합니다. 악성 응용프로그램은 이 기능을 이용하여 GPS 또는 기타 위치 소스의 작동을 방해할 수 있습니다."</string>
+ <string name="permlab_accessFineLocation">"자세한 (GPS) 위치"</string>
+ <string name="permdesc_accessFineLocation">"가능한 경우 전화기에서 GPS(범지구 위치 측정 시스템) 등의 자세한 위치 소스에 액세스합니다. 악성 응용프로그램은 이 기능을 이용하여 사용자의 위치를 측정하고 추가 배터리 전원을 소비할 수 있습니다."</string>
+ <string name="permlab_accessCoarseLocation">"광범위한 네트워크 기반 위치"</string>
+ <string name="permdesc_accessCoarseLocation">"전화기의 대략적인 위치를 측정하기 위해 셀룰러 네트워크 데이터베이스와 같은 광범위한 위치 소스에 액세스합니다. 악성 응용프로그램은 이 기능을 이용하여 사용자의 위치를 대략적으로 측정할 수 있습니다."</string>
+ <string name="permlab_accessSurfaceFlinger">"SurfaceFlinger 액세스"</string>
+ <string name="permdesc_accessSurfaceFlinger">"응용프로그램이 SurfaceFlinger의 하위 수준 기능을 사용할 수 있습니다."</string>
+ <string name="permlab_readFrameBuffer">"프레임 버퍼 읽기"</string>
+ <string name="permdesc_readFrameBuffer">"응용프로그램이 프레임 버퍼의 콘텐츠를 읽을 수 있습니다."</string>
+ <string name="permlab_modifyAudioSettings">"오디오 설정 변경"</string>
+ <string name="permdesc_modifyAudioSettings">"응용프로그램이 볼륨 및 경로 지정 같은 전체 오디오 설정을 수정할 수 있습니다."</string>
+ <string name="permlab_recordAudio">"오디오 녹음"</string>
+ <string name="permdesc_recordAudio">"응용프로그램이 오디오 레코드 경로에 액세스할 수 있습니다."</string>
+ <string name="permlab_camera">"사진 촬영"</string>
+ <string name="permdesc_camera">"응용프로그램이 카메라로 사진을 찍을 수 있습니다. 이 경우 응용프로그램은 카메라에 표시되는 이미지를 언제든지 수집할 수 있습니다."</string>
+ <string name="permlab_brick">"전화기를 영구적으로 비활성화"</string>
+ <string name="permdesc_brick">"응용프로그램이 전화기를 영구적으로 사용하지 않도록 설정할 수 있습니다. 이 기능은 매우 위험합니다."</string>
+ <string name="permlab_reboot">"전화기 강제로 다시 부팅"</string>
+ <string name="permdesc_reboot">"응용프로그램이 전화기를 강제로 다시 부팅할 수 있습니다."</string>
+ <string name="permlab_mount_unmount_filesystems">"파일시스템 마운트 및 마운트 해제"</string>
+ <string name="permdesc_mount_unmount_filesystems">"응용프로그램이 이동식 저장소의 파일시스템을 마운트하고 마운트 해제할 수 있습니다."</string>
+ <string name="permlab_mount_format_filesystems">"외부 저장소 포맷"</string>
+ <string name="permdesc_mount_format_filesystems">"응용프로그램이 제거 가능한 저장소를 포맷하도록 합니다."</string>
+ <string name="permlab_vibrate">"진동 제어"</string>
+ <string name="permdesc_vibrate">"응용프로그램이 진동을 제어할 수 있습니다."</string>
+ <string name="permlab_flashlight">"손전등 제어"</string>
+ <string name="permdesc_flashlight">"응용프로그램이 손전등을 제어할 수 있습니다."</string>
+ <string name="permlab_hardware_test">"하드웨어 테스트"</string>
+ <string name="permdesc_hardware_test">"응용프로그램이 하드웨어를 테스트할 목적으로 다양한 주변장치를 제어할 수 있습니다."</string>
+ <string name="permlab_callPhone">"전화번호로 직접 전화걸기"</string>
+ <string name="permdesc_callPhone">"응용프로그램이 사용자의 조작 없이 전화번호로 전화를 걸 수 있습니다. 악성 응용프로그램은 전화요금 청구서에 예상치 못한 통화 요금이 부과되도록 할 수 있습니다. 이 권한으로 응용프로그램은 비상 전화를 걸 수 없습니다."</string>
+ <string name="permlab_callPrivileged">"전화번호로 직접 전화걸기"</string>
+ <string name="permdesc_callPrivileged">"응용프로그램이 사용자의 조작 없이 비상 번호를 포함한 전화번호로 전화를 걸 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 응급 서비스를 불필요하거나 불법적으로 호출할 수 있습니다."</string>
+ <string name="permlab_locationUpdates">"위치 업데이트 알림 제어"</string>
+ <string name="permdesc_locationUpdates">"무선의 위치 업데이트 알림을 활성화하거나 비활성화할 수 있습니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+ <string name="permlab_checkinProperties">"체크인 속성 액세스"</string>
+ <string name="permdesc_checkinProperties">"체크인 서비스에서 업로드한 속성에 대한 읽기/쓰기 액세스를 허용합니다. 일반 응용프로그램에서는 사용하지 않습니다."</string>
+ <string name="permlab_bindGadget">"가젯 선택"</string>
+ <string name="permdesc_bindGadget">"어느 응용프로그램이 어느 가젯을 사용할 수 있는지 시스템에 알려 주는 권한을 본 응용프로그램에 부여합니다. 이 권한을 사용하면 응용프로그램이 개인 데이터에 대한 액세스 권한을 다른 응용프로그램에 제공할 수 있습니다. 일반 응용프로그램은 이 권한을 사용할 수 없습니다."</string>
+ <string name="permlab_modifyPhoneState">"전화기 상태 수정"</string>
+ <string name="permdesc_modifyPhoneState">"응용프로그램이 장치의 전화 기능을 제어할 수 있습니다. 이 권한을 갖는 응용프로그램은 사용자에게 알리지 않고 네트워크를 전환하거나, 전화 무선 기능을 켜고 끌 수 있습니다."</string>
+ <string name="permlab_readPhoneState">"전화기 상태 읽기"</string>
+ <string name="permdesc_readPhoneState">"응용프로그램이 장치의 전화 기능에 액세스할 수 있습니다. 이 권한을 갖는 응용프로그램은 전화기의 전화번호, 통화가 활성인지 여부, 통화가 연결된 번호 등을 확인할 수 있습니다."</string>
+ <string name="permlab_wakeLock">"전화기가 절전 모드로 전환되지 않도록 설정"</string>
+ <string name="permdesc_wakeLock">"응용프로그램이 전화기가 절전 모드로 전환되지 않도록 할 수 있습니다."</string>
+ <string name="permlab_devicePower">"전화기 전원 켜고 끄기"</string>
+ <string name="permdesc_devicePower">"응용프로그램이 전화기를 켜거나 끌 수 있습니다."</string>
+ <string name="permlab_factoryTest">"출고 테스트 모드로 실행"</string>
+ <string name="permdesc_factoryTest">"전화기 하드웨어에 대한 완전한 액세스를 허용하는 하위 수준의 제조업체 테스트로 실행됩니다. 전화기가 제조업체 테스트 모드로 실행 중일 때만 사용할 수 있습니다."</string>
+ <string name="permlab_setWallpaper">"배경화면 설정"</string>
+ <string name="permdesc_setWallpaper">"응용프로그램이 시스템 배경화면을 설정할 수 있습니다."</string>
+ <string name="permlab_setWallpaperHints">"배경화면 크기 힌트 설정"</string>
+ <string name="permdesc_setWallpaperHints">"응용프로그램이 시스템 배경화면 크기 힌트를 설정할 수 있습니다."</string>
+ <string name="permlab_masterClear">"시스템을 공장 기본값으로 재설정"</string>
+ <string name="permdesc_masterClear">"응용프로그램이 모든 데이터, 구성 및 설치된 응용프로그램을 지워서 시스템을 공장 기본값으로 완전히 재설정할 수 있습니다."</string>
+ <string name="permlab_setTimeZone">"표준시간대 설정"</string>
+ <string name="permdesc_setTimeZone">"응용프로그램이 전화기의 표준시간대를 변경할 수 있습니다."</string>
+ <string name="permlab_getAccounts">"알려진 계정 검색"</string>
+ <string name="permdesc_getAccounts">"응용프로그램이 전화기에 알려진 계정 목록을 가져올 수 있습니다."</string>
+ <string name="permlab_accessNetworkState">"네트워크 상태 보기"</string>
+ <string name="permdesc_accessNetworkState">"응용프로그램이 모든 네트워크의 상태를 볼 수 있습니다."</string>
+ <string name="permlab_createNetworkSockets">"인터넷에 완전히 액세스"</string>
+ <string name="permdesc_createNetworkSockets">"응용프로그램이 네트워크 소켓을 만들 수 있습니다."</string>
+ <string name="permlab_writeApnSettings">"액세스포인트 이름 설정 쓰기"</string>
+ <string name="permdesc_writeApnSettings">"응용프로그램이 APN의 프록시 및 포트 같은 APN 설정을 수정할 수 있습니다."</string>
+ <string name="permlab_changeNetworkState">"네트워크 연결 변경"</string>
+ <string name="permdesc_changeNetworkState">"응용프로그램이 네트워크 연결 상태를 변경할 수 있습니다."</string>
+ <string name="permlab_changeBackgroundDataSetting">"백그라운드 데이터 사용 설정 변경"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"백그라운드 데이터 사용 설정을 변경할 수 있는 권한을 응용프로그램에 부여합니다."</string>
+ <string name="permlab_accessWifiState">"Wi-Fi 상태 보기"</string>
+ <string name="permdesc_accessWifiState">"응용프로그램이 Wi-Fi의 상태에 대한 정보를 볼 수 있습니다."</string>
+ <string name="permlab_changeWifiState">"Wi-Fi 상태 변경"</string>
+ <string name="permdesc_changeWifiState">"응용프로그램이 Wi-Fi 액세스포인트에 연결하거나 연결을 끊고, 구성된 Wi-Fi 네트워크를 변경할 수 있습니다."</string>
+ <string name="permlab_bluetoothAdmin">"Bluetooth 관리"</string>
+ <string name="permdesc_bluetoothAdmin">"응용프로그램이 로컬 Bluetooth 전화를 구성한 다음 원격 장치를 검색하여 페어링할 수 있습니다."</string>
+ <string name="permlab_bluetooth">"Bluetooth 연결 만들기"</string>
+ <string name="permdesc_bluetooth">"응용프로그램이 로컬 Bluetooth 전화의 구성을 보고 페어링된 장치에 연결하거나 연결을 수락할 수 있습니다."</string>
+ <string name="permlab_disableKeyguard">"키 잠금 사용 안 함"</string>
+ <string name="permdesc_disableKeyguard">"응용프로그램이 키 잠금 및 연결된 비밀번호 보안을 비활성화할 수 있습니다. 예를 들어, 전화기가 수신전화를 받을 때 키 잠금을 비활성화했다가 통화가 끝나면 키 잠금을 다시 활성화할 수 있습니다."</string>
+ <string name="permlab_readSyncSettings">"동기화 설정 읽기"</string>
+ <string name="permdesc_readSyncSettings">"응용프로그램이 연락처에 대해 동기화를 활성화할지 여부 같은 동기화 설정을 읽을 수 있습니다."</string>
+ <string name="permlab_writeSyncSettings">"동기화 설정 쓰기"</string>
+ <string name="permdesc_writeSyncSettings">"응용프로그램이 연락처에 대해 동기화를 활성화할지 여부 같은 동기화 설정을 수정할 수 있습니다."</string>
+ <string name="permlab_readSyncStats">"동기화 통계 읽기"</string>
+ <string name="permdesc_readSyncStats">"응용프로그램이 동기화 통계(예: 실행된 동기화 기록)을 읽을 수 있습니다."</string>
+ <string name="permlab_subscribedFeedsRead">"가입된 피드 읽기"</string>
+ <string name="permdesc_subscribedFeedsRead">"응용프로그램이 현재 동기화된 피드에 대한 상세정보를 가져올 수 있습니다."</string>
+ <string name="permlab_subscribedFeedsWrite">"가입 피드 작성"</string>
+ <string name="permdesc_subscribedFeedsWrite">"응용프로그램이 현재 동기화된 피드를 수정할 수 있습니다. 악성 응용프로그램은 이 기능을 이용하여 동기화된 피드를 변경할 수 있습니다."</string>
+ <string name="permlab_readDictionary">"상용자 정의 사전 읽기"</string>
+ <string name="permdesc_readDictionary">"응용프로그램이 사용자 사전에 보관되어 있을 수 있는 비공개 단어, 이름 및 구문을 읽도록 합니다."</string>
+ <string name="permlab_writeDictionary">"상용자 정의 사전에 작성"</string>
+ <string name="permdesc_writeDictionary">"응용프로그램이 사용자 사전에 새 단어를 입력할 수 있습니다."</string>
+ <string-array name="phoneTypes">
+ <item>"집"</item>
+ <item>"휴대전화"</item>
+ <item>"회사"</item>
+ <item>"회사 팩스"</item>
+ <item>"집(팩스)"</item>
+ <item>"호출기"</item>
+ <item>"기타"</item>
+ <item>"사용자설정"</item>
+ </string-array>
+ <string-array name="emailAddressTypes">
+ <item>"집"</item>
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"사용자설정"</item>
+ </string-array>
+ <string-array name="postalAddressTypes">
+ <item>"집"</item>
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"사용자설정"</item>
+ </string-array>
+ <string-array name="imAddressTypes">
+ <item>"집"</item>
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"사용자설정"</item>
+ </string-array>
+ <string-array name="organizationTypes">
+ <item>"회사"</item>
+ <item>"기타"</item>
+ <item>"사용자설정"</item>
+ </string-array>
+ <string-array name="imProtocols">
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google 토크"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
+ </string-array>
+ <string name="keyguard_password_enter_pin_code">"PIN 코드 입력"</string>
+ <string name="keyguard_password_wrong_pin_code">"PIN 코드가 잘못되었습니다."</string>
+ <string name="keyguard_label_text">"잠금해제하려면 메뉴를 누른 다음 0을 누릅니다."</string>
+ <string name="emergency_call_dialog_number_for_display">"비상 전화번호"</string>
+ <string name="lockscreen_carrier_default">"(서비스 안 됨)"</string>
+ <string name="lockscreen_screen_locked">"화면 잠김"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"비상 전화를 걸거나 잠금해제하려면 메뉴를 누르세요."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"잠금해제하려면 메뉴를 누르세요."</string>
+ <string name="lockscreen_pattern_instructions">"잠금해제를 위해 패턴 그리기"</string>
+ <string name="lockscreen_emergency_call">"비상 전화"</string>
+ <string name="lockscreen_pattern_correct">"맞습니다."</string>
+ <string name="lockscreen_pattern_wrong">"죄송합니다. 다시 시도하세요."</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
+ <string name="lockscreen_low_battery">"충전기를 연결하세요."</string>
+ <string name="lockscreen_missing_sim_message_short">"SIM 카드가 없습니다."</string>
+ <string name="lockscreen_missing_sim_message">"전화기에 SIM 카드가 없습니다."</string>
+ <string name="lockscreen_missing_sim_instructions">"SIM 카드를 삽입하세요."</string>
+ <string name="lockscreen_network_locked_message">"네트워크 잠김"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM 카드의 PUK가 잠겨 있습니다."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"고객지원팀에 문의하세요."</string>
+ <string name="lockscreen_sim_locked_message">"SIM 카드가 잠겨 있습니다."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM 카드 잠금해제 중..."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 가져왔습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도하세요."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 Google 로그인을 통해 전화기를 잠금해제하도록 요청됩니다."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도하세요."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"<xliff:g id="NUMBER">%d</xliff:g>초 후에 다시 입력하세요."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"패턴을 잊으셨나요?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"패턴을 너무 많이 시도했습니다."</string>
+ <string name="lockscreen_glogin_instructions">"잠금해제하려면"\n"Google 계정으로 로그인하세요."</string>
+ <string name="lockscreen_glogin_username_hint">"사용자 이름(이메일)"</string>
+ <string name="lockscreen_glogin_password_hint">"비밀번호"</string>
+ <string name="lockscreen_glogin_submit_button">"로그인"</string>
+ <string name="lockscreen_glogin_invalid_input">"사용자 이름 또는 비밀번호가 잘못되었습니다."</string>
+ <string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
+ <string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
+ <skip />
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
+ <skip />
+ <string name="status_bar_clear_all_button">"알림 지우기"</string>
+ <string name="status_bar_no_notifications_title">"알림 없음"</string>
+ <string name="status_bar_ongoing_events_title">"사용 중"</string>
+ <string name="status_bar_latest_events_title">"알림"</string>
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
+ <skip />
+ <string name="battery_status_charging">"충전 중..."</string>
+ <string name="battery_low_title">"충전기를 연결하세요."</string>
+ <string name="battery_low_subtitle">"배터리 전원이 부족합니다."</string>
+ <string name="battery_low_percent_format">"<xliff:g id="NUMBER">%d%%</xliff:g> 미만 남음"</string>
+ <string name="factorytest_failed">"출고 테스트 불합격"</string>
+ <string name="factorytest_not_system">"FACTORY_TEST 작업은 /system/app 디렉토리에 설치된 패키지에 대해서만 지원됩니다."</string>
+ <string name="factorytest_no_action">"FACTORY_TEST 작업을 제공하는 패키지가 없습니다."</string>
+ <string name="factorytest_reboot">"다시 부팅"</string>
+ <string name="js_dialog_title">"\'<xliff:g id="TITLE">%s</xliff:g>\' 페이지 내용:"</string>
+ <string name="js_dialog_title_default">"자바스크립트"</string>
+ <string name="js_dialog_before_unload">"다른 페이지를 탐색하시겠습니까?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"계속하려면 \'확인\'을 선택하고 현재 페이지에 그대로 있으려면 \'취소\'를 선택하세요."</string>
+ <string name="save_password_label">"확인"</string>
+ <string name="save_password_message">"브라우저에 이 비밀번호를 저장하시겠습니까?"</string>
+ <string name="save_password_notnow">"나중에"</string>
+ <string name="save_password_remember">"저장"</string>
+ <string name="save_password_never">"저장 안 함"</string>
+ <string name="open_permission_deny">"페이지를 열 수 있는 권한이 없습니다."</string>
+ <string name="text_copied">"텍스트가 클립보드에 복사되었습니다."</string>
+ <string name="more_item_label">"자세히"</string>
+ <string name="prepend_shortcut_label">"Menu+"</string>
+ <string name="menu_space_shortcut_label">"스페이스바"</string>
+ <string name="menu_enter_shortcut_label">"입력"</string>
+ <string name="menu_delete_shortcut_label">"삭제"</string>
+ <string name="search_go">"검색"</string>
+ <string name="today">"오늘"</string>
+ <string name="yesterday">"어제"</string>
+ <string name="tomorrow">"내일"</string>
+ <string name="oneMonthDurationPast">"한 달 전"</string>
+ <string name="beforeOneMonthDurationPast">"한 달 전"</string>
+ <plurals name="num_seconds_ago">
+ <item quantity="one">"1초 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>초 전"</item>
+ </plurals>
+ <plurals name="num_minutes_ago">
+ <item quantity="one">"1분 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
+ </plurals>
+ <plurals name="num_hours_ago">
+ <item quantity="one">"1시간 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
+ </plurals>
+ <plurals name="num_days_ago">
+ <item quantity="one">"어제"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
+ </plurals>
+ <plurals name="in_num_seconds">
+ <item quantity="one">"1초 내"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>초 후"</item>
+ </plurals>
+ <plurals name="in_num_minutes">
+ <item quantity="one">"1분 내"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
+ </plurals>
+ <plurals name="in_num_hours">
+ <item quantity="one">"1시간 내"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
+ </plurals>
+ <plurals name="in_num_days">
+ <item quantity="one">"내일"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
+ </plurals>
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"1초 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 초 전"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"1분 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 전"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"1시간 전"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 전"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"어제"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>일 전"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"1초 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 초 후"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"1분 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>분 후"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"1시간 후"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>시간 후"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"내일"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g>일 후"</item>
+ </plurals>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"%s년"</string>
+ <string name="day">"일"</string>
+ <string name="days">"일"</string>
+ <string name="hour">"시간"</string>
+ <string name="hours">"시간"</string>
+ <string name="minute">"분"</string>
+ <string name="minutes">"분"</string>
+ <string name="second">"초"</string>
+ <string name="seconds">"초"</string>
+ <string name="week">"주"</string>
+ <string name="weeks">"주"</string>
+ <string name="year">"년"</string>
+ <string name="years">"년"</string>
+ <string name="sunday">"일요일"</string>
+ <string name="monday">"월요일"</string>
+ <string name="tuesday">"화요일"</string>
+ <string name="wednesday">"수요일"</string>
+ <string name="thursday">"목요일"</string>
+ <string name="friday">"금요일"</string>
+ <string name="saturday">"토요일"</string>
+ <string name="every_weekday">"주중 매일(월-금)"</string>
+ <string name="daily">"매일"</string>
+ <string name="weekly">"매주 <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"매월"</string>
+ <string name="yearly">"매년"</string>
+ <string name="VideoView_error_title">"동영상 재생 안 됨"</string>
+ <string name="VideoView_error_text_unknown">"죄송합니다. 동영상을 재생할 수 없습니다."</string>
+ <string name="VideoView_error_button">"확인"</string>
+ <string name="am">"AM"</string>
+ <string name="pm">"PM"</string>
+ <string name="numeric_date">"<xliff:g id="MONTH">%m</xliff:g>/<xliff:g id="DAY">%d</xliff:g>/<xliff:g id="YEAR">%Y</xliff:g>"</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="WEEKDAY2">%4$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
+ <string name="wday1_date1_wday2_date2">"<xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="WEEKDAY1">%1$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="WEEKDAY2">%4$s</xliff:g>"</string>
+ <string name="date1_time1_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g>, <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>, <xliff:g id="TIME2">%6$s</xliff:g>"</string>
+ <string name="date1_date2">"<xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>"</string>
+ <string name="time1_time2">"<xliff:g id="TIME1">%1$s</xliff:g> – <xliff:g id="TIME2">%2$s</xliff:g>"</string>
+ <string name="time_wday_date">"<xliff:g id="DATE">%3$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
+ <string name="time_date">"<xliff:g id="DATE">%3$s</xliff:g>, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="time_wday">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="YEAR">yyyy</xliff:g>' '<xliff:g id="MONTH">MMMM</xliff:g>', '<xliff:g id="DAY">d</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="YEAR">yyyy</xliff:g>' '<xliff:g id="MONTH">MMMM</xliff:g>', '<xliff:g id="DAY">d</xliff:g>"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMM</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="noon">"정오"</string>
+ <string name="Noon">"정오"</string>
+ <string name="midnight">"자정"</string>
+ <string name="Midnight">"자정"</string>
+ <!-- no translation found for month_day (3693060561170538204) -->
+ <skip />
+ <!-- no translation found for month (1976700695144952053) -->
+ <skip />
+ <string name="month_day_year">"<xliff:g id="YEAR">%Y</xliff:g>, <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>"</string>
+ <!-- no translation found for month_year (2106203387378728384) -->
+ <skip />
+ <string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
+ <string name="date_and_time">"<xliff:g id="YEAR">%Y</xliff:g>, <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
+ <string name="same_year_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>"</string>
+ <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="WEEKDAY1">%1$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
+ <string name="same_year_mdy1_mdy2">"<xliff:g id="YEAR">%9$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>"</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR">%9$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="WEEKDAY1">%1$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
+ <string name="same_year_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>"</string>
+ <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="WEEKDAY1">%1$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
+ <string name="numeric_mdy1_mdy2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>/"</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR1">%4$s</xliff:g>/<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="WEEKDAY1">%1$s</xliff:g> – <xliff:g id="YEAR2">%9$s</xliff:g>/<xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
+ <string name="numeric_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g>/<xliff:g id="DAY1_0">%3$s</xliff:g>/<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g>/<xliff:g id="DAY2_1">%8$s</xliff:g>/<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>"</string>
+ <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="WEEKDAY1">%1$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
+ <string name="same_month_mdy1_mdy2">"<xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>"</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="WEEKDAY1">%1$s</xliff:g> – <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="WEEKDAY2">%6$s</xliff:g>"</string>
+ <string name="same_month_md1_time1_md2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="abbrev_month_day_year">"<xliff:g id="YEAR">%Y</xliff:g> <xliff:g id="MONTH">%b</xliff:g>, <xliff:g id="DAY">%-d</xliff:g>"</string>
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
+ <skip />
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
+ <skip />
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
+ <skip />
+ <string name="day_of_week_long_sunday">"일요일"</string>
+ <string name="day_of_week_long_monday">"월요일"</string>
+ <string name="day_of_week_long_tuesday">"화요일"</string>
+ <string name="day_of_week_long_wednesday">"수요일"</string>
+ <string name="day_of_week_long_thursday">"목요일"</string>
+ <string name="day_of_week_long_friday">"금요일"</string>
+ <string name="day_of_week_long_saturday">"토요일"</string>
+ <string name="day_of_week_medium_sunday">"일요일"</string>
+ <string name="day_of_week_medium_monday">"월"</string>
+ <string name="day_of_week_medium_tuesday">"화"</string>
+ <string name="day_of_week_medium_wednesday">"수"</string>
+ <string name="day_of_week_medium_thursday">"목"</string>
+ <string name="day_of_week_medium_friday">"금"</string>
+ <string name="day_of_week_medium_saturday">"토"</string>
+ <string name="day_of_week_short_sunday">"일"</string>
+ <string name="day_of_week_short_monday">"월"</string>
+ <string name="day_of_week_short_tuesday">"화"</string>
+ <string name="day_of_week_short_wednesday">"수"</string>
+ <string name="day_of_week_short_thursday">"목"</string>
+ <string name="day_of_week_short_friday">"금"</string>
+ <string name="day_of_week_short_saturday">"토"</string>
+ <string name="day_of_week_shorter_sunday">"일"</string>
+ <string name="day_of_week_shorter_monday">"월"</string>
+ <string name="day_of_week_shorter_tuesday">"화"</string>
+ <string name="day_of_week_shorter_wednesday">"수"</string>
+ <string name="day_of_week_shorter_thursday">"목"</string>
+ <string name="day_of_week_shorter_friday">"금"</string>
+ <string name="day_of_week_shorter_saturday">"토"</string>
+ <string name="day_of_week_shortest_sunday">"일"</string>
+ <string name="day_of_week_shortest_monday">"3월"</string>
+ <string name="day_of_week_shortest_tuesday">"목"</string>
+ <string name="day_of_week_shortest_wednesday">"수"</string>
+ <string name="day_of_week_shortest_thursday">"목"</string>
+ <string name="day_of_week_shortest_friday">"금"</string>
+ <string name="day_of_week_shortest_saturday">"토"</string>
+ <string name="month_long_january">"1월"</string>
+ <string name="month_long_february">"2월"</string>
+ <string name="month_long_march">"3월"</string>
+ <string name="month_long_april">"4월"</string>
+ <string name="month_long_may">"5월"</string>
+ <string name="month_long_june">"6월"</string>
+ <string name="month_long_july">"7월"</string>
+ <string name="month_long_august">"8월"</string>
+ <string name="month_long_september">"9월"</string>
+ <string name="month_long_october">"10월"</string>
+ <string name="month_long_november">"11월"</string>
+ <string name="month_long_december">"12월"</string>
+ <string name="month_medium_january">"1월"</string>
+ <string name="month_medium_february">"2월"</string>
+ <string name="month_medium_march">"3월"</string>
+ <string name="month_medium_april">"4월"</string>
+ <string name="month_medium_may">"5월"</string>
+ <string name="month_medium_june">"6월"</string>
+ <string name="month_medium_july">"7월"</string>
+ <string name="month_medium_august">"8월"</string>
+ <string name="month_medium_september">"9월"</string>
+ <string name="month_medium_october">"10월"</string>
+ <string name="month_medium_november">"11월"</string>
+ <string name="month_medium_december">"12월"</string>
+ <string name="month_shortest_january">"1월"</string>
+ <string name="month_shortest_february">"금"</string>
+ <string name="month_shortest_march">"3월"</string>
+ <string name="month_shortest_april">"4월"</string>
+ <string name="month_shortest_may">"5월"</string>
+ <string name="month_shortest_june">"6월"</string>
+ <string name="month_shortest_july">"7월"</string>
+ <string name="month_shortest_august">"8월"</string>
+ <string name="month_shortest_september">"9월"</string>
+ <string name="month_shortest_october">"10월"</string>
+ <string name="month_shortest_november">"11월"</string>
+ <string name="month_shortest_december">"12월"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"모두 선택"</string>
+ <string name="selectText">"텍스트 선택"</string>
+ <string name="stopSelectingText">"텍스트 선택 중지"</string>
+ <string name="cut">"잘라내기"</string>
+ <string name="cutAll">"모두 잘라내기"</string>
+ <string name="copy">"복사"</string>
+ <string name="copyAll">"모두 복사"</string>
+ <string name="paste">"붙여넣기"</string>
+ <string name="copyUrl">"URL 복사"</string>
+ <string name="inputMethod">"입력 방법"</string>
+ <string name="addToDictionary">"사전에 \'%s\' 추가"</string>
+ <string name="editTextMenuTitle">"텍스트 수정"</string>
+ <string name="low_internal_storage_view_title">"저장공간 부족"</string>
+ <string name="low_internal_storage_view_text">"전화기 저장공간이 부족합니다."</string>
+ <string name="ok">"확인"</string>
+ <string name="cancel">"취소"</string>
+ <string name="yes">"확인"</string>
+ <string name="no">"취소"</string>
+ <string name="dialog_alert_title">"주의"</string>
+ <string name="capital_on">"켜짐"</string>
+ <string name="capital_off">"끄기"</string>
+ <string name="whichApplication">"작업을 수행할 때 사용하는 권한"</string>
+ <string name="alwaysUse">"이 작업에 대해 기본값으로 사용"</string>
+ <string name="clearDefaultHintMsg">"홈 설정 &gt; 응용프로그램 &gt; 응용프로그램 관리에서 기본값을 지웁니다."</string>
+ <string name="chooseActivity">"작업 선택"</string>
+ <string name="noApplications">"작업을 수행할 수 있는 응용프로그램이 없습니다."</string>
+ <string name="aerr_title">"죄송합니다."</string>
+ <string name="aerr_application">"<xliff:g id="APPLICATION">%1$s</xliff:g> 응용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 예상치 않게 중지되었습니다. 다시 시도하세요."</string>
+ <string name="aerr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 예상치 않게 중지되었습니다. 다시 시도하세요."</string>
+ <string name="anr_title">"죄송합니다."</string>
+ <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 활동(<xliff:g id="APPLICATION">%2$s</xliff:g> 응용프로그램)이 응답하지 않습니다."</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 활동(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 응답하지 않습니다."</string>
+ <string name="anr_application_process">"<xliff:g id="APPLICATION">%1$s</xliff:g> 응용프로그램(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 응답하지 않습니다."</string>
+ <string name="anr_process">"<xliff:g id="PROCESS">%1$s</xliff:g> 프로세스가 응답하지 않습니다."</string>
+ <string name="force_close">"강제로 닫기"</string>
+ <string name="wait">"대기"</string>
+ <string name="debug">"디버깅"</string>
+ <string name="sendText">"텍스트에 대한 작업 선택"</string>
+ <string name="volume_ringtone">"벨소리 볼륨"</string>
+ <string name="volume_music">"미디어 볼륨"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Bluetooth를 통해 재생"</string>
+ <string name="volume_call">"통화볼륨"</string>
+ <string name="volume_bluetooth_call">"Bluetooth 통화 볼륨"</string>
+ <string name="volume_alarm">"알람 볼륨"</string>
+ <string name="volume_notification">"알림 볼륨"</string>
+ <string name="volume_unknown">"볼륨"</string>
+ <string name="ringtone_default">"기본 벨소리"</string>
+ <string name="ringtone_default_with_actual">"기본 벨소리(<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"무음"</string>
+ <string name="ringtone_picker_title">"벨소리"</string>
+ <string name="ringtone_unknown">"알 수 없는 벨소리"</string>
+ <plurals name="wifi_available">
+ <item quantity="one">"Wi-Fi 네트워크 사용가능"</item>
+ <item quantity="other">"Wi-Fi 네트워크 사용가능"</item>
+ </plurals>
+ <plurals name="wifi_available_detailed">
+ <item quantity="one">"개방형 Wi-Fi 네트워크 사용가능"</item>
+ <item quantity="other">"개방형 Wi-Fi 네트워크 사용가능"</item>
+ </plurals>
+ <string name="select_character">"문자 삽입"</string>
+ <string name="sms_control_default_app_name">"알 수 없는 응용프로그램"</string>
+ <string name="sms_control_title">"SMS 메시지를 보내는 중"</string>
+ <string name="sms_control_message">"여러 개의 SMS 메시지를 보내는 중입니다. 계속하려면 \'확인\'을 선택하고 전송을 중지하려면 \'취소\'를 선택하세요."</string>
+ <string name="sms_control_yes">"확인"</string>
+ <string name="sms_control_no">"취소"</string>
+ <string name="date_time_set">"설정"</string>
+ <string name="default_permission_group">"기본값"</string>
+ <string name="no_permissions">"권한이 필요하지 않음"</string>
+ <string name="perms_hide"><b>"숨기기"</b></string>
+ <string name="perms_show_all"><b>"모두 표시"</b></string>
+ <string name="googlewebcontenthelper_loading">"로드 중..."</string>
+ <string name="usb_storage_title">"USB 연결됨"</string>
+ <string name="usb_storage_message">"USB를 통해 전화기를 컴퓨터에 연결했습니다. 컴퓨터와 전화기 SD 카드 간에 파일을 복사하려면 \'마운트\'를 선택하세요."</string>
+ <string name="usb_storage_button_mount">"마운트"</string>
+ <string name="usb_storage_button_unmount">"마운트 안 함"</string>
+ <string name="usb_storage_error_message">"USB 저장소에 SD 카드를 사용하는 동안 문제가 발생했습니다."</string>
+ <string name="usb_storage_notification_title">"USB 연결됨"</string>
+ <string name="usb_storage_notification_message">"컴퓨터에 파일을 복사하거나 컴퓨터의 파일을 복사하려면 선택합니다."</string>
+ <string name="usb_storage_stop_notification_title">"USB 저장소 끄기"</string>
+ <string name="usb_storage_stop_notification_message">"USB 저장소 끄기를 선택하세요."</string>
+ <string name="usb_storage_stop_title">"USB 저장소 끄기"</string>
+ <string name="usb_storage_stop_message">"USB 저장소를 끄기 전에 반드시 USB 호스를 마운트 해제하세요. USB 저장소를 끄려면 \'끄기\'를 선택하세요."</string>
+ <string name="usb_storage_stop_button_mount">"USB 저장소 끄기"</string>
+ <string name="usb_storage_stop_button_unmount">"취소"</string>
+ <string name="usb_storage_stop_error_message">"USB 저장소를 끄는 동안 Weve에 문제가 발행했습니다. USB 호스트를 마운트 해제했는지 확인한 후 다시 시도하세요."</string>
+ <string name="extmedia_format_title">"SD 카드 포맷"</string>
+ <string name="extmedia_format_message">"SD 카드를 포맷하시겠습니까? 포맷하면 카드의 모든 데이터를 잃게 됩니다."</string>
+ <string name="extmedia_format_button_format">"포맷"</string>
+ <string name="select_input_method">"입력 방법 선택"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"가능한 원인"</u></string>
+ <string name="ext_media_checking_notification_title">"SD 카드 준비 중"</string>
+ <string name="ext_media_checking_notification_message">"오류 확인 중"</string>
+ <string name="ext_media_nofs_notification_title">"빈 SD 카드"</string>
+ <string name="ext_media_nofs_notification_message">"SD 카드가 비어 있거나 지원되지 않는 파일시스템입니다."</string>
+ <string name="ext_media_unmountable_notification_title">"손상된 SD 카드"</string>
+ <string name="ext_media_unmountable_notification_message">"SD 카드가 손상되었습니다. 카드를 다시 포맷하시기 바랍니다."</string>
+ <string name="ext_media_badremoval_notification_title">"SD 카드가 예상치 않게 제거되었습니다."</string>
+ <string name="ext_media_badremoval_notification_message">"데이터 손실을 피하려면 SD 카드를 제거하기 전에 마운트 해제합니다."</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD 카드를 안전하게 제거할 수 있습니다."</string>
+ <string name="ext_media_safe_unmount_notification_message">"이제 SD 카드를 안전하게 제거할 수 있습니다."</string>
+ <string name="ext_media_nomedia_notification_title">"SD 카드를 제거했습니다."</string>
+ <string name="ext_media_nomedia_notification_message">"SD가 제거되었습니다. 기기의 저장 용량을 늘리려면 새 SD 카드를 삽입하세요."</string>
+ <string name="activity_list_empty">"일치하는 활동이 없습니다."</string>
+ <string name="permlab_pkgUsageStats">"구성요소 사용 통계 업데이트"</string>
+ <string name="permdesc_pkgUsageStats">"수집된 구성요소 사용 통계를 수정할 수 있는 권한을 부여합니다. 일반 응용프로그램은 이 권한을 사용할 수 없습니다."</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
+</resources>
diff --git a/core/res/res/values-mcc204-ko/strings.xml b/core/res/res/values-mcc204-ko/strings.xml
new file mode 100644
index 0000000..7d96230
--- /dev/null
+++ b/core/res/res/values-mcc204-ko/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="locale_replacement">"nl_nl"</string>
+</resources>
diff --git a/core/res/res/values-mcc230-ko/strings.xml b/core/res/res/values-mcc230-ko/strings.xml
new file mode 100644
index 0000000..d3ecdbb
--- /dev/null
+++ b/core/res/res/values-mcc230-ko/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="locale_replacement">"cs_cz"</string>
+</resources>
diff --git a/core/res/res/values-mcc232-ko/strings.xml b/core/res/res/values-mcc232-ko/strings.xml
new file mode 100644
index 0000000..4773838
--- /dev/null
+++ b/core/res/res/values-mcc232-ko/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="locale_replacement">"de_at"</string>
+</resources>
diff --git a/core/res/res/values-mcc234-ko/strings.xml b/core/res/res/values-mcc234-ko/strings.xml
new file mode 100644
index 0000000..2538b73
--- /dev/null
+++ b/core/res/res/values-mcc234-ko/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="locale_replacement">"en_gb"</string>
+</resources>
diff --git a/core/res/res/values-mcc260-ko/strings.xml b/core/res/res/values-mcc260-ko/strings.xml
new file mode 100644
index 0000000..1161f9a
--- /dev/null
+++ b/core/res/res/values-mcc260-ko/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="locale_replacement">"pl_pl"</string>
+</resources>
diff --git a/core/res/res/values-mcc262-ko/strings.xml b/core/res/res/values-mcc262-ko/strings.xml
new file mode 100644
index 0000000..9505cf4
--- /dev/null
+++ b/core/res/res/values-mcc262-ko/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="locale_replacement">"de_de"</string>
+</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
new file mode 100644
index 0000000..c1944a4
--- /dev/null
+++ b/core/res/res/values-nb/strings.xml
@@ -0,0 +1,815 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="byteShort">"B"</string>
+ <string name="kilobyteShort">"kB"</string>
+ <string name="megabyteShort">"MB"</string>
+ <string name="gigabyteShort">"GB"</string>
+ <string name="terabyteShort">"TB"</string>
+ <string name="petabyteShort">"PB"</string>
+ <string name="untitled">"&lt;uten navn&gt;"</string>
+ <string name="ellipsis">"…"</string>
+ <string name="emptyPhoneNumber">"(Mangler telefonnummer)"</string>
+ <string name="unknownName">"(Ukjent)"</string>
+ <string name="defaultVoiceMailAlphaTag">"Telefonsvarer"</string>
+ <string name="defaultMsisdnAlphaTag">"MSISDN1"</string>
+ <string name="mmiError">"Tilkoblingsproblem eller ugyldig MMI-kode."</string>
+ <string name="serviceEnabled">"Tjenesten ble aktivert."</string>
+ <string name="serviceEnabledFor">"Tjenesten ble aktivert for:"</string>
+ <string name="serviceDisabled">"Tjenesten ble deaktivert."</string>
+ <string name="serviceRegistered">"Registreringen er vellykket."</string>
+ <string name="serviceErased">"Registreringen ble fjernet."</string>
+ <string name="passwordIncorrect">"Ugyldig passord."</string>
+ <string name="mmiComplete">"MMI utført."</string>
+ <string name="badPin">"Den gamle PIN-koden du skrev inn er feil."</string>
+ <string name="badPuk">"PUK-koden du skrev inn er feil."</string>
+ <string name="mismatchPin">"PIN-kodene stemmer ikke overens."</string>
+ <string name="invalidPin">"PIN-koden må være mellom fire og åtte siffer."</string>
+ <string name="needPuk">"SIM-kortet ditt er PUK-låst. Skriv inn PUK-koden for å låse det opp."</string>
+ <string name="needPuk2">"Skriv inn PUK2 for å låse opp SIM-kortet."</string>
+ <string name="ClipMmi">"Inngående nummervisning"</string>
+ <string name="ClirMmi">"Utgående nummervisning"</string>
+ <string name="CfMmi">"Viderekobling"</string>
+ <string name="CwMmi">"Samtale venter"</string>
+ <string name="BaMmi">"Samtaleblokkering"</string>
+ <string name="PwdMmi">"Passordbytte"</string>
+ <string name="PinMmi">"PIN-kode-bytte"</string>
+ <string name="CLIRDefaultOnNextCallOn">"Nummervisning er begrenset som standard. Neste anrop: Begrenset"</string>
+ <string name="CLIRDefaultOnNextCallOff">"Nummervisning er begrenset som standard. Neste anrop: Ikke begrenset"</string>
+ <string name="CLIRDefaultOffNextCallOn">"Nummervisning er ikke begrenset som standard. Neste anrop: Begrenset"</string>
+ <string name="CLIRDefaultOffNextCallOff">"Nummervisning er ikke begrenset som standard. Neste anrop: Ikke begrenset"</string>
+ <string name="serviceNotProvisioned">"SIM-kortet er ikke tilrettelagt for tjenesten."</string>
+ <string name="CLIRPermanent">"Kunne ikke endre innstilling for nummervisning."</string>
+ <string name="serviceClassVoice">"Tale"</string>
+ <string name="serviceClassData">"Data"</string>
+ <string name="serviceClassFAX">"Fax"</string>
+ <string name="serviceClassSMS">"SMS"</string>
+ <string name="serviceClassDataAsync">"Asynkron"</string>
+ <string name="serviceClassDataSync">"Synkron"</string>
+ <string name="serviceClassPacket">"Pakkedata"</string>
+ <string name="serviceClassPAD">"PAD"</string>
+ <string name="cfTemplateNotForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
+ <string name="cfTemplateForwarded">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> etter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
+ <string name="cfTemplateRegistered">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
+ <string name="cfTemplateRegisteredTime">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
+ <string name="httpErrorOk">"OK"</string>
+ <string name="httpError">"Nettsiden inneholder en feil."</string>
+ <string name="httpErrorLookup">"Kunne ikke finne adressen."</string>
+ <string name="httpErrorUnsupportedAuthScheme">"Støtter ikke sidens autentiseringsmetode."</string>
+ <string name="httpErrorAuth">"Autentiseringen feilet."</string>
+ <string name="httpErrorProxyAuth">"Autentisering via mellomtjeneren feilet."</string>
+ <string name="httpErrorConnect">"Kunne ikke koble til tjeneren."</string>
+ <string name="httpErrorIO">"Klarte ikke å kommunisere med tjeneren. Prøv igjen senere."</string>
+ <string name="httpErrorTimeout">"Det oppsto et tidsavbrudd under tilkobling til tjeneren."</string>
+ <string name="httpErrorRedirectLoop">"Siden inneholder for mange videresendinger."</string>
+ <string name="httpErrorUnsupportedScheme">"Protokollen er ikke støttet."</string>
+ <string name="httpErrorFailedSslHandshake">"Kunne ikke opprette en sikker tilkobling."</string>
+ <string name="httpErrorBadUrl">"Kunne ikke åpne siden, siden adressen er ugyldig."</string>
+ <string name="httpErrorFile">"Kunne ikke åpne filen."</string>
+ <string name="httpErrorFileNotFound">"Fant ikke den forespurte filen."</string>
+ <string name="httpErrorTooManyRequests">"For mange forespørsler blir behandlet. Prøv igjen senere."</string>
+ <string name="contentServiceSync">"Synkronisering"</string>
+ <string name="contentServiceSyncNotificationTitle">"Synkronisering"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc">"For mange slettinger av <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+ <string name="low_memory">"Telefonens lagringsminne er fullt! Slett noen filer for å frigjøre plass."</string>
+ <string name="me">"Meg"</string>
+ <string name="power_dialog">"Telefoninnstillinger"</string>
+ <string name="silent_mode">"Stillemodus"</string>
+ <string name="turn_on_radio">"Slå på trådløst nett"</string>
+ <string name="turn_off_radio">"Slå av trådløst nett"</string>
+ <string name="screen_lock">"Lås skjermen"</string>
+ <string name="power_off">"Slå av"</string>
+ <string name="shutdown_progress">"Avslutter…"</string>
+ <string name="shutdown_confirm">"Telefonen vil bli slått av."</string>
+ <string name="no_recent_tasks">"Ingen nylig brukte applikasjoner."</string>
+ <string name="global_actions">"Telefoninnstillinger"</string>
+ <string name="global_action_lock">"Lås skjermen"</string>
+ <string name="global_action_power_off">"Slå av"</string>
+ <string name="global_action_toggle_silent_mode">"Stillemodus"</string>
+ <string name="global_action_silent_mode_on_status">"Lyden er av"</string>
+ <string name="global_action_silent_mode_off_status">"Lyden er på"</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
+ <string name="safeMode">"Sikkermodus"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
+ <string name="permgrouplab_costMoney">"Betaltjenester"</string>
+ <string name="permgroupdesc_costMoney">"Lar applikasjoner utføre operasjoner som kan koste deg penger."</string>
+ <string name="permgrouplab_messages">"Meldinger"</string>
+ <string name="permgroupdesc_messages">"Lese og skrive SMS, e-post og andre meldinger på telefonen."</string>
+ <string name="permgrouplab_personalInfo">"Personlig informasjon"</string>
+ <string name="permgroupdesc_personalInfo">"Direkte tilgang til kontakter og kalendre lagret på telefonen."</string>
+ <string name="permgrouplab_location">"Plassering"</string>
+ <string name="permgroupdesc_location">"Overvåking av telefonens fysiske plassering"</string>
+ <string name="permgrouplab_network">"Nettverkstilgang"</string>
+ <string name="permgroupdesc_network">"Gir applikasjoner tilgang til diverse nettverksfunksjoner."</string>
+ <string name="permgrouplab_accounts">"Google-kontoer"</string>
+ <string name="permgroupdesc_accounts">"Tilgang til tilgjengelige Google-kontoer."</string>
+ <string name="permgrouplab_hardwareControls">"Maskinvarekontroll"</string>
+ <string name="permgroupdesc_hardwareControls">"Direkte tilgang til maskinvaren på telefonen."</string>
+ <string name="permgrouplab_phoneCalls">"Telefonsamtaler"</string>
+ <string name="permgroupdesc_phoneCalls">"Overvåk, ta opp, og behandle telefonsamtaler."</string>
+ <string name="permgrouplab_systemTools">"Systemverktøy"</string>
+ <string name="permgroupdesc_systemTools">"Lavnivå tilgang og kontroll over systemet."</string>
+ <string name="permgrouplab_developmentTools">"Utviklingsverktøy"</string>
+ <string name="permgroupdesc_developmentTools">"Funksjonalitet kun utviklere trenger."</string>
+ <string name="permlab_statusBar">"deaktivere eller endre statusfeltet"</string>
+ <string name="permdesc_statusBar">"Lar applikasjonen deaktivere statusfeltet, samt legge til og fjerne systemikoner."</string>
+ <string name="permlab_expandStatusBar">"utvide/slå sammen statusfeltet"</string>
+ <string name="permdesc_expandStatusBar">"Lar applikasjonen utvide eller slå sammen statusfeltet."</string>
+ <string name="permlab_processOutgoingCalls">"avskjære utgående anrop"</string>
+ <string name="permdesc_processOutgoingCalls">"Lar applikasjonen behandle utgående anrop og endre nummeret som ringes. Ondsinnede applikasjoner kan overvåke, videresende, eller hindre utgående anrop."</string>
+ <string name="permlab_receiveSms">"motta SMS"</string>
+ <string name="permdesc_receiveSms">"Lar applikasjonen motta og behandle SMS-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
+ <string name="permlab_receiveMms">"motta MMS"</string>
+ <string name="permdesc_receiveMms">"Lar applikasjonen motta og behandle MMS-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
+ <string name="permlab_sendSms">"sende SMS-meldinger"</string>
+ <string name="permdesc_sendSms">"Lar applikasjonen sende SMS-meldinger. Ondsinnede applikasjoner kan koste deg penger ved å sende meldinger uten bekreftelse."</string>
+ <string name="permlab_readSms">"lese SMS- og MMS-meldinger"</string>
+ <string name="permdesc_readSms">"Lar applikasjonen lese SMS-meldinger lagret i telefonen eller på SIM-kortet. Ondsinnede applikasjoner kan lese private meldinger."</string>
+ <string name="permlab_writeSms">"redigere SMS- og MMS-meldinger"</string>
+ <string name="permdesc_writeSms">"Lar applikasjonen skrive til SMS-meldinger lagret i telefonen eller på SIM-kortet. Ondsinnede applikasjoner kan slette meldinger."</string>
+ <string name="permlab_receiveWapPush">"motta WAP"</string>
+ <string name="permdesc_receiveWapPush">"Lar applikasjonen motta og behandle WAP-meldinger. Ondsinnede applikasjoner kan overvåke meldinger eller slette dem uten at de vises."</string>
+ <string name="permlab_getTasks">"se kjørende applikasjoner"</string>
+ <string name="permdesc_getTasks">"Tillater applikasjonen å hente informasjon om aktive og nylig kjørte programmer. Kan tillate ondsinnede applikasjoner å oppdage privat informasjon om andre applikasjoner."</string>
+ <string name="permlab_reorderTasks">"omordne kjørende applikasjoner"</string>
+ <string name="permdesc_reorderTasks">"Tillater applikasjonen å flytte programmer til forgrunnen eller bakgrunnen. Ondsinnede applikasjoner kan tvinge seg selv til fronten."</string>
+ <string name="permlab_setDebugApp">"aktiver applikasjonsdebugging"</string>
+ <string name="permdesc_setDebugApp">"Lar applikasjonen skru på debugging for en annen applikasjon. Ondsinnede applikasjoner kan bruke dette til å drepe andre applikasjoner."</string>
+ <string name="permlab_changeConfiguration">"endre innstillingene for brukergrensesnitt"</string>
+ <string name="permdesc_changeConfiguration">"Tillater applikasjonen å endre gjeldende innstillinger, slik som språk eller skriftstørrelse."</string>
+ <string name="permlab_restartPackages">"omstarte andre applikasjoner"</string>
+ <string name="permdesc_restartPackages">"Lar applikasjonen tvinge andre applikasjoner til å starte på nytt."</string>
+ <string name="permlab_setProcessForeground">"unngå å bli stoppet"</string>
+ <string name="permdesc_setProcessForeground">"Lar applikasjonen sette en vilkårlig prosess i forgrunnen, så den ikke kan bli drept. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_forceBack">"tvinge applikasjoner til å lukkes"</string>
+ <string name="permdesc_forceBack">"Lar applikasjonen tvinge enhver aktivitet som er i forgrunnen til å lukkes og gå tilbake. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_dump">"hente intern systemtilstand"</string>
+ <string name="permdesc_dump">"Lar applikasjonen hente intern tilstand fra systemet. Onsdinnede applikasjoner kan hente et bredt spekter av privat og sikker informasjon som de vanligvis aldri burde ha behov for."</string>
+ <string name="permlab_addSystemService">"publisere lavnivåtjenester"</string>
+ <string name="permdesc_addSystemService">"Lar applikasjonen publisere sine egne lavnivås systemtjenester. Ondsinnede applikasjoner kan kapre systemet, og stjele eller ødelegge alle data på det."</string>
+ <string name="permlab_runSetActivityWatcher">"overvåke og kontrollere all applikasjonsoppstart"</string>
+ <string name="permdesc_runSetActivityWatcher">"Lar applikasjonen overvåke og kontrollere hvordan systemet starter applikasjoner. Ondsinnede applikasjoner kan ta over systemet helt. Denne rettigheten behøves bare for utvikling, aldri for vanlig bruk av telefonen."</string>
+ <string name="permlab_broadcastPackageRemoved">"kringkaste melding om fjernet pakke"</string>
+ <string name="permdesc_broadcastPackageRemoved">"Lar applikasjonen kringkaste en melding om at en applikasjonspakke er blitt fjernet. Ondsinnede applikasjoner kan bruke dette til å drepe vilkårlige andre kjørende applikasjoner."</string>
+ <string name="permlab_broadcastSmsReceived">"kringkaste melding om mottatt SMS"</string>
+ <string name="permdesc_broadcastSmsReceived">"Lar applikasjonen kringkaste en melding om at en SMS-melding er mottatt. Ondsinnede applikasjoner kan bruke dette til å forfalske innkommende SMS-meldinger."</string>
+ <string name="permlab_broadcastWapPush">"kringkaste melding om mottatt WAP-PUSH"</string>
+ <string name="permdesc_broadcastWapPush">"Lar applikasjonen kringkaste en melding om at en WAP-PUSH-melding er blitt mottatt. Ondsinnede applikasjoner kan bruke dette for å forfalske MMS-kvitteringer eller i det stille erstatte innholdet av vilkårlige nettsider med ondsinnede varianter."</string>
+ <string name="permlab_setProcessLimit">"begrense antallet kjørende prosesser"</string>
+ <string name="permdesc_setProcessLimit">"Lar applikasjonen kontrollere maksimalt antall kjørende prosesser. Behøves aldri for vanlige applikasjoner."</string>
+ <string name="permlab_setAlwaysFinish">"få alle bakgrunnsapplikasjoner til å lukkes"</string>
+ <string name="permdesc_setAlwaysFinish">"Lar applikasjonen kontrollere om aktiviteter alltid avsluttes når de sendes til bakgrunnen. Behøves aldri for vanlige applikasjoner."</string>
+ <string name="permlab_fotaUpdate">"installere systemoppdateringer automatisk"</string>
+ <string name="permdesc_fotaUpdate">"Lar applikasjonen motta meldinger om pågående systemoppdateringer, og starte installeringen av dem. Ondsinnede applikasjoner kan bruke dette for å skade systemet med uautoriserte oppdateringer, eller generelt forstyrre oppdateringsprosessen."</string>
+ <string name="permlab_batteryStats">"endre batteristatistikk"</string>
+ <string name="permdesc_batteryStats">"Lar applikasjonen endre på innsamlet batteristatistikk. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_internalSystemWindow">"vis uautoriserte vinduer"</string>
+ <string name="permdesc_internalSystemWindow">"Tillater at det opprettes vinduer ment for bruk av systemets interne brukergrensesnitt. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_systemAlertWindow">"vise advarsler på systemnivå"</string>
+ <string name="permdesc_systemAlertWindow">"Lar applikasjonen vise systemadvarselvinduer. Ondsinnede applikasjoner kan ta over hele skjermen."</string>
+ <string name="permlab_setAnimationScale">"endre global animasjonshastighet"</string>
+ <string name="permdesc_setAnimationScale">"Lar applikasjonen endre den globale animasjonshastigheten (raskere eller tregere animasjoner) når som helst."</string>
+ <string name="permlab_manageAppTokens">"styre applikasjonssymboler"</string>
+ <string name="permdesc_manageAppTokens">"Lar applikasjoner lage og vedlikeholde sine egne symboler, noe som lar dem overstyre den vanlige Z-ordningen. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_injectEvents">"trykke taster og kontrolknapper"</string>
+ <string name="permdesc_injectEvents">"Lar applikasjonen levere sine egne inndatahendelser (tastetrykk osv.) til andre applikasjoner. Ondsinnede applikasjoner kan bruke dette for å ta over telefonen."</string>
+ <string name="permlab_readInputState">"ta opp hva som skrives og gjøres"</string>
+ <string name="permdesc_readInputState">"Lar applikasjonen overvåke tastetrykk selv når interaksjonen er med et annet program (som å skrive inn et passord). Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_bindInputMethod">"binde til en inndatametode"</string>
+ <string name="permdesc_bindInputMethod">"Lar applikasjonen binde til toppnivågrensesnittet for en inndatametode. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_setOrientation">"snu skjermen"</string>
+ <string name="permdesc_setOrientation">"Lar applikasjonen rotere skjermen når som helst. Vanlige applikasjoner bør aldri trenge dette."</string>
+ <string name="permlab_signalPersistentProcesses">"sende Linux-signaler til applikasjoner"</string>
+ <string name="permdesc_signalPersistentProcesses">"Lar applikasjonen spørre om at et gitt signal blir sendt til alle varige prosesser."</string>
+ <string name="permlab_persistentActivity">"forbli kjørende"</string>
+ <string name="permdesc_persistentActivity">"Lar applikasjonen gjøre deler av seg selv varig, så systemet ikke kan bruke det til andre applikasjoner."</string>
+ <string name="permlab_deletePackages">"slette applikasjoner"</string>
+ <string name="permdesc_deletePackages">"Lar applikasjonen slette Android-pakker. Ondsinnede applikasjoner kan bruke dette for å slette viktige applikasjoner."</string>
+ <string name="permlab_clearAppUserData">"slette andre applikasjoners data"</string>
+ <string name="permdesc_clearAppUserData">"Lar applikasjonen fjerne brukerdata."</string>
+ <string name="permlab_deleteCacheFiles">"slette andre applikasjoners hurtigbuffer"</string>
+ <string name="permdesc_deleteCacheFiles">"Lar applikasjonen to slette hurtigbufferfiler."</string>
+ <string name="permlab_getPackageSize">"måle lagringsplass for applikasjon"</string>
+ <string name="permdesc_getPackageSize">"Lar applikasjonen hente kode-, data- og hurtigbufferstørrelser"</string>
+ <string name="permlab_installPackages">"installere applikasjoner direkte"</string>
+ <string name="permdesc_installPackages">"Lar applikasjonen installere nye eller oppdaterte Android-pakker. Ondsinnede applikasjoner kan bruke dette for å legge til nye applikasjoner med vilkårlig kraftige rettigheter."</string>
+ <string name="permlab_clearAppCache">"slette hurtigbufferdata for alle applikasjoner"</string>
+ <string name="permdesc_clearAppCache">"Lar applikasjonen frigjøre lagringsplass ved å slette filer i applikasjoners hurtigbufferkatalog. Tilgangen er vanligvis sterkt begrenset, til systemprosesser."</string>
+ <string name="permlab_readLogs">"lese systemets loggfiler"</string>
+ <string name="permdesc_readLogs">"Lar applikasjonen to lese fra diverse loggfiler på systemet. Disse inneholder generell informasjon om hva som gjøres med telefonen, men skal ikke inneholde personlig eller privat informasjon."</string>
+ <string name="permlab_diagnostic">"lese/skrive ressurser eid av diag"</string>
+ <string name="permdesc_diagnostic">"Lar applikasjonen to lese og skrive enhver ressurs eid av gruppen diag; for eksempel, filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør KUN brukes for maskinvarespesifikke diagnoseverktøy laget av operatøren eller produsenten."</string>
+ <string name="permlab_changeComponentState">"aktivere eller deaktigere applikasjonskomponenter"</string>
+ <string name="permdesc_changeComponentState">"Lar applikasjonen endre om en komponent i en annen applikasjon er aktivert eller ikke. Ondsinnede applikasjoner kan bruke dette for å deaktivere viktige telefonfunksjoner. Denne rettigheten må brukes med forsiktighet, ettersom det er mulig å få applikasjonskomponenter inn i en ubrukelig, inkonsistent eller ustabil tilstand."</string>
+ <string name="permlab_setPreferredApplications">"velge foretrukne applikasjoner"</string>
+ <string name="permdesc_setPreferredApplications">"Lar applikasjonen endre valgene for foretrukne applikasjoner. Dette kan gi ondsinnede applikasjoner tilgang til i det stille å endre hvilke applikasjoner som kjøres, og slik gi seg ut for å være en eksisterende applikasjon og samle private data."</string>
+ <string name="permlab_writeSettings">"endre globale systeminnstillinger"</string>
+ <string name="permdesc_writeSettings">"Lar applikasjonen endre systemets innstillingsdata. Ondsinnede applikasjoner kan skade systemets innstillinger."</string>
+ <string name="permlab_writeSecureSettings">"endre sikre systeminnstillinger"</string>
+ <string name="permdesc_writeSecureSettings">"Lar applikasjonen endre systemets sikre innstillingsdata. Ikke ment for bruk av vanlige applikasjoner."</string>
+ <string name="permlab_writeGservices">"redigere Google-tjenestekartet"</string>
+ <string name="permdesc_writeGservices">"Lar applikasjonen redigere Google-tjenestekartet. Ikke ment for bruk av vanlige applikasjoner."</string>
+ <string name="permlab_receiveBootCompleted">"starte automatisk sammen med systemet"</string>
+ <string name="permdesc_receiveBootCompleted">"Lar applikasjonen sette opp at den selv skal starte så fort systemet er ferdig med å slå seg på. Dette kan gjøre at det tar lengre tid å starte telefonen, og at den kan bli tregere fordi applikasjonen alltid kjører."</string>
+ <string name="permlab_broadcastSticky">"sende varige kringkastinger"</string>
+ <string name="permdesc_broadcastSticky">"Lar applikasjonen sende varige kringkastinger, som forblir på systemet etter at kringkastingen er avsluttet. Ondsinnede applikasjoner kan gjøre telefonen treg eller ustabil ved å få den til å bruke for mye minne."</string>
+ <string name="permlab_readContacts">"lese kontaktinformasjon"</string>
+ <string name="permdesc_readContacts">"Lar applikasjonen lese all kontakt- og adresseinformasjon lagret på telefonen. Ondsinnede applikasjoner kan bruke dette for å sende personlige data til andre."</string>
+ <string name="permlab_writeContacts">"skrive kontaktinformasjon"</string>
+ <string name="permdesc_writeContacts">"Lar applikasjonen endre kontakt- og adresseinformasjon lagret på telefonen. Ondsinnede applikasjoner kan bruke dette for å redigere eller endre kontaktinformasjonen."</string>
+ <string name="permlab_writeOwnerData">"skrive eierinformasjon"</string>
+ <string name="permdesc_writeOwnerData">"Lar applikasjonen endre dataene om telefoneieren. Ondsinnede applikasjoner kan bruke dette til å slette eller redigere telefonens eierdata."</string>
+ <string name="permlab_readOwnerData">"lese eierinformasjon"</string>
+ <string name="permdesc_readOwnerData">"Lar applikasjonen lese dataene om telefoneieren. Ondsinnede applikasjoner kan bruke dette til å lese telefonens eierdata."</string>
+ <string name="permlab_readCalendar">"lese kalenderinformasjon"</string>
+ <string name="permdesc_readCalendar">"Lar applikasjonen lese alle kalenderhendelser lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å sende kalenderhendelser til andre."</string>
+ <string name="permlab_writeCalendar">"skrive kalenderinformasjon"</string>
+ <string name="permdesc_writeCalendar">"Lar applikasjonen endre kalenderhendelser lagret på telefonen. Ondsinnede applikasjoner kan bruke dette til å slette eller endre kalenderinformasjon."</string>
+ <string name="permlab_accessMockLocation">"lage falske plasseringskilder for testing"</string>
+ <string name="permdesc_accessMockLocation">"Lage falske plassingskilder for testing. Ondsinnede applikasjoner kan bruke dette for å overstyre plasseringen og/eller statusen rapportert av ekte plasseringskilder slik som GPS eller nettverksoperatører."</string>
+ <string name="permlab_accessLocationExtraCommands">"få tilgang til ekstra plasseringskommandoer"</string>
+ <string name="permdesc_accessLocationExtraCommands">"Få tilgang til ekstra kommandoer for plasseringskilder. Ondsinnede applikasjoner kan bruke dette til å forstyrre GPS eller andre plasseringskilder."</string>
+ <string name="permlab_accessFineLocation">"nøyaktig (GPS-) plassering"</string>
+ <string name="permdesc_accessFineLocation">"Få tilgang til nøyaktige plasseringskilder som Global Positioning System (GPS) på telefonen, når det er tilgjengelig. Ondsinnede applikasjoner kan bruke dette for å finne ut hvor du er, og kan bruke mer batteri."</string>
+ <string name="permlab_accessCoarseLocation">"grov (nettverksbasert) plassering"</string>
+ <string name="permdesc_accessCoarseLocation">"Få tilgang til grove plasseringskilder som databasen over basestasjoner for å finne ut omtrent hvor telefonen er, når det er tilgjengelig. Ondsinnede applikasjoner kan bruke dette for å finne ut omtrent hvor du er."</string>
+ <string name="permlab_accessSurfaceFlinger">"få tilgang til SurfaceFlinger"</string>
+ <string name="permdesc_accessSurfaceFlinger">"Lar applikasjonen bruke lavnivåfunksjonalitet i SurfaceFlinger."</string>
+ <string name="permlab_readFrameBuffer">"lese skjermbufferet"</string>
+ <string name="permdesc_readFrameBuffer">"Lar applikasjonen lese innholdet i skjermbufferet."</string>
+ <string name="permlab_modifyAudioSettings">"endre lydinnstillinger"</string>
+ <string name="permdesc_modifyAudioSettings">"Lar applikasjonen endre globale lydinnstillinger som volum og ruting."</string>
+ <string name="permlab_recordAudio">"ta opp lyd"</string>
+ <string name="permdesc_recordAudio">"Gir applikasjonen tilgang til opptaksstien for lyd."</string>
+ <string name="permlab_camera">"ta bilder"</string>
+ <string name="permdesc_camera">"Lar applikasjonen ta bilder med kameraet. Dette gir applikasjonen til når som helst å se og lagre det kameraet ser."</string>
+ <string name="permlab_brick">"deaktivere telefonen permanent"</string>
+ <string name="permdesc_brick">"Lar applikasjonen deaktivere hele telefonen permanent. Dette er svært farlig."</string>
+ <string name="permlab_reboot">"tvinge omstart av telefon"</string>
+ <string name="permdesc_reboot">"Lar applikasjonen tvinge telefonen til å starte på nytt."</string>
+ <string name="permlab_mount_unmount_filesystems">"montere og avmontere filsystemer"</string>
+ <string name="permdesc_mount_unmount_filesystems">"Lar applikasjonen montere og avmontere filsystemer for uttagbar lagring."</string>
+ <string name="permlab_mount_format_filesystems">"formatere ekstern lagringsplass"</string>
+ <string name="permdesc_mount_format_filesystems">"Lar applikasjonen formatere ekstern lagringsplass."</string>
+ <string name="permlab_vibrate">"kontrollere vibratoren"</string>
+ <string name="permdesc_vibrate">"Lar applikasjonen kontrollere vibratoren."</string>
+ <string name="permlab_flashlight">"kontrollere lommelykten"</string>
+ <string name="permdesc_flashlight">"Lar applikasjonen kontrollere lommelykten."</string>
+ <string name="permlab_hardware_test">"teste maskinvare"</string>
+ <string name="permdesc_hardware_test">"Lar applikasjonen styre diverse enheter med det formål å teste maskinvaren."</string>
+ <string name="permlab_callPhone">"ringe telefonnummer direkte"</string>
+ <string name="permdesc_callPhone">"Lar applikasjonen ringe telefonnummer uten inngripen fra brukeren. Ondsinnede applikasjoner kan forårsake uventede oppringinger på telefonregningen. Merk at dette ikke gir applikasjonen lov til å ringe nødnummer."</string>
+ <string name="permlab_callPrivileged">"ringe vilkårlige telefonnummer direkte"</string>
+ <string name="permdesc_callPrivileged">"Lar applikasjonen ringe hvilket som helst telefonnummer, inkludert nødnummer, uten inngripen fra brukeren. Ondsinnede applikasjoner kan forårsake unødvendige og ulovlige samtaler til nødtjenester."</string>
+ <string name="permlab_locationUpdates">"kontrollere varsling for plasseringsendring"</string>
+ <string name="permdesc_locationUpdates">"Lar applikasjonen slå av/på varsling om plasseringsendringer fra radioen. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_checkinProperties">"få tilgang til egenskaper for innsjekking"</string>
+ <string name="permdesc_checkinProperties">"Gir lese- og skrivetilgang til egenskaper lastet opp av innsjekkingstjenesten. Ikke ment for vanlige applikasjoner."</string>
+ <string name="permlab_bindGadget">"velg gadgeter"</string>
+ <string name="permdesc_bindGadget">"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."</string>
+ <string name="permlab_modifyPhoneState">"endre telefontilstand"</string>
+ <string name="permdesc_modifyPhoneState">"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."</string>
+ <string name="permlab_readPhoneState">"lese telefontilstand"</string>
+ <string name="permdesc_readPhoneState">"Lar applikasjonen få tilgang til telefonfunksjonaliteten i enheten. En applikasjon med denne rettigheten kan få vite enhetens telefonnummer, om en samtale pågår, nummeret samtalen er koblet til og lignende."</string>
+ <string name="permlab_wakeLock">"forhindre telefonen fra å sove"</string>
+ <string name="permdesc_wakeLock">"Lar applikasjonen forhindre telefonen fra å gå i hvilemodus."</string>
+ <string name="permlab_devicePower">"slå telefonen av eller på"</string>
+ <string name="permdesc_devicePower">"Lar applikasjonen skru telefonen av eller på."</string>
+ <string name="permlab_factoryTest">"kjøre i fabrikktestmodus"</string>
+ <string name="permdesc_factoryTest">"Kjøre som en lavnivås produsenttest, med full tilgang til telefonens maskinvare. Kun tilgjengelig når telefonen kjører i produsenttestmodus."</string>
+ <string name="permlab_setWallpaper">"endre bakgrunnsbilde"</string>
+ <string name="permdesc_setWallpaper">"Lar applikasjonen sette systemets bakgrunnsbilde."</string>
+ <string name="permlab_setWallpaperHints">"sette størrelseshint for bakgrunn"</string>
+ <string name="permdesc_setWallpaperHints">"Lar applikasjonen sette størrelseshint for systemets bakgrunnsbilde."</string>
+ <string name="permlab_masterClear">"nullstille systemet til fabrikkinnstillinger"</string>
+ <string name="permdesc_masterClear">"Lar applikasjonen nullstille systemet til fabrikkinnstillinger, noe som vil fjerne alle data, alt oppsett, og alle installerte applikasjoner."</string>
+ <string name="permlab_setTimeZone">"endre tidssone"</string>
+ <string name="permdesc_setTimeZone">"Lar applikasjonen endre telefonens tidssone."</string>
+ <string name="permlab_getAccounts">"oppdage kjente kontoer"</string>
+ <string name="permdesc_getAccounts">"Lar applikasjonen hente listen over kontoer telefonen kjenner til."</string>
+ <string name="permlab_accessNetworkState">"se nettverkstilstand"</string>
+ <string name="permdesc_accessNetworkState">"Lar applikasjonen se tilstanden til alle nettverk."</string>
+ <string name="permlab_createNetworkSockets">"full internett-tilgang"</string>
+ <string name="permdesc_createNetworkSockets">"Lar applikasjonen opprette vilkårlige nettverkstilkoblinger."</string>
+ <string name="permlab_writeApnSettings">"skrive APN-innstillinger"</string>
+ <string name="permdesc_writeApnSettings">"Lar applikasjonen to endre APN-innstillinger slik som mellomtjener eller port for hvilket som helst aksesspunkt."</string>
+ <string name="permlab_changeNetworkState">"endre nettverkskonnektivitet"</string>
+ <string name="permdesc_changeNetworkState">"Lar applikasjonen endre tilstanden til nettverkskonnektivitet."</string>
+ <string name="permlab_changeBackgroundDataSetting">"endre innstilling for bakgrunnsdata"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Lar applikasjonen endre innstillingen for bakgrunnsdata."</string>
+ <string name="permlab_accessWifiState">"se tilstand for trådløse nettverk"</string>
+ <string name="permdesc_accessWifiState">"Lar applikasjonen få se informasjon om tilstanden til de trådløse nettene."</string>
+ <string name="permlab_changeWifiState">"endre tilstand for trådløse nettverk"</string>
+ <string name="permdesc_changeWifiState">"Lar applikasjonen koble til og fra trådløse aksesspunkt, og å gjøre endringer i konfigurerte trådløse nettverk."</string>
+ <string name="permlab_bluetoothAdmin">"Bluetooth-administrasjon"</string>
+ <string name="permdesc_bluetoothAdmin">"Lar applikasjonen konfigurere den lokale Bluetooth-telefonen, og å oppdage og pare med andre enheter."</string>
+ <string name="permlab_bluetooth">"opprette Bluetooth-tilkoblinger"</string>
+ <string name="permdesc_bluetooth">"Lar applikasjonen se konfigurasjonen til den lokale Bluetooth-telefonen, og å opprette og godta tilkoblinger med parede enheter."</string>
+ <string name="permlab_disableKeyguard">"slå av tastaturlås"</string>
+ <string name="permdesc_disableKeyguard">"Lar applikasjonen slå av tastaturlåsen og enhver tilknyttet passordsikkerhet. Et legitimt eksempel på dette er at telefonen slår av tastaturlåsen når den mottar et innkommende anrop, og så slår den på igjen når samtalen er over."</string>
+ <string name="permlab_readSyncSettings">"lese synkroniseringsinnstillinger"</string>
+ <string name="permdesc_readSyncSettings">"Lar applikasjonen lese synkroniseringsinnstillingene, som for eksempel om kontakter blir synkronisert."</string>
+ <string name="permlab_writeSyncSettings">"skrive synkroniseringsinnstillinger"</string>
+ <string name="permdesc_writeSyncSettings">"Lar applikasjonen to endre på synkroniseringsinnstillingene, som for eksempel om kontakter blir synkronisert."</string>
+ <string name="permlab_readSyncStats">"lese synkroniseringsstatistikk"</string>
+ <string name="permdesc_readSyncStats">"Lar applikasjonen lese synkroniseringsstatistikk, som for eksempel historien over alle synkroniseringer utført."</string>
+ <string name="permlab_subscribedFeedsRead">"lese abonnement på nyhetskilder"</string>
+ <string name="permdesc_subscribedFeedsRead">"Lar applikasjonen hente detaljer om hvilke nyhetskilder som synkroniseres."</string>
+ <string name="permlab_subscribedFeedsWrite">"endre abonnement på nyhetskilder"</string>
+ <string name="permdesc_subscribedFeedsWrite">"Lar applikasjonen redigere hvilke nyhetskilder som synkroniseres. Dette kan gi en ondsinnet applikasjon tilgang til å endre hvilke nyhetskilder som synkroniseres."</string>
+ <string name="permlab_readDictionary">"lese brukerdefinert ordliste"</string>
+ <string name="permdesc_readDictionary">"Lar applikasjonen lese private ord, navn og uttrykk som brukeren har lagret i den brukerdefinerte ordlisten."</string>
+ <string name="permlab_writeDictionary">"skrive til brukerdefinert ordliste"</string>
+ <string name="permdesc_writeDictionary">"Lar applikasjonen skrive nye ord til den brukerdefinerte ordlisten."</string>
+ <string-array name="phoneTypes">
+ <item>"Hjemme"</item>
+ <item>"Mobil"</item>
+ <item>"Arbeid"</item>
+ <item>"Faks arbeid"</item>
+ <item>"Faks hjemme"</item>
+ <item>"Personsøker"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
+ </string-array>
+ <string-array name="emailAddressTypes">
+ <item>"Hjemme"</item>
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
+ </string-array>
+ <string-array name="postalAddressTypes">
+ <item>"Hjemme"</item>
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
+ </string-array>
+ <string-array name="imAddressTypes">
+ <item>"Hjemme"</item>
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
+ </string-array>
+ <string-array name="organizationTypes">
+ <item>"Arbeid"</item>
+ <item>"Annen"</item>
+ <item>"Egendefinert…"</item>
+ </string-array>
+ <string-array name="imProtocols">
+ <item>"AIM"</item>
+ <item>"Windows Live"</item>
+ <item>"Yahoo"</item>
+ <item>"Skype"</item>
+ <item>"QQ"</item>
+ <item>"Google Talk"</item>
+ <item>"ICQ"</item>
+ <item>"Jabber"</item>
+ </string-array>
+ <string name="keyguard_password_enter_pin_code">"Skriv inn PIN-kode:"</string>
+ <string name="keyguard_password_wrong_pin_code">"Gal PIN-kode!"</string>
+ <string name="keyguard_label_text">"For å låse opp, trykk menuknappen fulgt av 0."</string>
+ <string name="emergency_call_dialog_number_for_display">"Nødnummer"</string>
+ <string name="lockscreen_carrier_default">"(Ingen operatør)"</string>
+ <string name="lockscreen_screen_locked">"Skjermen er låst"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Trykk på menyknappen for å låse opp eller ringe et nødnummer."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Trykk på menyknappen for å låse opp."</string>
+ <string name="lockscreen_pattern_instructions">"Tegn mønster for å låse opp"</string>
+ <string name="lockscreen_emergency_call">"Nødanrop"</string>
+ <string name="lockscreen_pattern_correct">"Riktig!"</string>
+ <string name="lockscreen_pattern_wrong">"Beklager, prøv igjen:"</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
+ <string name="lockscreen_low_battery">"Koble til en batterilader."</string>
+ <string name="lockscreen_missing_sim_message_short">"Mangler SIM-kort."</string>
+ <string name="lockscreen_missing_sim_message">"Ikke noe SIM-kort i telefonen."</string>
+ <string name="lockscreen_missing_sim_instructions">"Sett inn et SIM-kort."</string>
+ <string name="lockscreen_network_locked_message">"Nettverk ikke tillatt"</string>
+ <string name="lockscreen_sim_puk_locked_message">"SIM-kortet er PUK-låst."</string>
+ <string name="lockscreen_sim_puk_locked_instructions">"Vennligst ring kundeservice."</string>
+ <string name="lockscreen_sim_locked_message">"SIM-kortet er låst."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"Låser opp SIM-kort…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown">"Prøv igjen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+ <string name="lockscreen_forgot_pattern_button_text">"Glemt mønsteret?"</string>
+ <string name="lockscreen_glogin_too_many_attempts">"Too many pattern attempts!"</string>
+ <string name="lockscreen_glogin_instructions">"To unlock,"\n"sign in with your Google account"</string>
+ <string name="lockscreen_glogin_username_hint">"Username (email)"</string>
+ <string name="lockscreen_glogin_password_hint">"Password"</string>
+ <string name="lockscreen_glogin_submit_button">"Sign in"</string>
+ <string name="lockscreen_glogin_invalid_input">"Invalid username or password."</string>
+ <string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
+ <string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
+ <string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
+ <skip />
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
+ <skip />
+ <string name="status_bar_clear_all_button">"Fjern varslinger"</string>
+ <string name="status_bar_no_notifications_title">"Ingen varslinger"</string>
+ <string name="status_bar_ongoing_events_title">"Aktiviteter"</string>
+ <string name="status_bar_latest_events_title">"Varslinger"</string>
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
+ <skip />
+ <string name="battery_status_charging">"Lader…"</string>
+ <string name="battery_low_title">"Koble til en lader"</string>
+ <string name="battery_low_subtitle">"Batteriet er nesten tomt:"</string>
+ <string name="battery_low_percent_format">"mindre enn <xliff:g id="NUMBER">%d%%</xliff:g> igjen."</string>
+ <string name="factorytest_failed">"Factory test failed"</string>
+ <string name="factorytest_not_system">"The FACTORY_TEST action is only supported for packages installed in /system/app."</string>
+ <string name="factorytest_no_action">"No package was found that provides the FACTORY_TEST action."</string>
+ <string name="factorytest_reboot">"Reboot"</string>
+ <string name="js_dialog_title">"Siden \'<xliff:g id="TITLE">%s</xliff:g> sier:\""</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Naviger bort fra denne siden?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Velg OK for å fortsette, eller Avbryt for å forbli på denne siden."</string>
+ <string name="save_password_label">"Bekreft"</string>
+ <string name="save_password_message">"Ønsker du at nettleseren skal huske dette passordet?"</string>
+ <string name="save_password_notnow">"Ikke nå"</string>
+ <string name="save_password_remember">"Husk"</string>
+ <string name="save_password_never">"Aldri"</string>
+ <string name="open_permission_deny">"Du har ikke de nødvendige rettighetene til å åpne denne siden."</string>
+ <string name="text_copied">"Kopierte tekst til utklippstavlen."</string>
+ <string name="more_item_label">"Mer"</string>
+ <string name="prepend_shortcut_label">"menyknapp+"</string>
+ <string name="menu_space_shortcut_label">"mellomrom"</string>
+ <string name="menu_enter_shortcut_label">"enter"</string>
+ <string name="menu_delete_shortcut_label">"slett"</string>
+ <string name="search_go">"Søk"</string>
+ <string name="today">"I dag"</string>
+ <string name="yesterday">"I går"</string>
+ <string name="tomorrow">"I morgen"</string>
+ <string name="oneMonthDurationPast">"For en måned siden"</string>
+ <string name="beforeOneMonthDurationPast">"For over en måned siden"</string>
+ <plurals name="num_seconds_ago">
+ <item quantity="one">"for et sekund siden"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> sekunder siden"</item>
+ </plurals>
+ <plurals name="num_minutes_ago">
+ <item quantity="one">"for et minutt siden"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> minutter siden"</item>
+ </plurals>
+ <plurals name="num_hours_ago">
+ <item quantity="one">"for en time siden"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> timer siden"</item>
+ </plurals>
+ <plurals name="num_days_ago">
+ <item quantity="one">"i går"</item>
+ <item quantity="other">"for <xliff:g id="COUNT">%d</xliff:g> dager siden"</item>
+ </plurals>
+ <plurals name="in_num_seconds">
+ <item quantity="one">"om et sekund"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sekunder"</item>
+ </plurals>
+ <plurals name="in_num_minutes">
+ <item quantity="one">"om et minutt"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> minutter"</item>
+ </plurals>
+ <plurals name="in_num_hours">
+ <item quantity="one">"om et minutt"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> timer"</item>
+ </plurals>
+ <plurals name="in_num_days">
+ <item quantity="one">"i morgen"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> dager"</item>
+ </plurals>
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"1 sek siden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> sek siden"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"1 min siden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> min siden"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"1 t siden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> t siden"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"i går"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> d siden"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"om 1 sek"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> sek"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"om 1 min"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"om 1 t"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> t"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"i morgen"</item>
+ <item quantity="other">"om <xliff:g id="COUNT">%d</xliff:g> d"</item>
+ </plurals>
+ <string name="preposition_for_date">"%s"</string>
+ <string name="preposition_for_time">"%s"</string>
+ <string name="preposition_for_year">"%s"</string>
+ <string name="day">"dag"</string>
+ <string name="days">"dager"</string>
+ <string name="hour">"time"</string>
+ <string name="hours">"timer"</string>
+ <string name="minute">"min"</string>
+ <string name="minutes">"min"</string>
+ <string name="second">"s"</string>
+ <string name="seconds">"s"</string>
+ <string name="week">"uke"</string>
+ <string name="weeks">"uker"</string>
+ <string name="year">"år"</string>
+ <string name="years">"år"</string>
+ <string name="sunday">"søndag"</string>
+ <string name="monday">"mandag"</string>
+ <string name="tuesday">"tirsdag"</string>
+ <string name="wednesday">"onsdag"</string>
+ <string name="thursday">"torsdag"</string>
+ <string name="friday">"fredag"</string>
+ <string name="saturday">"lørdag"</string>
+ <string name="every_weekday">"Hverdager (man–fre)"</string>
+ <string name="daily">"Hver dag"</string>
+ <string name="weekly">"Hver <xliff:g id="DAY">%s</xliff:g>"</string>
+ <string name="monthly">"En gang i måneden"</string>
+ <string name="yearly">"En gang i året"</string>
+ <string name="VideoView_error_title">"Cannot play video"</string>
+ <string name="VideoView_error_text_unknown">"Sorry, this video cannot be played."</string>
+ <string name="VideoView_error_button">"OK"</string>
+ <string name="am">"AM"</string>
+ <string name="pm">"PM"</string>
+ <string name="numeric_date">"<xliff:g id="YEAR">%Y</xliff:g>-<xliff:g id="MONTH">%m</xliff:g>-<xliff:g id="DAY">%d</xliff:g>"</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DATE1">%2$s</xliff:g> <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g> <xliff:g id="DATE2">%5$s</xliff:g> <xliff:g id="TIME2">%6$s</xliff:g>"</string>
+ <string name="wday1_date1_wday2_date2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%4$s</xliff:g> <xliff:g id="DATE2">%5$s</xliff:g>"</string>
+ <string name="date1_time1_date2_time2">"<xliff:g id="DATE1">%2$s</xliff:g> <xliff:g id="TIME1">%3$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g> <xliff:g id="TIME2">%6$s</xliff:g>"</string>
+ <string name="date1_date2">"<xliff:g id="DATE1">%2$s</xliff:g> – <xliff:g id="DATE2">%5$s</xliff:g>"</string>
+ <string name="time1_time2">"<xliff:g id="TIME1">%1$s</xliff:g> – <xliff:g id="TIME2">%2$s</xliff:g>"</string>
+ <string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g> <xliff:g id="DATE">%3$s</xliff:g>"</string>
+ <string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g> <xliff:g id="DATE">%3$s</xliff:g>PLACEHOLDERplaceholder"</string>
+ <string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>'., '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>'. '<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>'. '<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="noon">"middag"</string>
+ <string name="Noon">"Middag"</string>
+ <string name="midnight">"midnatt"</string>
+ <string name="Midnight">"Midnatt"</string>
+ <!-- no translation found for month_day (3693060561170538204) -->
+ <skip />
+ <!-- no translation found for month (1976700695144952053) -->
+ <skip />
+ <string name="month_day_year">"<xliff:g id="DAY">%-d</xliff:g>. <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
+ <!-- no translation found for month_year (2106203387378728384) -->
+ <skip />
+ <string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
+ <string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="DAY">%-d</xliff:g>. <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
+ <string name="same_year_md1_md2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>"</string>
+ <string name="same_year_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+ <string name="same_year_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR">%9$s</xliff:g>"</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR">%9$s</xliff:g>"</string>
+ <string name="same_year_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>. – <xliff:g id="DAY2">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>."</string>
+ <string name="numeric_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>. – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>."</string>
+ <string name="numeric_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>.<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>.<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>.<xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>.<xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+ <string name="numeric_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>. <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>. <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>. <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>. <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>.<xliff:g id="YEAR1">%4$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>.<xliff:g id="YEAR2">%9$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>.<xliff:g id="MONTH1">%2$s</xliff:g>.<xliff:g id="YEAR1">%4$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>.<xliff:g id="MONTH2">%7$s</xliff:g>.<xliff:g id="YEAR2">%9$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_md1_md2">"<xliff:g id="DAY1">%3$s</xliff:g>.–<xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g>"</string>
+ <string name="same_month_wday1_md1_wday2_md2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g>"</string>
+ <string name="same_month_mdy1_mdy2">"<xliff:g id="DAY1">%3$s</xliff:g>.–<xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>"</string>
+ <string name="same_month_md1_time1_md2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>. <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>. <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
+ <string name="abbrev_month_day_year">"<xliff:g id="DAY">%-d</xliff:g>. <xliff:g id="MONTH">%b</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
+ <skip />
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
+ <skip />
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
+ <skip />
+ <string name="day_of_week_long_sunday">"søndag"</string>
+ <string name="day_of_week_long_monday">"mandag"</string>
+ <string name="day_of_week_long_tuesday">"tirsdag"</string>
+ <string name="day_of_week_long_wednesday">"onsdag"</string>
+ <string name="day_of_week_long_thursday">"torsdag"</string>
+ <string name="day_of_week_long_friday">"fredag"</string>
+ <string name="day_of_week_long_saturday">"lørdag"</string>
+ <string name="day_of_week_medium_sunday">"søn"</string>
+ <string name="day_of_week_medium_monday">"man"</string>
+ <string name="day_of_week_medium_tuesday">"tir"</string>
+ <string name="day_of_week_medium_wednesday">"ons"</string>
+ <string name="day_of_week_medium_thursday">"tor"</string>
+ <string name="day_of_week_medium_friday">"fre"</string>
+ <string name="day_of_week_medium_saturday">"lør"</string>
+ <string name="day_of_week_short_sunday">"sø"</string>
+ <string name="day_of_week_short_monday">"ma"</string>
+ <string name="day_of_week_short_tuesday">"ti"</string>
+ <string name="day_of_week_short_wednesday">"on"</string>
+ <string name="day_of_week_short_thursday">"to"</string>
+ <string name="day_of_week_short_friday">"fr"</string>
+ <string name="day_of_week_short_saturday">"lø"</string>
+ <string name="day_of_week_shorter_sunday">"S"</string>
+ <string name="day_of_week_shorter_monday">"M"</string>
+ <string name="day_of_week_shorter_tuesday">"Ti"</string>
+ <string name="day_of_week_shorter_wednesday">"O"</string>
+ <string name="day_of_week_shorter_thursday">"To"</string>
+ <string name="day_of_week_shorter_friday">"F"</string>
+ <string name="day_of_week_shorter_saturday">"L"</string>
+ <string name="day_of_week_shortest_sunday">"S"</string>
+ <string name="day_of_week_shortest_monday">"M"</string>
+ <string name="day_of_week_shortest_tuesday">"T"</string>
+ <string name="day_of_week_shortest_wednesday">"O"</string>
+ <string name="day_of_week_shortest_thursday">"T"</string>
+ <string name="day_of_week_shortest_friday">"F"</string>
+ <string name="day_of_week_shortest_saturday">"L"</string>
+ <string name="month_long_january">"januar"</string>
+ <string name="month_long_february">"februar"</string>
+ <string name="month_long_march">"mars"</string>
+ <string name="month_long_april">"april"</string>
+ <string name="month_long_may">"mai"</string>
+ <string name="month_long_june">"juni"</string>
+ <string name="month_long_july">"juli"</string>
+ <string name="month_long_august">"august"</string>
+ <string name="month_long_september">"september"</string>
+ <string name="month_long_october">"oktober"</string>
+ <string name="month_long_november">"november"</string>
+ <string name="month_long_december">"desember"</string>
+ <string name="month_medium_january">"jan"</string>
+ <string name="month_medium_february">"feb"</string>
+ <string name="month_medium_march">"mar"</string>
+ <string name="month_medium_april">"apr"</string>
+ <string name="month_medium_may">"mai"</string>
+ <string name="month_medium_june">"jun"</string>
+ <string name="month_medium_july">"jul"</string>
+ <string name="month_medium_august">"aug"</string>
+ <string name="month_medium_september">"sep"</string>
+ <string name="month_medium_october">"okt"</string>
+ <string name="month_medium_november">"nov"</string>
+ <string name="month_medium_december">"des"</string>
+ <string name="month_shortest_january">"J"</string>
+ <string name="month_shortest_february">"F"</string>
+ <string name="month_shortest_march">"M"</string>
+ <string name="month_shortest_april">"A"</string>
+ <string name="month_shortest_may">"M"</string>
+ <string name="month_shortest_june">"J"</string>
+ <string name="month_shortest_july">"J"</string>
+ <string name="month_shortest_august">"A"</string>
+ <string name="month_shortest_september">"S"</string>
+ <string name="month_shortest_october">"O"</string>
+ <string name="month_shortest_november">"N"</string>
+ <string name="month_shortest_december">"D"</string>
+ <string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll">"Merk alt"</string>
+ <string name="selectText">"Merk tekst"</string>
+ <string name="stopSelectingText">"Slutt å merke tekst"</string>
+ <string name="cut">"Klipp ut"</string>
+ <string name="cutAll">"Klipp ut alt"</string>
+ <string name="copy">"Kopier"</string>
+ <string name="copyAll">"Kopier alt"</string>
+ <string name="paste">"Lim inn"</string>
+ <string name="copyUrl">"Kopier URL"</string>
+ <string name="inputMethod">"Inndatametode"</string>
+ <string name="addToDictionary">"Legg \\\"%s\\\" til ordlisten"</string>
+ <string name="editTextMenuTitle">"Rediger tekst"</string>
+ <string name="low_internal_storage_view_title">"Lite plass"</string>
+ <string name="low_internal_storage_view_text">"Det begynner å bli lite lagringsplass på telefonen."</string>
+ <string name="ok">"OK"</string>
+ <string name="cancel">"Avbryt"</string>
+ <string name="yes">"OK"</string>
+ <string name="no">"Avbryt"</string>
+ <string name="dialog_alert_title">"Merk"</string>
+ <string name="capital_on">"På"</string>
+ <string name="capital_off">"Av"</string>
+ <string name="whichApplication">"Complete action using"</string>
+ <string name="alwaysUse">"Use by default for this action."</string>
+ <string name="clearDefaultHintMsg">"Clear default in Home Settings &gt; Applications &gt; Manage applications."</string>
+ <string name="chooseActivity">"Select an action"</string>
+ <string name="noApplications">"No applications can perform this action."</string>
+ <string name="aerr_title">"Sorry!"</string>
+ <string name="aerr_application">"The application <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has stopped unexpectedly. Please try again."</string>
+ <string name="aerr_process">"The process <xliff:g id="PROCESS">%1$s</xliff:g> has stopped unexpectedly. Please try again."</string>
+ <string name="anr_title">"Sorry!"</string>
+ <string name="anr_activity_application">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in application <xliff:g id="APPLICATION">%2$s</xliff:g>) is not responding."</string>
+ <string name="anr_activity_process">"Activity <xliff:g id="ACTIVITY">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
+ <string name="anr_application_process">"Application <xliff:g id="APPLICATION">%1$s</xliff:g> (in process <xliff:g id="PROCESS">%2$s</xliff:g>) is not responding."</string>
+ <string name="anr_process">"Process <xliff:g id="PROCESS">%1$s</xliff:g> is not responding."</string>
+ <string name="force_close">"Force close"</string>
+ <string name="wait">"Wait"</string>
+ <string name="debug">"Debug"</string>
+ <string name="sendText">"Select an action for text"</string>
+ <string name="volume_ringtone">"Ringetonevolum"</string>
+ <string name="volume_music">"Medievolum"</string>
+ <string name="volume_music_hint_playing_through_bluetooth">"Spiller over Bluetooth"</string>
+ <string name="volume_call">"Samtalevolum"</string>
+ <string name="volume_bluetooth_call">"Bluetooth-samtalevolum"</string>
+ <string name="volume_alarm">"Alarmvolum"</string>
+ <string name="volume_notification">"Varslingsvolum"</string>
+ <string name="volume_unknown">"Volum"</string>
+ <string name="ringtone_default">"Standard ringetone"</string>
+ <string name="ringtone_default_with_actual">"Standard ringetone (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent">"Stille"</string>
+ <string name="ringtone_picker_title">"Ringetoner"</string>
+ <string name="ringtone_unknown">"Ukjent ringetone"</string>
+ <plurals name="wifi_available">
+ <item quantity="one">"Trådløsnett i nærheten"</item>
+ <item quantity="other">"Trådløsnett i nærheten"</item>
+ </plurals>
+ <plurals name="wifi_available_detailed">
+ <item quantity="one">"Åpent trådløsnett i nærheten"</item>
+ <item quantity="other">"Åpne trådløsnett i nærheten"</item>
+ </plurals>
+ <string name="select_character">"Sett inn tegn"</string>
+ <string name="sms_control_default_app_name">"Ukjent applikasjon"</string>
+ <string name="sms_control_title">"Sending SMS messages"</string>
+ <string name="sms_control_message">"A large number of SMS messages are being sent. Select \"OK\" to continue, or \"Cancel\" to stop sending."</string>
+ <string name="sms_control_yes">"OK"</string>
+ <string name="sms_control_no">"Avbryt"</string>
+ <string name="date_time_set">"Lagre"</string>
+ <string name="default_permission_group">"Standard"</string>
+ <string name="no_permissions">"Trenger ingen rettigheter"</string>
+ <string name="perms_hide"><b>"Skjul"</b></string>
+ <string name="perms_show_all"><b>"Vis alle"</b></string>
+ <string name="googlewebcontenthelper_loading">"Laster inn…"</string>
+ <string name="usb_storage_title">"USB koblet til"</string>
+ <string name="usb_storage_message">"Du har koblet telefonen til en datamaskin via USB. Velg \"Monter\" dersom du ønsker å kopiere filer mellom datmaskinen og minnekortet i telefonen."</string>
+ <string name="usb_storage_button_mount">"Monter"</string>
+ <string name="usb_storage_button_unmount">"Ikke monter"</string>
+ <string name="usb_storage_error_message">"Det oppsto et problem med å bruke minnekortet ditt for USB-lagring."</string>
+ <string name="usb_storage_notification_title">"USB tilkoblet"</string>
+ <string name="usb_storage_notification_message">"Velg om du ønsker å kopiere filer til/fra en datamaskin."</string>
+ <string name="usb_storage_stop_notification_title">"Slå av USB-lagring"</string>
+ <string name="usb_storage_stop_notification_message">"Velg for å slå av USB-lagring."</string>
+ <string name="usb_storage_stop_title">"Slå av USB-lagring"</string>
+ <string name="usb_storage_stop_message">"Før du slår av USB-lagring, sjekk at du har avmontert enheten i USB-verten. Velg «slå av» for å slå av USB-lagring."</string>
+ <string name="usb_storage_stop_button_mount">"Slå av"</string>
+ <string name="usb_storage_stop_button_unmount">"Avbryt"</string>
+ <string name="usb_storage_stop_error_message">"Det oppsto et problem under avslutningen av USB-lagring. Sjekk at USB-verten har avmontert og prøv igjen."</string>
+ <string name="extmedia_format_title">"Formatere minnekort"</string>
+ <string name="extmedia_format_message">"Er du sikker på at du ønsker å formatere minnekortet? Alle data på kortet vil gå tapt."</string>
+ <string name="extmedia_format_button_format">"Format"</string>
+ <string name="select_input_method">"Velg inndatametode"</string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
+ <string name="candidates_style">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
+ <string name="ext_media_checking_notification_title">"Forbereder minnekort"</string>
+ <string name="ext_media_checking_notification_message">"Sjekker for feil"</string>
+ <string name="ext_media_nofs_notification_title">"Tomt minnekort"</string>
+ <string name="ext_media_nofs_notification_message">"Minnekortet er tomt eller bruker et ustøttet filsystem."</string>
+ <string name="ext_media_unmountable_notification_title">"Skadet minnekort"</string>
+ <string name="ext_media_unmountable_notification_message">"Minnekortet er skadet. Det kan være du må formatere kortet."</string>
+ <string name="ext_media_badremoval_notification_title">"Minnekortet ble tatt ut uventet"</string>
+ <string name="ext_media_badremoval_notification_message">"Avmonter minnekortet før det tas ut, for å unngå datatap."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Trygt å ta ut minnekort"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Minnekortet kan nå trygt tas ut."</string>
+ <string name="ext_media_nomedia_notification_title">"Minnekortet ble tatt ut"</string>
+ <string name="ext_media_nomedia_notification_message">"Minnekortet ble tatt ut. Sett inn et nytt minnekort for å øke lagringsplassen."</string>
+ <string name="activity_list_empty">"Fant ingen tilsvarende aktiviteter"</string>
+ <string name="permlab_pkgUsageStats">"oppdater statistikk over komponentbruk"</string>
+ <string name="permdesc_pkgUsageStats">"Tillater endring av innsamlet data om bruk av komponenter. Ikke ment for vanlige applikasjoner."</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
+</resources>
diff --git a/core/res/res/values-nl-rNL/strings.xml b/core/res/res/values-nl-rNL/strings.xml
deleted file mode 100644
index 1dc48bb..0000000
--- a/core/res/res/values-nl-rNL/strings.xml
+++ /dev/null
@@ -1,905 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="byteShort">"b"</string>
- <string name="kilobyteShort">"Kb"</string>
- <string name="megabyteShort">"Mb"</string>
- <string name="gigabyteShort">"Gb"</string>
- <string name="terabyteShort">"Tb"</string>
- <string name="petabyteShort">"Pb"</string>
- <string name="untitled">"&lt;Naamloos&gt;"</string>
- <string name="ellipsis">"…"</string>
- <string name="emptyPhoneNumber">"(geen telefoonnummer)"</string>
- <string name="unknownName">"(onbekend)"</string>
- <string name="defaultVoiceMailAlphaTag">"Voicemail"</string>
- <string name="defaultMsisdnAlphaTag">"Msisdn1"</string>
- <string name="mmiError">"Netwerkfout of onjuiste MMI-code."</string>
- <string name="serviceEnabled">"Service ingeschakeld"</string>
- <string name="serviceEnabledFor">"Service ingeschakeld voor:"</string>
- <string name="serviceDisabled">"Service uitgeschakeld"</string>
- <string name="serviceRegistered">"Registratie gelukt"</string>
- <string name="serviceErased">"Wissen gelukt"</string>
- <string name="passwordIncorrect">"Ongeldig wachtwoord"</string>
- <string name="mmiComplete">"MMI voltooid"</string>
- <!-- no translation found for badPin (5103184589972647739) -->
- <skip />
- <!-- no translation found for badPuk (2200634943393540609) -->
- <skip />
- <!-- no translation found for mismatchPin (5055729703806180857) -->
- <skip />
- <!-- no translation found for invalidPin (6201854814319326475) -->
- <skip />
- <!-- no translation found for needPuk (4788728144863892764) -->
- <skip />
- <!-- no translation found for needPuk2 (7056908944942451033) -->
- <skip />
- <string name="ClipMmi">"Nummerweergave inkomend gesprek"</string>
- <string name="ClirMmi">"Nummerweergave uitgaand gesprek"</string>
- <string name="CfMmi">"Oproep doorschakelen"</string>
- <string name="CwMmi">"Gesprek in wachtstand"</string>
- <string name="BaMmi">"Oproep blokkeren"</string>
- <string name="PwdMmi">"Wachtwoord wijzigen"</string>
- <string name="PinMmi">"Pincode wijzigen"</string>
- <string name="CLIRDefaultOnNextCallOn">"ID-beperkingsstandaarden op beperkt. Volgend gesprek: beperkt"</string>
- <string name="CLIRDefaultOnNextCallOff">"ID-beperkingsstandaarden op beperkt. Volgend gesprek: niet beperkt"</string>
- <string name="CLIRDefaultOffNextCallOn">"ID-beperkingsstandaarden op onbeperkt. Volgend gesprek: beperkt"</string>
- <string name="CLIRDefaultOffNextCallOff">"ID-beperkingsstandaarden op onbeperkt. Volgend gesprek: niet beperkt"</string>
- <string name="serviceNotProvisioned">"Service niet opgenomen."</string>
- <string name="CLIRPermanent">"ID-beperking ingesteld op permanente modus."</string>
- <string name="serviceClassVoice">"Spraak"</string>
- <string name="serviceClassData">"Gegevens"</string>
- <string name="serviceClassFAX">"FAX"</string>
- <string name="serviceClassSMS">"SMS"</string>
- <string name="serviceClassDataAsync">"Async"</string>
- <string name="serviceClassDataSync">"Sync"</string>
- <string name="serviceClassPacket">"Pakket"</string>
- <string name="serviceClassPAD">"PAD"</string>
- <string name="cfTemplateNotForwarded">"{0}: Niet doorgestuurd"</string>
- <string name="cfTemplateForwarded">"{0}: {1}"</string>
- <string name="cfTemplateForwardedTime">"{0}: {1} na {2} seconden"</string>
- <string name="cfTemplateRegistered">"{0}: Niet doorgestuurd ({1})"</string>
- <string name="cfTemplateRegisteredTime">"{0}: Niet doorgestuurd ({1} na {2} seconden)"</string>
- <string name="httpErrorOk">"OK"</string>
- <string name="httpError">"Onbekende fout"</string>
- <string name="httpErrorLookup">"Onbekende host"</string>
- <string name="httpErrorUnsupportedAuthScheme">"Niet-ondersteund verificatieschema. Verificeren mislukt."</string>
- <string name="httpErrorAuth">"Verificatie mislukt"</string>
- <string name="httpErrorProxyAuth">"Verificeren van proxyserver mislukt"</string>
- <string name="httpErrorConnect">"Verbinding maken met server mislukt"</string>
- <string name="httpErrorIO">"Lezen van of schrijven naar server mislukt"</string>
- <string name="httpErrorTimeout">"Time-out bij serververbinding"</string>
- <string name="httpErrorRedirectLoop">"Te veel omleidingen door server"</string>
- <string name="httpErrorUnsupportedScheme">"Protocol wordt niet ondersteund"</string>
- <string name="httpErrorFailedSslHandshake">"Uitvoeren van ssl-handshake mislukt"</string>
- <string name="httpErrorBadUrl">"Ongeldige url"</string>
- <string name="httpErrorFile">"Bestandfout"</string>
- <string name="httpErrorFileNotFound">"Bestand niet gevonden"</string>
- <!-- no translation found for httpErrorTooManyRequests (3764334538393544875) -->
- <skip />
- <string name="contentServiceSync">"Sync"</string>
- <string name="contentServiceSyncNotificationTitle">"Sync"</string>
- <!-- no translation found for contentServiceTooManyDeletesNotificationDesc (8477597194404210723) -->
- <skip />
- <!-- no translation found for low_memory (4191592786596642367) -->
- <skip />
- <!-- no translation found for me (4616693653158602117) -->
- <skip />
- <string name="power_dialog">"Energieopties"</string>
- <string name="silent_mode">"Stille modus"</string>
- <string name="turn_on_radio">"Radio uitschakelen"</string>
- <string name="turn_off_radio">"Radio uitschakelen"</string>
- <string name="screen_lock">"Vergrendeling"</string>
- <string name="power_off">"Uitschakelen"</string>
- <!-- no translation found for shutdown_progress (3735034517335251808) -->
- <skip />
- <!-- no translation found for shutdown_confirm (699224922526414097) -->
- <skip />
- <string name="no_recent_tasks">"Geen recente toepassingen"</string>
- <string name="global_actions">"Globale handelingen"</string>
- <string name="global_action_lock">"Vergrendeling"</string>
- <string name="global_action_power_off">"Uitschakelen"</string>
- <string name="global_action_toggle_silent_mode">"Stille modus"</string>
- <string name="global_action_silent_mode_on_status">"Geluid staat UIT"</string>
- <string name="global_action_silent_mode_off_status">"Geluid staat AAN"</string>
- <string name="safeMode">"Veilige modus"</string>
- <!-- no translation found for permgrouplab_costMoney (904087853776533085) -->
- <skip />
- <!-- no translation found for permgroupdesc_costMoney (4662370555643969515) -->
- <skip />
- <!-- no translation found for permgrouplab_messages (2984053976424233925) -->
- <skip />
- <!-- no translation found for permgroupdesc_messages (2129093134354989379) -->
- <skip />
- <!-- no translation found for permgrouplab_personalInfo (4548406335021507392) -->
- <skip />
- <!-- no translation found for permgroupdesc_personalInfo (8499310823817958034) -->
- <skip />
- <!-- no translation found for permgrouplab_location (8535677827151907069) -->
- <skip />
- <!-- no translation found for permgroupdesc_location (2341662219604651887) -->
- <skip />
- <!-- no translation found for permgrouplab_network (3597781730625751831) -->
- <skip />
- <!-- no translation found for permgroupdesc_network (8332572695347918340) -->
- <skip />
- <!-- no translation found for permgrouplab_accounts (8631201594657951893) -->
- <skip />
- <!-- no translation found for permgroupdesc_accounts (443982868906396781) -->
- <skip />
- <!-- no translation found for permgrouplab_hardwareControls (5074512938567152139) -->
- <skip />
- <!-- no translation found for permgroupdesc_hardwareControls (8772503144945278440) -->
- <skip />
- <!-- no translation found for permgrouplab_phoneCalls (7096448531266882376) -->
- <skip />
- <!-- no translation found for permgroupdesc_phoneCalls (6703873478653366233) -->
- <skip />
- <!-- no translation found for permgrouplab_systemTools (1840847965111633430) -->
- <skip />
- <!-- no translation found for permgroupdesc_systemTools (2810337951496685271) -->
- <skip />
- <!-- no translation found for permgrouplab_developmentTools (692844635256963358) -->
- <skip />
- <!-- no translation found for permgroupdesc_developmentTools (5253915519857796400) -->
- <skip />
- <string name="permlab_statusBar">"Statusbalk besturen"</string>
- <string name="permdesc_statusBar">"Hiermee kan een toepassing de statusbalk en pictogrammen openen, sluiten of uitschakelen."</string>
- <!-- no translation found for permlab_expandStatusBar (6382500803293284173) -->
- <skip />
- <!-- no translation found for permdesc_expandStatusBar (90953162060681436) -->
- <skip />
- <!-- no translation found for permlab_processOutgoingCalls (786316295241100144) -->
- <skip />
- <!-- no translation found for permdesc_processOutgoingCalls (1655242138991854396) -->
- <skip />
- <string name="permlab_receiveSms">"Sms-berichten ontvangen"</string>
- <string name="permdesc_receiveSms">"Hiermee kan een toepassing tekstberichten ontvangen en verwerken. Slechte toepassingen kunnen uw berichten in de gaten houden of verwijderen zonder dat dit wordt aangegeven."</string>
- <string name="permlab_receiveMms">"Mms-berichten ontvangen"</string>
- <string name="permdesc_receiveMms">"Hiermee kan een toepassing multimediaberichten ontvangen en verwerken. Slechte toepassingen kunnen uw berichten in de gaten houden of verwijderen zonder dat dit wordt aangegeven."</string>
- <string name="permlab_sendSms">"Sms-berichten verzenden"</string>
- <string name="permdesc_sendSms">"Hiermee kan een toepassing tekstberichten verzenden. Slechte toepassingen kunnen u op kosten jagen door zonder toestemming berichten te verzenden."</string>
- <string name="permlab_readSms">"Sms/mms-berichten lezen"</string>
- <string name="permdesc_readSms">"Hiermee kan een toepassing sms-berichten op telefoon of SIM-kaart lezen. Slechte toepassingen kunnen vertrouwelijke berichten lezen."</string>
- <string name="permlab_writeSms">"Sms/mms-berichten schrijven"</string>
- <string name="permdesc_writeSms">"Hiermee kan een toepassing sms-berichten op telefoon of SIM-kaart schrijven. Slechte toepassingen kunnen berichten verwijderen."</string>
- <string name="permlab_receiveWapPush">"Wap-berichten ontvangen"</string>
- <string name="permdesc_receiveWapPush">"Hiermee kan een toepassing wap-berichten ontvangen en verwerken. Slechte toepassingen kunnen uw berichten in de gaten houden of verwijderen zonder dat dit wordt aangegeven."</string>
- <string name="permlab_getTasks">"Taakinformatie verkrijgen"</string>
- <string name="permdesc_getTasks">"Hiermee kan een toepassing informatie ophalen over geactiveerde en recent geactiveerde taken. Verkeerde toepassingen kunnen hierdoor toegang krijgen tot privé-informatie over andere toepassingen."</string>
- <string name="permlab_reorderTasks">"Taken herschikken"</string>
- <string name="permdesc_reorderTasks">"Hiermee kan een toepassing taken naar de voorgrond en achtergrond verplaatsen. Slechte toepassingen kunnen zichzelf zonder tussenkomst naar de voorgrond forceren."</string>
- <string name="permlab_setDebugApp">"Foutopsporing instellen"</string>
- <string name="permdesc_setDebugApp">"Hiermee kan een toepassing foutopsporing voor andere toepassingen inschakelen. Slechte toepassingen kunnen dit misbruiken om andere toepassingen te stoppen."</string>
- <string name="permlab_changeConfiguration">"Configuratie wijzigen"</string>
- <string name="permdesc_changeConfiguration">"Hiermee kan een toepassing de actuele configuratie veranderen, zoals de locatie of algemene tekengrootte."</string>
- <!-- no translation found for permlab_restartPackages (5836367540766044606) -->
- <skip />
- <!-- no translation found for permdesc_restartPackages (1764965996765573321) -->
- <skip />
- <!-- no translation found for permlab_setProcessForeground (4860990420780868638) -->
- <skip />
- <!-- no translation found for permdesc_setProcessForeground (3795477299954784360) -->
- <skip />
- <string name="permlab_forceBack">"Terug forceren"</string>
- <string name="permdesc_forceBack">"Hiermee kan een toepassing elke activiteit die op de voorgrond staat sluiten en terugkeren. Is bij normale toepassingen nooit nodig."</string>
- <string name="permlab_dump">"Systeemstatus dumpen"</string>
- <string name="permdesc_dump">"Hiermee kan een toepassingen de interne toestand van het systeem opvragen. Verkeerde toepassingen kunnen een diverse privé- en veiligheidsinformatie verkrijgen die ze normaal gesproken niet nodig hebben."</string>
- <string name="permlab_addSystemService">"Systeemservice toevoegen"</string>
- <string name="permdesc_addSystemService">"Toepassingen mogen hun eigen systeemdiensten van laag-niveau publiceren. Verkeerde toepassingen kunnen het systeem kapen en gegevens erop beschadigen of stelen."</string>
- <string name="permlab_runSetActivityWatcher">"Activiteitenmonitor instellen"</string>
- <string name="permdesc_runSetActivityWatcher">"Hiermee kan een toepassing de wijze waarop het systeem activiteiten start in de gaten houden en besturen. Slechte toepassingen kunnen zo het systeem in gevaar brengen. Deze toepassing is alleen nodig voor ontwikkelingsdoeleinden, nooit voor normaal gebruik van het toestel."</string>
- <string name="permlab_broadcastPackageRemoved">"Uitzendpakket verwijderd"</string>
- <string name="permdesc_broadcastPackageRemoved">"Hiermee kan een toepassing een melding uitzenden met de mededeling dat een toepassingspakket is verwijderd. Verkeerde toepassingen kunnen dit gebruiken om andere actieve toepassingen te stoppen."</string>
- <!-- no translation found for permlab_broadcastSmsReceived (1994692154847312518) -->
- <skip />
- <!-- no translation found for permdesc_broadcastSmsReceived (6072362543164841432) -->
- <skip />
- <!-- no translation found for permlab_broadcastWapPush (3070023012636951639) -->
- <skip />
- <!-- no translation found for permdesc_broadcastWapPush (726912255218924336) -->
- <skip />
- <string name="permlab_setProcessLimit">"Proceslimiet instellen"</string>
- <string name="permdesc_setProcessLimit">"Hiermee kan een toepassing het maximumaantal geactiveerde processen besturen. Nooit nodig voor normale toepassingen."</string>
- <string name="permlab_setAlwaysFinish">"Altijd voltooien instellen"</string>
- <string name="permdesc_setAlwaysFinish">"Hiermee kan een toepassing besturen of activiteiten altijd voltooid moeten zijn als ze naar de achtergrond gaan. Nooit nodig voor normale toepassingen."</string>
- <string name="permlab_fotaUpdate">"Installatie van systeemupdate"</string>
- <string name="permdesc_fotaUpdate">"Hiermee kan een toepassing meldingen ontvangen over systeemupdates die in behandeling zijn en hun installatie in gang zetten. Slechte toepassingen kunnen dit misbruiken om het te beschadigen met niet toegestane updates, of algemeen het updaten te verstoren."</string>
- <!-- no translation found for permlab_batteryStats (1598947993704535568) -->
- <skip />
- <!-- no translation found for permdesc_batteryStats (6247598531831307989) -->
- <skip />
- <string name="permlab_internalSystemWindow">"Intern systeemvenster"</string>
- <string name="permdesc_internalSystemWindow">"Hiermee kunnen vensters worden gemaakt die bedoeld zijn voor gebruik door het interne systeem van de gebruikersinterface. Niet bedoeld voor normale toepassingen."</string>
- <string name="permlab_systemAlertWindow">"Systeemmeldingen"</string>
- <string name="permdesc_systemAlertWindow">"Hiermee kan een toepassing systeemmeldingen weergeven. Slechte toepassingen kunnen het volledige toestelscherm overnemen."</string>
- <string name="permlab_setAnimationScale">"Animatieschaal instellen"</string>
- <string name="permdesc_setAnimationScale">"Hiermee kan een toepassing op elk moment de globale animatiesnelheid (snellere of tragere animaties) veranderen."</string>
- <string name="permlab_manageAppTokens">"Toepassingstokens beheren"</string>
- <string name="permdesc_manageAppTokens">"Hiermee kunnen toepassingen hun eigen tokens maken, en zo de normale Z-ordening buiten spel zetten. Is bij normale toepassingen nooit nodig."</string>
- <string name="permlab_injectEvents">"Invoergebeurtenissen invoegen"</string>
- <string name="permdesc_injectEvents">"Hiermee kan een toepassing zijn eigen invoergebeurtenissen (toetsindrukken enz.) naar andere toepassingen sturen. Slechte toepassingen kunnen dit misbruiken om controle over het toestel te krijgen."</string>
- <string name="permlab_readInputState">"Invoerstatus lezen"</string>
- <string name="permdesc_readInputState">"Hiermee kunnen toepassingen de toetsen zien die u indrukt, ook bij interactie met een andere toepassing (zoals het invoeren van een wachtwoord). Is bij normale toepassingen nooit nodig."</string>
- <string name="permlab_setOrientation">"Ligging instellen"</string>
- <string name="permdesc_setOrientation">"Hiermee kan een toepassing op elk moment de schermligging veranderen. Is bij normale toepassingen nooit nodig."</string>
- <string name="permlab_signalPersistentProcesses">"Signaal naar aanhoudende processen"</string>
- <string name="permdesc_signalPersistentProcesses">"Hiermee kan een toepassing verzoeken dat het meegeleverde signaal naar alle aanhoudende processen wordt gestuurd."</string>
- <string name="permlab_persistentActivity">"Aanhoudende handelingen"</string>
- <string name="permdesc_persistentActivity">"Hiermee kan een toepassing gedeeltes van zichzelf fixeren, zodat het systeem deze niet meer kan gebruiken voor andere toepassingen."</string>
- <string name="permlab_deletePackages">"Pakketten verwijderen"</string>
- <string name="permdesc_deletePackages">"Hiermee kan een toepassing Android-pakketten verwijderen. Slechte toepassingen kunnen dit misbruiken om belangrijke toepassingen te wissen."</string>
- <!-- no translation found for permlab_clearAppUserData (3858185484601410171) -->
- <skip />
- <!-- no translation found for permdesc_clearAppUserData (7233537744753081136) -->
- <skip />
- <string name="permlab_deleteCacheFiles">"Cachebestanden wissen"</string>
- <string name="permdesc_deleteCacheFiles">"Hiermee kan een toepassing cachebestanden verwijderen."</string>
- <!-- no translation found for permlab_getPackageSize (6743556676630447973) -->
- <skip />
- <!-- no translation found for permdesc_getPackageSize (2893996655828539776) -->
- <skip />
- <string name="permlab_installPackages">"Pakketten installeren"</string>
- <string name="permdesc_installPackages">"Hiermee kan een toepassing nieuwe Android- pakketten installeren of updaten. Slechte toepassingen kunnen dit misbruiken om nieuwe toepassingen met twijfelachtig verstrekkende rechten toe te voegen."</string>
- <string name="permlab_clearAppCache">"Cachegegevens van toepassing wissen"</string>
- <string name="permdesc_clearAppCache">"Hiermee kan een toepassing toestelgeheugen vrijmaken door bestanden uit de cachemap te verwijderen. Toegang wordt meestal beperkt tot systeemprocessen."</string>
- <!-- no translation found for permlab_readLogs (6653488552442991707) -->
- <skip />
- <!-- no translation found for permdesc_readLogs (356352685800884319) -->
- <skip />
- <!-- no translation found for permlab_diagnostic (2955142476313469329) -->
- <skip />
- <!-- no translation found for permdesc_diagnostic (1282409892215520166) -->
- <skip />
- <string name="permlab_changeComponentState">"Toepassingscomponenten in- of uitschakelen"</string>
- <string name="permdesc_changeComponentState">"Hiermee kan een toepassing veranderen of een component van een andere toepassing wordt ingeschakeld of niet. Slechte toepassingen kunnen dit gebruiken om belangrijke toestelfuncties uit te schakelen. Wees voorzichtig met het verlenen van toestemmingen, omdat het mogelijk is dat toepassingscomponenten in een onbruikbare, inconsistente of instabiele toestand geraken."</string>
- <string name="permlab_setPreferredApplications">"Voorkeurstoepassingen instellen"</string>
- <string name="permdesc_setPreferredApplications">"Hiermee kan een toepassing uw voorkeurstoepassingen veranderen. Slechte toepassingen kunnen zo stilletjes veranderen welke toepassingen gestart moeten worden, zodat bestaande toepassingen privégegevens over u verzamelen."</string>
- <string name="permlab_writeSettings">"Systeeminstellingen schrijven"</string>
- <string name="permdesc_writeSettings">"Hiermee kan een toepassing de instellingsgegevens van het systeem aanpassen. Slechte toepassingen kunnen de configuratie van het systeem beschadigen."</string>
- <!-- no translation found for permlab_writeSecureSettings (4851801872124242319) -->
- <skip />
- <!-- no translation found for permdesc_writeSecureSettings (2080620249472761366) -->
- <skip />
- <!-- no translation found for permlab_writeGservices (296370685945777755) -->
- <skip />
- <!-- no translation found for permdesc_writeGservices (2496928471286495053) -->
- <skip />
- <string name="permlab_receiveBootCompleted">"Uitvoeren bij opstarten"</string>
- <string name="permdesc_receiveBootCompleted">"Hiermee kan een toepassing zichzelf starten zodra het systeem is opgestart. Hierdoor kan het opstarten van het toestel langer duren en de toepassing het toestel afremmen omdat het altijd is geactiveerd."</string>
- <string name="permlab_broadcastSticky">"Belangrijke uitzending"</string>
- <string name="permdesc_broadcastSticky">"Hiermee kan een toepassing plakuitzendingen versturen, die blijven hangen als de uitzending stopt. Verkeerde toepassingen kunnen het toestel traag of instabiel maken door te veel geheugengebruik te veroorzaken."</string>
- <string name="permlab_readContacts">"Contactgegevens lezen"</string>
- <string name="permdesc_readContacts">"Hiermee kan een toepassing alle contactgegevens (adres) op het toestel lezen. Slechte toepassingen kunnen dit misbruiken om uw gegevens naar andere personen te sturen."</string>
- <string name="permlab_writeContacts">"Contactgegevens schrijven"</string>
- <string name="permdesc_writeContacts">"Hiermee kan een toepassing alle contactgegevens (adres) op het toestel aanpassen. Slechte toepassingen kunnen dit misbruiken om contactgegevens te wissen of wijzigen."</string>
- <!-- no translation found for permlab_writeOwnerData (8036840529708535113) -->
- <skip />
- <!-- no translation found for permdesc_writeOwnerData (5873447528845878348) -->
- <skip />
- <!-- no translation found for permlab_readOwnerData (1847040178513733757) -->
- <skip />
- <!-- no translation found for permdesc_readOwnerData (7563299529149214764) -->
- <skip />
- <!-- no translation found for permlab_readCalendar (2111238731453410895) -->
- <skip />
- <!-- no translation found for permdesc_readCalendar (4408253940601239114) -->
- <skip />
- <!-- no translation found for permlab_writeCalendar (7518052789370653396) -->
- <skip />
- <!-- no translation found for permdesc_writeCalendar (8057304232140147596) -->
- <skip />
- <!-- no translation found for permlab_accessMockLocation (321094551062270213) -->
- <skip />
- <!-- no translation found for permdesc_accessMockLocation (3651565866471419739) -->
- <skip />
- <!-- no translation found for permlab_accessLocationExtraCommands (8291822077788811687) -->
- <skip />
- <!-- no translation found for permdesc_accessLocationExtraCommands (5135782633548630731) -->
- <skip />
- <string name="permlab_accessFineLocation">"Toegang tot gps-locatie"</string>
- <string name="permdesc_accessFineLocation">"Open, indien beschikbaar, het Global Positioning System op het toestel. Verkeerde toepassingen kunnen dit gebruiken om te bepalen waar u zich bevindt en extra batterijstroom verbruiken."</string>
- <string name="permlab_accessCoarseLocation">"Toegang tot netwerklocatie"</string>
- <string name="permdesc_accessCoarseLocation">"Gebruik, indien beschikbaar, een netwerkdatabank om de locatie van het toestel te schatten. Verkeerde toepassingen kunnen dit gebruiken om te schatten waar u zich bevindt."</string>
- <string name="permlab_accessSurfaceFlinger">"Toegang tot SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger">"Toepassingen mogen de functies op laag niveau van SurfaceFlinger gebruiken."</string>
- <string name="permlab_readFrameBuffer">"Framebuffer lezen"</string>
- <string name="permdesc_readFrameBuffer">"Hiermee kan een toepassing de gegevens van de framebuffer lezen."</string>
- <string name="permlab_modifyAudioSettings">"Audioinstellingen wijzigen"</string>
- <string name="permdesc_modifyAudioSettings">"Hiermee kan een toepassing globale audioinstellingen aanpassen, zoals volume en route."</string>
- <string name="permlab_recordAudio">"Audio opnemen"</string>
- <string name="permdesc_recordAudio">"Hierdoor kan een toepassing het opnamepad voor audio openen."</string>
- <string name="permlab_camera">"Camera"</string>
- <!-- unknown placeholder BREAK in permdesc_camera -->
- <skip />
- <string name="permlab_brick">"Toestel uitschakelen"</string>
- <string name="permdesc_brick">"Hiermee kan de toepassing de gehele dienst permanent uitschakelen. Dit is erg gevaarlijk."</string>
- <!-- no translation found for permlab_reboot (8844650672567077423) -->
- <skip />
- <!-- no translation found for permdesc_reboot (4704919552870918328) -->
- <skip />
- <string name="permlab_mount_unmount_filesystems">"Bestandssystemen koppelen en losmaken"</string>
- <string name="permdesc_mount_unmount_filesystems">"Hiermee kan de toepassing bestandssystemen voor verwisselbaar geheugen koppelen en loskoppelen."</string>
- <string name="permlab_vibrate">"Triller"</string>
- <string name="permdesc_vibrate">"Hiermee kan de toepassing de triller besturen."</string>
- <string name="permlab_flashlight">"Flitser"</string>
- <string name="permdesc_flashlight">"Hiermee kan de toepassing de flitser besturen."</string>
- <string name="permlab_hardware_test">"Hardwaretest"</string>
- <string name="permdesc_hardware_test">"Hiermee kan de toepassing diverse randapparaten besturen met als doel het testen van de hardware."</string>
- <string name="permlab_callPhone">"Telefoonnummers bellen"</string>
- <string name="permdesc_callPhone">"Hiermee kunnen toepassingen telefoonnummers bellen zonder uw tussenkomst. Verkeerde toepassingen kunnen ongewilde gesprekken op uw telefoonrekening veroorzaken."</string>
- <!-- no translation found for permlab_callPrivileged (2166923597287697159) -->
- <skip />
- <!-- no translation found for permdesc_callPrivileged (5109789447971735501) -->
- <skip />
- <!-- no translation found for permlab_locationUpdates (4216418293360456836) -->
- <skip />
- <!-- no translation found for permdesc_locationUpdates (7635814693478743648) -->
- <skip />
- <!-- no translation found for permlab_checkinProperties (2260796787386280708) -->
- <skip />
- <!-- no translation found for permdesc_checkinProperties (3508022022841741945) -->
- <skip />
- <!-- no translation found for permlab_modifyPhoneState (7791696535097912313) -->
- <skip />
- <!-- no translation found for permdesc_modifyPhoneState (6352405226410454770) -->
- <skip />
- <!-- no translation found for permlab_readPhoneState (7320082586621086653) -->
- <skip />
- <!-- no translation found for permdesc_readPhoneState (8004450067066407969) -->
- <skip />
- <!-- no translation found for permlab_wakeLock (1591164750935072136) -->
- <skip />
- <!-- no translation found for permdesc_wakeLock (160471538196734936) -->
- <skip />
- <string name="permlab_devicePower">"Toestel inschakelen"</string>
- <string name="permdesc_devicePower">"Hiermee kan de toepassing het toestel in- of uitschakelen, of ingeschakeld laten."</string>
- <string name="permlab_factoryTest">"Fabriekstest"</string>
- <string name="permdesc_factoryTest">"Uitvoeren als een fabriekstest op laag niveau, waardoor volledige toegang tot de toestelhardware gegeven is. Alleen beschikbaar als een toestel in de fabriekstestmodus staat."</string>
- <string name="permlab_setWallpaper">"Achtergrond instellen"</string>
- <string name="permdesc_setWallpaper">"Hiermee kan de toepassing de systeemachtergrond instellen."</string>
- <!-- no translation found for permlab_setWallpaperHints (4192438316932517807) -->
- <skip />
- <!-- no translation found for permdesc_setWallpaperHints (738757439960921674) -->
- <skip />
- <string name="permlab_masterClear">"Volledige systeemreset"</string>
- <string name="permdesc_masterClear">"Hiermee kan een toepassing het systeem volledig opnieuw instellen op fabrieksinstellingen, waardoor alle gegevens, configuratie en geïnstalleerde toepassingen worden gewist."</string>
- <!-- no translation found for permlab_setTimeZone (477196167239548690) -->
- <skip />
- <!-- no translation found for permdesc_setTimeZone (8564892020460841198) -->
- <skip />
- <!-- no translation found for permlab_getAccounts (2764070033402295170) -->
- <skip />
- <!-- no translation found for permdesc_getAccounts (1203491378748649898) -->
- <skip />
- <!-- no translation found for permlab_accessNetworkState (2032916924886010827) -->
- <skip />
- <!-- no translation found for permdesc_accessNetworkState (7081329402551195933) -->
- <skip />
- <!-- no translation found for permlab_createNetworkSockets (4706698319966917864) -->
- <skip />
- <!-- no translation found for permdesc_createNetworkSockets (2580337178778551792) -->
- <skip />
- <!-- no translation found for permlab_writeApnSettings (3190585220761979369) -->
- <skip />
- <!-- no translation found for permdesc_writeApnSettings (4093875220468761052) -->
- <skip />
- <!-- no translation found for permlab_changeNetworkState (2710779001260856872) -->
- <skip />
- <!-- no translation found for permdesc_changeNetworkState (8076109230787022270) -->
- <skip />
- <!-- no translation found for permlab_accessWifiState (3613679494230374297) -->
- <skip />
- <!-- no translation found for permdesc_accessWifiState (8226508433563326925) -->
- <skip />
- <!-- no translation found for permlab_changeWifiState (6043889338995432957) -->
- <skip />
- <!-- no translation found for permdesc_changeWifiState (7829372845909567994) -->
- <skip />
- <!-- no translation found for permlab_bluetoothAdmin (5513286736585647334) -->
- <skip />
- <!-- no translation found for permdesc_bluetoothAdmin (1838208497914347365) -->
- <skip />
- <!-- no translation found for permlab_bluetooth (6378797624765639115) -->
- <skip />
- <!-- no translation found for permdesc_bluetooth (8592386018922265273) -->
- <skip />
- <!-- no translation found for permlab_disableKeyguard (4574886811903233903) -->
- <skip />
- <!-- no translation found for permdesc_disableKeyguard (815972646344251271) -->
- <skip />
- <!-- no translation found for permlab_readSyncSettings (8818819977141505127) -->
- <skip />
- <!-- no translation found for permdesc_readSyncSettings (8454705401908767847) -->
- <skip />
- <!-- no translation found for permlab_writeSyncSettings (4514911143753152941) -->
- <skip />
- <!-- no translation found for permdesc_writeSyncSettings (7630627689635091836) -->
- <skip />
- <!-- no translation found for permlab_readSyncStats (5748337739678952863) -->
- <skip />
- <!-- no translation found for permdesc_readSyncStats (582551457321957183) -->
- <skip />
- <!-- no translation found for permlab_subscribedFeedsRead (2043206814904506589) -->
- <skip />
- <!-- no translation found for permdesc_subscribedFeedsRead (6977343942680042449) -->
- <skip />
- <!-- no translation found for permlab_subscribedFeedsWrite (2556727307229571556) -->
- <skip />
- <!-- no translation found for permdesc_subscribedFeedsWrite (4134783294590266220) -->
- <skip />
- <!-- no translation found for phoneTypes:0 (6070018634209800981) -->
- <!-- no translation found for phoneTypes:1 (1514509689885965711) -->
- <!-- no translation found for phoneTypes:2 (497473201754095234) -->
- <!-- no translation found for phoneTypes:3 (5554432614281047787) -->
- <!-- no translation found for phoneTypes:4 (2222084401110150993) -->
- <!-- no translation found for phoneTypes:5 (2290007103906353121) -->
- <!-- no translation found for phoneTypes:6 (6930783706213719251) -->
- <!-- no translation found for phoneTypes:7 (1326005699931077792) -->
- <!-- no translation found for emailAddressTypes:0 (1540640638077615417) -->
- <!-- no translation found for emailAddressTypes:1 (4252853367575831977) -->
- <!-- no translation found for emailAddressTypes:2 (7158046581744435718) -->
- <!-- no translation found for emailAddressTypes:3 (3625034471181268169) -->
- <!-- no translation found for postalAddressTypes:0 (5732960259696659380) -->
- <!-- no translation found for postalAddressTypes:1 (7132240704786130285) -->
- <!-- no translation found for postalAddressTypes:2 (1317604357745852817) -->
- <!-- no translation found for postalAddressTypes:3 (1582953598462826702) -->
- <!-- no translation found for imAddressTypes:0 (7806620012096518833) -->
- <!-- no translation found for imAddressTypes:1 (5748846799950672787) -->
- <!-- no translation found for imAddressTypes:2 (6196536810275073680) -->
- <!-- no translation found for imAddressTypes:3 (8519128375350623648) -->
- <!-- no translation found for organizationTypes:0 (1299224825223821142) -->
- <!-- no translation found for organizationTypes:1 (2455717447227299354) -->
- <!-- no translation found for organizationTypes:2 (7027570839313438290) -->
- <!-- no translation found for imProtocols:0 (3318725788774688043) -->
- <!-- no translation found for imProtocols:1 (1787713387022932886) -->
- <!-- no translation found for imProtocols:2 (6751174158442316516) -->
- <!-- no translation found for imProtocols:3 (1151283347465052653) -->
- <!-- no translation found for imProtocols:4 (2157980008878817934) -->
- <!-- no translation found for imProtocols:5 (7836237460308230767) -->
- <!-- no translation found for imProtocols:6 (1180789904462172516) -->
- <!-- no translation found for imProtocols:7 (21955111672779862) -->
- <string name="keyguard_password_enter_pin_code">"Pincode invoeren"</string>
- <string name="keyguard_password_wrong_pin_code">"Onjuiste pincode!"</string>
- <string name="keyguard_label_text">"Om vrij te geven drukt u op Menu en vervolgens op 0."</string>
- <string name="emergency_call_dialog_number_for_display">"Alarmnummers"</string>
- <string name="lockscreen_carrier_default">"(Geen service)"</string>
- <string name="lockscreen_screen_locked">"Schermblokkering"</string>
- <string name="lockscreen_instructions_when_pattern_enabled">"Druk op Menu om vrij te geven of bel een alarmnummer"</string>
- <string name="lockscreen_instructions_when_pattern_disabled">"Druk op Menu om vrij te geven"</string>
- <string name="lockscreen_pattern_instructions">"Patroon tekenen om vrij te geven"</string>
- <string name="lockscreen_emergency_call">"Noodoproep"</string>
- <string name="lockscreen_pattern_correct">"Juist!"</string>
- <string name="lockscreen_pattern_wrong">"Verkeerd patroon! Nogmaals proberen"</string>
- <string name="lockscreen_plugged_in">"Bezig met opladen (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
- <string name="lockscreen_low_battery">"Oplader verbinden"</string>
- <!-- no translation found for lockscreen_missing_sim_message_short (5051192587315492957) -->
- <skip />
- <string name="lockscreen_missing_sim_message">"Geen SIM in toestel"</string>
- <string name="lockscreen_missing_sim_instructions">"Voer een SIM-kaart in"</string>
- <!-- no translation found for lockscreen_network_locked_message (323609607922245071) -->
- <skip />
- <!-- no translation found for lockscreen_sim_puk_locked_message (1005803622871256359) -->
- <skip />
- <!-- no translation found for lockscreen_sim_puk_locked_instructions (5033160098036646955) -->
- <skip />
- <!-- no translation found for lockscreen_sim_locked_message (7398401200962556379) -->
- <skip />
- <!-- no translation found for lockscreen_sim_unlock_progress_dialog_message (5939537246164692076) -->
- <skip />
- <!-- unknown placeholder BREAK in lockscreen_too_many_failed_attempts_dialog_message -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_almost_glogin (1569017295989454551) -->
- <skip />
- <string name="lockscreen_too_many_failed_attempts_countdown">"Probeer opnieuw over <xliff:g id="NUMBER">%d</xliff:g> seconden"</string>
- <!-- no translation found for lockscreen_forgot_pattern_button_text (4219994639843985488) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_too_many_attempts (7504679498838839295) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_instructions (6542400673357252011) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_username_hint (6378418320242015111) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_password_hint (3224230234042131153) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_submit_button (5562051040043760034) -->
- <skip />
- <!-- no translation found for lockscreen_glogin_invalid_input (4881057177478491580) -->
- <skip />
- <!-- unknown placeholder FORMAT in status_bar_time_format -->
- <skip />
- <!-- no translation found for hour_minute_ampm (1850330605794978742) -->
- <skip />
- <!-- no translation found for hour_minute_cap_ampm (1122840227537374196) -->
- <skip />
- <!-- no translation found for hour_ampm (7665432130905376251) -->
- <skip />
- <!-- no translation found for hour_cap_ampm (3600295014648400268) -->
- <skip />
- <!-- no translation found for status_bar_clear_all_button (2202004591253243750) -->
- <skip />
- <string name="status_bar_no_notifications_title">"Meldingen"</string>
- <string name="status_bar_ongoing_events_title">"Actueel"</string>
- <string name="status_bar_latest_events_title">"Nieuwste gebeurtenissen"</string>
- <string name="battery_status_text_percent_format">"<xliff:g id="NUMBER">%d</xliff:g>"</string>
- <string name="battery_status_charging">"Bezig met opladen…"</string>
- <string name="battery_low_title">"Oplader verbinden"</string>
- <string name="battery_low_subtitle">"Lage batterijstroom"</string>
- <string name="battery_low_percent_format">"Minder dan <xliff:g id="NUMBER">%d%%</xliff:g> resterend"</string>
- <string name="factorytest_failed">"Fabriekstest mislukt"</string>
- <string name="factorytest_not_system">"De handeling FACTORY_TEST wordt alleen ondersteund voor pakketten die geïnstalleerd zijn in /system/app."</string>
- <string name="factorytest_no_action">"Geen pakket gevonden dat de handeling FACTORY_TEST levert."</string>
- <string name="factorytest_reboot">"Opnieuw opstarten"</string>
- <string name="save_password_label">"Bevestigen"</string>
- <string name="save_password_message">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
- <string name="save_password_notnow">"Niet nu"</string>
- <string name="save_password_remember">"Onthouden"</string>
- <string name="save_password_never">"Nooit"</string>
- <string name="open_permission_deny">"U hebt geen toestemming om deze pagina te openen."</string>
- <!-- no translation found for text_copied (6106873823411904723) -->
- <skip />
- <string name="more_item_label">"Meer"</string>
- <string name="prepend_shortcut_label">"Menu+"</string>
- <!-- no translation found for menu_space_shortcut_label (194586306440382711) -->
- <skip />
- <!-- no translation found for menu_enter_shortcut_label (7214761412193519345) -->
- <skip />
- <!-- no translation found for menu_delete_shortcut_label (2854936426194985313) -->
- <skip />
- <string name="search_go">"Ga naar"</string>
- <string name="today">"Vandaag"</string>
- <string name="yesterday">"Gisteren"</string>
- <string name="tomorrow">"Morgen"</string>
- <!-- no translation found for oneMonthDurationPast (3402179395240209557) -->
- <skip />
- <!-- no translation found for beforeOneMonthDurationPast (7578100953282866827) -->
- <skip />
- <!-- no translation found for num_seconds_ago:one (7416512229671810725) -->
- <!-- no translation found for num_seconds_ago:other (8138756910300398447) -->
- <!-- no translation found for num_minutes_ago:one (8620869479299420562) -->
- <!-- no translation found for num_minutes_ago:other (5065488162050522741) -->
- <!-- no translation found for num_hours_ago:one (853404611989669641) -->
- <!-- no translation found for num_hours_ago:other (3558873784561756849) -->
- <!-- no translation found for num_days_ago:one (4222479980812128212) -->
- <!-- no translation found for num_days_ago:other (5445701370433601703) -->
- <!-- no translation found for in_num_seconds:one (4253290037777327003) -->
- <!-- no translation found for in_num_seconds:other (1280033870920841404) -->
- <!-- no translation found for in_num_minutes:one (1487585791027953091) -->
- <!-- no translation found for in_num_minutes:other (6274204576475209932) -->
- <!-- no translation found for in_num_hours:one (6501470863235186391) -->
- <!-- no translation found for in_num_hours:other (4415358752953289251) -->
- <!-- no translation found for in_num_days:one (5608475533104443893) -->
- <!-- no translation found for in_num_days:other (3827193006163842267) -->
- <string name="preposition_for_date">"op %s"</string>
- <string name="preposition_for_time">"bij %s"</string>
- <string name="preposition_for_year">"in %s"</string>
- <string name="day">"dag"</string>
- <string name="days">"dagen"</string>
- <string name="hour">"uur"</string>
- <string name="hours">"uur"</string>
- <string name="minute">"minuut"</string>
- <string name="minutes">"minuten"</string>
- <string name="second">"seconde"</string>
- <string name="seconds">"seconden"</string>
- <string name="week">"week"</string>
- <string name="weeks">"weken"</string>
- <!-- no translation found for year (8024790425994085153) -->
- <skip />
- <!-- no translation found for years (8592090054773244417) -->
- <skip />
- <string name="sunday">"Zondag"</string>
- <string name="monday">"Maandag"</string>
- <string name="tuesday">"Dinsdag"</string>
- <string name="wednesday">"Woensdag"</string>
- <string name="thursday">"Donderdag"</string>
- <string name="friday">"Vrijdag"</string>
- <string name="saturday">"Zaterdag"</string>
- <string name="every_weekday">"Elke werkdag (Maa–vri)"</string>
- <string name="daily">"Elke dag"</string>
- <string name="weekly">"Wekelijks op <xliff:g id="DAY">%s</xliff:g>"</string>
- <string name="monthly">"Elke mnd"</string>
- <string name="yearly">"Elk jaar"</string>
- <string name="VideoView_error_title">"Videoafspeelfout"</string>
- <string name="VideoView_error_text_unknown">"Fout opgetreden bij afspelen van geselecteerde video."</string>
- <string name="VideoView_error_button">"OK"</string>
- <string name="am">"AM"</string>
- <string name="pm">"PM"</string>
- <!-- unknown placeholder FORMAT in numeric_date -->
- <skip />
- <!-- unknown placeholder FORMAT in wday1_date1_time1_wday2_date2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in wday1_date1_wday2_date2 -->
- <skip />
- <!-- unknown placeholder FORMAT in date1_time1_date2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in date1_date2 -->
- <skip />
- <!-- unknown placeholder FORMAT in time1_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in time_wday_date -->
- <skip />
- <!-- unknown placeholder FORMAT in wday_date -->
- <skip />
- <!-- unknown placeholder FORMAT in time_date -->
- <skip />
- <!-- unknown placeholder FORMAT in time_wday -->
- <skip />
- <!-- no translation found for full_date_month_first (6011143962222283357) -->
- <skip />
- <!-- no translation found for full_date_day_first (8621594762705478189) -->
- <skip />
- <!-- no translation found for medium_date_month_first (48990963718825728) -->
- <skip />
- <!-- no translation found for medium_date_day_first (2898992016440387123) -->
- <skip />
- <!-- no translation found for twelve_hour_time_format (6015557937879492156) -->
- <skip />
- <!-- no translation found for twenty_four_hour_time_format (5176807998669709535) -->
- <skip />
- <string name="noon">"12 uur \'smiddags"</string>
- <string name="Noon">"12 uur \'smiddags"</string>
- <string name="midnight">"middernacht"</string>
- <string name="Midnight">"Middernacht"</string>
- <!-- unknown placeholder FORMAT in month_day -->
- <skip />
- <!-- unknown placeholder FORMAT in month -->
- <skip />
- <!-- unknown placeholder FORMAT in month_day_year -->
- <skip />
- <!-- unknown placeholder FORMAT in month_year -->
- <skip />
- <!-- no translation found for time_of_day (8375993139317154157) -->
- <skip />
- <!-- no translation found for date_and_time (9197690194373107109) -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_md1_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_md1_wday2_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_mdy1_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_wday2_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_md1_time1_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_md1_time1_wday2_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_mdy1_time1_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_year_wday1_mdy1_time1_wday2_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_md1_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_md1_wday2_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_mdy1_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_wday2_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_md1_time1_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_md1_time1_wday2_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_mdy1_time1_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in numeric_wday1_mdy1_time1_wday2_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_md1_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_md1_wday2_md2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_mdy1_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_wday2_mdy2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_md1_time1_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_md1_time1_wday2_md2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_mdy1_time1_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in same_month_wday1_mdy1_time1_wday2_mdy2_time2 -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month_day_year -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month_year -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month_day -->
- <skip />
- <!-- unknown placeholder FORMAT in abbrev_month -->
- <skip />
- <string name="day_of_week_long_sunday">"Zondag"</string>
- <string name="day_of_week_long_monday">"Maandag"</string>
- <string name="day_of_week_long_tuesday">"Dinsdag"</string>
- <string name="day_of_week_long_wednesday">"Woensdag"</string>
- <string name="day_of_week_long_thursday">"Donderdag"</string>
- <string name="day_of_week_long_friday">"Vrijdag"</string>
- <string name="day_of_week_long_saturday">"Zaterdag"</string>
- <string name="day_of_week_medium_sunday">"Zon"</string>
- <string name="day_of_week_medium_monday">"Maa"</string>
- <string name="day_of_week_medium_tuesday">"Din"</string>
- <string name="day_of_week_medium_wednesday">"Woe"</string>
- <string name="day_of_week_medium_thursday">"Don"</string>
- <string name="day_of_week_medium_friday">"Vri"</string>
- <string name="day_of_week_medium_saturday">"Zat"</string>
- <string name="day_of_week_short_sunday">"Zo"</string>
- <string name="day_of_week_short_monday">"Ma"</string>
- <string name="day_of_week_short_tuesday">"Di"</string>
- <string name="day_of_week_short_wednesday">"Wo"</string>
- <string name="day_of_week_short_thursday">"Do"</string>
- <string name="day_of_week_short_friday">"Vr"</string>
- <string name="day_of_week_short_saturday">"Za"</string>
- <string name="day_of_week_shorter_sunday">"Zo"</string>
- <string name="day_of_week_shorter_monday">"M"</string>
- <string name="day_of_week_shorter_tuesday">"Di"</string>
- <string name="day_of_week_shorter_wednesday">"W"</string>
- <string name="day_of_week_shorter_thursday">"Do"</string>
- <string name="day_of_week_shorter_friday">"V"</string>
- <string name="day_of_week_shorter_saturday">"Za"</string>
- <string name="day_of_week_shortest_sunday">"Z"</string>
- <string name="day_of_week_shortest_monday">"M"</string>
- <string name="day_of_week_shortest_tuesday">"Di"</string>
- <string name="day_of_week_shortest_wednesday">"W"</string>
- <string name="day_of_week_shortest_thursday">"Do"</string>
- <string name="day_of_week_shortest_friday">"V"</string>
- <string name="day_of_week_shortest_saturday">"Z"</string>
- <string name="month_long_january">"Januari"</string>
- <string name="month_long_february">"Februari"</string>
- <string name="month_long_march">"Maart"</string>
- <string name="month_long_april">"April"</string>
- <string name="month_long_may">"Mei"</string>
- <string name="month_long_june">"Juni"</string>
- <string name="month_long_july">"Juli"</string>
- <string name="month_long_august">"Augustus"</string>
- <string name="month_long_september">"September"</string>
- <string name="month_long_october">"Oktober"</string>
- <string name="month_long_november">"November"</string>
- <string name="month_long_december">"December"</string>
- <string name="month_medium_january">"jan"</string>
- <string name="month_medium_february">"feb"</string>
- <string name="month_medium_march">"mrt"</string>
- <string name="month_medium_april">"apr"</string>
- <string name="month_medium_may">"mei"</string>
- <string name="month_medium_june">"jun"</string>
- <string name="month_medium_july">"jul"</string>
- <string name="month_medium_august">"aug"</string>
- <string name="month_medium_september">"sep"</string>
- <string name="month_medium_october">"okt"</string>
- <string name="month_medium_november">"nov"</string>
- <string name="month_medium_december">"dec"</string>
- <string name="month_shortest_january">"J"</string>
- <string name="month_shortest_february">"F"</string>
- <string name="month_shortest_march">"M"</string>
- <string name="month_shortest_april">"A"</string>
- <string name="month_shortest_may">"M"</string>
- <string name="month_shortest_june">"J"</string>
- <string name="month_shortest_july">"J"</string>
- <string name="month_shortest_august">"A"</string>
- <string name="month_shortest_september">"S"</string>
- <string name="month_shortest_october">"O"</string>
- <string name="month_shortest_november">"N"</string>
- <string name="month_shortest_december">"D"</string>
- <!-- unknown placeholder FORMAT in elapsed_time_short_format_mm_ss -->
- <skip />
- <!-- unknown placeholder FORMAT in elapsed_time_short_format_h_mm_ss -->
- <skip />
- <string name="selectAll">"Alles selecteren"</string>
- <string name="cut">"Knippen"</string>
- <!-- no translation found for cutAll (4474519683293791451) -->
- <skip />
- <string name="copy">"Kopiëren"</string>
- <!-- no translation found for copyAll (4777548804630476932) -->
- <skip />
- <string name="paste">"Plakken"</string>
- <string name="copyUrl">"URL kopiëren"</string>
- <!-- no translation found for inputMethod (7911866729148111492) -->
- <skip />
- <!-- no translation found for editTextMenuTitle (3984253728638788023) -->
- <skip />
- <string name="low_internal_storage_view_title">"Weinig intern geheugen"</string>
- <string name="low_internal_storage_view_text">"Toestel heeft weinig intern geheugen"</string>
- <string name="ok">"OK"</string>
- <string name="cancel">"Annuleren"</string>
- <string name="yes">"OK"</string>
- <string name="no">"Annuleren"</string>
- <string name="capital_on">"AAN"</string>
- <string name="capital_off">"UIT"</string>
- <string name="whichApplication">"Welke toepassing wilt u gebruiken?"</string>
- <string name="alwaysUse">"Deze toepassing altijd gebruiken voor deze toepassing"</string>
- <!-- no translation found for clearDefaultHintMsg (5742432113023174321) -->
- <skip />
- <string name="chooseActivity">"Een actie selecteren"</string>
- <string name="noApplications">"Geen toepassingen beschikbaar om de handeling uit te voeren"</string>
- <!-- no translation found for aerr_title (2654390351574026098) -->
- <skip />
- <!-- no translation found for aerr_application (4917288809565116720) -->
- <skip />
- <!-- no translation found for aerr_process (1273819861108073461) -->
- <skip />
- <!-- no translation found for anr_title (3305935690891435915) -->
- <skip />
- <!-- no translation found for anr_activity_application (1653036325679156678) -->
- <skip />
- <!-- no translation found for anr_activity_process (2674027618362070465) -->
- <skip />
- <!-- no translation found for anr_application_process (2163656674970221928) -->
- <skip />
- <!-- no translation found for anr_process (7747550780123472160) -->
- <skip />
- <!-- no translation found for force_close (9020954128872810669) -->
- <skip />
- <!-- no translation found for wait (7973775702304037058) -->
- <skip />
- <!-- no translation found for debug (857932504764728770) -->
- <skip />
- <string name="sendText">"Kiezen wat met de tekst gebeurt"</string>
- <!-- no translation found for volume_ringtone (4121694816346562058) -->
- <skip />
- <!-- no translation found for volume_music (4869950240104717493) -->
- <skip />
- <!-- no translation found for volume_call (5723421277753250395) -->
- <skip />
- <!-- no translation found for volume_alarm (2752102730973081294) -->
- <skip />
- <!-- no translation found for volume_unknown (6908187627672375742) -->
- <skip />
- <!-- no translation found for ringtone_default (2873893375149093475) -->
- <skip />
- <!-- no translation found for ringtone_default_with_actual (5474076151665761913) -->
- <skip />
- <!-- no translation found for ringtone_silent (7477159279081654685) -->
- <skip />
- <!-- no translation found for ringtone_picker_title (7055241890764367884) -->
- <skip />
- <!-- no translation found for ringtone_unknown (6888219771401173795) -->
- <skip />
- <!-- no translation found for wifi_available:one (8168012881468888470) -->
- <!-- no translation found for wifi_available:other (4666122955807117718) -->
- <!-- no translation found for wifi_available_detailed:one (5107769161192143259) -->
- <!-- no translation found for wifi_available_detailed:other (853347657960575809) -->
- <!-- no translation found for select_character (3735110139249491726) -->
- <skip />
- <!-- no translation found for sms_control_default_app_name (7522184737840550841) -->
- <skip />
- <!-- no translation found for sms_control_title (2742400596989418394) -->
- <skip />
- <!-- no translation found for sms_control_message (3447126217666595989) -->
- <skip />
- <!-- no translation found for sms_control_yes (8839660939359273650) -->
- <skip />
- <!-- no translation found for sms_control_no (909756849988183801) -->
- <skip />
- <!-- no translation found for date_time_set (2495199891239480952) -->
- <skip />
- <!-- no translation found for default_permission_group (7742780381379652409) -->
- <skip />
- <!-- no translation found for no_permissions (85461124044682315) -->
- <skip />
- <!-- no translation found for perms_hide (4145325555929151849) -->
- <skip />
- <!-- no translation found for perms_show_all (6040194843455403173) -->
- <skip />
- <!-- no translation found for googlewebcontenthelper_loading (2140804350507245589) -->
- <skip />
- <!-- no translation found for usb_storage_title (8699631567051394409) -->
- <skip />
- <!-- no translation found for usb_storage_message (5344039189213308733) -->
- <skip />
- <!-- no translation found for usb_storage_button_mount (6700104384375121662) -->
- <skip />
- <!-- no translation found for usb_storage_button_unmount (465869657252626688) -->
- <skip />
- <!-- no translation found for usb_storage_error_message (3192564550748426087) -->
- <skip />
- <!-- no translation found for usb_storage_notification_title (6237028017872246940) -->
- <skip />
- <!-- no translation found for usb_storage_notification_message (7371717280517625905) -->
- <skip />
- <!-- no translation found for select_input_method (2658280517827502015) -->
- <skip />
- <!-- no translation found for fast_scroll_alphabet (1017432309285755759) -->
- <skip />
- <!-- no translation found for fast_scroll_numeric_alphabet (3092587363718901074) -->
- <skip />
- <!-- no translation found for candidates_style (7738463880139922176) -->
- <skip />
-</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5c54226..725e369 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -40,7 +40,7 @@
<string name="mismatchPin">"De PIN-codes die u heeft ingevoerd, komen niet overeen."</string>
<string name="invalidPin">"Voer een PIN-code van 4 tot 8 cijfers in."</string>
<string name="needPuk">"Uw SIM-kaart is geblokkeerd met de PUK-code. Typ de PUK-code om de blokkering op te heffen."</string>
- <string name="needPuk2">"Voer de PUK2-code in om de SIM-kaart te deblokkeren."</string>
+ <string name="needPuk2">"Voer de PUK2-code in om de SIM-kaart te ontgrendelen."</string>
<string name="ClipMmi">"Inkomende beller-id"</string>
<string name="ClirMmi">"Uitgaande beller-id"</string>
<string name="CfMmi">"Oproep doorschakelen"</string>
@@ -103,13 +103,21 @@
<string name="global_action_toggle_silent_mode">"Stille modus"</string>
<string name="global_action_silent_mode_on_status">"Geluid is UIT"</string>
<string name="global_action_silent_mode_off_status">"Geluid is AAN"</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
<string name="safeMode">"Veilige modus"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
<string name="permgrouplab_costMoney">"Services waarvoor u moet betalen"</string>
<string name="permgroupdesc_costMoney">"Toepassingen toestaan activiteiten uit te voeren waarvoor mogelijk kosten in rekening worden gebracht."</string>
<string name="permgrouplab_messages">"Uw berichten"</string>
<string name="permgroupdesc_messages">"SMS, e-mail en andere berichten lezen en schrijven."</string>
<string name="permgrouplab_personalInfo">"Uw persoonlijke informatie"</string>
- <string name="permgroupdesc_personalInfo">"Rechtstreekse toegang tot de op uw telefoon opgeslagen contactpersonen en agenda."</string>
+ <string name="permgroupdesc_personalInfo">"Rechtstreekse toegang tot de op uw telefoon opgeslagen contacten en agenda."</string>
<string name="permgrouplab_location">"Uw locatie"</string>
<string name="permgroupdesc_location">"Uw fysieke locatie bijhouden"</string>
<string name="permgrouplab_network">"Netwerkcommunicatie"</string>
@@ -154,7 +162,7 @@
<string name="permdesc_restartPackages">"Hiermee kan een toepassing andere toepassingen opnieuw starten."</string>
<string name="permlab_setProcessForeground">"stoppen voorkomen"</string>
<string name="permdesc_setProcessForeground">"Hiermee kan een toepassing ervoor zorgen dat elk willekeurig proces op de voorgrond wordt uitgevoerd en dus niet kan worden afgesloten. Nooit vereist voor normale toepassingen."</string>
- <string name="permlab_forceBack">"toepassing gedwongen sluiten"</string>
+ <string name="permlab_forceBack">"toepassing nu sluiten"</string>
<string name="permdesc_forceBack">"Hiermee kan een toepassing elke willekeurige activiteit die op de voorgrond wordt uitgevoerd, sluiten en naar de achtergrond verplaatsen. Nooit vereist voor normale toepassingen."</string>
<string name="permlab_dump">"interne systeemstatus ophalen"</string>
<string name="permdesc_dump">"Hiermee kan een toepassing de interne status van het systeem ophalen. Schadelijke toepassingen kunnen privé- of veiligheidsgegevens ophalen die ze normaal niet nodig hebben."</string>
@@ -258,10 +266,12 @@
<string name="permdesc_camera">"Hiermee kan een toepassing foto\'s maken met de camera. De toepassing kan op deze manier op elk gewenste moment foto\'s verzamelen van wat de camera ziet."</string>
<string name="permlab_brick">"telefoon permanent uitschakelen"</string>
<string name="permdesc_brick">"Hiermee kan de toepassing de telefoon permanent uitschakelen. Dit is erg gevaarlijk."</string>
- <string name="permlab_reboot">"telefoon gedwongen opnieuw opstarten"</string>
- <string name="permdesc_reboot">"Hiermee kan de toepassing de telefoon gedwongen opnieuw opstarten."</string>
+ <string name="permlab_reboot">"telefoon nu opnieuw opstarten"</string>
+ <string name="permdesc_reboot">"Hiermee kan de toepassing de telefoon nu opnieuw opstarten."</string>
<string name="permlab_mount_unmount_filesystems">"bestandssystemen koppelen en ontkoppelen"</string>
<string name="permdesc_mount_unmount_filesystems">"Hiermee kan de toepassing bestandssystemen koppelen en ontkoppelen voor verwisselbare opslagruimte."</string>
+ <string name="permlab_mount_format_filesystems">"externe opslag formatteren"</string>
+ <string name="permdesc_mount_format_filesystems">"Hiermee kan de toepassing de externe opslag formatteren."</string>
<string name="permlab_vibrate">"trilstand beheren"</string>
<string name="permdesc_vibrate">"Hiermee kan de toepassing de trilstand beheren."</string>
<string name="permlab_flashlight">"zaklamp bedienen"</string>
@@ -276,6 +286,8 @@
<string name="permdesc_locationUpdates">"Hiermee kunnen updatemeldingen voor locaties van de radio worden ingeschakeld/uitgeschakeld. Niet voor gebruik door normale toepassingen."</string>
<string name="permlab_checkinProperties">"toegang tot checkin-eigenschappen"</string>
<string name="permdesc_checkinProperties">"Hiermee wordt lees-/schrijftoegang gegeven tot eigenschappen die door de checkin-service zijn geüpload. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permlab_bindGadget">"gadgets kiezen"</string>
+ <string name="permdesc_bindGadget">"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."</string>
<string name="permlab_modifyPhoneState">"telefoonstatus wijzigen"</string>
<string name="permdesc_modifyPhoneState">"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."</string>
<string name="permlab_readPhoneState">"telefoonstatus lezen"</string>
@@ -304,6 +316,8 @@
<string name="permdesc_writeApnSettings">"Hiermee kan een toepassing de APN-instellingen, zoals proxy en poort, van elke APN wijzigen."</string>
<string name="permlab_changeNetworkState">"netwerkverbinding wijzigen"</string>
<string name="permdesc_changeNetworkState">"Hiermee kan een toepassing de verbindingsstatus van het netwerk wijzigen."</string>
+ <string name="permlab_changeBackgroundDataSetting">"instelling voor gebruik van achtergrondgegevens van gegevens wijzigen"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Hiermee kan een toepassing de instelling voor gebruik van achtergrondgegevens wijzigen."</string>
<string name="permlab_accessWifiState">"Wi-Fi-status bekijken"</string>
<string name="permdesc_accessWifiState">"Hiermee kan een toepassing informatie over de Wi-Fi-status bekijken."</string>
<string name="permlab_changeWifiState">"Wi-Fi-status wijzigen"</string>
@@ -315,23 +329,19 @@
<string name="permlab_disableKeyguard">"toetsblokkering uitschakelen"</string>
<string name="permdesc_disableKeyguard">"Hiermee kan een toepassing de toetsblokkering en bijbehorende wachtwoordbeveiliging uitschakelen. Een voorbeeld: de telefoon schakelt de toetsblokkering uit als er een oproep binnenkomt en schakelt de toetsblokkering weer in als de oproep is beëindigd."</string>
<string name="permlab_readSyncSettings">"synchronisatie-instellingen lezen"</string>
- <string name="permdesc_readSyncSettings">"Hiermee kan een toepassing de synchronisatie-instellingen lezen, bijvoorbeeld of de synchronisatie van contactpersonen is ingeschakeld."</string>
+ <string name="permdesc_readSyncSettings">"Hiermee kan een toepassing de synchronisatie-instellingen lezen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
<string name="permlab_writeSyncSettings">"synchronisatie-instellingen schrijven"</string>
- <string name="permdesc_writeSyncSettings">"Hiermee kan een toepassing uw synchronisatie-instellingen wijzigen, bijvoorbeeld of de synchronisatie van contactpersonen is ingeschakeld."</string>
+ <string name="permdesc_writeSyncSettings">"Hiermee kan een toepassing uw synchronisatie-instellingen wijzigen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
<string name="permlab_readSyncStats">"synchronisatiestatistieken lezen"</string>
<string name="permdesc_readSyncStats">"Hiermee kan een toepassing de synchronisatiestatistieken lezen, zoals de geschiedenis van uitgevoerde synchronisaties."</string>
<string name="permlab_subscribedFeedsRead">"geabonneerde feeds lezen"</string>
<string name="permdesc_subscribedFeedsRead">"Hiermee kan een toepassing details over de huidige gesynchroniseerde feeds achterhalen."</string>
<string name="permlab_subscribedFeedsWrite">"geabonneerde feeds schrijven"</string>
<string name="permdesc_subscribedFeedsWrite">"Hiermee kan een toepassing uw huidige gesynchroniseerde feeds wijzigen. Een schadelijke toepassing kan op deze manier uw gesynchroniseerde feeds wijzigen."</string>
- <!-- no translation found for permlab_readDictionary (432535716804748781) -->
- <skip />
- <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
- <skip />
- <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
- <skip />
- <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
- <skip />
+ <string name="permlab_readDictionary">"door gebruiker gedefinieerd woordenboek lezen"</string>
+ <string name="permdesc_readDictionary">"Hiermee kan een toepassing privéwoorden, namen en woordcombinaties lezen die de gebruiker heeft opgeslagen in het gebruikerswoordenboek."</string>
+ <string name="permlab_writeDictionary">"schrijven naar door gebruiker gedefinieerd woordenboek"</string>
+ <string name="permdesc_writeDictionary">"Hiermee kan een toepassing nieuwe woorden schrijven naar het gebruikerswoordenboek."</string>
<string-array name="phoneTypes">
<item>"Thuis"</item>
<item>"Mobiel"</item>
@@ -377,17 +387,18 @@
</string-array>
<string name="keyguard_password_enter_pin_code">"PIN-code invoeren"</string>
<string name="keyguard_password_wrong_pin_code">"Onjuiste PIN-code!"</string>
- <string name="keyguard_label_text">"Druk op \'Menu\' en vervolgens op 0 om te deblokkeren."</string>
+ <string name="keyguard_label_text">"Druk op \'Menu\' en vervolgens op 0 om te ontgrendelen."</string>
<string name="emergency_call_dialog_number_for_display">"Alarmnummer"</string>
<string name="lockscreen_carrier_default">"(Geen service)"</string>
<string name="lockscreen_screen_locked">"Scherm geblokkeerd."</string>
- <string name="lockscreen_instructions_when_pattern_enabled">"Druk op \'Menu\' om te deblokkeren of noodoproep te plaatsen."</string>
- <string name="lockscreen_instructions_when_pattern_disabled">"Druk op \'Menu\' om te deblokkeren."</string>
- <string name="lockscreen_pattern_instructions">"Patroon tekenen om te deblokkeren"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Druk op \'Menu\' om te ontgrendelen of noodoproep te plaatsen."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Druk op \'Menu\' om te ontgrendelen."</string>
+ <string name="lockscreen_pattern_instructions">"Patroon tekenen om te ontgrendelen"</string>
<string name="lockscreen_emergency_call">"Noodoproep"</string>
<string name="lockscreen_pattern_correct">"Juist!"</string>
<string name="lockscreen_pattern_wrong">"Probeer het opnieuw"</string>
- <string name="lockscreen_plugged_in">"Opladen (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
<string name="lockscreen_low_battery">"Sluit de oplader aan."</string>
<string name="lockscreen_missing_sim_message_short">"Geen SIM-kaart."</string>
<string name="lockscreen_missing_sim_message">"Geen SIM-kaart in telefoon."</string>
@@ -396,13 +407,13 @@
<string name="lockscreen_sim_puk_locked_message">"SIM-kaart is geblokkeerd met PUK-code."</string>
<string name="lockscreen_sim_puk_locked_instructions">"Neem contact op met de klantenservice."</string>
<string name="lockscreen_sim_locked_message">"SIM-kaart is geblokkeerd."</string>
- <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM-kaart deblokkeren..."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message">"SIM-kaart ontgrendelen..."</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message">"U heeft uw deblokkeringspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
- <string name="lockscreen_failed_attempts_almost_glogin">"U heeft uw deblokkeringspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen, wordt u gevraagd om uw telefoon te deblokkeren met uw Google aanmelding."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin">"U heeft uw deblokkeringspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen, wordt u gevraagd om uw telefoon te ontgrendelen met uw Google aanmelding."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
<string name="lockscreen_too_many_failed_attempts_countdown">"Probeer het over <xliff:g id="NUMBER">%d</xliff:g> seconden opnieuw."</string>
<string name="lockscreen_forgot_pattern_button_text">"Patroon vergeten?"</string>
<string name="lockscreen_glogin_too_many_attempts">"Te veel patroonpogingen!"</string>
- <string name="lockscreen_glogin_instructions">"U moet zich aanmelden bij uw Google-account"\n"om te deblokkeren"</string>
+ <string name="lockscreen_glogin_instructions">"U moet zich aanmelden bij uw Google-account"\n"om te ontgrendelen"</string>
<string name="lockscreen_glogin_username_hint">"Gebruikersnaam (e-mail)"</string>
<string name="lockscreen_glogin_password_hint">"Wachtwoord"</string>
<string name="lockscreen_glogin_submit_button">"Aanmelden"</string>
@@ -410,15 +421,15 @@
<string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
<string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <!-- no translation found for hour_ampm (7618670480400517084) -->
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
<skip />
- <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
<skip />
<string name="status_bar_clear_all_button">"Meldingen wissen"</string>
<string name="status_bar_no_notifications_title">"Geen meldingen"</string>
<string name="status_bar_ongoing_events_title">"Actief"</string>
<string name="status_bar_latest_events_title">"Meldingen"</string>
- <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
<skip />
<string name="battery_status_charging">"Opladen..."</string>
<string name="battery_low_title">"Sluit de oplader aan"</string>
@@ -428,12 +439,9 @@
<string name="factorytest_not_system">"De actie FACTORY_TEST wordt alleen ondersteund voor pakketten die zijn geïnstalleerd in /system/app."</string>
<string name="factorytest_no_action">"Er is geen pakket gevonden dat de actie FACTORY_TEST levert."</string>
<string name="factorytest_reboot">"Opnieuw opstarten"</string>
- <!-- no translation found for js_dialog_title (8143918455087008109) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
- <skip />
+ <string name="js_dialog_title">"De pagina op \'<xliff:g id="TITLE">%s</xliff:g>\' zegt:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Wilt u deze pagina verlaten?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Kies OK om door te gaan of Annuleren om op de huidige pagina te blijven."</string>
<string name="save_password_label">"Bevestigen"</string>
<string name="save_password_message">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
<string name="save_password_notnow">"Niet nu"</string>
@@ -484,22 +492,38 @@
<item quantity="one">"morgen"</item>
<item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
</plurals>
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"1 seconde geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> seconden geleden"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"1 minuut geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> minuten geleden"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"1 uur geleden"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> uur geleden"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"gisteren"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dagen geleden"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"over 1 seconde"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> seconden"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"over 1 minuut"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> minuten"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"over 1 uur"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> uur"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"morgen"</item>
+ <item quantity="other">"over <xliff:g id="COUNT">%d</xliff:g> dagen"</item>
+ </plurals>
<string name="preposition_for_date">"op %s"</string>
<string name="preposition_for_time">"om %s"</string>
<string name="preposition_for_year">"in %s"</string>
@@ -541,27 +565,25 @@
<string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
- <!-- no translation found for date_time (6104442718633642836) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
- <string name="full_date_month_first">"<xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="DAY">dd</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="full_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMMM</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_month_first">"<xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="DAY">dd</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMM</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
- <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMMM</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMM</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
<string name="noon">"twaalf uur \'s middags"</string>
<string name="Noon">"Twaalf uur \'s middags"</string>
<string name="midnight">"middernacht"</string>
<string name="Midnight">"Middernacht"</string>
- <!-- no translation found for month_day (5565829181417740906) -->
+ <!-- no translation found for month_day (3693060561170538204) -->
<skip />
- <!-- no translation found for month (7026169712234774086) -->
+ <!-- no translation found for month (1976700695144952053) -->
<skip />
<string name="month_day_year">"<xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for month_year (9219019380312413367) -->
+ <!-- no translation found for month_year (2106203387378728384) -->
<skip />
<string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
@@ -590,11 +612,11 @@
<string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="abbrev_month_day_year">"<xliff:g id="MONTH">%b</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
<skip />
- <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
<skip />
- <!-- no translation found for abbrev_month (3131032032850777433) -->
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
<skip />
<string name="day_of_week_long_sunday">"Zondag"</string>
<string name="day_of_week_long_monday">"Maandag"</string>
@@ -679,6 +701,7 @@
<string name="paste">"Plakken"</string>
<string name="copyUrl">"URL kopiëren"</string>
<string name="inputMethod">"Invoermethode"</string>
+ <string name="addToDictionary">"%s\' toevoegen aan woordenboek"</string>
<string name="editTextMenuTitle">"Tekst bewerken"</string>
<string name="low_internal_storage_view_title">"Weinig ruimte"</string>
<string name="low_internal_storage_view_text">"Opslagruimte van telefoon raakt op."</string>
@@ -686,6 +709,7 @@
<string name="cancel">"Annuleren"</string>
<string name="yes">"OK"</string>
<string name="no">"Annuleren"</string>
+ <string name="dialog_alert_title">"Let op"</string>
<string name="capital_on">"AAN"</string>
<string name="capital_off">"UIT"</string>
<string name="whichApplication">"Actie voltooien met"</string>
@@ -701,7 +725,7 @@
<string name="anr_activity_process">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
<string name="anr_application_process">"Toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
<string name="anr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> reageert niet."</string>
- <string name="force_close">"Gedwongen sluiten"</string>
+ <string name="force_close">"Nu sluiten"</string>
<string name="wait">"Wachten"</string>
<string name="debug">"Foutopsporing"</string>
<string name="sendText">"Selecteer een actie voor tekst"</string>
@@ -709,7 +733,7 @@
<string name="volume_music">"Mediavolume"</string>
<string name="volume_music_hint_playing_through_bluetooth">"Afspelen via Bluetooth"</string>
<string name="volume_call">"Volume inkomende oproep"</string>
- <string name="volume_call_hint_playing_through_bluetooth">"Afspelen via Bluetooth"</string>
+ <string name="volume_bluetooth_call">"Volume tijdens gesprek in Bluetooth-modus"</string>
<string name="volume_alarm">"Alarmvolume"</string>
<string name="volume_notification">"Meldingsvolume"</string>
<string name="volume_unknown">"Volume"</string>
@@ -745,8 +769,47 @@
<string name="usb_storage_error_message">"Er is een probleem bij het gebruik van uw SD-kaart voor USB-opslag."</string>
<string name="usb_storage_notification_title">"USB-verbinding"</string>
<string name="usb_storage_notification_message">"Selecteer dit om bestanden naar/van uw computer te kopiëren."</string>
+ <string name="usb_storage_stop_notification_title">"USB-opslag uitschakelen"</string>
+ <string name="usb_storage_stop_notification_message">"Selecteer dit om USB-opslag uit te schakelen."</string>
+ <string name="usb_storage_stop_title">"USB-opslag uitschakelen"</string>
+ <string name="usb_storage_stop_message">"Voordat u de USB-opslag uitschakelt, moet u de koppeling met de USB-host verbreken. Selecteer \'Uitschakelen\' om USB-opslag uit te schakelen."</string>
+ <string name="usb_storage_stop_button_mount">"Uitschakelen"</string>
+ <string name="usb_storage_stop_button_unmount">"Annuleren"</string>
+ <string name="usb_storage_stop_error_message">"Er is een probleem opgetreden tijdens het uitschakelen van USB-opslag. Controleer of u de USB-host heeft losgekoppeld en probeer het opnieuw."</string>
+ <string name="extmedia_format_title">"SD-kaart formatteren"</string>
+ <string name="extmedia_format_message">"Weet u zeker dat u de SD-kaart wilt formatteren? Alle gegevens op uw kaart gaan dan verloren."</string>
+ <string name="extmedia_format_button_format">"Formatteren"</string>
<string name="select_input_method">"Invoermethode selecteren"</string>
- <string name="fast_scroll_alphabet">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style"><font fgcolor="#ff000000" bgcolor="#ff8080ff"><u>"kandidaten"</u>"u&gt;"</font></string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"kandidaten"</u></string>
+ <string name="ext_media_checking_notification_title">"SD-kaart voorbereiden"</string>
+ <string name="ext_media_checking_notification_message">"Controleren op fouten"</string>
+ <string name="ext_media_nofs_notification_title">"Lege SD-kaart"</string>
+ <string name="ext_media_nofs_notification_message">"De SD-kaart is leeg of gebruikt een niet-ondersteund bestandssysteem."</string>
+ <string name="ext_media_unmountable_notification_title">"Beschadigde SD-kaart"</string>
+ <string name="ext_media_unmountable_notification_message">"De SD-kaart is beschadigd. U moet de kaart mogelijk opnieuw formatteren."</string>
+ <string name="ext_media_badremoval_notification_title">"SD-kaart onverwachts verwijderd"</string>
+ <string name="ext_media_badremoval_notification_message">"Ontkoppel de SD-kaart voordat u deze verwijdert om gegevensverlies te voorkomen."</string>
+ <string name="ext_media_safe_unmount_notification_title">"De SD-kaart kan veilig worden verwijderd"</string>
+ <string name="ext_media_safe_unmount_notification_message">"De SD-kaart kan nu veilig worden verwijderd."</string>
+ <string name="ext_media_nomedia_notification_title">"SD-kaart is verwijderd"</string>
+ <string name="ext_media_nomedia_notification_message">"De SD-kaart is verwijderd. Plaats een nieuwe SD-kaart om de opslagcapaciteit van uw apparaat te vergroten."</string>
+ <string name="activity_list_empty">"Geen overeenkomende activiteiten gevonden"</string>
+ <string name="permlab_pkgUsageStats">"gebruiksstatistieken van component bijwerken"</string>
+ <string name="permdesc_pkgUsageStats">"Hiermee kunnen verzamelde gebruiksstatistieken van een component worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index c3e3a46..641d335 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -43,8 +43,8 @@
<string name="needPuk2">"Wprowadź kod PUK2, aby odblokować kartę SIM."</string>
<string name="ClipMmi">"Identyfikator dzwoniącego przy połączeniach przychodzących"</string>
<string name="ClirMmi">"Identyfikator dzwoniącego przy połączeniach wychodzących"</string>
- <string name="CfMmi">"Przekierowanie połączeń"</string>
- <string name="CwMmi">"Połączenie oczekujące"</string>
+ <string name="CfMmi">"Przekierowania połączeń"</string>
+ <string name="CwMmi">"Połączenia oczekujące"</string>
<string name="BaMmi">"Blokada dzwonienia"</string>
<string name="PwdMmi">"Zmiana hasła"</string>
<string name="PinMmi">"Zmiana kodu PIN"</string>
@@ -103,7 +103,15 @@
<string name="global_action_toggle_silent_mode">"Tryb cichy"</string>
<string name="global_action_silent_mode_on_status">"Dźwięk jest wyłączony"</string>
<string name="global_action_silent_mode_off_status">"Dźwięk jest włączony"</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
<string name="safeMode">"Tryb awaryjny"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
<string name="permgrouplab_costMoney">"Usługi płatne"</string>
<string name="permgroupdesc_costMoney">"Pozwól aplikacjom na wykonywanie płatnych operacji."</string>
<string name="permgrouplab_messages">"Twoje wiadomości"</string>
@@ -244,7 +252,7 @@
<string name="permdesc_accessLocationExtraCommands">"Dostęp do dodatkowych poleceń dostawcy informacji o położeniu. Szkodliwe aplikacje mogą go wykorzystać, aby wpływać na działanie urządzenia GPS lub innych źródeł ustalania położenia."</string>
<string name="permlab_accessFineLocation">"dokładne położenie (GPS)"</string>
<string name="permdesc_accessFineLocation">"Uzyskiwanie dostępu do dokładnych źródeł ustalania położenia w telefonie, takich jak system GPS, tam, gdzie są one dostępne. Szkodliwe aplikacje mogą to wykorzystać do określenia położenia użytkownika oraz mogą zużywać więcej energii baterii."</string>
- <string name="permlab_accessCoarseLocation">"zgrubne (oparte o sieć) ustalanie położenia"</string>
+ <string name="permlab_accessCoarseLocation">"przybliżone ustalanie położenia (oparte o sieć)"</string>
<string name="permdesc_accessCoarseLocation">"Dostęp do źródeł, takich jak bazy danych sieci komórkowych, jeśli są dostępne, które pozwalają określić przybliżone położenie telefonu. Szkodliwe aplikacje mogą go wykorzystać do określenia, gdzie w przybliżeniu znajduje się użytkownik."</string>
<string name="permlab_accessSurfaceFlinger">"dostęp do usługi SurfaceFlinger"</string>
<string name="permdesc_accessSurfaceFlinger">"Pozwala aplikacji na wykorzystanie funkcji niskiego poziomu usługi SurfaceFlinger."</string>
@@ -260,8 +268,10 @@
<string name="permdesc_brick">"Pozwala aplikacji na wyłączenie całego telefonu na stałe. Jest to bardzo niebezpieczne."</string>
<string name="permlab_reboot">"wymuszanie ponownego uruchomienia telefonu"</string>
<string name="permdesc_reboot">"Pozwala aplikacji na wymuszenie ponownego uruchomienia telefonu."</string>
- <string name="permlab_mount_unmount_filesystems">"montowanie i odmontowanie systemów plików"</string>
+ <string name="permlab_mount_unmount_filesystems">"podłączanie i odłączanie systemów plików"</string>
<string name="permdesc_mount_unmount_filesystems">"Pozwala aplikacjom na podłączanie i odłączanie systemów plików w pamięciach przenośnych."</string>
+ <string name="permlab_mount_format_filesystems">"formatowanie pamięci zewnętrznej"</string>
+ <string name="permdesc_mount_format_filesystems">"Zezwala aplikacji na formatowanie wymiennych nośników."</string>
<string name="permlab_vibrate">"kontrolowanie wibracji"</string>
<string name="permdesc_vibrate">"Pozwala aplikacjom na kontrolowanie wibracji."</string>
<string name="permlab_flashlight">"kontrolowanie latarki"</string>
@@ -276,6 +286,8 @@
<string name="permdesc_locationUpdates">"Pozwala włączyć/wyłączyć powiadomienia o aktualizacji położenia przez radio. Nie wykorzystywane przez normalne aplikacje."</string>
<string name="permlab_checkinProperties">"dostęp do właściwości usługi rezerwacji"</string>
<string name="permdesc_checkinProperties">"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."</string>
+ <string name="permlab_bindGadget">"wybieranie gadżetów"</string>
+ <string name="permdesc_bindGadget">"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."</string>
<string name="permlab_modifyPhoneState">"zmiana stanu telefonu"</string>
<string name="permdesc_modifyPhoneState">"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."</string>
<string name="permlab_readPhoneState">"czytanie stanu telefonu"</string>
@@ -304,6 +316,8 @@
<string name="permdesc_writeApnSettings">"Pozwala aplikacji na zmianę ustawień APN, takich jak serwer proxy oraz port dowolnego APN."</string>
<string name="permlab_changeNetworkState">"zmienianie połączeń sieci"</string>
<string name="permdesc_changeNetworkState">"Pozwala aplikacji na zmianę stanu połączeń sieciowych."</string>
+ <string name="permlab_changeBackgroundDataSetting">"zmienianie ustawienia używania danych w tle"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Zezwala aplikacji na zmianę ustawień użycia danych w tle."</string>
<string name="permlab_accessWifiState">"wyświetlanie stanu Wi-Fi"</string>
<string name="permdesc_accessWifiState">"Pozwala aplikacji na wyświetlanie informacji o stanie Wi-Fi."</string>
<string name="permlab_changeWifiState">"zmiana stanu Wi-Fi"</string>
@@ -324,16 +338,12 @@
<string name="permdesc_subscribedFeedsRead">"Pozwala aplikacjom na pobieranie informacji szczegółowych na temat obecnie zsynchronizowanych źródeł."</string>
<string name="permlab_subscribedFeedsWrite">"zapisywanie subskrybowanych źródeł"</string>
<string name="permdesc_subscribedFeedsWrite">"Umożliwia aplikacji zmianę obecnie zsynchronizowanych źródeł. Może to pozwolić szkodliwej aplikacji na zmianę zsynchronizowanych źródeł."</string>
- <!-- no translation found for permlab_readDictionary (432535716804748781) -->
- <skip />
- <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
- <skip />
- <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
- <skip />
- <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
- <skip />
+ <string name="permlab_readDictionary">"odczytywanie słownika zdefiniowanego przez użytkownika"</string>
+ <string name="permdesc_readDictionary">"Zezwala aplikacji na odczytywanie wszelkich prywatnych słów, nazw i wyrażeń zapisanych przez użytkownika w swoim słowniku."</string>
+ <string name="permlab_writeDictionary">"zapisywanie w słowniku zdefiniowanym przez użytkownika"</string>
+ <string name="permdesc_writeDictionary">"Zezwala aplikacjom na zapisywanie nowych słów w słowniku użytkownika."</string>
<string-array name="phoneTypes">
- <item>"Strona główna"</item>
+ <item>"Dom"</item>
<item>"Komórka"</item>
<item>"Praca"</item>
<item>"Faks w pracy"</item>
@@ -343,19 +353,19 @@
<item>"Niestandardowy"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item>"Strona główna"</item>
+ <item>"Dom"</item>
<item>"Praca"</item>
<item>"Inne"</item>
<item>"Niestandardowy"</item>
</string-array>
<string-array name="postalAddressTypes">
- <item>"Strona główna"</item>
+ <item>"Dom"</item>
<item>"Praca"</item>
<item>"Inny"</item>
<item>"Niestandardowy"</item>
</string-array>
<string-array name="imAddressTypes">
- <item>"Strona główna"</item>
+ <item>"Dom"</item>
<item>"Praca"</item>
<item>"Inne"</item>
<item>"Niestandardowy"</item>
@@ -377,17 +387,18 @@
</string-array>
<string name="keyguard_password_enter_pin_code">"Wprowadź kod PIN"</string>
<string name="keyguard_password_wrong_pin_code">"Błędny kod PIN!"</string>
- <string name="keyguard_label_text">"Aby odblokować, naciśnij przycisk Menu, a następnie 0."</string>
+ <string name="keyguard_label_text">"Aby odblokować, naciśnij Menu, a następnie 0."</string>
<string name="emergency_call_dialog_number_for_display">"Numer alarmowy"</string>
<string name="lockscreen_carrier_default">"(Brak usługi)"</string>
<string name="lockscreen_screen_locked">"Ekran zablokowany."</string>
- <string name="lockscreen_instructions_when_pattern_enabled">"Naciśnij przycisk Menu, aby odblokować lub wykonać połączenie alarmowe."</string>
- <string name="lockscreen_instructions_when_pattern_disabled">"Naciśnij przycisk Menu, aby odblokować."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled">"Naciśnij Menu, aby odblokować lub wykonać połączenie alarmowe."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled">"Naciśnij Menu, aby odblokować."</string>
<string name="lockscreen_pattern_instructions">"Narysuj wzór, aby odblokować"</string>
<string name="lockscreen_emergency_call">"Połączenie alarmowe"</string>
<string name="lockscreen_pattern_correct">"Poprawnie!"</string>
<string name="lockscreen_pattern_wrong">"Niestety, spróbuj ponownie"</string>
- <string name="lockscreen_plugged_in">"Ładowanie (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
<string name="lockscreen_low_battery">"Podłącz ładowarkę."</string>
<string name="lockscreen_missing_sim_message_short">"Brak karty SIM."</string>
<string name="lockscreen_missing_sim_message">"Brak karty SIM w telefonie."</string>
@@ -410,15 +421,15 @@
<string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
<string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <!-- no translation found for hour_ampm (7618670480400517084) -->
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
<skip />
- <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
<skip />
<string name="status_bar_clear_all_button">"Wyczyść powiadomienia"</string>
<string name="status_bar_no_notifications_title">"Brak powiadomień"</string>
<string name="status_bar_ongoing_events_title">"Trwające"</string>
<string name="status_bar_latest_events_title">"Powiadomienia"</string>
- <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
<skip />
<string name="battery_status_charging">"Ładowanie..."</string>
<string name="battery_low_title">"Podłącz ładowarkę"</string>
@@ -428,12 +439,9 @@
<string name="factorytest_not_system">"Czynność FACTORY_TEST jest obsługiwana tylko dla pakietów zainstalowanych w katalogu /system/app."</string>
<string name="factorytest_no_action">"Nie znaleziono żadnego pakietu, który zapewnia działanie FACTORY_TEST."</string>
<string name="factorytest_reboot">"Uruchom ponownie"</string>
- <!-- no translation found for js_dialog_title (8143918455087008109) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
- <skip />
+ <string name="js_dialog_title">"Komunikat ze strony pod adresem „<xliff:g id="TITLE">%s</xliff:g>”:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Czy opuścić tę stronę?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wybierz opcję OK, aby kontynuować, lub opcję Anuluj, aby pozostać na tej stronie."</string>
<string name="save_password_label">"Potwierdź"</string>
<string name="save_password_message">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string>
<string name="save_password_notnow">"Nie teraz"</string>
@@ -450,7 +458,7 @@
<string name="today">"Dzisiaj"</string>
<string name="yesterday">"Wczoraj"</string>
<string name="tomorrow">"Jutro"</string>
- <string name="oneMonthDurationPast">"miesiąc temu"</string>
+ <string name="oneMonthDurationPast">"1 miesiąc temu"</string>
<string name="beforeOneMonthDurationPast">"Ponad 1 miesiąc temu"</string>
<plurals name="num_seconds_ago">
<item quantity="one">"sekundę temu"</item>
@@ -484,22 +492,38 @@
<item quantity="one">"jutro"</item>
<item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
</plurals>
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"sekundę temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> sek. temu"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"minutę temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> min temu"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"godzinę temu"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> godz. temu"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"wczoraj"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> dni temu"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"za sekundę"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> sek."</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"za minutę"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> min"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"za godzinę"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> godz."</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"jutro"</item>
+ <item quantity="other">"za <xliff:g id="COUNT">%d</xliff:g> dni"</item>
+ </plurals>
<string name="preposition_for_date">"dnia %s"</string>
<string name="preposition_for_time">"o %s"</string>
<string name="preposition_for_year">"w %s"</string>
@@ -515,13 +539,13 @@
<string name="weeks">"tygodni"</string>
<string name="year">"rok"</string>
<string name="years">"lat"</string>
- <string name="sunday">"Niedziela"</string>
- <string name="monday">"Poniedziałek"</string>
- <string name="tuesday">"Wtorek"</string>
- <string name="wednesday">"Środa"</string>
- <string name="thursday">"Czwartek"</string>
- <string name="friday">"Piątek"</string>
- <string name="saturday">"Sobota"</string>
+ <string name="sunday">"niedziela"</string>
+ <string name="monday">"poniedziałek"</string>
+ <string name="tuesday">"wtorek"</string>
+ <string name="wednesday">"środa"</string>
+ <string name="thursday">"czwartek"</string>
+ <string name="friday">"piątek"</string>
+ <string name="saturday">"sobota"</string>
<string name="every_weekday">"W każdy dzień roboczy (pon–pt)"</string>
<string name="daily">"Codziennie"</string>
<string name="weekly">"Co tydzień w <xliff:g id="DAY">%s</xliff:g>"</string>
@@ -541,27 +565,25 @@
<string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
- <!-- no translation found for date_time (6104442718633642836) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
- <string name="full_date_month_first">"<xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="DAY">dd</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="full_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMMM</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_month_first">"<xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="DAY">dd</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMM</xliff:g>, <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
- <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMMM</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMM</xliff:g>', '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
<string name="noon">"południe"</string>
<string name="Noon">"Południe"</string>
<string name="midnight">"północ"</string>
<string name="Midnight">"Północ"</string>
- <!-- no translation found for month_day (5565829181417740906) -->
+ <!-- no translation found for month_day (3693060561170538204) -->
<skip />
- <!-- no translation found for month (7026169712234774086) -->
+ <!-- no translation found for month (1976700695144952053) -->
<skip />
<string name="month_day_year">"<xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for month_year (9219019380312413367) -->
+ <!-- no translation found for month_year (2106203387378728384) -->
<skip />
<string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
@@ -590,19 +612,19 @@
<string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>, <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>, <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="abbrev_month_day_year">"<xliff:g id="MONTH">%b</xliff:g> <xliff:g id="DAY">%-d</xliff:g>, <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
<skip />
- <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
<skip />
- <!-- no translation found for abbrev_month (3131032032850777433) -->
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
<skip />
- <string name="day_of_week_long_sunday">"Niedziela"</string>
- <string name="day_of_week_long_monday">"Poniedziałek"</string>
- <string name="day_of_week_long_tuesday">"Wtorek"</string>
- <string name="day_of_week_long_wednesday">"Środa"</string>
- <string name="day_of_week_long_thursday">"Czwartek"</string>
- <string name="day_of_week_long_friday">"Piątek"</string>
- <string name="day_of_week_long_saturday">"Sobota"</string>
+ <string name="day_of_week_long_sunday">"niedziela"</string>
+ <string name="day_of_week_long_monday">"poniedziałek"</string>
+ <string name="day_of_week_long_tuesday">"wtorek"</string>
+ <string name="day_of_week_long_wednesday">"środa"</string>
+ <string name="day_of_week_long_thursday">"czwartek"</string>
+ <string name="day_of_week_long_friday">"piątek"</string>
+ <string name="day_of_week_long_saturday">"sobota"</string>
<string name="day_of_week_medium_sunday">"Nie"</string>
<string name="day_of_week_medium_monday">"Pon"</string>
<string name="day_of_week_medium_tuesday">"Wt"</string>
@@ -670,7 +692,7 @@
<string name="elapsed_time_short_format_mm_ss">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll">"Zaznacz wszystko"</string>
- <string name="selectText">"Wybierz tekst"</string>
+ <string name="selectText">"Zaznacz tekst"</string>
<string name="stopSelectingText">"Zatrzymaj wybieranie tekstu"</string>
<string name="cut">"Wytnij"</string>
<string name="cutAll">"Wytnij wszystko"</string>
@@ -678,7 +700,8 @@
<string name="copyAll">"Kopiuj wszystko"</string>
<string name="paste">"Wklej"</string>
<string name="copyUrl">"Kopiuj adres URL"</string>
- <string name="inputMethod">"Metoda wejściowa"</string>
+ <string name="inputMethod">"Wprowadzanie tekstu"</string>
+ <string name="addToDictionary">"Dodaj „%s” do słownika"</string>
<string name="editTextMenuTitle">"Edytuj tekst"</string>
<string name="low_internal_storage_view_title">"Mało miejsca"</string>
<string name="low_internal_storage_view_text">"Maleje ilość dostępnej pamięci telefonu."</string>
@@ -686,9 +709,10 @@
<string name="cancel">"Anuluj"</string>
<string name="yes">"OK"</string>
<string name="no">"Anuluj"</string>
+ <string name="dialog_alert_title">"Uwaga"</string>
<string name="capital_on">"Włącz"</string>
<string name="capital_off">"Wyłącz"</string>
- <string name="whichApplication">"Zakończ działanie, korzystając z"</string>
+ <string name="whichApplication">"Zakończ czynność korzystając z"</string>
<string name="alwaysUse">"Używaj domyślnie dla tej czynności."</string>
<string name="clearDefaultHintMsg">"Wyczyść domyślne w: Ustawienia strony głównej &gt; Aplikacje &gt; Zarządzaj aplikacjami."</string>
<string name="chooseActivity">"Wybierz czynność"</string>
@@ -697,8 +721,8 @@
<string name="aerr_application">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) została niespodziewanie zatrzymana. Spróbuj ponownie."</string>
<string name="aerr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> został niespodziewanie zatrzymany. Spróbuj ponownie."</string>
<string name="anr_title">"Przepraszamy!"</string>
- <string name="anr_activity_application">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> (w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>) nie odpowiada."</string>
- <string name="anr_activity_process">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> (w procesie <xliff:g id="PROCESS">%2$s</xliff:g>) nie odpowiada."</string>
+ <string name="anr_activity_application">"<xliff:g id="ACTIVITY">%1$s</xliff:g> (w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>) nie odpowiada."</string>
+ <string name="anr_activity_process">"<xliff:g id="ACTIVITY">%1$s</xliff:g> (w procesie <xliff:g id="PROCESS">%2$s</xliff:g>) nie odpowiada."</string>
<string name="anr_application_process">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (w procesie <xliff:g id="PROCESS">%2$s</xliff:g>) nie odpowiada."</string>
<string name="anr_process">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> nie odpowiada."</string>
<string name="force_close">"Wymuś zamknięcie"</string>
@@ -709,7 +733,7 @@
<string name="volume_music">"Głośność multimediów"</string>
<string name="volume_music_hint_playing_through_bluetooth">"Odtwarzanie przez Bluetooth"</string>
<string name="volume_call">"Głośność podczas połączenia"</string>
- <string name="volume_call_hint_playing_through_bluetooth">"Odtwarzanie przez Bluetooth"</string>
+ <string name="volume_bluetooth_call">"Głośność Bluetooth w czasie połączenia"</string>
<string name="volume_alarm">"Głośność alarmu"</string>
<string name="volume_notification">"Głośność powiadomienia"</string>
<string name="volume_unknown">"Głośność"</string>
@@ -739,14 +763,53 @@
<string name="perms_show_all"><b>"Pokaż wszystko"</b></string>
<string name="googlewebcontenthelper_loading">"Ładowanie..."</string>
<string name="usb_storage_title">"Połączenie przez USB"</string>
- <string name="usb_storage_message">"Telefon został podłączony do komputera przez port USB. Wybierz polecenie „Montuj”, jeśli chcesz skopiować pliki między komputerem a kartą SD w telefonie."</string>
- <string name="usb_storage_button_mount">"Zamontuj"</string>
- <string name="usb_storage_button_unmount">"Nie montuj"</string>
+ <string name="usb_storage_message">"Telefon został podłączony do komputera przez port USB. Wybierz polecenie „Podłącz”, jeśli chcesz skopiować pliki między komputerem a kartą SD w telefonie."</string>
+ <string name="usb_storage_button_mount">"Podłącz"</string>
+ <string name="usb_storage_button_unmount">"Nie podłączaj"</string>
<string name="usb_storage_error_message">"Wystąpił problem z wykorzystaniem karty SD dla pamięci USB."</string>
<string name="usb_storage_notification_title">"Połączenie przez USB"</string>
<string name="usb_storage_notification_message">"Wybierz, aby skopiować pliki do/z komputera"</string>
- <string name="select_input_method">"Wybierz metodę wejściową"</string>
- <string name="fast_scroll_alphabet">"AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
- <string name="fast_scroll_numeric_alphabet">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style"><font fgcolor="#ff000000" bgcolor="#ff8080ff"><u>"kandydaci"</u></font></string>
+ <string name="usb_storage_stop_notification_title">"Wyłącz nośnik USB"</string>
+ <string name="usb_storage_stop_notification_message">"Wybierz, aby wyłączyć nośnik USB."</string>
+ <string name="usb_storage_stop_title">"Wyłącz nośnik USB"</string>
+ <string name="usb_storage_stop_message">"Przed wyłączeniem nośnika USB upewnij się, że odłączono go od hosta USB. Wybierz „Wyłącz”, aby wyłączyć nośnik USB."</string>
+ <string name="usb_storage_stop_button_mount">"Wyłącz"</string>
+ <string name="usb_storage_stop_button_unmount">"Anuluj"</string>
+ <string name="usb_storage_stop_error_message">"Napotkano problem przy wyłączaniu nośnika USB. Sprawdź, czy host USB został odłączony i spróbuj ponownie."</string>
+ <string name="extmedia_format_title">"Formatuj kartę SD"</string>
+ <string name="extmedia_format_message">"Czy na pewno sformatować kartę SD? Wszystkie dane na karcie zostaną utracone."</string>
+ <string name="extmedia_format_button_format">"Formatuj"</string>
+ <string name="select_input_method">"Sposób wprowadzania tekstu"</string>
+ <string name="fast_scroll_alphabet">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"kandydaci"</u></string>
+ <string name="ext_media_checking_notification_title">"Przygotowywanie karty SD"</string>
+ <string name="ext_media_checking_notification_message">"Sprawdzanie w poszukiwaniu błędów"</string>
+ <string name="ext_media_nofs_notification_title">"Pusta karta SD"</string>
+ <string name="ext_media_nofs_notification_message">"Karta SD jest pusta lub używa nieobsługiwanego systemu plików."</string>
+ <string name="ext_media_unmountable_notification_title">"Uszkodzona karta SD"</string>
+ <string name="ext_media_unmountable_notification_message">"Karta SD jest uszkodzona. Konieczne może być przeformatowanie karty."</string>
+ <string name="ext_media_badremoval_notification_title">"Karta SD została nieoczekiwanie wyjęta"</string>
+ <string name="ext_media_badremoval_notification_message">"Odłącz kartę SD przed jej wyjęciem, aby uniknąć utraty danych."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Można bezpiecznie usunąć kartę SD"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Można teraz bezpiecznie usunąć kartę SD."</string>
+ <string name="ext_media_nomedia_notification_title">"Usunięta karta SD"</string>
+ <string name="ext_media_nomedia_notification_message">"Karta SD została usunięta. Włóż nową kartę SD, aby zwiększyć pamięć urządzenia."</string>
+ <string name="activity_list_empty">"Nie znaleziono pasujących działań"</string>
+ <string name="permlab_pkgUsageStats">"aktualizowanie statystyk użycia komponentu"</string>
+ <string name="permdesc_pkgUsageStats">"Zezwala na modyfikacje zebranych statystyk użycia komponentu. Nieprzeznaczone dla zwykłych aplikacji."</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 33efbf6..ba88667 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -103,7 +103,15 @@
<string name="global_action_toggle_silent_mode">"Беззвучный режим"</string>
<string name="global_action_silent_mode_on_status">"Звук выключен"</string>
<string name="global_action_silent_mode_off_status">"Звук включен"</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
<string name="safeMode">"Безопасный режим"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
<string name="permgrouplab_costMoney">"Платные службы"</string>
<string name="permgroupdesc_costMoney">"Разрешить приложениям выполнять действия, за которые может взиматься плата."</string>
<string name="permgrouplab_messages">"Сообщения"</string>
@@ -262,6 +270,8 @@
<string name="permdesc_reboot">"Разрешает приложению принудительно перезагружать телефон."</string>
<string name="permlab_mount_unmount_filesystems">"подключаться и отключаться от файловых систем"</string>
<string name="permdesc_mount_unmount_filesystems">"Разрешает приложению подключаться и отключаться от файловых систем съемных устройств хранения."</string>
+ <string name="permlab_mount_format_filesystems">"форматировать внешний накопитель"</string>
+ <string name="permdesc_mount_format_filesystems">"Позволяет приложению форматировать съемный накопитель."</string>
<string name="permlab_vibrate">"управлять вибрацией"</string>
<string name="permdesc_vibrate">"Разрешает приложению управлять вибровызовом."</string>
<string name="permlab_flashlight">"управлять фонарем"</string>
@@ -276,6 +286,8 @@
<string name="permdesc_locationUpdates">"Разрешает включение/отключение уведомлений о местоположении по радиосвязи. Не используется обычными приложениями."</string>
<string name="permlab_checkinProperties">"открывать свойства проверки"</string>
<string name="permdesc_checkinProperties">"Разрешает доступ на чтение и запись к свойствам, загруженным службой проверки. Не используется обычными приложениями."</string>
+ <string name="permlab_bindGadget">"выбирать гаджеты"</string>
+ <string name="permdesc_bindGadget">"Позволяет приложению сообщить системе, какие приложения могут использовать какие гаджеты. Это разрешение позволяет приложениям предоставлять другим приложениям доступ к личной информации. Не предназначено для использования обычными приложениями."</string>
<string name="permlab_modifyPhoneState">"изменять состояние телефона"</string>
<string name="permdesc_modifyPhoneState">"Позволяет приложению управлять телефонными функциями устройства. Приложение с такими полномочиями может переключать сети, включать и выключать радиосвязь и т.д., не сообщая вам об этом."</string>
<string name="permlab_readPhoneState">"считывать состояние телефона"</string>
@@ -304,6 +316,8 @@
<string name="permdesc_writeApnSettings">"Разрешает приложению изменять настройки APN, например прокси и порт любого APN."</string>
<string name="permlab_changeNetworkState">"изменять подключение к сети"</string>
<string name="permdesc_changeNetworkState">"Позволяет приложению изменять подключение к сети."</string>
+ <string name="permlab_changeBackgroundDataSetting">"изменить настройку использования фоновых данных"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"Позволяет приложению изменять настройку использования фоновых данных."</string>
<string name="permlab_accessWifiState">"просматривать состояние Wi-Fi"</string>
<string name="permdesc_accessWifiState">"Разрешает приложению просматривать сведения о состоянии Wi-Fi."</string>
<string name="permlab_changeWifiState">"изменять состояние Wi-Fi"</string>
@@ -324,14 +338,10 @@
<string name="permdesc_subscribedFeedsRead">"Позволяет приложению получать сведения о синхронизированных фидах."</string>
<string name="permlab_subscribedFeedsWrite">"записывать фиды с подпиской"</string>
<string name="permdesc_subscribedFeedsWrite">"Разрешает приложению изменять ваши синхронизированные фиды. Это может позволить вредоносному ПО изменять ваши синхронизированные фиды."</string>
- <!-- no translation found for permlab_readDictionary (432535716804748781) -->
- <skip />
- <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
- <skip />
- <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
- <skip />
- <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
- <skip />
+ <string name="permlab_readDictionary">"выполнять чтение из пользовательского словаря"</string>
+ <string name="permdesc_readDictionary">"Позволяет приложению считывать любые слова, имена и фразы личного пользования, которые могут храниться в пользовательском словаре."</string>
+ <string name="permlab_writeDictionary">"записывать в пользовательский словарь"</string>
+ <string name="permdesc_writeDictionary">"Позволяет приложению записывать новые слова в пользовательский словарь."</string>
<string-array name="phoneTypes">
<item>"Домашний"</item>
<item>"Мобильный"</item>
@@ -387,7 +397,8 @@
<string name="lockscreen_emergency_call">"Экстренный вызов"</string>
<string name="lockscreen_pattern_correct">"Верно!"</string>
<string name="lockscreen_pattern_wrong">"Неверно, попробуйте еще раз"</string>
- <string name="lockscreen_plugged_in">"Зарядка (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
<string name="lockscreen_low_battery">"Подключите зарядное устройство."</string>
<string name="lockscreen_missing_sim_message_short">"Нет SIM-карты."</string>
<string name="lockscreen_missing_sim_message">"В телефоне нет SIM-карты."</string>
@@ -410,15 +421,15 @@
<string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
<string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <!-- no translation found for hour_ampm (7618670480400517084) -->
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
<skip />
- <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
<skip />
<string name="status_bar_clear_all_button">"Очистить уведомления"</string>
<string name="status_bar_no_notifications_title">"Нет уведомлений"</string>
<string name="status_bar_ongoing_events_title">"Текущие"</string>
<string name="status_bar_latest_events_title">"Уведомления"</string>
- <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
<skip />
<string name="battery_status_charging">"Идет зарядка..."</string>
<string name="battery_low_title">"Подключите зарядное устройство"</string>
@@ -428,12 +439,9 @@
<string name="factorytest_not_system">"Действие FACTORY_TEST поддерживается только для пакетов, установленных в папке /system/app."</string>
<string name="factorytest_no_action">"Пакет, предоставляющий действие FACTORY_TEST, не найден."</string>
<string name="factorytest_reboot">"Перезагрузить"</string>
- <!-- no translation found for js_dialog_title (8143918455087008109) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
- <skip />
+ <string name="js_dialog_title">"На странице по адресу \"<xliff:g id="TITLE">%s</xliff:g>\" сказано:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"Перейти с этой страницы?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Нажмите \"ОК\", чтобы продолжить, или \"Отмена\", чтобы остаться на текущей странице."</string>
<string name="save_password_label">"Подтверждение"</string>
<string name="save_password_message">"Сохранить этот пароль в браузере?"</string>
<string name="save_password_notnow">"Не сейчас"</string>
@@ -484,22 +492,38 @@
<item quantity="one">"завтра"</item>
<item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
</plurals>
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"1 сек. назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> сек. назад"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"1 мин. назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> мин. назад"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"1 час назад"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> ч. назад"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"вчера"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> дн. назад"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"через 1 сек."</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> сек."</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"через 1 мин."</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> мин."</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"через 1 час"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> час."</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"завтра"</item>
+ <item quantity="other">"через <xliff:g id="COUNT">%d</xliff:g> дн."</item>
+ </plurals>
<string name="preposition_for_date">"%s"</string>
<string name="preposition_for_time">"в %s"</string>
<string name="preposition_for_year">"в %s"</string>
@@ -541,27 +565,25 @@
<string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="DATE">%3$s</xliff:g>"</string>
- <!-- no translation found for date_time (6104442718633642836) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, <xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
- <string name="full_date_month_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="full_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_month_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
- <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
<string name="noon">"полдень"</string>
<string name="Noon">"Полдень"</string>
<string name="midnight">"полночь"</string>
<string name="Midnight">"Полночь"</string>
- <!-- no translation found for month_day (5565829181417740906) -->
+ <!-- no translation found for month_day (3693060561170538204) -->
<skip />
- <!-- no translation found for month (7026169712234774086) -->
+ <!-- no translation found for month (1976700695144952053) -->
<skip />
<string name="month_day_year">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for month_year (9219019380312413367) -->
+ <!-- no translation found for month_year (2106203387378728384) -->
<skip />
<string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
@@ -590,11 +612,11 @@
<string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="DAY1">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="DAY2">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>, <xliff:g id="DAY1_0">%3$s</xliff:g> <xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="YEAR1">%4$s</xliff:g>, <xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>, <xliff:g id="DAY2_1">%8$s</xliff:g> <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="YEAR2">%9$s</xliff:g>, <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="abbrev_month_day_year">"<xliff:g id="DAY">%-d</xliff:g> <xliff:g id="MONTH">%b</xliff:g> <xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
<skip />
- <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
<skip />
- <!-- no translation found for abbrev_month (3131032032850777433) -->
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
<skip />
<string name="day_of_week_long_sunday">"воскресенье"</string>
<string name="day_of_week_long_monday">"понедельник"</string>
@@ -679,6 +701,7 @@
<string name="paste">"Вставить"</string>
<string name="copyUrl">"Копировать URL"</string>
<string name="inputMethod">"Способ ввода"</string>
+ <string name="addToDictionary">"Добавить \"%s\" в словарь"</string>
<string name="editTextMenuTitle">"Правка текста"</string>
<string name="low_internal_storage_view_title">"Недостаточно места"</string>
<string name="low_internal_storage_view_text">"В памяти телефона осталось мало места."</string>
@@ -686,6 +709,7 @@
<string name="cancel">"Отмена"</string>
<string name="yes">"ОК"</string>
<string name="no">"Отмена"</string>
+ <string name="dialog_alert_title">"Внимание"</string>
<string name="capital_on">"ВКЛ"</string>
<string name="capital_off">"ВЫКЛ"</string>
<string name="whichApplication">"Выполнить действие с помощью"</string>
@@ -709,7 +733,7 @@
<string name="volume_music">"Громкость звука мультимедиа"</string>
<string name="volume_music_hint_playing_through_bluetooth">"Воспроизводится через Bluetooth"</string>
<string name="volume_call">"Громкость звонка"</string>
- <string name="volume_call_hint_playing_through_bluetooth">"Воспроизводится через Bluetooth"</string>
+ <string name="volume_bluetooth_call">"Громкость входящего вызова Bluetooth"</string>
<string name="volume_alarm">"Громкость будильника"</string>
<string name="volume_notification">"Громкость уведомления"</string>
<string name="volume_unknown">"Громкость"</string>
@@ -745,8 +769,47 @@
<string name="usb_storage_error_message">"Не удается использовать карту SD в качестве USB-хранилища."</string>
<string name="usb_storage_notification_title">"Подключение через USB"</string>
<string name="usb_storage_notification_message">"Выберите для копирования файлов на/с компьютера."</string>
+ <string name="usb_storage_stop_notification_title">"Выключить USB-накопитель"</string>
+ <string name="usb_storage_stop_notification_message">"Выберите, чтобы выключить USB-накопитель."</string>
+ <string name="usb_storage_stop_title">"Выключить USB-накопитель"</string>
+ <string name="usb_storage_stop_message">"Перед выключением USB-накопителя обязательно отключите USB-хост. Выберите \"Выключить\", чтобы выключить USB-накопитель."</string>
+ <string name="usb_storage_stop_button_mount">"Выключить"</string>
+ <string name="usb_storage_stop_button_unmount">"Отмена"</string>
+ <string name="usb_storage_stop_error_message">"При выключении USB-накопителя произошла проблема. Убедитесь, что USB-хост отключен, и повторите попытку."</string>
+ <string name="extmedia_format_title">"Форматировать карту SD"</string>
+ <string name="extmedia_format_message">"Отформатировать карту SD? Все данные, находящиеся на карте, будут уничтожены."</string>
+ <string name="extmedia_format_button_format">"Формат"</string>
<string name="select_input_method">"Выбор способа ввода"</string>
- <string name="fast_scroll_alphabet">"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЭЮЯ"</string>
- <string name="fast_scroll_numeric_alphabet">"0123456789АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЭЮЯ"</string>
- <string name="candidates_style"><font fgcolor="#ff000000" bgcolor="#ff8080ff"><u>"кандидаты"</u>"u&gt;"</font></string>
+ <string name="fast_scroll_alphabet">" АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЭЮЯ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЭЮЯ"</string>
+ <string name="candidates_style"><u>"кандидаты"</u></string>
+ <string name="ext_media_checking_notification_title">"Подготовка карты SD"</string>
+ <string name="ext_media_checking_notification_message">"Поиск ошибок"</string>
+ <string name="ext_media_nofs_notification_title">"Пустая карта SD"</string>
+ <string name="ext_media_nofs_notification_message">"Карта SD пуста или использует неподдерживаемую файловую систему."</string>
+ <string name="ext_media_unmountable_notification_title">"Поврежденная карта SD"</string>
+ <string name="ext_media_unmountable_notification_message">"Карта SD повреждена. Может потребоваться переформатировать ее."</string>
+ <string name="ext_media_badremoval_notification_title">"Карта SD неожиданно извлечена"</string>
+ <string name="ext_media_badremoval_notification_message">"Перед извлечением карты SD отключите ее во избежание потери данных."</string>
+ <string name="ext_media_safe_unmount_notification_title">"Безопасное удаление карты SD"</string>
+ <string name="ext_media_safe_unmount_notification_message">"Теперь карту SD можно безопасно удалить."</string>
+ <string name="ext_media_nomedia_notification_title">"Карта SD удалена"</string>
+ <string name="ext_media_nomedia_notification_message">"Карта SD была удалена. Для увеличения емкости устройства вставьте новую карту SD."</string>
+ <string name="activity_list_empty">"Подходящих действий не найдено"</string>
+ <string name="permlab_pkgUsageStats">"обновлять статистику использования компонентов"</string>
+ <string name="permdesc_pkgUsageStats">"Позволяет изменять собранную статистику использования компонентов. Не предназначено для использования обычными приложениями."</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index cb13390..346e254 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -103,7 +103,15 @@
<string name="global_action_toggle_silent_mode">"静音模式"</string>
<string name="global_action_silent_mode_on_status">"声音已关闭"</string>
<string name="global_action_silent_mode_off_status">"声音已开启"</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
<string name="safeMode">"安全模式"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
<string name="permgrouplab_costMoney">"需要您支付费用的服务"</string>
<string name="permgroupdesc_costMoney">"允许应用程序执行可能需要您支付费用的操作。"</string>
<string name="permgrouplab_messages">"您的信息"</string>
@@ -262,6 +270,8 @@
<string name="permdesc_reboot">"允许应用程序强制手机重新引导。"</string>
<string name="permlab_mount_unmount_filesystems">"装载和卸载文件系统"</string>
<string name="permdesc_mount_unmount_filesystems">"允许应用程序装载和卸载文件系统以进行可移动存储。"</string>
+ <string name="permlab_mount_format_filesystems">"格式化外部存储设备"</string>
+ <string name="permdesc_mount_format_filesystems">"允许应用程序格式化可移除的存储设备。"</string>
<string name="permlab_vibrate">"控制振动器"</string>
<string name="permdesc_vibrate">"允许应用程序控制振动器。"</string>
<string name="permlab_flashlight">"控制闪光灯"</string>
@@ -276,6 +286,8 @@
<string name="permdesc_locationUpdates">"允许启用/禁用来自收音机的位置更新通知。普通应用程序不能使用此权限。"</string>
<string name="permlab_checkinProperties">"访问检入属性"</string>
<string name="permdesc_checkinProperties">"允许对检入服务上传的属性进行读/写访问。普通应用程序不能使用此权限。"</string>
+ <string name="permlab_bindGadget">"选择小工具"</string>
+ <string name="permdesc_bindGadget">"允许应用程序告诉系统哪些应用程序可以使用哪些小工具。应用程序可以借此授予其他应用程序访问个人数据的权限。普通应用程序不能使用此权限。"</string>
<string name="permlab_modifyPhoneState">"修改手机状态"</string>
<string name="permdesc_modifyPhoneState">"允许应用程序控制设备的手机功能。具有此权限的应用程序可能会切换网络,打开和关闭手机收音机以及类似操作,而不会通知您。"</string>
<string name="permlab_readPhoneState">"读取手机状态"</string>
@@ -304,6 +316,8 @@
<string name="permdesc_writeApnSettings">"允许应用程序修改 APN 设置,例如任何 APN 的代理和端口。"</string>
<string name="permlab_changeNetworkState">"更改网络连接性"</string>
<string name="permdesc_changeNetworkState">"允许应用程序更改状态网络连接性。"</string>
+ <string name="permlab_changeBackgroundDataSetting">"更改背景数据使用设置"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"允许应用程序更改背景数据使用设置。"</string>
<string name="permlab_accessWifiState">"查看 Wi-Fi 状态"</string>
<string name="permdesc_accessWifiState">"允许应用程序查看有关 Wi-Fi 状态的信息。"</string>
<string name="permlab_changeWifiState">"更改 Wi-Fi 状态"</string>
@@ -324,14 +338,10 @@
<string name="permdesc_subscribedFeedsRead">"允许应用程序获取有关当前同步的供稿的详情。"</string>
<string name="permlab_subscribedFeedsWrite">"写入订阅的供稿"</string>
<string name="permdesc_subscribedFeedsWrite">"允许应用程序修改您当前同步的供稿。这样恶意程序可以更改您同步的供稿。"</string>
- <!-- no translation found for permlab_readDictionary (432535716804748781) -->
- <skip />
- <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
- <skip />
- <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
- <skip />
- <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
- <skip />
+ <string name="permlab_readDictionary">"读取用户定义的词典"</string>
+ <string name="permdesc_readDictionary">"允许应用程序读取用户在用户词典中存储的任意私有字词、名称和短语。"</string>
+ <string name="permlab_writeDictionary">"写入用户定义的词典"</string>
+ <string name="permdesc_writeDictionary">"允许应用程序向用户词典中写入新词。"</string>
<string-array name="phoneTypes">
<item>"家庭"</item>
<item>"手机"</item>
@@ -387,7 +397,8 @@
<string name="lockscreen_emergency_call">"紧急电话"</string>
<string name="lockscreen_pattern_correct">"正确!"</string>
<string name="lockscreen_pattern_wrong">"很抱歉,请重试"</string>
- <string name="lockscreen_plugged_in">"正在充电 (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
<string name="lockscreen_low_battery">"连接您的充电器。"</string>
<string name="lockscreen_missing_sim_message_short">"没有 SIM 卡。"</string>
<string name="lockscreen_missing_sim_message">"手机中无 SIM 卡。"</string>
@@ -410,15 +421,15 @@
<string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
<string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <!-- no translation found for hour_ampm (7618670480400517084) -->
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
<skip />
- <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
<skip />
<string name="status_bar_clear_all_button">"清除通知"</string>
<string name="status_bar_no_notifications_title">"无通知"</string>
<string name="status_bar_ongoing_events_title">"正在进行的"</string>
<string name="status_bar_latest_events_title">"通知"</string>
- <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
<skip />
<string name="battery_status_charging">"正在充电..."</string>
<string name="battery_low_title">"请连接充电器"</string>
@@ -428,12 +439,9 @@
<string name="factorytest_not_system">"只有在 /system/app 中安装的包支持 FACTORY_TEST 操作。"</string>
<string name="factorytest_no_action">"未发现支持 FACTORY_TEST 操作的包。"</string>
<string name="factorytest_reboot">"重新引导"</string>
- <!-- no translation found for js_dialog_title (8143918455087008109) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
- <skip />
+ <string name="js_dialog_title">"“<xliff:g id="TITLE">%s</xliff:g>”处的页面表明:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"是否从该页面导航至它处?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"选择“确定”继续,或选择“取消”留在当前页面。"</string>
<string name="save_password_label">"确认"</string>
<string name="save_password_message">"是否希望浏览器记住此密码?"</string>
<string name="save_password_notnow">"暂不保存"</string>
@@ -484,22 +492,38 @@
<item quantity="one">"明天"</item>
<item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
</plurals>
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"1 秒前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒前"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"1 分钟前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分钟前"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"1 小时前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小时前"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"昨天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天前"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"1 秒后"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒后"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"1 分钟后"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分钟后"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"1 小时后"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小时后"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"明天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天后"</item>
+ </plurals>
<string name="preposition_for_date">"在 %s"</string>
<string name="preposition_for_time">"在 %s"</string>
<string name="preposition_for_year">"%s 年内"</string>
@@ -541,27 +565,25 @@
<string name="time_wday_date">"<xliff:g id="DATE">%3$s</xliff:g><xliff:g id="WEEKDAY">%2$s</xliff:g> <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
<string name="wday_date">"<xliff:g id="DATE">%3$s</xliff:g><xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
<string name="time_date">"<xliff:g id="DATE">%3$s</xliff:g> <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
- <!-- no translation found for date_time (6104442718633642836) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g><xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g><xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="time_wday">"<xliff:g id="WEEKDAY">%2$s</xliff:g> <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
- <string name="full_date_month_first">"<xliff:g id="YEAR">yyyy</xliff:g> 年 <xliff:g id="MONTH">MMMM</xliff:g> 月 <xliff:g id="DAY">dd</xliff:g> 日"</string>
- <string name="full_date_day_first">"<xliff:g id="YEAR">yyyy</xliff:g> 年 <xliff:g id="MONTH">MMMM</xliff:g> 月 <xliff:g id="DAY">dd</xliff:g> 日"</string>
- <string name="medium_date_month_first">"<xliff:g id="YEAR">yyyy</xliff:g> 年 <xliff:g id="MONTH">MMM</xliff:g> 月 <xliff:g id="DAY">dd</xliff:g> 日"</string>
- <string name="medium_date_day_first">"<xliff:g id="YEAR">yyyy</xliff:g> 年 <xliff:g id="DAY">dd</xliff:g> 月 <xliff:g id="MONTH">MMM</xliff:g> 日"</string>
- <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
- <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="YEAR">yyyy</xliff:g>' 年 '<xliff:g id="MONTH">MMMM</xliff:g>' 月 '<xliff:g id="DAY">d</xliff:g>' 日'"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="YEAR">yyyy</xliff:g>' 年 '<xliff:g id="MONTH">MMMM</xliff:g>' 月 '<xliff:g id="DAY">d</xliff:g>' 日'"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="YEAR">yyyy</xliff:g>' 年 '<xliff:g id="MONTH">MMM</xliff:g>' 月 '<xliff:g id="DAY">d</xliff:g>' 日'"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="YEAR">yyyy</xliff:g>' 年 '<xliff:g id="DAY">d</xliff:g>' 月 '<xliff:g id="MONTH">MMM</xliff:g>' 日'"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
<string name="noon">"中午"</string>
<string name="Noon">"中午"</string>
<string name="midnight">"午夜"</string>
<string name="Midnight">"午夜"</string>
- <!-- no translation found for month_day (5565829181417740906) -->
+ <!-- no translation found for month_day (3693060561170538204) -->
<skip />
- <!-- no translation found for month (7026169712234774086) -->
+ <!-- no translation found for month (1976700695144952053) -->
<skip />
<string name="month_day_year">"<xliff:g id="YEAR">%Y</xliff:g> 年 <xliff:g id="MONTH">%B</xliff:g> 月 <xliff:g id="DAY">%-d</xliff:g> 日"</string>
- <!-- no translation found for month_year (9219019380312413367) -->
+ <!-- no translation found for month_year (2106203387378728384) -->
<skip />
<string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<string name="date_and_time">"<xliff:g id="YEAR">%Y</xliff:g> 年 <xliff:g id="MONTH">%B</xliff:g> 月 <xliff:g id="DAY">%-d</xliff:g> 日 <xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
@@ -590,11 +612,11 @@
<string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g> 年 <xliff:g id="MONTH1">%2$s</xliff:g> 月 <xliff:g id="DAY1">%3$s</xliff:g> 日 <xliff:g id="TIME1">%5$s</xliff:g> 至 <xliff:g id="YEAR2">%9$s</xliff:g> 年 <xliff:g id="MONTH2">%7$s</xliff:g> 月 <xliff:g id="DAY2">%8$s</xliff:g> 日 <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="YEAR1">%4$s</xliff:g> 年 <xliff:g id="MONTH1">%2$s</xliff:g> 月 <xliff:g id="DAY1_0">%3$s</xliff:g> 日<xliff:g id="WEEKDAY1">%1$s</xliff:g> <xliff:g id="TIME1">%5$s</xliff:g> 至 <xliff:g id="YEAR2">%9$s</xliff:g> 年 <xliff:g id="MONTH2">%7$s</xliff:g> 月 <xliff:g id="DAY2_1">%8$s</xliff:g> 日<xliff:g id="WEEKDAY2">%6$s</xliff:g> <xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="abbrev_month_day_year">"<xliff:g id="YEAR">%Y</xliff:g> 年 <xliff:g id="MONTH">%b</xliff:g> 月 <xliff:g id="DAY">%-d</xliff:g> 日"</string>
- <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
<skip />
- <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
<skip />
- <!-- no translation found for abbrev_month (3131032032850777433) -->
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
<skip />
<string name="day_of_week_long_sunday">"周日"</string>
<string name="day_of_week_long_monday">"周一"</string>
@@ -679,6 +701,7 @@
<string name="paste">"粘贴"</string>
<string name="copyUrl">"复制网址"</string>
<string name="inputMethod">"输入方法"</string>
+ <string name="addToDictionary">"将“%s”添加到词典"</string>
<string name="editTextMenuTitle">"编辑文本"</string>
<string name="low_internal_storage_view_title">"存储空间不足"</string>
<string name="low_internal_storage_view_text">"手机存储空间在减少。"</string>
@@ -686,6 +709,7 @@
<string name="cancel">"取消"</string>
<string name="yes">"正常"</string>
<string name="no">"取消"</string>
+ <string name="dialog_alert_title">"注意事项"</string>
<string name="capital_on">"开启"</string>
<string name="capital_off">"关闭"</string>
<string name="whichApplication">"使用以下内容完成操作"</string>
@@ -709,7 +733,7 @@
<string name="volume_music">"媒体音量"</string>
<string name="volume_music_hint_playing_through_bluetooth">"正通过蓝牙播放"</string>
<string name="volume_call">"来电音量"</string>
- <string name="volume_call_hint_playing_through_bluetooth">"正通过蓝牙播放"</string>
+ <string name="volume_bluetooth_call">"使用蓝牙时的通话音量"</string>
<string name="volume_alarm">"警告音量"</string>
<string name="volume_notification">"通知音量"</string>
<string name="volume_unknown">"音量"</string>
@@ -745,8 +769,47 @@
<string name="usb_storage_error_message">"使用 SD 卡进行 USB 存储时出现问题。"</string>
<string name="usb_storage_notification_title">"USB 已连接"</string>
<string name="usb_storage_notification_message">"选择以将文件复制到计算机或从计算机复制文件。"</string>
+ <string name="usb_storage_stop_notification_title">"关闭 USB 存储设备"</string>
+ <string name="usb_storage_stop_notification_message">"选中以关闭 USB 存储设备。"</string>
+ <string name="usb_storage_stop_title">"关闭 USB 存储设备"</string>
+ <string name="usb_storage_stop_message">"在关闭 USB 存储设备前,请确保您已卸载了 USB 主设备。选择“关闭”关闭 USB 存储设备。"</string>
+ <string name="usb_storage_stop_button_mount">"关闭"</string>
+ <string name="usb_storage_stop_button_unmount">"取消"</string>
+ <string name="usb_storage_stop_error_message">"关闭 USB 存储设备时遇到问题。请检查是否卸载了 USB 主设备,然后重试。"</string>
+ <string name="extmedia_format_title">"格式化 SD 卡"</string>
+ <string name="extmedia_format_message">"您确定要格式化 SD 卡?卡上的所有数据都会丢失。"</string>
+ <string name="extmedia_format_button_format">"格式化"</string>
<string name="select_input_method">"选择输入方法"</string>
- <string name="fast_scroll_alphabet">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style"><font fgcolor="#ff000000" bgcolor="#ff8080ff"><u>"候选人"</u>"u&gt;"</font></string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"候选"</u></string>
+ <string name="ext_media_checking_notification_title">"正在准备 SD 卡"</string>
+ <string name="ext_media_checking_notification_message">"检查是否有错误"</string>
+ <string name="ext_media_nofs_notification_title">"空 SD 卡"</string>
+ <string name="ext_media_nofs_notification_message">"SD 卡为空或使用不支持的文件系统。"</string>
+ <string name="ext_media_unmountable_notification_title">"SD 卡受损"</string>
+ <string name="ext_media_unmountable_notification_message">"SD 卡受损。您可能需要重新格式化您的卡。"</string>
+ <string name="ext_media_badremoval_notification_title">"SD 卡被意外拔除"</string>
+ <string name="ext_media_badremoval_notification_message">"先卸载 SD 卡再拔除,以避免数据丢失。"</string>
+ <string name="ext_media_safe_unmount_notification_title">"SD 卡已安全移除"</string>
+ <string name="ext_media_safe_unmount_notification_message">"现在可以安全移除 SD 卡。"</string>
+ <string name="ext_media_nomedia_notification_title">"已移除 SD 卡"</string>
+ <string name="ext_media_nomedia_notification_message">"SD 卡已移除。请插入新 SD 卡来增加您的设备存储空间。"</string>
+ <string name="activity_list_empty">"找不到匹配的活动"</string>
+ <string name="permlab_pkgUsageStats">"更新组件使用情况统计"</string>
+ <string name="permdesc_pkgUsageStats">"允许修改收集的组件使用情况统计。普通应用程序不能使用此权限。"</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 758bf82..6d4b821 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -103,7 +103,15 @@
<string name="global_action_toggle_silent_mode">"靜音模式"</string>
<string name="global_action_silent_mode_on_status">"音效已關閉"</string>
<string name="global_action_silent_mode_off_status">"聲音已開啟"</string>
+ <!-- no translation found for global_actions_toggle_airplane_mode (5884330306926307456) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_on_status (2719557982608919750) -->
+ <skip />
+ <!-- no translation found for global_actions_airplane_mode_off_status (5075070442854490296) -->
+ <skip />
<string name="safeMode">"安全模式"</string>
+ <!-- no translation found for android_system_label (6577375335728551336) -->
+ <skip />
<string name="permgrouplab_costMoney">"需要額外費用的服務。"</string>
<string name="permgroupdesc_costMoney">"若您允許應用程式執行此操作,可能需要支付一些費用。"</string>
<string name="permgrouplab_messages">"您的簡訊"</string>
@@ -262,6 +270,8 @@
<string name="permdesc_reboot">"允許應用程式強制重開機。"</string>
<string name="permlab_mount_unmount_filesystems">"掛載/卸載檔案系統"</string>
<string name="permdesc_mount_unmount_filesystems">"允許應用程式掛載/卸載抽取式儲存設備的檔案系統。"</string>
+ <string name="permlab_mount_format_filesystems">"將外接式儲存裝置格式化"</string>
+ <string name="permdesc_mount_format_filesystems">"允許應用程式將可移除式儲存裝置格式化。"</string>
<string name="permlab_vibrate">"控制震動器"</string>
<string name="permdesc_vibrate">"允許應用程式控制震動器。"</string>
<string name="permlab_flashlight">"控制閃光燈"</string>
@@ -276,6 +286,8 @@
<string name="permdesc_locationUpdates">"允許啟用/停用無線通訊位置更新通知。一般應用程式不會使用此功能。"</string>
<string name="permlab_checkinProperties">"存取登機選項"</string>
<string name="permdesc_checkinProperties">"允許讀寫登機服務上傳的資料。一般應用程式不會使用此功能。"</string>
+ <string name="permlab_bindGadget">"選擇小工具"</string>
+ <string name="permdesc_bindGadget">"允許應用程式告知系統哪些應用程式可以使用哪些小工具。擁有此權限的應用程式可以讓其他應用程式使用個人資料。一般應用程式不會使用此功能。"</string>
<string name="permlab_modifyPhoneState">"修改手機狀態"</string>
<string name="permdesc_modifyPhoneState">"允許應用程式控制電話功能。擁有此權限的程式可自行切換網路、開關無線通訊功能。"</string>
<string name="permlab_readPhoneState">"讀取手機狀態"</string>
@@ -304,6 +316,8 @@
<string name="permdesc_writeApnSettings">"允許應用程式修改 APN 設定,例如:Proxy 及 APN 的連接埠。"</string>
<string name="permlab_changeNetworkState">"變更網路連線"</string>
<string name="permdesc_changeNetworkState">"允許應用程式變更網路連線狀態。"</string>
+ <string name="permlab_changeBackgroundDataSetting">"變更背景資料使用設定"</string>
+ <string name="permdesc_changeBackgroundDataSetting">"允許應用程式變更背景資料使用設定。"</string>
<string name="permlab_accessWifiState">"檢視 Wi-Fi 狀態"</string>
<string name="permdesc_accessWifiState">"允許應用程式檢視 Wi-Fi 狀態資訊。"</string>
<string name="permlab_changeWifiState">"變更 Wi-Fi 狀態"</string>
@@ -324,14 +338,10 @@
<string name="permdesc_subscribedFeedsRead">"允許應用程式取得目前已同步處理的資訊提供。"</string>
<string name="permlab_subscribedFeedsWrite">"寫入訂閱資訊提供"</string>
<string name="permdesc_subscribedFeedsWrite">"允許應用程式修改已同步處理的資訊提供。惡意程式可使用此功能變更已同步處理的資訊提供。"</string>
- <!-- no translation found for permlab_readDictionary (432535716804748781) -->
- <skip />
- <!-- no translation found for permdesc_readDictionary (1082972603576360690) -->
- <skip />
- <!-- no translation found for permlab_writeDictionary (6703109511836343341) -->
- <skip />
- <!-- no translation found for permdesc_writeDictionary (2241256206524082880) -->
- <skip />
+ <string name="permlab_readDictionary">"讀取使用者定義的字典"</string>
+ <string name="permdesc_readDictionary">"允許應用程式讀取使用者儲存在使用者字典內的任何私人字詞、名稱和詞組。"</string>
+ <string name="permlab_writeDictionary">"寫入使用者定義的字典"</string>
+ <string name="permdesc_writeDictionary">"允許應用程式將新字詞寫入使用者的字典。"</string>
<string-array name="phoneTypes">
<item>"首頁"</item>
<item>"行動"</item>
@@ -387,7 +397,8 @@
<string name="lockscreen_emergency_call">"緊急電話"</string>
<string name="lockscreen_pattern_correct">"正確!"</string>
<string name="lockscreen_pattern_wrong">"抱歉,請再試一次"</string>
- <string name="lockscreen_plugged_in">"充電中 (<xliff:g id="NUMBER">%d%%</xliff:g>)"</string>
+ <!-- no translation found for lockscreen_plugged_in (613343852842944435) -->
+ <skip />
<string name="lockscreen_low_battery">"請連接充電器。"</string>
<string name="lockscreen_missing_sim_message_short">"沒有 SIM 卡。"</string>
<string name="lockscreen_missing_sim_message">"手機未插入 SIM 卡。"</string>
@@ -410,15 +421,15 @@
<string name="status_bar_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">AA</xliff:g>"</string>
<string name="hour_minute_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%P</xliff:g>"</string>
<string name="hour_minute_cap_ampm">"<xliff:g id="HOUR">%-l</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
- <!-- no translation found for hour_ampm (7618670480400517084) -->
+ <!-- no translation found for hour_ampm (4329881288269772723) -->
<skip />
- <!-- no translation found for hour_cap_ampm (5117798389811605468) -->
+ <!-- no translation found for hour_cap_ampm (1829009197680861107) -->
<skip />
<string name="status_bar_clear_all_button">"清除通知"</string>
<string name="status_bar_no_notifications_title">"沒有通知"</string>
<string name="status_bar_ongoing_events_title">"進行中"</string>
<string name="status_bar_latest_events_title">"通知"</string>
- <!-- no translation found for battery_status_text_percent_format (8818848472818880005) -->
+ <!-- no translation found for battery_status_text_percent_format (7660311274698797147) -->
<skip />
<string name="battery_status_charging">"充電中"</string>
<string name="battery_low_title">"請連接充電器"</string>
@@ -428,12 +439,9 @@
<string name="factorytest_not_system">"FACTORY_TEST 動作只支援安裝在 /system/app 裡的程式。"</string>
<string name="factorytest_no_action">"找不到提供 FACTORY_TEST 的程式。"</string>
<string name="factorytest_reboot">"重新開機"</string>
- <!-- no translation found for js_dialog_title (8143918455087008109) -->
- <skip />
- <!-- no translation found for js_dialog_title_default (6961903213729667573) -->
- <skip />
- <!-- no translation found for js_dialog_before_unload (1901675448179653089) -->
- <skip />
+ <string name="js_dialog_title">"「<xliff:g id="TITLE">%s</xliff:g>」的網頁指出:"</string>
+ <string name="js_dialog_title_default">"JavaScript"</string>
+ <string name="js_dialog_before_unload">"離開此頁?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n" 選取 [確定] 離開此頁;或 [取消] 留在此頁。"</string>
<string name="save_password_label">"確認"</string>
<string name="save_password_message">"是否記憶此密碼?"</string>
<string name="save_password_notnow">"現在不要"</string>
@@ -484,22 +492,38 @@
<item quantity="one">"明天"</item>
<item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
</plurals>
- <!-- no translation found for abbrev_num_seconds_ago:one (1849036840200069118) -->
- <!-- no translation found for abbrev_num_seconds_ago:other (3699169366650930415) -->
- <!-- no translation found for abbrev_num_minutes_ago:one (6361490147113871545) -->
- <!-- no translation found for abbrev_num_minutes_ago:other (851164968597150710) -->
- <!-- no translation found for abbrev_num_hours_ago:one (4796212039724722116) -->
- <!-- no translation found for abbrev_num_hours_ago:other (6889970745748538901) -->
- <!-- no translation found for abbrev_num_days_ago:one (8463161711492680309) -->
- <!-- no translation found for abbrev_num_days_ago:other (3453342639616481191) -->
- <!-- no translation found for abbrev_in_num_seconds:one (5842225370795066299) -->
- <!-- no translation found for abbrev_in_num_seconds:other (5495880108825805108) -->
- <!-- no translation found for abbrev_in_num_minutes:one (562786149928284878) -->
- <!-- no translation found for abbrev_in_num_minutes:other (4216113292706568726) -->
- <!-- no translation found for abbrev_in_num_hours:one (3274708118124045246) -->
- <!-- no translation found for abbrev_in_num_hours:other (3705373766798013406) -->
- <!-- no translation found for abbrev_in_num_days:one (2178576254385739855) -->
- <!-- no translation found for abbrev_in_num_days:other (2973062968038355991) -->
+ <plurals name="abbrev_num_seconds_ago">
+ <item quantity="one">"1 秒以前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒以前"</item>
+ </plurals>
+ <plurals name="abbrev_num_minutes_ago">
+ <item quantity="one">"1 分鐘以前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分鐘以前"</item>
+ </plurals>
+ <plurals name="abbrev_num_hours_ago">
+ <item quantity="one">"1 小時以前"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小時以前"</item>
+ </plurals>
+ <plurals name="abbrev_num_days_ago">
+ <item quantity="one">"昨天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天以前"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_seconds">
+ <item quantity="one">"1 秒內"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 秒內"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_minutes">
+ <item quantity="one">"1 分鐘內"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 分鐘內"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_hours">
+ <item quantity="one">"1 小時內"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 小時內"</item>
+ </plurals>
+ <plurals name="abbrev_in_num_days">
+ <item quantity="one">"明天"</item>
+ <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> 天內"</item>
+ </plurals>
<string name="preposition_for_date">"%s"</string>
<string name="preposition_for_time">"%s"</string>
<string name="preposition_for_year">"%s"</string>
@@ -541,27 +565,25 @@
<string name="time_wday_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>,<xliff:g id="WEEKDAY">%2$s</xliff:g>,<xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="wday_date">"<xliff:g id="WEEKDAY">%2$s</xliff:g>,<xliff:g id="DATE">%3$s</xliff:g>"</string>
<string name="time_date">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>,<xliff:g id="DATE">%3$s</xliff:g>"</string>
- <!-- no translation found for date_time (6104442718633642836) -->
- <skip />
- <!-- no translation found for relative_time (1818557177829411417) -->
- <skip />
+ <string name="date_time">"<xliff:g id="DATE">%1$s</xliff:g>,<xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time">"<xliff:g id="DATE">%1$s</xliff:g>,<xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="time_wday">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>,<xliff:g id="WEEKDAY">%2$s</xliff:g>"</string>
- <string name="full_date_month_first">"<xliff:g id="MONTH">MMMM</xliff:g> <xliff:g id="DAY">dd</xliff:g>,<xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="full_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMMM</xliff:g>,<xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_month_first">"<xliff:g id="MONTH">MMM</xliff:g> <xliff:g id="DAY">dd</xliff:g>,<xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="medium_date_day_first">"<xliff:g id="DAY">dd</xliff:g> <xliff:g id="MONTH">MMM</xliff:g>,<xliff:g id="YEAR">yyyy</xliff:g>"</string>
- <string name="twelve_hour_time_format">"<xliff:g id="HOUR">h</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g> <xliff:g id="AMPM">a</xliff:g>"</string>
- <string name="twenty_four_hour_time_format">"<xliff:g id="HOUR">H</xliff:g>:<xliff:g id="MINUTE">mm</xliff:g>"</string>
+ <string name="full_date_month_first" format="date">"<xliff:g id="MONTH">MMMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>','<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="full_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMMM</xliff:g>','<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_month_first" format="date">"<xliff:g id="MONTH">MMM</xliff:g>' '<xliff:g id="DAY">d</xliff:g>','<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="medium_date_day_first" format="date">"<xliff:g id="DAY">d</xliff:g>' '<xliff:g id="MONTH">MMM</xliff:g>','<xliff:g id="YEAR">yyyy</xliff:g>"</string>
+ <string name="twelve_hour_time_format" format="date">"<xliff:g id="HOUR">h</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>' '<xliff:g id="AMPM">a</xliff:g>"</string>
+ <string name="twenty_four_hour_time_format" format="date">"<xliff:g id="HOUR">H</xliff:g>':'<xliff:g id="MINUTE">mm</xliff:g>"</string>
<string name="noon">"中午"</string>
<string name="Noon">"中午"</string>
<string name="midnight">"午夜"</string>
<string name="Midnight">"午夜"</string>
- <!-- no translation found for month_day (5565829181417740906) -->
+ <!-- no translation found for month_day (3693060561170538204) -->
<skip />
- <!-- no translation found for month (7026169712234774086) -->
+ <!-- no translation found for month (1976700695144952053) -->
<skip />
<string name="month_day_year">"<xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>,<xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for month_year (9219019380312413367) -->
+ <!-- no translation found for month_year (2106203387378728384) -->
<skip />
<string name="time_of_day">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g>"</string>
<string name="date_and_time">"<xliff:g id="HOUR">%H</xliff:g>:<xliff:g id="MINUTE">%M</xliff:g>:<xliff:g id="SECOND">%S</xliff:g> <xliff:g id="MONTH">%B</xliff:g> <xliff:g id="DAY">%-d</xliff:g>,<xliff:g id="YEAR">%Y</xliff:g>"</string>
@@ -590,11 +612,11 @@
<string name="same_month_mdy1_time1_mdy2_time2">"<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1">%3$s</xliff:g>,<xliff:g id="YEAR1">%4$s</xliff:g>,<xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2">%8$s</xliff:g>,<xliff:g id="YEAR2">%9$s</xliff:g>,<xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">"<xliff:g id="WEEKDAY1">%1$s</xliff:g>,<xliff:g id="MONTH1">%2$s</xliff:g> <xliff:g id="DAY1_0">%3$s</xliff:g>,<xliff:g id="YEAR1">%4$s</xliff:g>,<xliff:g id="TIME1">%5$s</xliff:g> – <xliff:g id="WEEKDAY2">%6$s</xliff:g>,<xliff:g id="MONTH2">%7$s</xliff:g> <xliff:g id="DAY2_1">%8$s</xliff:g>,<xliff:g id="YEAR2">%9$s</xliff:g>,<xliff:g id="TIME2">%10$s</xliff:g>"</string>
<string name="abbrev_month_day_year">"<xliff:g id="MONTH">%b</xliff:g> <xliff:g id="DAY">%-d</xliff:g>,<xliff:g id="YEAR">%Y</xliff:g>"</string>
- <!-- no translation found for abbrev_month_year (3856424847226891943) -->
+ <!-- no translation found for abbrev_month_year (5966980891147982768) -->
<skip />
- <!-- no translation found for abbrev_month_day (5028815883653985933) -->
+ <!-- no translation found for abbrev_month_day (3156047263406783231) -->
<skip />
- <!-- no translation found for abbrev_month (3131032032850777433) -->
+ <!-- no translation found for abbrev_month (7304935052615731208) -->
<skip />
<string name="day_of_week_long_sunday">"星期日"</string>
<string name="day_of_week_long_monday">"星期一"</string>
@@ -679,6 +701,7 @@
<string name="paste">"貼上"</string>
<string name="copyUrl">"複製網址"</string>
<string name="inputMethod">"輸入法"</string>
+ <string name="addToDictionary">"將「%s」新增到字典"</string>
<string name="editTextMenuTitle">"編輯文字"</string>
<string name="low_internal_storage_view_title">"儲存空間太少"</string>
<string name="low_internal_storage_view_text">"手機儲存空間即將不足。"</string>
@@ -686,6 +709,7 @@
<string name="cancel">"取消"</string>
<string name="yes">"確定"</string>
<string name="no">"取消"</string>
+ <string name="dialog_alert_title">"注意"</string>
<string name="capital_on">"開啟"</string>
<string name="capital_off">"關閉"</string>
<string name="whichApplication">"選取...完成動作"</string>
@@ -709,7 +733,7 @@
<string name="volume_music">"媒體音量"</string>
<string name="volume_music_hint_playing_through_bluetooth">"透過藍牙播放"</string>
<string name="volume_call">"來電音量"</string>
- <string name="volume_call_hint_playing_through_bluetooth">"透過藍牙播放"</string>
+ <string name="volume_bluetooth_call">"藍牙通話音量"</string>
<string name="volume_alarm">"鬧鐘音量"</string>
<string name="volume_notification">"通知音量"</string>
<string name="volume_unknown">"音量"</string>
@@ -745,8 +769,47 @@
<string name="usb_storage_error_message">"把 SD 卡當成 USB 儲存裝置時發生問題。"</string>
<string name="usb_storage_notification_title">"USB 已連接"</string>
<string name="usb_storage_notification_message">"選取此項將檔案複製到電腦,或從電腦複製。"</string>
+ <string name="usb_storage_stop_notification_title">"關閉 USB 儲存裝置"</string>
+ <string name="usb_storage_stop_notification_message">"選取此處關閉 USB 儲存裝置。"</string>
+ <string name="usb_storage_stop_title">"關閉 USB 儲存裝置"</string>
+ <string name="usb_storage_stop_message">"關閉 USB 儲存裝置之前,請確定先從 USB Host 卸載。選取 [關閉] 即可關閉 USB 儲存裝置。"</string>
+ <string name="usb_storage_stop_button_mount">"關閉"</string>
+ <string name="usb_storage_stop_button_unmount">"取消"</string>
+ <string name="usb_storage_stop_error_message">"關閉 USB 儲存裝置時發生問題。請檢查確認您是否已卸載 USB Host,然後再試一次。"</string>
+ <string name="extmedia_format_title">"將 SD 卡格式化"</string>
+ <string name="extmedia_format_message">"確定要將 SD 卡格式化嗎?該 SD 卡中的所有資料將會遺失。"</string>
+ <string name="extmedia_format_button_format">"格式化"</string>
<string name="select_input_method">"選取輸入法"</string>
- <string name="fast_scroll_alphabet">"ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="fast_scroll_numeric_alphabet">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
- <string name="candidates_style"><font fgcolor="#ff000000" bgcolor="#ff8080ff"><u>"candidates"</u>"u&gt;"</font></string>
+ <string name="fast_scroll_alphabet">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style"><u>"待選項目"</u></string>
+ <string name="ext_media_checking_notification_title">"正在準備 SD 卡"</string>
+ <string name="ext_media_checking_notification_message">"正在檢查錯誤"</string>
+ <string name="ext_media_nofs_notification_title">"SD 卡為空白"</string>
+ <string name="ext_media_nofs_notification_message">"SD 卡為空白或使用不支援的檔案系統。"</string>
+ <string name="ext_media_unmountable_notification_title">"SD 卡已損壞"</string>
+ <string name="ext_media_unmountable_notification_message">"SD 卡已損壞。您可能需要將 SD 卡重新格式化。"</string>
+ <string name="ext_media_badremoval_notification_title">"SD 卡未預期移除"</string>
+ <string name="ext_media_badremoval_notification_message">"請先卸載 SD 卡,再將其移除,以免資料遺失。"</string>
+ <string name="ext_media_safe_unmount_notification_title">"可安全移除 SD 卡"</string>
+ <string name="ext_media_safe_unmount_notification_message">"現在可以安全移除 SD 卡。"</string>
+ <string name="ext_media_nomedia_notification_title">"已移除 SD 卡"</string>
+ <string name="ext_media_nomedia_notification_message">"已移除 SD 卡。請插入新的 SD 卡來增加裝置的儲存容量。"</string>
+ <string name="activity_list_empty">"找不到符合的活動"</string>
+ <string name="permlab_pkgUsageStats">"更新元件使用統計資料"</string>
+ <string name="permdesc_pkgUsageStats">"允許修改收集到的元件使用統計資料。一般應用程式不會使用此功能。"</string>
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (2613287218853846830) -->
+ <skip />
+ <!-- no translation found for ime_action_go (8320845651737369027) -->
+ <skip />
+ <!-- no translation found for ime_action_search (658110271822807811) -->
+ <skip />
+ <!-- no translation found for ime_action_send (2316166556349314424) -->
+ <skip />
+ <!-- no translation found for ime_action_next (3138843904009813834) -->
+ <skip />
+ <!-- no translation found for ime_action_default (2840921885558045721) -->
+ <skip />
</resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 9f2c840..81fd87d 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -4,89 +4,95 @@
**
** Copyright 2006, 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
+** 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
+** 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
+** 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.
*/
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Do not translate. These are all of the drawable resources that should be preloaded by
the zygote process before it starts forking application processes. -->
<array name="preloaded_drawables">
- <item>@drawable/scrollbar_handle_vertical</item>
- <item>@drawable/scrollbar_handle_horizontal</item>
- <item>@drawable/scrollbar_horizontal</item>
- <item>@drawable/scrollbar_vertical</item>
-
- <item>@drawable/edit_text</item>
-
- <item>@drawable/title_bar</item>
-
- <item>@drawable/spinner_dropdown_background_down</item>
- <item>@drawable/divider_horizontal_bright</item>
-
- <item>@drawable/popup_full_dark</item>
- <item>@drawable/panel_background</item>
-
<item>@drawable/sym_def_app_icon</item>
-
- <item>@drawable/progress_horizontal</item>
- <item>@drawable/list_selector_background</item>
- <item>@drawable/btn_default</item>
-
- <!-- New additions... -->
- <item>@drawable/popup_top_dark</item>
- <item>@drawable/popup_center_dark</item>
- <item>@drawable/popup_bottom_dark</item>
- <item>@drawable/popup_top_bright</item>
- <item>@drawable/popup_center_bright</item>
- <item>@drawable/popup_bottom_bright</item>
-
- <!-- These are not normally referenced at first boot, but maybe
- would be good to preload? -->
+ <item>@drawable/arrow_down_float</item>
<item>@drawable/btn_check</item>
+ <item>@drawable/btn_check_label_background</item>
+ <item>@drawable/btn_check_off</item>
+ <item>@drawable/btn_check_on</item>
+ <item>@drawable/btn_default</item>
+ <item>@drawable/btn_default_small</item>
<item>@drawable/btn_dropdown</item>
+ <item>@drawable/btn_plus</item>
+ <item>@drawable/btn_minus</item>
<item>@drawable/btn_radio</item>
- <item>@drawable/list_selector_background</item>
- <item>@drawable/btn_default_small</item>
- <item>@drawable/btn_toggle</item>
-
- <!-- Contacts -->
- <item>@drawable/tab_indicator</item>
<item>@drawable/btn_star</item>
- <item>@drawable/button_inset</item>
-
- <!-- Menus -->
+ <item>@drawable/btn_toggle</item>
+ <item>@drawable/ic_emergency</item>
+ <item>@drawable/divider_horizontal_bright</item>
+ <item>@drawable/divider_horizontal_dark</item>
+ <item>@drawable/edit_text</item>
+ <item>@drawable/expander_group</item>
+ <item>@drawable/list_selector_background</item>
<item>@drawable/menu_background</item>
<item>@drawable/menu_background_fill_parent_width</item>
<item>@drawable/menu_selector</item>
- <item>@drawable/divider_vertical_bright</item>
-
- <item>@drawable/expander_group</item>
-
+ <item>@drawable/panel_background</item>
+ <item>@drawable/popup_bottom_bright</item>
+ <item>@drawable/popup_bottom_dark</item>
+ <item>@drawable/popup_bottom_medium</item>
+ <item>@drawable/popup_center_bright</item>
+ <item>@drawable/popup_center_dark</item>
+ <item>@drawable/popup_full_dark</item>
+ <item>@drawable/popup_top_bright</item>
+ <item>@drawable/popup_top_dark</item>
+ <item>@drawable/progress_horizontal</item>
+ <item>@drawable/progress_indeterminate_horizontal</item>
+ <item>@drawable/progress_small</item>
+ <item>@drawable/progress_small_titlebar</item>
+ <item>@drawable/screen_background_dark</item>
+ <item>@drawable/screen_background_light</item>
+ <item>@drawable/scrollbar_handle_horizontal</item>
+ <item>@drawable/scrollbar_handle_vertical</item>
+ <item>@drawable/spinner_dropdown_background</item>
+ <item>@drawable/title_bar</item>
+ <item>@drawable/title_bar_shadow</item>
<!-- Visual lock screen -->
<item>@drawable/indicator_code_lock_drag_direction_green_up</item>
<item>@drawable/indicator_code_lock_drag_direction_red_up</item>
<item>@drawable/indicator_code_lock_point_area_default</item>
<item>@drawable/indicator_code_lock_point_area_green</item>
<item>@drawable/indicator_code_lock_point_area_red</item>
-
- <!-- Zoom controls for maps, browser, etc. -->
- <item>@drawable/btn_plus</item>
- <item>@drawable/btn_minus</item>
- <item>@drawable/zoom_plate</item>
-
</array>
-
+
+ <!-- Do not translate. These are all of the color state list resources that should be
+ preloaded by the zygote process before it starts forking application processes. -->
+ <array name="preloaded_color_state_lists">
+ <item>@color/hint_foreground_dark</item>
+ <item>@color/hint_foreground_light</item>
+ <item>@color/primary_text_dark</item>
+ <item>@color/primary_text_dark_disable_only</item>
+ <item>@color/primary_text_light</item>
+ <item>@color/primary_text_light_disable_only</item>
+ <item>@color/primary_text_light_nodisable</item>
+ <item>@color/secondary_text_dark</item>
+ <item>@color/secondary_text_light</item>
+ <item>@color/tab_indicator_text</item>
+ <item>@color/tertiary_text_dark</item>
+ <item>@color/tertiary_text_light</item>
+ <item>#ff000000</item>
+ <item>#00000000</item>
+ <item>#ffffffff</item>
+ </array>
+
<!-- Do not translate. -->
<integer-array name="maps_starting_lat_lng">
<item>36149777</item>
@@ -100,19 +106,19 @@
<!-- Do not translate. Defines the slots for the right-hand side icons. That is to say, the
icons in the status bar that are not notifications. -->
<string-array name="status_bar_icon_order">
- <item>clock</item>
- <item>alarm_clock</item>
- <item>battery</item>
- <item>phone_signal</item>
- <item>data_connection</item>
- <item>volume</item>
- <item>mute</item>
- <item>speakerphone</item>
- <item>wifi</item>
- <item>bluetooth</item>
- <item>gps</item>
- <item>sync_active</item>
- <item>sync_failing</item>
- <item>ime</item>
+ <item><xliff:g id="id">clock</xliff:g></item>
+ <item><xliff:g id="id">alarm_clock</xliff:g></item>
+ <item><xliff:g id="id">battery</xliff:g></item>
+ <item><xliff:g id="id">phone_signal</xliff:g></item>
+ <item><xliff:g id="id">data_connection</xliff:g></item>
+ <item><xliff:g id="id">volume</xliff:g></item>
+ <item><xliff:g id="id">mute</xliff:g></item>
+ <item><xliff:g id="id">speakerphone</xliff:g></item>
+ <item><xliff:g id="id">wifi</xliff:g></item>
+ <item><xliff:g id="id">bluetooth</xliff:g></item>
+ <item><xliff:g id="id">gps</xliff:g></item>
+ <item><xliff:g id="id">sync_active</xliff:g></item>
+ <item><xliff:g id="id">sync_failing</xliff:g></item>
+ <item><xliff:g id="id">ime</xliff:g></item>
</string-array>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5477538..899d109 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -224,15 +224,18 @@
<!-- Leave the soft input window as-is, in whatever state it
last was. -->
<flag name="stateUnchanged" value="1" />
- <!-- Don't display the soft input area, there is no reason to
- do so on this window. -->
+ <!-- Make the soft input area hidden when normally appropriate
+ (when the user is navigating forward to your window). -->
<flag name="stateHidden" value="2" />
+ <!-- Always make the soft input area hidden when this window
+ has input focus. -->
+ <flag name="stateAlwaysHidden" value="3" />
<!-- Make the soft input area visible when normally appropriate
(when the user is navigating forward to your window). -->
- <flag name="stateVisible" value="3" />
+ <flag name="stateVisible" value="4" />
<!-- Always make the soft input area visible when this window
has input focus. -->
- <flag name="stateAlwaysVisible" value="4" />
+ <flag name="stateAlwaysVisible" value="5" />
<!-- The window resize/pan adjustment has not been specified,
the system will automatically select between resize and pan
@@ -261,6 +264,14 @@
actual instance is shown to the user. -->
<attr name="windowDisablePreview" format="boolean" />
+ <!-- Flag indicating that this window should not be displayed at all.
+ The default value is false; if set to true, and this window is
+ the main window of an Activity, then it will never actually
+ be added to the window manager. This means that your activity
+ must immediately quit without waiting for user interaction,
+ because there will be no such interaction coming. -->
+ <attr name="windowNoDisplay" format="boolean" />
+
<!-- ============ -->
<!-- Alert Dialog styles -->
<!-- ============ -->
@@ -336,6 +347,8 @@
<attr name="radioButtonStyle" format="reference" />
<!-- Default ScrollView style. -->
<attr name="scrollViewStyle" format="reference" />
+ <!-- Default HorizontalScrollView style. -->
+ <attr name="horizontalScrollViewStyle" format="reference" />
<!-- Default Spinner style. -->
<attr name="spinnerStyle" format="reference" />
<!-- Default Star style. -->
@@ -392,7 +405,8 @@
<!-- **************************************************************** -->
<eat-comment />
- <!-- Size of text (example: 15sp). Supported values include the following:<p/>
+ <!-- Size of text. Recommended dimension type for text is "sp" for scaled-pixels (example: 15sp).
+ Supported values include the following:<p/>
<ul>
<li><b>px</b> Pixels</li>
<li><b>sp</b> Scaled pixels (scaled to relative pixel size on screen). See {@link android.util.DisplayMetrics} for more information.</li>
@@ -401,6 +415,7 @@
</ul>
-->
<attr name="textSize" format="dimension" />
+
<!-- Default text typeface. -->
<attr name="typeface">
<enum name="normal" value="0" />
@@ -408,20 +423,26 @@
<enum name="serif" value="2" />
<enum name="monospace" value="3" />
</attr>
+
<!-- Default text typeface style. -->
<attr name="textStyle">
<flag name="normal" value="0" />
<flag name="bold" value="1" />
<flag name="italic" value="2" />
</attr>
+
<!-- Color of text (usually same as colorForeground). -->
<attr name="textColor" format="reference|color" />
+
<!-- Color of highlighted text. -->
<attr name="textColorHighlight" format="reference|color" />
+
<!-- Color of hint text (displayed when the field is empty). -->
<attr name="textColorHint" format="reference|color" />
+
<!-- Color of link text (URLs). -->
<attr name="textColorLink" format="reference|color" />
+
<!-- Where to ellipsize text. -->
<attr name="ellipsize">
<enum name="none" value="0" />
@@ -430,6 +451,7 @@
<enum name="end" value="3" />
<enum name="marquee" value="4" />
</attr>
+
<!-- The type of data being placed in a text field, used to help an
input method decide how to let the user enter text. The constants
here correspond to those defined by
@@ -466,13 +488,15 @@
{@link android.text.InputType#TYPE_TEXT_FLAG_AUTO_COMPLETE}. -->
<flag name="textAutoComplete" value="0x00010001" />
<!-- Can be combined with <var>text</var> and its variations to
- allow multiple lines of text in the field. Corresponds to
+ allow multiple lines of text in the field. If this flag is not set,
+ the text field will be constrained to a single line. Corresponds to
{@link android.text.InputType#TYPE_TEXT_FLAG_MULTI_LINE}. -->
<flag name="textMultiLine" value="0x00020001" />
<!-- Can be combined with <var>text</var> and its variations to
- indicate that a search string is being entered. Corresponds to
- {@link android.text.InputType#TYPE_TEXT_FLAG_SEARCH}. -->
- <flag name="textSearch" value="0x00040001" />
+ indicate that though the regular text view should not be multiple
+ lines, the IME should provide multiple lines if it can. Corresponds to
+ {@link android.text.InputType#TYPE_TEXT_FLAG_IME_MULTI_LINE}. -->
+ <flag name="textImeMultiLine" value="0x00040001" />
<!-- Text that will be used as a URI. Corresponds to
{@link android.text.InputType#TYPE_CLASS_TEXT} |
{@link android.text.InputType#TYPE_TEXT_VARIATION_URI}. -->
@@ -485,31 +509,43 @@
{@link android.text.InputType#TYPE_CLASS_TEXT} |
{@link android.text.InputType#TYPE_TEXT_VARIATION_EMAIL_SUBJECT}. -->
<flag name="textEmailSubject" value="0x00000031" />
- <!-- Text that is being supplied as the content of an e-mail. Corresponds to
+ <!-- Text that is the content of a short message. Corresponds to
+ {@link android.text.InputType#TYPE_CLASS_TEXT} |
+ {@link android.text.InputType#TYPE_TEXT_VARIATION_SHORT_MESSAGE}. -->
+ <flag name="textShortMessage" value="0x00000041" />
+ <!-- Text that is the content of a long message. Corresponds to
{@link android.text.InputType#TYPE_CLASS_TEXT} |
- {@link android.text.InputType#TYPE_TEXT_VARIATION_EMAIL_CONTENT}. -->
- <flag name="textEmailContent" value="0x00000041" />
+ {@link android.text.InputType#TYPE_TEXT_VARIATION_LONG_MESSAGE}. -->
+ <flag name="textLongMessage" value="0x00000051" />
<!-- Text that is the name of a person. Corresponds to
{@link android.text.InputType#TYPE_CLASS_TEXT} |
{@link android.text.InputType#TYPE_TEXT_VARIATION_PERSON_NAME}. -->
- <flag name="textPersonName" value="0x00000051" />
+ <flag name="textPersonName" value="0x00000061" />
<!-- Text that is being supplied as a postal mailing address. Corresponds to
{@link android.text.InputType#TYPE_CLASS_TEXT} |
{@link android.text.InputType#TYPE_TEXT_VARIATION_POSTAL_ADDRESS}. -->
- <flag name="textPostalAddress" value="0x00000061" />
+ <flag name="textPostalAddress" value="0x00000071" />
<!-- Text that is a password. Corresponds to
{@link android.text.InputType#TYPE_CLASS_TEXT} |
{@link android.text.InputType#TYPE_TEXT_VARIATION_PASSWORD}. -->
- <flag name="textPassword" value="0x00000071" />
- <!-- Text that will be used for free form search strings. Corresponds to
+ <flag name="textPassword" value="0x00000081" />
+ <!-- Text that is a password that should be visible. Corresponds to
{@link android.text.InputType#TYPE_CLASS_TEXT} |
- {@link android.text.InputType#TYPE_TEXT_VARIATION_SEARCH_STRING} |
- {@link android.text.InputType#TYPE_TEXT_FLAG_SEARCH}. -->
- <flag name="textSearchString" value="0x00040081" />
+ {@link android.text.InputType#TYPE_TEXT_VARIATION_VISIBLE_PASSWORD}. -->
+ <flag name="textVisiblePassword" value="0x00000091" />
<!-- Text that is being supplied as text in a web form. Corresponds to
{@link android.text.InputType#TYPE_CLASS_TEXT} |
{@link android.text.InputType#TYPE_TEXT_VARIATION_WEB_EDIT_TEXT}. -->
- <flag name="textWebEditText" value="0x00000091" />
+ <flag name="textWebEditText" value="0x000000a1" />
+ <!-- Text that is filtering some other data. Corresponds to
+ {@link android.text.InputType#TYPE_CLASS_TEXT} |
+ {@link android.text.InputType#TYPE_TEXT_VARIATION_FILTER}. -->
+ <flag name="textFilter" value="0x000000b1" />
+ <!-- Text that is for phonetic pronunciation, such as a phonetic name
+ field in a contact entry. Corresponds to
+ {@link android.text.InputType#TYPE_CLASS_TEXT} |
+ {@link android.text.InputType#TYPE_TEXT_VARIATION_PHONETIC}. -->
+ <flag name="textPhonetic" value="0x000000c1" />
<!-- A numeric only field. Corresponds to
{@link android.text.InputType#TYPE_CLASS_NUMBER}. -->
<flag name="number" value="0x00000002" />
@@ -540,6 +576,61 @@
<flag name="time" value="0x00000024" />
</attr>
+ <!-- Additional features you can enable in an IME associated with an editor,
+ to improve the integration with your application. The constants
+ here correspond to those defined by
+ {@link android.view.inputmethod.EditorInfo#imeOptions}. -->
+ <attr name="imeOptions">
+ <!-- There are no special semantics associated with this editor. -->
+ <flag name="normal" value="0x00000000" />
+ <!-- There is no specific action associated with this editor, let the
+ editor come up with its own if it can.
+ Corresponds to
+ {@link android.view.inputmethod.EditorInfo#IME_NULL}. -->
+ <flag name="actionUnspecified" value="0x00000000" />
+ <!-- This editor has no action associated with it.
+ Corresponds to
+ {@link android.view.inputmethod.EditorInfo#IME_ACTION_NONE}. -->
+ <flag name="actionNone" value="0x00000001" />
+ <!-- The action key performs a "go"
+ operation to take the user to the target of the text they typed.
+ Typically used, for example, when entering a URL.
+ Corresponds to
+ {@link android.view.inputmethod.EditorInfo#IME_ACTION_GO}. -->
+ <flag name="actionGo" value="0x00000002" />
+ <!-- The action key performs a "search"
+ operation, taking the user to the results of searching for the text
+ the have typed (in whatever context is appropriate).
+ Corresponds to
+ {@link android.view.inputmethod.EditorInfo#IME_ACTION_SEARCH}. -->
+ <flag name="actionSearch" value="0x00000003" />
+ <!-- The action key performs a "send"
+ operation, delivering the text to its target. This is typically used
+ when composing a message.
+ Corresponds to
+ {@link android.view.inputmethod.EditorInfo#IME_ACTION_SEND}. -->
+ <flag name="actionSend" value="0x00000004" />
+ <!-- The action key performs a "next"
+ operation, taking the user to the next field that will accept text.
+ Corresponds to
+ {@link android.view.inputmethod.EditorInfo#IME_ACTION_NEXT}. -->
+ <flag name="actionNext" value="0x00000005" />
+ <!-- The action key performs a "done"
+ operation, closing the soft input method.
+ Corresponds to
+ {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE}. -->
+ <flag name="actionDone" value="0x00000006" />
+ <!-- Used in conjunction with a custom action,
+ this indicates that the action should not
+ be available in-line as the same as a "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.
+ <p>Corresponds to
+ {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_ENTER_ACTION}. -->
+ <flag name="flagNoEnterAction" value="0x40000000" />
+ </attr>
+
<!-- A coordinate in the X dimension. -->
<attr name="x" format="dimension" />
<!-- A coordinate in the Y dimension. -->
@@ -744,6 +835,7 @@
<enum name="KEYCODE_PREVIOUSSONG" value="88" />
<enum name="KEYCODE_REWIND" value="89" />
<enum name="KEYCODE_FORWARD" value="90" />
+ <enum name="KEYCODE_MUTE" value="91" />
</attr>
<!-- ***************************************************************** -->
@@ -767,6 +859,7 @@
<attr name="windowAnimationStyle" />
<attr name="windowSoftInputMode" />
<attr name="windowDisablePreview" />
+ <attr name="windowNoDisplay" />
<attr name="textColor" />
<attr name="backgroundDimEnabled" />
<attr name="backgroundDimAmount" />
@@ -1040,6 +1133,10 @@
enabled for events such as clicking and touching. -->
<attr name="soundEffectsEnabled" format="boolean" />
+ <!-- Boolean that controls whether a view should have haptic feedback
+ enabled for events such as long presses. -->
+ <attr name="hapticFeedbackEnabled" format="boolean" />
+
</declare-styleable>
<!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
@@ -1578,7 +1675,7 @@
<declare-styleable name="TextAppearance">
<!-- Text color. -->
<attr name="textColor" />
- <!-- Size of the text. -->
+ <!-- Size of the text. Recommended dimension type for text is "sp" for scaled-pixels (example: 15sp). -->
<attr name="textSize" />
<!-- Style (bold, italic, bolditalic) for the text. -->
<attr name="textStyle" />
@@ -1619,7 +1716,7 @@
<attr name="textColorHint" />
<!-- Base text color, typeface, size, and style. -->
<attr name="textAppearance" />
- <!-- Size of the text. -->
+ <!-- Size of the text. Recommended dimension type for text is "sp" for scaled-pixels (example: 15sp). -->
<attr name="textSize" />
<!-- Sets the horizontal scaling factor for the text -->
<attr name="textScaleX" format="float" />
@@ -1673,9 +1770,15 @@
instead of letting it wrap onto multiple lines, and advances
focus instead of inserting a newline when you press the
enter key. Note: for editable text views, it is better
- to set this using the textMultiLine flag in inputType;
- if both this and inputType are supplied, the input
- type overrides the value here. -->
+ to control this using the textMultiLine flag in the inputType
+ attribute. (If both singleLine and inputType are supplied,
+ the inputType flags will override the value of singleLine.)
+ {@deprecated This attribute is deprecated and is replaced by the textMultiLine flag
+ in the inputType attribute. Use caution when altering existing layouts, as the
+ default value of singeLine is false (multi-line mode), but if you specify any
+ value for inputType, the default is single-line mode. (If both singleLine and
+ inputType attributes are found, the inputType flags will override the value of
+ singleLine.) } -->
<attr name="singleLine" format="boolean" />
<!-- {@deprecated Use state_enabled instead.} -->
<attr name="enabled" format="boolean" />
@@ -1785,13 +1888,22 @@
<enum name="marquee_forever" value="-1" />
</attr>
<attr name="inputType" />
+ <attr name="imeOptions" />
<!-- An addition content type description to supply to the input
method attached to the text view, which is private to the
implementation of the input method. This simply fills in
- the {@link android.view.inputmethod.EditorInfo#privateContentType
- EditorInfo.privateContentType} field when the input
+ the {@link android.view.inputmethod.EditorInfo#privateImeOptions
+ EditorInfo.privateImeOptions} field when the input
method is connected. -->
- <attr name="editorPrivateContentType" format="string" />
+ <attr name="privateImeOptions" format="string" />
+ <!-- Supply a value for
+ {@link android.view.inputmethod.EditorInfo#actionLabel EditorInfo.actionLabel}
+ used when an input method is connected to the text view. -->
+ <attr name="imeActionLabel" format="string" />
+ <!-- Supply a value for
+ {@link android.view.inputmethod.EditorInfo#actionId EditorInfo.actionId}
+ used when an input method is connected to the text view. -->
+ <attr name="imeActionId" format="integer" />
<!-- Reference to an
{@link android.R.styleable#InputExtras &lt;input-extras&gt;}
XML resource containing additional data to
@@ -1821,6 +1933,19 @@
<attr name="dropDownVerticalOffset" format="dimension" />
<!-- Amount of pixels by which the drop down should be offset horizontally. -->
<attr name="dropDownHorizontalOffset" format="dimension" />
+ <!-- View to anchor the auto-complete dropdown to. If not specified, the text view itself
+ is used. -->
+ <attr name="dropDownAnchor" format="reference" />
+ <!-- Specifies the basic width of the dropdown. Its value may
+ be a dimension (such as "12dip") for a constant width, fill_parent
+ to fill the width of the screen, or wrap_content to match the width
+ of the anchored view. -->
+ <attr name="dropDownWidth" format="dimension">
+ <!-- The dropdown should fill the width of the screen. -->
+ <enum name="fill_parent" value="-1" />
+ <!-- The dropdown should fit the width of its anchor. -->
+ <enum name="wrap_content" value="-2" />
+ </attr>
<attr name="inputType" />
</declare-styleable>
<declare-styleable name="PopupWindow">
@@ -1839,6 +1964,10 @@
<!-- Defines whether the scrollview should stretch its content to fill the viewport. -->
<attr name="fillViewport" format="boolean" />
</declare-styleable>
+ <declare-styleable name="HorizontalScrollView">
+ <!-- Defines whether the scrollview should stretch its content to fill the viewport. -->
+ <attr name="fillViewport" />
+ </declare-styleable>
<declare-styleable name="Spinner">
<!-- The prompt to display when the spinner's dialog is shown. -->
<attr name="prompt" format="reference" />
@@ -1936,10 +2065,10 @@
Accommodates top margin. -->
<attr name="layout_alignParentTop" format="boolean" />
<!-- If true, makes the right edge of this view match the right edge of the parent.
- Accommodates top margin. -->
+ Accommodates right margin. -->
<attr name="layout_alignParentRight" format="boolean" />
- <!-- f true, makes the bottom edge of this view match the bottom edge of the parent.
- Accommodates top margin. -->
+ <!-- If true, makes the bottom edge of this view match the bottom edge of the parent.
+ Accommodates bottom margin. -->
<attr name="layout_alignParentBottom" format="boolean" />
<!-- If true, centers this child horizontally and vertically within its parent. -->
<attr name="layout_centerInParent" format="boolean" />
@@ -2009,8 +2138,18 @@
<enum name="line" value="2" />
<enum name="ring" value="3" />
</attr>
+ <!-- Inner radius of the ring expressed as a ratio of the ring's width. For instance,
+ if innerRadiusRatio=9, then the inner radius equals the ring's width divided by 9.
+ This value is ignored if innerRadius is defined. Default value is 9. -->
<attr name="innerRadiusRatio" format="float" />
+ <!-- Thickness of the ring expressed as a ratio of the ring's width. For instance,
+ if thicknessRatio=3, then the thickness equals the ring's width divided by 3.
+ This value is ignored if innerRadius is defined. Default value is 3. -->
<attr name="thicknessRatio" format="float" />
+ <!-- Inner radius of the ring. When defined, innerRadiusRatio is ignored. -->
+ <attr name="innerRadius" format="dimension" />
+ <!-- Thickness of the ring. When defined, thicknessRatio is ignored. -->
+ <attr name="thickness" format="dimension" />
<attr name="useLevel" />
</declare-styleable>
@@ -2072,7 +2211,9 @@
</declare-styleable>
<declare-styleable name="LevelListDrawableItem">
+ <!-- The minimum level allowed for this item. -->
<attr name="minLevel" format="integer" />
+ <!-- The maximum level allowed for this item. -->
<attr name="maxLevel" format="integer" />
<attr name="drawable" />
</declare-styleable>
@@ -2126,6 +2267,16 @@
</attr>
</declare-styleable>
+ <!-- Drawable used to draw 9-patches. -->
+ <declare-styleable name="NinePatchDrawable">
+ <!-- Identifier of the bitmap file. This attribute is mandatory. -->
+ <attr name="src" />
+ <!-- Enables or disables dithering of the bitmap if the bitmap does not have the
+ same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
+ an RGB 565 screen.) -->
+ <attr name="dither" />
+ </declare-styleable>
+
<!-- Drawable used to draw a single color. -->
<declare-styleable name="ColorDrawable">
<!-- The color to use. -->
@@ -2490,6 +2641,7 @@
changing to use only icons for its buttons.}-->
<attr name="searchButtonText" format="string" />
<attr name="inputType" />
+ <attr name="imeOptions" />
<!-- Additional features are controlled by mode bits in this field. Omitting
this field, or setting to zero, provides default behavior. <i>Optional attribute.</i>
@@ -2513,6 +2665,43 @@
values are not suitable for user inspection and editing. -->
<flag name="queryRewriteFromText" value="0x20" />
</attr>
+
+ <!-- Voice search features are controlled by mode bits in this field. Omitting
+ this field, or setting to zero, provides default behavior.
+ If showVoiceSearchButton is set, then launchWebSearch or launchRecognizer must
+ also be set. <i>Optional attribute.</i>
+ -->
+ <attr name="voiceSearchMode">
+ <!-- If set, display a voice search button. This only takes effect if voice search is
+ available on the device. -->
+ <flag name="showVoiceSearchButton" value="0x01" />
+ <!-- If set, the voice search button will take the user directly to a built-in
+ voice web search activity. Most applications will not use this flag, as it
+ will take the user away from your searchable activity. -->
+ <flag name="launchWebSearch" value="0x02" />
+ <!-- If set, the voice search button will take the user directly to a built-in
+ voice recording activity. This activity will prompt the user to speak,
+ transcribe the spoke text, and forward the resulting query text to your
+ searchable activity, just as if the user had typed it into the search UI. -->
+ <flag name="launchRecognizer" value="0x04" />
+ </attr>
+
+ <!-- If provided, this specifies the language model that should be used by the
+ voice recognition system. See
+ {@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL } for more information.
+ If not provided, the default value
+ {@link android.speech.RecognizerIntent#LANGUAGE_MODEL_FREE_FORM } will be used. -->
+ <attr name="voiceLanguageModel" format="string" />
+ <!-- If provided, this specifies a prompt that will be displayed during voice input. -->
+ <attr name="voicePromptText" format="string" />
+ <!-- If provided, this specifies the spoken language to be expected, and that it will be
+ different than the one set in the {@link java.util.Locale#getDefault()}. -->
+ <attr name="voiceLanguage" format="string" />
+ <!-- If provided, enforces the maximum number of results to return, including the "best"
+ result which will always be provided as the SEARCH intent's primary query. Must be one
+ or greater. If not provided, the recognizer will choose how many results to return.
+ -->
+ <attr name="voiceMaxResults" format="integer" />
<!-- If provided, this is the trigger indicating that the searchable activity
provides suggestions as well. The value must be a fully-qualified content provider
@@ -2936,18 +3125,25 @@
</declare-styleable>
<!-- =============================== -->
- <!-- Gadget package class attributes -->
+ <!-- AppWidget package class attributes -->
<!-- =============================== -->
- <!-- Use <code>gadget-provider</code> as the root tag of the XML resource that
- describes a gadget provider. See TODO android.gadget android.gadget package
+ <!-- Use <code>appwidget-provider</code> as the root tag of the XML resource that
+ describes an AppWidget provider. See TODO android.appwidget package
for more info.
-->
- <declare-styleable name="GadgetProviderInfo">
+ <declare-styleable name="AppWidgetProviderInfo">
+ <!-- Minimum width of the AppWidget. -->
<attr name="minWidth"/>
+ <!-- Minimum height of the AppWidget. -->
<attr name="minHeight"/>
+ <!-- Update period in milliseconds, or 0 if the AppWidget will update itself. -->
<attr name="updatePeriodMillis" format="integer" />
+ <!-- A resource id of a layout. -->
<attr name="initialLayout" format="reference" />
+ <!-- A class name in the AppWidget's package to be launched to configure.
+ If not supplied, then no activity will be launched. -->
+ <attr name="configure" format="string" />
</declare-styleable>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index e215141..2ff0962 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -87,19 +87,19 @@
<!-- Specify a permission that a client is required to have in order to
use the associated object. If the client does not hold the named
permission, its request will fail. See the
- <a href="{@docRoot}devel/security.html">Security Model</a>
+ <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
document for more information on permissions. -->
<attr name="permission" format="string" />
<!-- A specific {@link android.R.attr#permission} name for read-only
access to a {@link android.content.ContentProvider}. See the
- <a href="{@docRoot}devel/security.html">Security Model</a>
+ <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
document for more information on permissions. -->
<attr name="readPermission" format="string" />
<!-- A specific {@link android.R.attr#permission} name for write
access to a {@link android.content.ContentProvider}. See the
- <a href="{@docRoot}devel/security.html">Security Model</a>
+ <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
document for more information on permissions. -->
<attr name="writePermission" format="string" />
@@ -170,6 +170,12 @@
user ID, they must also be signed with the same signature. -->
<attr name="sharedUserId" format="string" />
+ <!-- Specify a label for the shared user UID of this package. This is
+ only used if you have also used android:sharedUserId. This must
+ be a reference to a string resource; it can not be an explicit
+ string. -->
+ <attr name="sharedUserLabel" format="reference" />
+
<!-- Internal version code. This is the number used to determine whether
one version is more recent than another: it has no other meaning than
that higher numbers are more recent. You could use this number to
@@ -376,7 +382,7 @@
<attr name="priority" format="integer" />
<!-- Specify how an activity should be launched. See the
- <a href="{@docRoot}intro/appmodel.html">Application Model</a>
+ <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application Fundamentals</a>
documentation for important information on how these options impact
the behavior of your application.
@@ -413,7 +419,7 @@
of the activity being started at the top of the stack, it will
receive the Intent as described there (without the
FLAG_ACTIVITY_BROUGHT_TO_FRONT flag set). See the
- <a href="{@docRoot}intro/appmodel.html">Application Model</a>
+ <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application Fundamentals</a>
documentation for more details on tasks.-->
<enum name="singleTask" value="2" />
<!-- Only allow one instance of this activity to ever be
@@ -424,7 +430,7 @@
method called. If this
activity tries to start a new activity, that new activity will be
launched in a separate task. See the
- <a href="{@docRoot}intro/appmodel.html">Application Model</a>
+ <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application Fundamentals</a>
documentation for more details on tasks. -->
<enum name="singleInstance" value="3" />
</attr>
@@ -579,6 +585,7 @@
<attr name="versionCode" />
<attr name="versionName" />
<attr name="sharedUserId" />
+ <attr name="sharedUserLabel" />
</declare-styleable>
<!-- The <code>application</code> tag describes application-level components
@@ -633,7 +640,7 @@
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
features in your package (or other packages). See the
- <a href="{@docRoot}devel/security.html">Security Model</a>
+ <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
document for more information on permissions.
<p>This appears as a child tag of the root
@@ -705,7 +712,7 @@
<!-- The <code>uses-permission</code> tag requests a
{@link #AndroidManifestPermission &lt;permission&gt;} that the containing
package must be granted in order for it to operate correctly.
- See the <a href="{@docRoot}devel/security.html">Security Model</a>
+ See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
document for more information on permissions. Also available is a
{@link android.Manifest.permission list of permissions} included
with the base platform.
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 59f3a8f..8150067 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -19,7 +19,7 @@
-->
<resources>
<drawable name="screen_background_light">#ffffffff</drawable>
- <drawable name="screen_background_dark">#ff191919</drawable>
+ <drawable name="screen_background_dark">#ff1a1a1a</drawable>
<drawable name="status_bar_closed_default_background">#ff000000</drawable>
<drawable name="status_bar_opened_default_background">#ff000000</drawable>
<drawable name="search_bar_default_color">#ff000000</drawable>
@@ -28,7 +28,7 @@
<color name="white">#ffffffff</color>
<color name="black">#ff000000</color>
<color name="transparent">#00000000</color>
- <color name="background_dark">#ff191919</color>
+ <color name="background_dark">#ff1a1a1a</color>
<color name="bright_foreground_dark">#ffffffff</color>
<color name="bright_foreground_dark_disabled">#80ffffff</color>
<color name="bright_foreground_dark_inverse">#ff000000</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
new file mode 100644
index 0000000..83ac8e2
--- /dev/null
+++ b/core/res/res/values/config.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources>
+ <!-- Flag indicating whether the surface flinger has limited
+ alpha compositing functionality in hardware. If set, the window
+ manager will disable alpha trasformation in animations where not
+ strictly needed. -->
+ <bool name="config_sf_limitedAlpha">false</bool>
+
+ <!-- The duration (in milliseconds) of a short animation. -->
+ <integer name="config_shortAnimTime">100</integer>
+
+ <!-- The duration (in milliseconds) of a medium-length animation. -->
+ <integer name="config_mediumAnimTime">150</integer>
+
+ <!-- The duration (in milliseconds) of a long animation. -->
+ <integer name="config_longAnimTime">300</integer>
+</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 2abb26f..6461460 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -26,4 +26,6 @@
will be displayed in the app launcher and elsewhere. -->
<dimen name="app_icon_size">48dip</dimen>
<dimen name="toast_y_offset">64dip</dimen>
+ <!-- Height of the status bar -->
+ <dimen name="status_bar_height">25dip</dimen>
</resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index c5dbfd8..7e9b7ea 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -59,9 +59,10 @@
<item type="id" name="copy" />
<item type="id" name="paste" />
<item type="id" name="copyUrl" />
- <item type="id" name="inputMethod" />
+ <item type="id" name="switchInputMethod" />
<item type="id" name="keyboardView" />
<item type="id" name="button_close" />
- <item type="id" name="selectText" />
+ <item type="id" name="startSelectingText" />
<item type="id" name="stopSelectingText" />
+ <item type="id" name="addToDictionary" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c757c56..88c7b35 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -937,11 +937,12 @@
=============================================================== -->
<eat-comment />
+ <public type="attr" name="windowNoDisplay" id="0x0101021e" />
<public type="attr" name="backgroundDimEnabled" id="0x0101021f" />
<public type="attr" name="inputType" id="0x01010220" />
<public type="attr" name="isDefault" id="0x01010221" />
<public type="attr" name="windowDisablePreview" id="0x01010222" />
- <public type="attr" name="editorPrivateContentType" id="0x01010223" />
+ <public type="attr" name="privateImeOptions" id="0x01010223" />
<public type="attr" name="editorExtras" id="0x01010224" />
<public type="attr" name="settingsActivity" id="0x01010225" />
<public type="attr" name="fastScrollEnabled" id="0x01010226" />
@@ -964,30 +965,51 @@
<public type="attr" name="keyPreviewLayout" id="0x01010237" />
<public type="attr" name="keyPreviewOffset" id="0x01010238" />
<public type="attr" name="keyPreviewHeight" id="0x01010239" />
- <public type="attr" name="verticalCorrection" id="0x01010240" />
- <public type="attr" name="popupLayout" id="0x01010241" />
- <public type="attr" name="state_long_pressable" id="0x01010242" />
- <public type="attr" name="keyWidth" id="0x01010243" />
- <public type="attr" name="keyHeight" id="0x01010244" />
- <public type="attr" name="horizontalGap" id="0x01010245" />
- <public type="attr" name="verticalGap" id="0x01010246" />
- <public type="attr" name="rowEdgeFlags" id="0x01010247" />
- <public type="attr" name="codes" id="0x01010248" />
- <public type="attr" name="popupKeyboard" id="0x01010249" />
- <public type="attr" name="popupCharacters" id="0x0101024a" />
- <public type="attr" name="keyEdgeFlags" id="0x0101024b" />
- <public type="attr" name="isModifier" id="0x0101024c" />
- <public type="attr" name="isSticky" id="0x0101024d" />
- <public type="attr" name="isRepeatable" id="0x0101024e" />
- <public type="attr" name="iconPreview" id="0x0101024f" />
- <public type="attr" name="keyOutputText" id="0x01010250" />
- <public type="attr" name="keyLabel" id="0x01010251" />
- <public type="attr" name="keyIcon" id="0x01010252" />
- <public type="attr" name="keyboardMode" id="0x01010253" />
- <public type="attr" name="isScrollContainer" id="0x01010254" />
- <public type="attr" name="fillEnabled" id="0x01010255" />
- <public type="attr" name="updatePeriodMillis" id="0x01010256" />
- <public type="attr" name="initialLayout" id="0x01010257" />
+ <public type="attr" name="verticalCorrection" id="0x0101023a" />
+ <public type="attr" name="popupLayout" id="0x0101023b" />
+ <public type="attr" name="state_long_pressable" id="0x0101023c" />
+ <public type="attr" name="keyWidth" id="0x0101023d" />
+ <public type="attr" name="keyHeight" id="0x0101023e" />
+ <public type="attr" name="horizontalGap" id="0x0101023f" />
+ <public type="attr" name="verticalGap" id="0x01010240" />
+ <public type="attr" name="rowEdgeFlags" id="0x01010241" />
+ <public type="attr" name="codes" id="0x01010242" />
+ <public type="attr" name="popupKeyboard" id="0x01010243" />
+ <public type="attr" name="popupCharacters" id="0x01010244" />
+ <public type="attr" name="keyEdgeFlags" id="0x01010245" />
+ <public type="attr" name="isModifier" id="0x01010246" />
+ <public type="attr" name="isSticky" id="0x01010247" />
+ <public type="attr" name="isRepeatable" id="0x01010248" />
+ <public type="attr" name="iconPreview" id="0x01010249" />
+ <public type="attr" name="keyOutputText" id="0x0101024a" />
+ <public type="attr" name="keyLabel" id="0x0101024b" />
+ <public type="attr" name="keyIcon" id="0x0101024c" />
+ <public type="attr" name="keyboardMode" id="0x0101024d" />
+ <public type="attr" name="isScrollContainer" id="0x0101024e" />
+ <public type="attr" name="fillEnabled" id="0x0101024f" />
+ <public type="attr" name="updatePeriodMillis" id="0x01010250" />
+ <public type="attr" name="initialLayout" id="0x01010251" />
+ <public type="attr" name="voiceSearchMode" id="0x01010252" />
+ <public type="attr" name="voiceLanguageModel" id="0x01010253" />
+ <public type="attr" name="voicePromptText" id="0x01010254" />
+ <public type="attr" name="voiceLanguage" id="0x01010255" />
+ <public type="attr" name="voiceMaxResults" id="0x01010256" />
+ <public type="attr" name="bottomOffset" id="0x01010257" />
+ <public type="attr" name="topOffset" id="0x01010258" />
+ <public type="attr" name="allowSingleTap" id="0x01010259" />
+ <public type="attr" name="handle" id="0x0101025a" />
+ <public type="attr" name="content" id="0x0101025b" />
+ <public type="attr" name="animateOnClick" id="0x0101025c" />
+ <public type="attr" name="configure" id="0x0101025d" />
+ <public type="attr" name="hapticFeedbackEnabled" id="0x0101025e" />
+ <public type="attr" name="innerRadius" id="0x0101025f" />
+ <public type="attr" name="thickness" id="0x01010260" />
+ <public type="attr" name="sharedUserLabel" id="0x01010261" />
+ <public type="attr" name="dropDownWidth" id="0x01010262" />
+ <public type="attr" name="dropDownAnchor" id="0x01010263" />
+ <public type="attr" name="imeOptions" id="0x01010264" />
+ <public type="attr" name="imeActionLabel" id="0x01010265" />
+ <public type="attr" name="imeActionId" id="0x01010266" />
<!-- The part of the UI shown by an
{@link android.inputmethodservice.InputMethodService} that contains the
@@ -1022,7 +1044,7 @@
<!-- Context menu ID for the "Input Method" menu item to being up the
input method picker dialog, allowing the user to switch to another
input method. -->
- <public type="id" name="inputMethod" id="0x01020024" />
+ <public type="id" name="switchInputMethod" id="0x01020024" />
<!-- View ID of the text editor inside of an extracted text layout. -->
<public type="id" name="inputExtractEditText" id="0x01020025" />
@@ -1032,10 +1054,21 @@
<!-- View ID of a {@link android.view.View} to close a popup keyboard -->
<public type="id" name="button_close" id="0x01020027" />
+ <!-- Menu ID to perform a "start selecting text" operation. -->
+ <public type="id" name="startSelectingText" id="0x01020028" />
+ <!-- Menu ID to perform a "stop selecting text" operation. -->
+ <public type="id" name="stopSelectingText" id="0x01020029" />
+ <!-- Menu ID to perform a "add to dictionary" operation. -->
+ <public type="id" name="addToDictionary" id="0x0102002a" />
+
<public type="style" name="Theme.InputMethod" id="0x01030054" />
<public type="style" name="Theme.NoDisplay" id="0x01030055" />
<public type="style" name="Animation.InputMethod" id="0x01030056" />
<public type="style" name="Widget.KeyboardView" id="0x01030057" />
+ <public type="style" name="ButtonBar" id="0x01030058" />
+
+ <public type="string" name="dialog_alert_title" id="0x01040014" />
+ <public type="string" name="VideoView_error_text_invalid_progressive_playback" id="0x01040015" />
<public type="drawable" name="emo_im_angel" id="0x010800a4" />
<public type="drawable" name="emo_im_cool" id="0x010800a5" />
@@ -1054,4 +1087,16 @@
<public type="drawable" name="emo_im_winking" id="0x010800b2" />
<public type="drawable" name="emo_im_wtf" id="0x010800b3" />
<public type="drawable" name="emo_im_yelling" id="0x010800b4" />
+
+ <public type="drawable" name="ic_btn_speak_now" id="0x010800b5" />
+
+ <!-- Drawable to use as a background for separators on a list with a dark background -->
+ <public type="drawable" name="dark_header" id="0x010800b6" />
+
+ <!-- Drawable to use as a background for a taller version of the titlebar -->
+ <public type="drawable" name="title_bar_tall" id="0x010800b7" />
+
+ <public type="integer" name="config_shortAnimTime" id="0x010e0000" />
+ <public type="integer" name="config_mediumAnimTime" id="0x010e0001" />
+ <public type="integer" name="config_longAnimTime" id="0x010e0002" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ca49c9f..340cd40 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -240,9 +240,21 @@
<!-- status message in phone options dialog for when silent mode is disabled -->
<string name="global_action_silent_mode_off_status">Sound is ON</string>
+ <!-- label for item that toggles airplane mode -->
+ <string name="global_actions_toggle_airplane_mode">Airplane mode</string>
+
+ <!-- status message in phone options dialog for when airplane mode is on -->
+ <string name="global_actions_airplane_mode_on_status">Airplane mode is ON</string>
+
+ <!-- status message in phone options dialog for when airplane mode is off -->
+ <string name="global_actions_airplane_mode_off_status">Airplane mode is OFF</string>
+
<!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
<string name="safeMode">Safe mode</string>
+ <!-- Label for the Android system components when they are shown to the user. -->
+ <string name="android_system_label">Android System</string>
+
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_costMoney">Services that cost you money</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
@@ -778,6 +790,11 @@
unmount filesystems for removable storage.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_mount_format_filesystems">format external storage</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_mount_format_filesystems">Allows the application to format removable storage.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_vibrate">control vibrator</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_vibrate">Allows the application to control
@@ -824,6 +841,15 @@
properties uploaded by the checkin service. Not for use by normal
applications.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindGadget">choose widgets</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindGadget">Allows the application to tell the system
+ which widgets can be used by which application. With this permission,
+ applications can give access to personal data to other applications.
+ Not for use by normal applications.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_modifyPhoneState">modify phone state</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -915,6 +941,12 @@
the state network connectivity.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_changeBackgroundDataSetting">change background data usage setting</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_changeBackgroundDataSetting">Allows an application to change
+ the background data usage setting.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_accessWifiState">view Wi-Fi state</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_accessWifiState">Allows an application to view
@@ -1093,7 +1125,7 @@
<!-- When the lock screen is showing and the phone plugged in, show the current
charge %. -->
- <string name="lockscreen_plugged_in">Charging (<xliff:g id="number">%d%%</xliff:g>)</string>
+ <string name="lockscreen_plugged_in">Charging (<xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g>)</string>
<!-- When the lock screen is showing and the battery is low, warn user to plug
in the phone soon. -->
@@ -1152,7 +1184,7 @@
<!-- Title of the unlock screen that uses your Google login and password -->
<string name="lockscreen_glogin_too_many_attempts">Too many pattern attempts!</string>
<!-- In the unlock screen, message telling the user that they need to use their Google login and password to unlock the phone -->
- <string name="lockscreen_glogin_instructions">To unlock,\nsign in with your Google account</string>
+ <string name="lockscreen_glogin_instructions">To unlock, sign in with your Google account</string>
<!-- Hint caption for the username field when unlocking the phone using login and password -->
<string name="lockscreen_glogin_username_hint">Username (email)</string>
<!-- Hint caption for the password field when unlocking the phone using login and password -->
@@ -1439,6 +1471,8 @@
<!-- Title for error alert when a video cannot be played. it can be used by any app. -->
<string name="VideoView_error_title">Cannot play video</string>
+ <!-- Text for error alert when a video container is not valid for progressive download/playback. -->
+ <string name="VideoView_error_text_invalid_progressive_playback">Sorry, this video is not valid for streaming to this device.</string>
<!-- Text for error alert when a video cannot be played. it can be used by any app. -->
<string name="VideoView_error_text_unknown">Sorry, this video cannot be played.</string>
<!-- Button to close error alert when a video cannot be played -->
@@ -1502,50 +1536,38 @@
<!-- Date format string used in contexts where the user has said they
want the month first, as used in the USA, with the month fully
spelled out. You can remove the comma or add a period,
- or make other punctuation changes appropriate for your locale.
- If you need to add letters, put apostrophes around them to keep
- them from being interpreted as format characters. -->
- <string name="full_date_month_first"><xliff:g id="month" example="December">MMMM</xliff:g> <xliff:g id="day" example="31">dd</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
+ or make other punctuation changes appropriate for your locale. -->
+ <string name="full_date_month_first" format="date"><xliff:g id="month" example="December">MMMM</xliff:g> <xliff:g id="day" example="31">d</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
<!-- Date format string used in contexts where the user has said they
want the day of the month first, as used in Europe, with the month
fully spelled out. You can remove the comma or add a period,
- or make other punctuation changes appropriate for your locale.
- If you need to add letters, put apostrophes around them to keep
- them from being interpreted as format characters. -->
- <string name="full_date_day_first"><xliff:g id="day" example="31">dd</xliff:g> <xliff:g id="month" example="December">MMMM</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
+ or make other punctuation changes appropriate for your locale. -->
+ <string name="full_date_day_first" format="date"><xliff:g id="day" example="31">d</xliff:g> <xliff:g id="month" example="December">MMMM</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
<!-- Date format string used in contexts where the user has said they
want the month first, as used in the USA, with the month
abbreviated. You can remove the comma or add a period,
- or make other punctuation changes appropriate for your locale.
- If you need to add letters, put apostrophes around them to keep
- them from being interpreted as format characters. -->
- <string name="medium_date_month_first"><xliff:g id="month" example="Dec.">MMM</xliff:g> <xliff:g id="day" example="31">dd</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
+ or make other punctuation changes appropriate for your locale. -->
+ <string name="medium_date_month_first" format="date"><xliff:g id="month" example="Dec.">MMM</xliff:g> <xliff:g id="day" example="31">d</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
<!-- Date format string used in contexts where the user has said they
want the day of the month first, as used in Europe, with the month
abbreviated. You can remove the comma or add a period,
- or make other punctuation changes appropriate for your locale.
- If you need to add letters, put apostrophes around them to keep
- them from being interpreted as format characters. -->
- <string name="medium_date_day_first"><xliff:g id="day" example="31">dd</xliff:g> <xliff:g id="month" example="December">MMM</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
+ or make other punctuation changes appropriate for your locale. -->
+ <string name="medium_date_day_first" format="date"><xliff:g id="day" example="31">d</xliff:g> <xliff:g id="month" example="December">MMM</xliff:g>, <xliff:g id="year" example="1972">yyyy</xliff:g></string>
<!-- Time format string used in the status bar when the user has said they
want a 12-hour clock with AM and PM.
You can remove the colon
- or make other punctuation changes appropriate for your locale.
- If you need to add letters, put apostrophes around them to keep
- them from being interpreted as format characters. -->
- <string name="twelve_hour_time_format"><xliff:g id="hour" example="11">h</xliff:g>:<xliff:g id="minute" example="59">mm</xliff:g> <xliff:g id="ampm" example="AM">a</xliff:g></string>
+ or make other punctuation changes appropriate for your locale. -->
+ <string name="twelve_hour_time_format" format="date"><xliff:g id="hour" example="11">h</xliff:g>:<xliff:g id="minute" example="59">mm</xliff:g> <xliff:g id="ampm" example="AM">a</xliff:g></string>
<!-- Time format string used in the status bar when the user has said they
want a 24-hour clock.
You can remove the colon
- or make other punctuation changes appropriate for your locale.
- If you need to add letters, put apostrophes around them to keep
- them from being interpreted as format characters. -->
- <string name="twenty_four_hour_time_format"><xliff:g id="hour" example="23">H</xliff:g>:<xliff:g id="minute" example="59">mm</xliff:g></string>
+ or make other punctuation changes appropriate for your locale. -->
+ <string name="twenty_four_hour_time_format" format="date"><xliff:g id="hour" example="23">HH</xliff:g>:<xliff:g id="minute" example="59">mm</xliff:g></string>
<!-- Quoted name for 12pm, lowercase -->
<string name="noon">"noon"</string>
@@ -2020,6 +2042,10 @@
<!-- EditText context menu -->
<string name="inputMethod">Input Method</string>
+ <!-- Item on EditText context menu, used to add a word to the
+ input method dictionary. -->
+ <string name="addToDictionary">"Add \"%s\" to dictionary</string>
+
<!-- Title for EditText context menu -->
<string name="editTextMenuTitle">Edit text</string>
@@ -2036,6 +2062,9 @@
<string name="yes">OK</string>
<!-- Preference framework strings. -->
<string name="no">Cancel</string>
+ <!-- This is the generic "attention" string to be used in attention dialogs. Typically
+ combined with setIcon(android.R.drawable.ic_dialog_alert) -->
+ <string name="dialog_alert_title">Attention</string>
<!-- Default text for a button that can be toggled on and off. -->
<string name="capital_on">ON</string>
@@ -2090,8 +2119,8 @@
<string name="volume_music_hint_playing_through_bluetooth">Playing through Bluetooth</string>
<!-- Title of the dialog where the user is adjusting the phone call volume -->
<string name="volume_call">In-call volume</string>
- <!-- Hint shown in the volume toast to inform the user that the in-call audio is playing through Bluetooth. -->
- <string name="volume_call_hint_playing_through_bluetooth">Playing through Bluetooth</string>
+ <!-- Title of the dialog where the user is adjusting the phone call volume when connected on bluetooth-->
+ <string name="volume_bluetooth_call">Bluetooth in-call volume</string>
<!-- Title of the dialog where the user is adjusting the audio volume for alarms -->
<string name="volume_alarm">Alarm volume</string>
<!-- Title of the dialog where the user is adjusting the audio volume for notifications -->
@@ -2165,12 +2194,38 @@
<string name="usb_storage_button_mount">Mount</string>
<!-- See USB_STORAGE. This is the button text to ignore the plugging in of the phone.. -->
<string name="usb_storage_button_unmount">Don\'t mount</string>
- <!-- See USB_STORAGE_DIALOG. IF there was an error mounting, this is hte text. -->
+ <!-- See USB_STORAGE_DIALOG. If there was an error mounting, this is the text. -->
<string name="usb_storage_error_message">There is a problem using your SD card for USB storage.</string>
- <!-- USB_STORAGE: When the user connects the phone to a computer via USB, we show a notification asking if he wnats to share files across. This is the title -->
+ <!-- USB_STORAGE: When the user connects the phone to a computer via USB, we show a notification asking if he wants to share files across. This is the title -->
<string name="usb_storage_notification_title">USB connected</string>
<!-- See USB_STORAGE. This is the message. -->
<string name="usb_storage_notification_message">Select to copy files to/from your computer.</string>
+ <!-- USB_STORAGE_STOP: While USB storage is enabled, we show a notification dialog asking if he wants to stop. This is the title -->
+ <string name="usb_storage_stop_notification_title">Turn off USB storage</string>
+ <!-- See USB_STORAGE. This is the message. -->
+ <string name="usb_storage_stop_notification_message">Select to turn off USB storage.</string>
+
+ <!-- USB storage stop dialog strings -->
+ <!-- This is the label for the activity, and should never be visible to the user. -->
+ <!-- See USB_STORAGE_STOP. USB_STORAGE_STOP_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to stop usb storage. This is the title. -->
+ <string name="usb_storage_stop_title">Turn off USB storage</string>
+ <!-- See USB_STORAGE_STOP. This is the message. -->
+ <string name="usb_storage_stop_message">Before turning off USB storage, make sure you have unmounted on the USB host. Select \"Turn Off\" to turn off USB storage.</string>
+ <!-- See USB_STORAGE_STOP. This is the button text to stop usb storage. -->
+ <string name="usb_storage_stop_button_mount">Turn Off</string>
+ <!-- See USB_STORAGE_STOP. This is the button text to cancel stoping usb storage. -->
+ <string name="usb_storage_stop_button_unmount">Cancel</string>
+ <!-- See USB_STORAGE_STOP_DIALOG. If there was an error stopping, this is the text. -->
+ <string name="usb_storage_stop_error_message">We've encountered a problem turning off USB storage. Check to make sure you have unmounted the USB host, then try again.</string>
+
+ <!-- External media format dialog strings -->
+ <!-- This is the label for the activity, and should never be visible to the user. -->
+ <!-- See EXTMEDIA_FORMAT. EXTMEDIA_FORMAT_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to format the SD card. This is the title. -->
+ <string name="extmedia_format_title">Format SD card</string>
+ <!-- See EXTMEDIA_FORMAT. This is the message. -->
+ <string name="extmedia_format_message">Are you sure you want to format the SD card? All data on your card will be lost.</string>
+ <!-- See EXTMEDIA_FORMAT. This is the button text to format the sd card. -->
+ <string name="extmedia_format_button_format">Format</string>
<!-- Used to replace %s in urls retreived from the signin server with locales. For Some -->
<!-- devices we don't support all the locales we ship to and need to replace the '%s' with a -->
@@ -2185,9 +2240,65 @@
<string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
<string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
- <string name="candidates_style"><font fgcolor="#ff000000"
- bgcolor="#ff8080ff"><u>candidates</u>u></font></string>
-</resources>
+ <string name="candidates_style"><u>candidates</u></string>
+
+ <!-- External media notification strings -->
+ <!-- Shown when external media is being checked -->
+ <string name="ext_media_checking_notification_title">Preparing SD card</string>
+ <string name="ext_media_checking_notification_message">Checking for errors</string>
+
+ <!-- Shown when external media is blank (or unsupported filesystem) -->
+ <string name="ext_media_nofs_notification_title">Blank SD card</string>
+ <string name="ext_media_nofs_notification_message">The SD card is blank or using an unsupported filesystem.</string>
+
+ <!-- Shown when external media is unmountable (corrupt)) -->
+ <string name="ext_media_unmountable_notification_title">Damaged SD card</string>
+ <string name="ext_media_unmountable_notification_message">The SD card is damaged. You may have to reformat your card.</string>
+
+ <!-- Shown when external media is unsafely removed -->
+ <string name="ext_media_badremoval_notification_title">SD card unexpectedly removed</string>
+ <string name="ext_media_badremoval_notification_message">Unmount SD card before removing to avoid data loss.</string>
+
+ <!-- Shown when external media has been safely removed -->
+ <string name="ext_media_safe_unmount_notification_title">SD card safe to remove</string>
+ <string name="ext_media_safe_unmount_notification_message">The SD card can now be safely removed.</string>
+
+ <!-- Shown when external media is missing -->
+ <string name="ext_media_nomedia_notification_title">Removed SD card</string>
+ <string name="ext_media_nomedia_notification_message">The SD has been removed. Insert a new SD card to increase your device storage.</string>
+
+ <!-- Shown in LauncherActivity when the requested target Intent didn't return any matching Activities, leaving the list empty. -->
+ <string name="activity_list_empty">No matching activities found</string>
+
+ <!-- permission attributes related to package usage statistics -->
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_pkgUsageStats">update component usage statistics</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_pkgUsageStats">Allows the modification of collected component usage statistics. Not for use by normal applications.</string>
+ <!-- Shown in the tutorial for tap twice for zoom control. -->
+ <string name="tutorial_double_tap_to_zoom_message_short">Tap twice for zoom control</string>
+ <!-- Shown in gadget hosts (e.g. the home screen) when there was an error inflating
+ the gadget. -->
+ <string name="gadget_host_error_inflating">Error inflating widget</string>
+ <!-- Long label for a button on a full-screen input method for the "Go" action. -->
+ <string name="ime_action_go">Go</string>
+
+ <!-- Long label for a button on a full-screen input method for the "Search" action. -->
+ <string name="ime_action_search">Search</string>
+
+ <!-- Long label for a button on a full-screen input method for the "Send" action. -->
+ <string name="ime_action_send">Send</string>
+
+ <!-- Long label for a button on a full-screen input method for the "Next" action. -->
+ <string name="ime_action_next">Next</string>
+
+ <!-- Long label for a button on a full-screen input method for the "Done" action. -->
+ <string name="ime_action_done">Done</string>
+
+ <!-- Long label for a button on a full-screen input method for an unknown action. -->
+ <string name="ime_action_default">Execute</string>
+
+</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 41d3a81..a152410 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -84,6 +84,11 @@
<style name="Animation.Translucent">
</style>
+ <!-- Standard animations for a non-full-screen window or activity. -->
+ <style name="Animation.LockScreen">
+ <item name="windowExitAnimation">@anim/lock_screen_exit</item>
+ </style>
+
<style name="Animation.OptionsPanel">
<item name="windowEnterAnimation">@anim/options_panel_enter</item>
<item name="windowExitAnimation">@anim/options_panel_exit</item>
@@ -126,6 +131,12 @@
<item name="windowExitAnimation">@anim/input_method_exit</item>
</style>
+ <!-- Special optional fancy IM animations. @hide -->
+ <style name="Animation.InputMethodFancy">
+ <item name="windowEnterAnimation">@anim/input_method_fancy_enter</item>
+ <item name="windowExitAnimation">@anim/input_method_fancy_exit</item>
+ </style>
+
<!-- Window animations that are applied to the search bar overlay window.
{@hide Pending API council approval} -->
<style name="Animation.SearchBar">
@@ -133,6 +144,13 @@
<item name="windowExitAnimation">@anim/search_bar_exit</item>
</style>
+ <!-- Window animations that are applied to the zoom buttons overlay window.
+ {@hide Pending API council approval} -->
+ <style name="Animation.ZoomButtons">
+ <item name="windowEnterAnimation">@anim/fade_in</item>
+ <item name="windowExitAnimation">@anim/fade_out</item>
+ </style>
+
<!-- Status Bar Styles -->
<style name="TextAppearance.StatusBarTitle">
@@ -158,7 +176,7 @@
<item name="android:focusable">true</item>
<item name="android:clickable">true</item>
<item name="android:textAppearance">?android:attr/textAppearanceSmallInverse</item>
- <item name="android:textColor">@android:color/primary_text_light_nodisable</item>
+ <item name="android:textColor">@android:color/primary_text_light</item>
<item name="android:gravity">center_vertical|center_horizontal</item>
</style>
@@ -289,13 +307,14 @@
</style>
<style name="Widget.TextView.ListSeparator">
- <item name="android:background">@android:drawable/settings_header</item>
+ <item name="android:background">@android:drawable/dark_header</item>
<item name="android:layout_width">fill_parent</item>
- <item name="android:layout_height">27dip</item>
- <item name="android:textSize">18sp</item>
- <item name="android:textColor">#FF000000</item>
+ <item name="android:layout_height">25dip</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textColor">?textColorSecondary</item>
+ <item name="android:textSize">14sp</item>
<item name="android:gravity">center_vertical</item>
- <item name="android:paddingLeft">5sp</item>
+ <item name="android:paddingLeft">5sp</item>
</style>
<style name="Widget.EditText">
@@ -337,8 +356,9 @@
<item name="android:completionThreshold">2</item>
<item name="android:dropDownSelector">@android:drawable/list_selector_background</item>
<item name="android:popupBackground">@android:drawable/spinner_dropdown_background</item>
- <item name="android:dropDownVerticalOffset">-8px</item>
- <item name="android:dropDownHorizontalOffset">2px</item>
+ <item name="android:dropDownVerticalOffset">-6px</item>
+ <item name="android:dropDownHorizontalOffset">0px</item>
+ <item name="android:dropDownWidth">wrap_content</item>
</style>
<style name="Widget.Spinner">
@@ -371,6 +391,11 @@
<item name="android:fadingEdge">vertical</item>
</style>
+ <style name="Widget.HorizontalScrollView">
+ <item name="android:scrollbars">horizontal</item>
+ <item name="android:fadingEdge">horizontal</item>
+ </style>
+
<style name="Widget.ListView" parent="Widget.AbsListView">
<item name="android:listSelector">@android:drawable/list_selector_background</item>
<item name="android:cacheColorHint">?android:attr/colorBackground</item>
@@ -423,12 +448,27 @@
<item name="android:popupBackground">@android:drawable/editbox_dropdown_background_dark</item>
</style>
+ <style name="Widget.KeyboardView" parent="android:Widget">
+ <item name="android:background">@android:drawable/keyboard_background</item>
+ <item name="android:keyBackground">@android:drawable/btn_keyboard_key</item>
+ <item name="android:keyTextSize">22sp</item>
+ <item name="android:keyTextColor">#FFFFFFFF</item>
+ <item name="android:keyPreviewLayout">@android:layout/keyboard_key_preview</item>
+ <item name="android:keyPreviewOffset">-12dp</item>
+ <item name="android:keyPreviewHeight">80dp</item>
+ <item name="android:labelTextSize">14sp</item>
+ <item name="android:popupLayout">@android:layout/keyboard_popup_keyboard</item>
+ <item name="android:verticalCorrection">-10dip</item>
+ <item name="android:shadowColor">#BB000000</item>
+ <item name="android:shadowRadius">2.75</item>
+ </style>
+
<!-- Text Appearances -->
<eat-comment />
<style name="TextAppearance">
<item name="android:textColor">?textColorPrimary</item>
- <item name="android:textColorHighlight">#FF1B82EB</item>
+ <item name="android:textColorHighlight">#FFFF9200</item>
<item name="android:textColorHint">?textColorHint</item>
<item name="android:textColorLink">#5C5CFF</item>
<item name="android:textSize">16sp</item>
@@ -542,36 +582,6 @@
<item name="android:textStyle">bold</item>
</style>
- <style name="MediaButton">
- <item name="android:background">@android:drawable/media_button_background</item>
- <item name="android:layout_width">71px</item>
- <item name="android:layout_height">52px</item>
- </style>
-
- <style name="MediaButton.Previous">
- <item name="android:src">@android:drawable/ic_media_previous</item>
- </style>
-
- <style name="MediaButton.Next">
- <item name="android:src">@android:drawable/ic_media_next</item>
- </style>
-
- <style name="MediaButton.Play">
- <item name="android:src">@android:drawable/ic_media_play</item>
- </style>
-
- <style name="MediaButton.Ffwd">
- <item name="android:src">@android:drawable/ic_media_ff</item>
- </style>
-
- <style name="MediaButton.Rew">
- <item name="android:src">@android:drawable/ic_media_rew</item>
- </style>
-
- <style name="MediaButton.Pause">
- <item name="android:src">@android:drawable/ic_media_pause</item>
- </style>
-
<!-- Preference Styles -->
<style name="Preference">
@@ -619,19 +629,37 @@
<item name="android:showDefault">true</item>
</style>
- <style name="Widget.KeyboardView" parent="android:Widget">
- <item name="android:background">@android:drawable/keyboard_background</item>
- <item name="android:keyBackground">@android:drawable/btn_keyboard_key</item>
- <item name="android:keyTextSize">22sp</item>
- <item name="android:keyTextColor">#FFFFFFFF</item>
- <item name="android:keyPreviewLayout">@android:layout/keyboard_key_preview</item>
- <item name="android:keyPreviewOffset">-12dp</item>
- <item name="android:keyPreviewHeight">80dp</item>
- <item name="android:labelTextSize">14sp</item>
- <item name="android:popupLayout">@android:layout/keyboard_popup_keyboard</item>
- <item name="android:verticalCorrection">-10dip</item>
- <item name="android:shadowColor">#BB000000</item>
- <item name="android:shadowRadius">2.75</item>
+ <!-- Other Misc Styles -->
+ <eat-comment />
+
+ <style name="MediaButton">
+ <item name="android:background">@android:drawable/media_button_background</item>
+ <item name="android:layout_width">71px</item>
+ <item name="android:layout_height">52px</item>
+ </style>
+
+ <style name="MediaButton.Previous">
+ <item name="android:src">@android:drawable/ic_media_previous</item>
+ </style>
+
+ <style name="MediaButton.Next">
+ <item name="android:src">@android:drawable/ic_media_next</item>
+ </style>
+
+ <style name="MediaButton.Play">
+ <item name="android:src">@android:drawable/ic_media_play</item>
+ </style>
+
+ <style name="MediaButton.Ffwd">
+ <item name="android:src">@android:drawable/ic_media_ff</item>
+ </style>
+
+ <style name="MediaButton.Rew">
+ <item name="android:src">@android:drawable/ic_media_rew</item>
+ </style>
+
+ <style name="MediaButton.Pause">
+ <item name="android:src">@android:drawable/ic_media_pause</item>
</style>
<style name="ZoomControls">
@@ -640,4 +668,15 @@
<item name="android:paddingLeft">15dip</item>
<item name="android:paddingRight">15dip</item>
</style>
+
+ <!-- Style you can use with a container (typically a horizontal
+ LinearLayout) to get the standard "button bar" background and
+ spacing. @hide -->
+ <style name="ButtonBar">
+ <item name="android:paddingTop">5dip</item>
+ <item name="android:paddingLeft">4dip</item>
+ <item name="android:paddingRight">4dip</item>
+ <item name="android:paddingBottom">1dip</item>
+ <item name="android:background">@android:drawable/bottom_bar</item>
+ </style>
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 3f07e70..01c46de 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -74,7 +74,7 @@
<item name="buttonStyleToggle">@android:style/Widget.Button.Toggle</item>
<!-- List attributes -->
- <item name="listPreferredItemHeight">64px</item>
+ <item name="listPreferredItemHeight">64dip</item>
<item name="listDivider">@drawable/divider_horizontal_dark</item>
<item name="listSeparatorTextViewStyle">@android:style/Widget.TextView.ListSeparator</item>
@@ -122,8 +122,8 @@
<item name="scrollbarSize">10dip</item>
<item name="scrollbarThumbHorizontal">@android:drawable/scrollbar_handle_horizontal</item>
<item name="scrollbarThumbVertical">@android:drawable/scrollbar_handle_vertical</item>
- <item name="scrollbarTrackHorizontal">@android:drawable/scrollbar_horizontal</item>
- <item name="scrollbarTrackVertical">@android:drawable/scrollbar_vertical</item>
+ <item name="scrollbarTrackHorizontal">@null</item>
+ <item name="scrollbarTrackVertical">@null</item>
<!-- Widget styles -->
<item name="absListViewStyle">@android:style/Widget.AbsListView</item>
@@ -150,6 +150,7 @@
<item name="ratingBarStyleSmall">@android:style/Widget.RatingBar.Small</item>
<item name="radioButtonStyle">@android:style/Widget.CompoundButton.RadioButton</item>
<item name="scrollViewStyle">@android:style/Widget.ScrollView</item>
+ <item name="horizontalScrollViewStyle">@android:style/Widget.HorizontalScrollView</item>
<item name="spinnerStyle">@android:style/Widget.Spinner</item>
<item name="starStyle">@android:style/Widget.CompoundButton.Star</item>
<item name="starStyleButtonless">@android:style/Widget.CompoundButton.StarButtonless</item>
@@ -276,7 +277,8 @@
<item name="android:windowBackground">@null</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowAnimationStyle">@null</item>
- <item name="android:windowDisablePreview">@null</item>
+ <item name="android:windowDisablePreview">true</item>
+ <item name="android:windowNoDisplay">true</item>
</style>
<!-- Default theme for dialog windows and activities, which is used by the
diff --git a/data/etc/Android.mk b/data/etc/Android.mk
index 4b5464f..a32d8ea 100644
--- a/data/etc/Android.mk
+++ b/data/etc/Android.mk
@@ -21,7 +21,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := platform.xml
-LOCAL_MODULE_TAGS := user development
+LOCAL_MODULE_TAGS := user
LOCAL_MODULE_CLASS := ETC
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 21e452e..b13a292 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -113,6 +113,7 @@
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_DRM" uid="media" />
+ <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
<!-- This is a list of all the libraries available for application
code to link against. -->
diff --git a/data/localization/export-to-xlb b/data/localization/export-to-xlb
deleted file mode 100755
index 323f6b7..0000000
--- a/data/localization/export-to-xlb
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-
-mkdir -p /tmp/Maps/res/values
-
-P4PORT=perforce3:3666 p4 print -q //depot/branches/gmm_android_1_1_release_branch/googleclient/wireless/android/Maps/res/values/strings.xml > /tmp/Maps/res/values/strings.xml
-
-extract()
-{
- module=$1
- xlb=$2
- map=""
-
- shift; shift
-
- while [ "$1" = '-m' ]
- do
- map="$map $1 $2 $3"
- shift; shift; shift
- done
-
- files=$(
- for i in $*
- do
- find $i -name '*.xml' -print0 |
- xargs -0 grep -l '<string' |
- grep -v -e '-[a-z][a-z]/' |
- grep -v -e '-[a-z][a-z]-' |
- grep -v -e '-r[A-Z][A-Z]/' |
- grep -v -e '-r[A-Z][A-Z]-'
- done
- )
-
- ../../../../out/host/linux-x86/bin/transconsole $map -p $module $files > ${xlb}.xlb
-}
-
-. ./tc-files
diff --git a/data/localization/import-from-xtb b/data/localization/import-from-xtb
deleted file mode 100755
index f0a0b7d..0000000
--- a/data/localization/import-from-xtb
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/bin/sh
-
-extract()
-{
- module=$1
- shift
-
- P4PORT=perforce1:1666 p4 print -q //depot/google3/googledata/transconsole/xtb/$module/$locale.xtb > $module-$locale.xtb
-
- files=$(
- for i in $3
- do
- find $i -name '*.xml' -print0 |
- xargs -0 grep -l '<string' |
- grep -v -e '-[a-z][a-z]/' |
- grep -v -e '-[a-z][a-z]-' |
- grep -v -e '-r[A-Z][A-Z]/' |
- grep -v -e '-r[A-Z][A-Z]-'
- done
- )
-
- for i in $files
- do
- out=$(
- perl -e '
- $file = $ARGV[0];
- $locale = $ARGV[1];
-
- $locale =~ s/([a-z][a-z])-([A-Z][A-Z])/$1-r$2/;
-
- $file =~ /^(.*)\/values([^\/]*)\/(.*)/;
- $prefix = $1;
- $values = $2;
- $suffix = $3;
-
- if ($values =~ /^(-mcc[^-]*)*(-mnc[^-]*)*(.*)$/) {
- print "$prefix/values$1$2-$locale$3/$suffix\n";
- } else {
- print "$prefix/values-$locale$values/$suffix\n";
- }
- ' $i $locale
- )
-
- p4 edit $out
- p4 add $out
- mkdir -p `dirname $out`
- if ../../../../out/host/linux-x86/bin/transconsole -m $1 $2 -p $module -i $module-$locale.xtb $i > $out
- then :
- else
- p4 revert $out
- p4 delete $out
- fi
- done
-}
-
-for locale in fr it es de nl cs pl ja zh-TW zh-CN ru
-do
-
-extract AndroidAlarmClock ../../../../packages/apps/AlarmClock ../../apps/AlarmClock ../../../../packages/apps/AlarmClock
-extract AndroidBrowser ../../../../packages/apps/Browser ../../apps/Browser ../../../../packages/apps/Browser
-extract AndroidCalculator ../../../../packages/apps/Calculator ../../apps/Calculator ../../../../packages/apps/Calculator
-extract AndroidCalendar ../../../../packages/apps/Calendar ../../apps/Calendar ../../../../packages/apps/Calendar
-extract AndroidCamera ../../../../packages/apps/Camera ../../apps/Camera ../../../../packages/apps/Camera
-extract AndroidContacts ../../../../packages/apps/Contacts ../../apps/Contacts ../../../../packages/apps/Contacts
-extract AndroidDownloads ../../../../packages/providers/DownloadProvider ../../content/providers/downloads ../../../../packages/providers/DownloadProvider
-extract AndroidDrm ../../../../packages/providers/DrmProvider ../../content/providers/drm ../../../../packages/providers/DrmProvider
-extract AndroidEmail ../../../../packages/apps/Email ../../apps/Email ../../../../packages/apps/Email
-extract AndroidFallback ../../../../development/apps/Fallback ../../apps/Fallback ../../../../development/apps/Fallback
-extract AndroidGmail ../../../../vendor ../../partner ../../../../vendor/google/providers/gmail
-extract AndroidGmail ../../../../vendor ../../partner ../../../../vendor/google/apps/Gmail
-extract AndroidGoogleApps ../../../../vendor ../../partner ../../../../vendor/google/apps/GoogleApps
-extract AndroidGoogleSearch ../../../../packages/apps/GoogleSearch ../../apps/GoogleSearch ../../../../packages/apps/GoogleSearch
-extract AndroidHome ../../../../packages/apps/Launcher ../../apps/Home ../../../../packages/apps/Launcher
-extract AndroidIM ../../../../packages/apps/IM ../../apps/IM ../../../../packages/apps/IM
-extract AndroidMaps ../../../../vendor ../../partner ../../../../vendor/google/apps/Maps
-extract AndroidMaps ../../../../vendor ../../partner ../../../../vendor/google/apps/Street
-extract AndroidMms ../../../../packages/apps/Mms ../../apps/Mms ../../../../packages/apps/Mms
-extract AndroidMusic ../../../../packages/apps/Music ../../apps/Music ../../../../packages/apps/Music
-extract AndroidPhone ../../../../packages/apps/Phone ../../apps/Phone ../../../../packages/apps/Phone
-extract AndroidPlatform ../../../../frameworks/base/core/res ../../apps/common ../../../../frameworks/base/core/res
-extract AndroidSettings ../../../../packages/apps/Settings ../../apps/Settings ../../../../packages/apps/Settings
-extract AndroidSetupWizard ../../../../vendor ../../partner ../../../../vendor/google/apps/SetupWizard
-extract AndroidSoundRecorder ../../../../packages/apps/SoundRecorder ../../apps/SoundRecorder ../../../../packages/apps/SoundRecorder
-extract AndroidStk ../../../../packages/apps/Stk ../../apps/Stk ../../../../packages/apps/Stk
-extract AndroidSync ../../../../packages/apps/Sync ../../apps/Sync ../../../../packages/apps/Sync
-extract AndroidTalk ../../../../vendor ../../partner ../../../../vendor/google/apps/Talk
-extract AndroidUpdater ../../../../packages/apps/Updater ../../apps/Updater ../../../../packages/apps/Updater
-extract AndroidVending ../../../../vendor ../../partner ../../../../vendor/google/apps/Vending
-extract AndroidVoiceDialer ../../../../packages/apps/VoiceDialer ../../apps/VoiceDialer ../../../../packages/apps/VoiceDialer
-extract AndroidYoutube ../../../../vendor ../../partner ../../../../vendor/google/apps/YouTube
-
-done
-
-exit 0
diff --git a/data/localization/tc-files b/data/localization/tc-files
deleted file mode 100644
index 5b32cb4..0000000
--- a/data/localization/tc-files
+++ /dev/null
@@ -1,33 +0,0 @@
-# TC-project XLB-file Newmap Oldmap Name...
-
-extract AndroidAlarmClock AlarmClock -m ../../../../packages/apps/AlarmClock ../../apps/AlarmClock ../../../../packages/apps/AlarmClock
-extract AndroidBrowser Browser -m ../../../../packages/apps/Browser ../../apps/Browser ../../../../packages/apps/Browser
-extract AndroidCalculator Calculator -m ../../../../packages/apps/Calculator ../../apps/Calculator ../../../../packages/apps/Calculator
-extract AndroidCalendar Calendar -m ../../../../packages/apps/Calendar ../../apps/Calendar ../../../../packages/apps/Calendar
-extract AndroidCamera Camera -m ../../../../packages/apps/Camera ../../apps/Camera ../../../../packages/apps/Camera
-extract AndroidContacts Contacts -m ../../../../packages/apps/Contacts ../../apps/Contacts ../../../../packages/apps/Contacts
-extract AndroidDownloads Downloads -m ../../../../packages/providers/DownloadProvider ../../content/providers/downloads ../../../../packages/providers/DownloadProvider
-extract AndroidDrm Drm -m ../../../../packages/providers/DrmProvider ../../content/providers/drm ../../../../packages/providers/DrmProvider
-extract AndroidEmail Email -m ../../../../packages/apps/Email ../../apps/Email ../../../../packages/apps/Email
-extract AndroidFallback Fallback -m ../../../../development/apps/Fallback ../../apps/Fallback ../../../../development/apps/Fallback
-extract AndroidGmail Gmail -m ../../../../vendor ../../partner ../../../../vendor/google/providers/gmail ../../../../vendor/google/apps/Gmail
-extract AndroidGoogleApps GoogleApps -m ../../../../vendor ../../partner ../../../../vendor/google/apps/GoogleApps
-extract AndroidGoogleSearch GoogleSearch -m ../../../../packages/apps/GoogleSearch ../../apps/GoogleSearch ../../../../packages/apps/GoogleSearch
-extract AndroidHome Home -m ../../../../packages/apps/Launcher ../../apps/Home ../../../../packages/apps/Launcher
-extract AndroidIM IM -m ../../../../packages/apps/IM ../../apps/IM ../../../../packages/apps/IM
-#extract AndroidMaps Maps -m ../../../../vendor ../../partner -m /home/build/googleclient/wireless/android ../../partner/google/apps /home/build/googleclient/wireless/android/Maps ../../../../vendor/google/apps/Street
-extract AndroidMaps Maps -m ../../../../vendor ../../partner -m /tmp/Maps ../../partner/google/apps/Maps /tmp/Maps ../../../../vendor/google/apps/Street
-extract AndroidMms Mms -m ../../../../packages/apps/Mms ../../apps/Mms ../../../../packages/apps/Mms
-extract AndroidMusic Music -m ../../../../packages/apps/Music ../../apps/Music ../../../../packages/apps/Music
-extract AndroidPhone Phone -m ../../../../packages/apps/Phone ../../apps/Phone ../../../../packages/apps/Phone
-extract AndroidPlatform AndroidSystem -m ../../../../frameworks/base/core/res ../../apps/common ../../../../frameworks/base/core/res
-extract AndroidSettings Settings -m ../../../../packages/apps/Settings ../../apps/Settings ../../../../packages/apps/Settings
-extract AndroidSetupWizard SetupWizard -m ../../../../vendor ../../partner ../../../../vendor/google/apps/SetupWizard
-extract AndroidSoundRecorder SoundRecorder -m ../../../../packages/apps/SoundRecorder ../../apps/SoundRecorder ../../../../packages/apps/SoundRecorder
-extract AndroidStk Stk -m ../../../../packages/apps/Stk ../../apps/Stk ../../../../packages/apps/Stk
-extract AndroidSync Sync -m ../../../../packages/apps/Sync ../../apps/Sync ../../../../packages/apps/Sync
-extract AndroidTalk Talk -m ../../../../vendor ../../partner ../../../../vendor/google/apps/Talk
-extract AndroidUpdater Updater -m ../../../../packages/apps/Updater ../../apps/Updater ../../../../packages/apps/Updater
-extract AndroidVending Vending -m ../../../../vendor ../../partner ../../../../vendor/google/apps/Vending
-extract AndroidVoiceDialer VoiceDialer -m ../../../../packages/apps/VoiceDialer ../../apps/VoiceDialer ../../../../packages/apps/VoiceDialer
-extract AndroidYoutube YouTube -m ../../../../vendor ../../partner ../../../../vendor/google/apps/YouTube
diff --git a/data/localization/xlb-merge b/data/localization/xlb-merge
deleted file mode 100755
index d62ca58..0000000
--- a/data/localization/xlb-merge
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-
-for i in *.xlb
-do
- perl -e '
- print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
- print "<localizationbundle locale=\"en\">\n";
-
- while (<>) {
- if (/<msg/) {
- $content = $_;
- } else {
- $content .= $_;
- }
-
- if (/<\/msg>/) {
- $content1 = $content;
- $content1 =~ s/desc="[^"]*"//;
-
- unless ($seen{$content1}) {
- print "$content";
- }
-
- $seen{$content1} = 1;
- $content = "";
- }
- }
-
- print "</localizationbundle>\n";
- ' $i ../../../../../../platform-1_0/device/data/localization/$i > /android/depot/googleclient/wireless/data/Android/$i
-done
diff --git a/data/sounds/Android.mk b/data/sounds/Android.mk
deleted file mode 100644
index 94e7670..0000000
--- a/data/sounds/Android.mk
+++ /dev/null
@@ -1,233 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# don't understand what's wrong here... bs
-#
-#copy_from := $(wildcard $(LOCAL_PATH)/*.mp3)
-#copy_to := $(addprefix $(TARGET_OUT)/sounds/,$(patsubst $(LOCAL_PATH)/%,%,$(copy_from)))
-#
-#$(copy_to) : PRIVATE_MODULE := sounds
-#$(copy_to) : $(TARGET_OUT)/sounds/% : $(LOCAL_PATH)/% | $(ACP)
-# $(transform-prebuilt-to-target)
-#
-#ALL_PREBUILT += $(copy_to)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/F1_MissedCall.ogg
-$(TARGET_OUT)/media/audio/notifications/F1_MissedCall.ogg : $(LOCAL_PATH)/F1_MissedCall.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/F1_New_MMS.ogg
-$(TARGET_OUT)/media/audio/notifications/F1_New_MMS.ogg : $(LOCAL_PATH)/F1_New_MMS.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/F1_New_SMS.ogg
-$(TARGET_OUT)/media/audio/notifications/F1_New_SMS.ogg : $(LOCAL_PATH)/F1_New_SMS.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/alarms/Alarm_Buzzer.ogg
-$(TARGET_OUT)/media/audio/alarms/Alarm_Buzzer.ogg : $(LOCAL_PATH)/Alarm_Buzzer.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/alarms/Alarm_Beep_01.ogg
-$(TARGET_OUT)/media/audio/alarms/Alarm_Beep_01.ogg : $(LOCAL_PATH)/Alarm_Beep_01.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/alarms/Alarm_Beep_02.ogg
-$(TARGET_OUT)/media/audio/alarms/Alarm_Beep_02.ogg : $(LOCAL_PATH)/Alarm_Beep_02.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/alarms/Alarm_Classic.ogg
-$(TARGET_OUT)/media/audio/alarms/Alarm_Classic.ogg : $(LOCAL_PATH)/Alarm_Classic.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/alarms/Alarm_Beep_03.ogg
-$(TARGET_OUT)/media/audio/alarms/Alarm_Beep_03.ogg : $(LOCAL_PATH)/Alarm_Beep_03.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/alarms/Alarm_Rooster_02.ogg
-$(TARGET_OUT)/media/audio/alarms/Alarm_Rooster_02.ogg : $(LOCAL_PATH)/Alarm_Rooster_02.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/Ring_Classic_02.ogg
-$(TARGET_OUT)/media/audio/ringtones/Ring_Classic_02.ogg : $(LOCAL_PATH)/Ring_Classic_02.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/Ring_Digital_02.ogg
-$(TARGET_OUT)/media/audio/ringtones/Ring_Digital_02.ogg : $(LOCAL_PATH)/Ring_Digital_02.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/Ring_Synth_04.ogg
-$(TARGET_OUT)/media/audio/ringtones/Ring_Synth_04.ogg : $(LOCAL_PATH)/Ring_Synth_04.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/Ring_Synth_02.ogg
-$(TARGET_OUT)/media/audio/ringtones/Ring_Synth_02.ogg : $(LOCAL_PATH)/Ring_Synth_02.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/sounds/test.mid
-$(TARGET_OUT)/sounds/test.mid : $(LOCAL_PATH)/test.mid | $(ACP)
- $(transform-prebuilt-to-target)
-#
-# --- New Wave Labs ringtones
-#
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/BeatPlucker.ogg
-$(TARGET_OUT)/media/audio/ringtones/BeatPlucker.ogg : $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/BentleyDubs.ogg
-$(TARGET_OUT)/media/audio/ringtones/BentleyDubs.ogg : $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/BirdLoop.ogg
-$(TARGET_OUT)/media/audio/ringtones/BirdLoop.ogg : $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/CaribbeanIce.ogg
-$(TARGET_OUT)/media/audio/ringtones/CaribbeanIce.ogg : $(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/CrazyDream.ogg
-$(TARGET_OUT)/media/audio/ringtones/CrazyDream.ogg : $(LOCAL_PATH)/newwavelabs/CrazyDream.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/CurveBall.ogg
-$(TARGET_OUT)/media/audio/ringtones/CurveBall.ogg : $(LOCAL_PATH)/newwavelabs/CurveBall.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/DreamTheme.ogg
-$(TARGET_OUT)/media/audio/ringtones/DreamTheme.ogg : $(LOCAL_PATH)/newwavelabs/DreamTheme.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/EtherShake.ogg
-$(TARGET_OUT)/media/audio/ringtones/EtherShake.ogg : $(LOCAL_PATH)/newwavelabs/EtherShake.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/FriendlyGhost.ogg
-$(TARGET_OUT)/media/audio/ringtones/FriendlyGhost.ogg : $(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/GameOverGuitar.ogg
-$(TARGET_OUT)/media/audio/ringtones/GameOverGuitar.ogg : $(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/Growl.ogg
-$(TARGET_OUT)/media/audio/ringtones/Growl.ogg : $(LOCAL_PATH)/newwavelabs/Growl.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/InsertCoin.ogg
-$(TARGET_OUT)/media/audio/ringtones/InsertCoin.ogg : $(LOCAL_PATH)/newwavelabs/InsertCoin.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/LoopyLounge.ogg
-$(TARGET_OUT)/media/audio/ringtones/LoopyLounge.ogg : $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/LoveFlute.ogg
-$(TARGET_OUT)/media/audio/ringtones/LoveFlute.ogg : $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/MidEvilJaunt.ogg
-$(TARGET_OUT)/media/audio/ringtones/MidEvilJaunt.ogg : $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/MildlyAlarming.ogg
-$(TARGET_OUT)/media/audio/ringtones/MildlyAlarming.ogg : $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/NewPlayer.ogg
-$(TARGET_OUT)/media/audio/ringtones/NewPlayer.ogg : $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/Noises1.ogg
-$(TARGET_OUT)/media/audio/ringtones/Noises1.ogg : $(LOCAL_PATH)/newwavelabs/Noises1.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/Noises2.ogg
-$(TARGET_OUT)/media/audio/ringtones/Noises2.ogg : $(LOCAL_PATH)/newwavelabs/Noises2.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/Noises3.ogg
-$(TARGET_OUT)/media/audio/ringtones/Noises3.ogg : $(LOCAL_PATH)/newwavelabs/Noises3.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/OrganDub.ogg
-$(TARGET_OUT)/media/audio/ringtones/OrganDub.ogg : $(LOCAL_PATH)/newwavelabs/OrganDub.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/RomancingTheTone.ogg
-$(TARGET_OUT)/media/audio/ringtones/RomancingTheTone.ogg : $(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/SitarVsSitar.ogg
-$(TARGET_OUT)/media/audio/ringtones/SitarVsSitar.ogg : $(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/SpringyJalopy.ogg
-$(TARGET_OUT)/media/audio/ringtones/SpringyJalopy.ogg : $(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/Terminated.ogg
-$(TARGET_OUT)/media/audio/ringtones/Terminated.ogg : $(LOCAL_PATH)/newwavelabs/Terminated.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/TwirlAway.ogg
-$(TARGET_OUT)/media/audio/ringtones/TwirlAway.ogg : $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/VeryAlarmed.ogg
-$(TARGET_OUT)/media/audio/ringtones/VeryAlarmed.ogg : $(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ringtones/World.ogg
-$(TARGET_OUT)/media/audio/ringtones/World.ogg : $(LOCAL_PATH)/newwavelabs/World.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-#
-# --- New Wave Labs notifications
-#
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/CaffeineSnake.ogg
-$(TARGET_OUT)/media/audio/notifications/CaffeineSnake.ogg : $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/DearDeer.ogg
-$(TARGET_OUT)/media/audio/notifications/DearDeer.ogg : $(LOCAL_PATH)/newwavelabs/DearDeer.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/DontPanic.ogg
-$(TARGET_OUT)/media/audio/notifications/DontPanic.ogg : $(LOCAL_PATH)/newwavelabs/DontPanic.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/Highwire.ogg
-$(TARGET_OUT)/media/audio/notifications/Highwire.ogg : $(LOCAL_PATH)/newwavelabs/Highwire.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/KzurbSonar.ogg
-$(TARGET_OUT)/media/audio/notifications/KzurbSonar.ogg : $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/OnTheHunt.ogg
-$(TARGET_OUT)/media/audio/notifications/OnTheHunt.ogg : $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/Voila.ogg
-$(TARGET_OUT)/media/audio/notifications/Voila.ogg : $(LOCAL_PATH)/newwavelabs/Voila.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/ui/Effect_Tick.ogg
-$(TARGET_OUT)/media/audio/ui/Effect_Tick.ogg : $(LOCAL_PATH)/Effect_Tick.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/Beat_Box_Android.ogg
-$(TARGET_OUT)/media/audio/notifications/Beat_Box_Android.ogg : $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/Heaven.ogg
-$(TARGET_OUT)/media/audio/notifications/Heaven.ogg : $(LOCAL_PATH)/notifications/Heaven.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/TaDa.ogg
-$(TARGET_OUT)/media/audio/notifications/TaDa.ogg : $(LOCAL_PATH)/notifications/TaDa.ogg | $(ACP)
- $(transform-prebuilt-to-target)
-
-ALL_PREBUILT += $(TARGET_OUT)/media/audio/notifications/Tinkerbell.ogg
-$(TARGET_OUT)/media/audio/notifications/Tinkerbell.ogg : $(LOCAL_PATH)/notifications/Tinkerbell.ogg | $(ACP)
- $(transform-prebuilt-to-target)
diff --git a/data/sounds/OriginalAudio.mk b/data/sounds/OriginalAudio.mk
new file mode 100644
index 0000000..8722983
--- /dev/null
+++ b/data/sounds/OriginalAudio.mk
@@ -0,0 +1,68 @@
+#
+# Original audio package that shipped on G1
+#
+# This file is included from core.mk so that all devices will have these sounds
+#
+# TODO: Clean up for future releases
+#
+
+LOCAL_PATH:= frameworks/base/data/sounds
+
+PRODUCT_COPY_FILES += \
+ $(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \
+ $(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \
+ $(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \
+ $(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \
+ $(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \
+ $(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \
+ $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \
+ $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \
+ $(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \
+ $(LOCAL_PATH)/Ring_Classic_02.ogg:system/media/audio/ringtones/Ring_Classic_02.ogg \
+ $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \
+ $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \
+ $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \
+ $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \
+ $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \
+ $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \
+ $(LOCAL_PATH)/newwavelabs/CaribbeanIce.ogg:system/media/audio/ringtones/CaribbeanIce.ogg \
+ $(LOCAL_PATH)/newwavelabs/CurveBall.ogg:system/media/audio/ringtones/CurveBall.ogg \
+ $(LOCAL_PATH)/newwavelabs/EtherShake.ogg:system/media/audio/ringtones/EtherShake.ogg \
+ $(LOCAL_PATH)/newwavelabs/FriendlyGhost.ogg:system/media/audio/ringtones/FriendlyGhost.ogg \
+ $(LOCAL_PATH)/newwavelabs/GameOverGuitar.ogg:system/media/audio/ringtones/GameOverGuitar.ogg \
+ $(LOCAL_PATH)/newwavelabs/Growl.ogg:system/media/audio/ringtones/Growl.ogg \
+ $(LOCAL_PATH)/newwavelabs/InsertCoin.ogg:system/media/audio/ringtones/InsertCoin.ogg \
+ $(LOCAL_PATH)/newwavelabs/LoopyLounge.ogg:system/media/audio/ringtones/LoopyLounge.ogg \
+ $(LOCAL_PATH)/newwavelabs/LoveFlute.ogg:system/media/audio/ringtones/LoveFlute.ogg \
+ $(LOCAL_PATH)/newwavelabs/MidEvilJaunt.ogg:system/media/audio/ringtones/MidEvilJaunt.ogg \
+ $(LOCAL_PATH)/newwavelabs/MildlyAlarming.ogg:system/media/audio/ringtones/MildlyAlarming.ogg \
+ $(LOCAL_PATH)/newwavelabs/NewPlayer.ogg:system/media/audio/ringtones/NewPlayer.ogg \
+ $(LOCAL_PATH)/newwavelabs/Noises1.ogg:system/media/audio/ringtones/Noises1.ogg \
+ $(LOCAL_PATH)/newwavelabs/Noises2.ogg:system/media/audio/ringtones/Noises2.ogg \
+ $(LOCAL_PATH)/newwavelabs/Noises3.ogg:system/media/audio/ringtones/Noises3.ogg \
+ $(LOCAL_PATH)/newwavelabs/OrganDub.ogg:system/media/audio/ringtones/OrganDub.ogg \
+ $(LOCAL_PATH)/newwavelabs/RomancingTheTone.ogg:system/media/audio/ringtones/RomancingTheTone.ogg \
+ $(LOCAL_PATH)/newwavelabs/SitarVsSitar.ogg:system/media/audio/ringtones/SitarVsSitar.ogg \
+ $(LOCAL_PATH)/newwavelabs/SpringyJalopy.ogg:system/media/audio/ringtones/SpringyJalopy.ogg \
+ $(LOCAL_PATH)/newwavelabs/Terminated.ogg:system/media/audio/ringtones/Terminated.ogg \
+ $(LOCAL_PATH)/newwavelabs/TwirlAway.ogg:system/media/audio/ringtones/TwirlAway.ogg \
+ $(LOCAL_PATH)/newwavelabs/VeryAlarmed.ogg:system/media/audio/ringtones/VeryAlarmed.ogg \
+ $(LOCAL_PATH)/newwavelabs/World.ogg:system/media/audio/ringtones/World.ogg \
+ $(LOCAL_PATH)/newwavelabs/CaffeineSnake.ogg:system/media/audio/notifications/CaffeineSnake.ogg \
+ $(LOCAL_PATH)/newwavelabs/DearDeer.ogg:system/media/audio/notifications/DearDeer.ogg \
+ $(LOCAL_PATH)/newwavelabs/DontPanic.ogg:system/media/audio/notifications/DontPanic.ogg \
+ $(LOCAL_PATH)/newwavelabs/Highwire.ogg:system/media/audio/notifications/Highwire.ogg \
+ $(LOCAL_PATH)/newwavelabs/KzurbSonar.ogg:system/media/audio/notifications/KzurbSonar.ogg \
+ $(LOCAL_PATH)/newwavelabs/OnTheHunt.ogg:system/media/audio/notifications/OnTheHunt.ogg \
+ $(LOCAL_PATH)/newwavelabs/Voila.ogg:system/media/audio/notifications/Voila.ogg \
+ $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \
+ $(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \
+ $(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \
+ $(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \
+ $(LOCAL_PATH)/effects/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
+ $(LOCAL_PATH)/effects/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
+ $(LOCAL_PATH)/effects/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
+ $(LOCAL_PATH)/effects/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
+ $(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
+ $(LOCAL_PATH)/newwavelabs/CrazyDream.ogg:system/media/audio/ringtones/CrazyDream.ogg \
+ $(LOCAL_PATH)/newwavelabs/DreamTheme.ogg:system/media/audio/ringtones/DreamTheme.ogg
diff --git a/data/sounds/Effect_Tick.ogg b/data/sounds/effects/Effect_Tick.ogg
index c899a7d..c899a7d 100644
--- a/data/sounds/Effect_Tick.ogg
+++ b/data/sounds/effects/Effect_Tick.ogg
Binary files differ
diff --git a/data/sounds/effects/KeypressDelete.ogg b/data/sounds/effects/KeypressDelete.ogg
new file mode 100644
index 0000000..738f6ae
--- /dev/null
+++ b/data/sounds/effects/KeypressDelete.ogg
Binary files differ
diff --git a/data/sounds/effects/KeypressDelete.wav b/data/sounds/effects/KeypressDelete.wav
new file mode 100644
index 0000000..0a2f3cc
--- /dev/null
+++ b/data/sounds/effects/KeypressDelete.wav
Binary files differ
diff --git a/data/sounds/effects/KeypressReturn.ogg b/data/sounds/effects/KeypressReturn.ogg
new file mode 100644
index 0000000..6c807b0
--- /dev/null
+++ b/data/sounds/effects/KeypressReturn.ogg
Binary files differ
diff --git a/data/sounds/effects/KeypressReturn.wav b/data/sounds/effects/KeypressReturn.wav
new file mode 100644
index 0000000..59ff13a
--- /dev/null
+++ b/data/sounds/effects/KeypressReturn.wav
Binary files differ
diff --git a/data/sounds/effects/KeypressSpacebar.ogg b/data/sounds/effects/KeypressSpacebar.ogg
new file mode 100644
index 0000000..b59c8ce
--- /dev/null
+++ b/data/sounds/effects/KeypressSpacebar.ogg
Binary files differ
diff --git a/data/sounds/effects/KeypressSpacebar.wav b/data/sounds/effects/KeypressSpacebar.wav
new file mode 100644
index 0000000..1f819c9
--- /dev/null
+++ b/data/sounds/effects/KeypressSpacebar.wav
Binary files differ
diff --git a/data/sounds/effects/KeypressStandard.ogg b/data/sounds/effects/KeypressStandard.ogg
new file mode 100644
index 0000000..a465cf8
--- /dev/null
+++ b/data/sounds/effects/KeypressStandard.ogg
Binary files differ
diff --git a/data/sounds/effects/KeypressStandard.wav b/data/sounds/effects/KeypressStandard.wav
new file mode 100644
index 0000000..56a7911
--- /dev/null
+++ b/data/sounds/effects/KeypressStandard.wav
Binary files differ
diff --git a/data/sounds/newwavelabs/BeatPlucker.ogg b/data/sounds/newwavelabs/BeatPlucker.ogg
index 347b5aa..f1bcef0 100644
--- a/data/sounds/newwavelabs/BeatPlucker.ogg
+++ b/data/sounds/newwavelabs/BeatPlucker.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/BentleyDubs.ogg b/data/sounds/newwavelabs/BentleyDubs.ogg
index 5bb082d..44c0631 100644
--- a/data/sounds/newwavelabs/BentleyDubs.ogg
+++ b/data/sounds/newwavelabs/BentleyDubs.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/BirdLoop.ogg b/data/sounds/newwavelabs/BirdLoop.ogg
index ed1074b..b484582 100644
--- a/data/sounds/newwavelabs/BirdLoop.ogg
+++ b/data/sounds/newwavelabs/BirdLoop.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/CaribbeanIce.ogg b/data/sounds/newwavelabs/CaribbeanIce.ogg
index bb150b5..7525123 100644
--- a/data/sounds/newwavelabs/CaribbeanIce.ogg
+++ b/data/sounds/newwavelabs/CaribbeanIce.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/CrazyDream.ogg b/data/sounds/newwavelabs/CrazyDream.ogg
index 907316a..5fa47b9 100644
--- a/data/sounds/newwavelabs/CrazyDream.ogg
+++ b/data/sounds/newwavelabs/CrazyDream.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/CurveBall.ogg b/data/sounds/newwavelabs/CurveBall.ogg
index e3d3fdf..733a004 100644
--- a/data/sounds/newwavelabs/CurveBall.ogg
+++ b/data/sounds/newwavelabs/CurveBall.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/DreamTheme.ogg b/data/sounds/newwavelabs/DreamTheme.ogg
index 2729f07..e602a38 100644
--- a/data/sounds/newwavelabs/DreamTheme.ogg
+++ b/data/sounds/newwavelabs/DreamTheme.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/EtherShake.ogg b/data/sounds/newwavelabs/EtherShake.ogg
index f1d645a..178aa21 100644
--- a/data/sounds/newwavelabs/EtherShake.ogg
+++ b/data/sounds/newwavelabs/EtherShake.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/FriendlyGhost.ogg b/data/sounds/newwavelabs/FriendlyGhost.ogg
index f250560..d993880 100644
--- a/data/sounds/newwavelabs/FriendlyGhost.ogg
+++ b/data/sounds/newwavelabs/FriendlyGhost.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/GameOverGuitar.ogg b/data/sounds/newwavelabs/GameOverGuitar.ogg
index 7c5c1d5..2adb0a8 100644
--- a/data/sounds/newwavelabs/GameOverGuitar.ogg
+++ b/data/sounds/newwavelabs/GameOverGuitar.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/Growl.ogg b/data/sounds/newwavelabs/Growl.ogg
index 5361b3f..c54bde0 100644
--- a/data/sounds/newwavelabs/Growl.ogg
+++ b/data/sounds/newwavelabs/Growl.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/InsertCoin.ogg b/data/sounds/newwavelabs/InsertCoin.ogg
index f5a4a38..8737da5 100644
--- a/data/sounds/newwavelabs/InsertCoin.ogg
+++ b/data/sounds/newwavelabs/InsertCoin.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/LoopyLounge.ogg b/data/sounds/newwavelabs/LoopyLounge.ogg
index ce559ec..6d168cd 100644
--- a/data/sounds/newwavelabs/LoopyLounge.ogg
+++ b/data/sounds/newwavelabs/LoopyLounge.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/LoveFlute.ogg b/data/sounds/newwavelabs/LoveFlute.ogg
index 35904b5..16cf413 100644
--- a/data/sounds/newwavelabs/LoveFlute.ogg
+++ b/data/sounds/newwavelabs/LoveFlute.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/MidEvilJaunt.ogg b/data/sounds/newwavelabs/MidEvilJaunt.ogg
index e4273a9..66d7fad 100644
--- a/data/sounds/newwavelabs/MidEvilJaunt.ogg
+++ b/data/sounds/newwavelabs/MidEvilJaunt.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/MildlyAlarming.ogg b/data/sounds/newwavelabs/MildlyAlarming.ogg
index 9f03f3b..9025b18 100644
--- a/data/sounds/newwavelabs/MildlyAlarming.ogg
+++ b/data/sounds/newwavelabs/MildlyAlarming.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/NewPlayer.ogg b/data/sounds/newwavelabs/NewPlayer.ogg
index 997aac1..c2df5d8 100644
--- a/data/sounds/newwavelabs/NewPlayer.ogg
+++ b/data/sounds/newwavelabs/NewPlayer.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/Noises1.ogg b/data/sounds/newwavelabs/Noises1.ogg
index 2950c6d..829b4fa 100644
--- a/data/sounds/newwavelabs/Noises1.ogg
+++ b/data/sounds/newwavelabs/Noises1.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/Noises2.ogg b/data/sounds/newwavelabs/Noises2.ogg
index 3f17526..69a3d72 100644
--- a/data/sounds/newwavelabs/Noises2.ogg
+++ b/data/sounds/newwavelabs/Noises2.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/Noises3.ogg b/data/sounds/newwavelabs/Noises3.ogg
index 788508e..3607c2a 100644
--- a/data/sounds/newwavelabs/Noises3.ogg
+++ b/data/sounds/newwavelabs/Noises3.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/OrganDub.ogg b/data/sounds/newwavelabs/OrganDub.ogg
index e18bbe0..c0a22f4 100644
--- a/data/sounds/newwavelabs/OrganDub.ogg
+++ b/data/sounds/newwavelabs/OrganDub.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/RomancingTheTone.ogg b/data/sounds/newwavelabs/RomancingTheTone.ogg
index aac4cb2..ebe54e5 100644
--- a/data/sounds/newwavelabs/RomancingTheTone.ogg
+++ b/data/sounds/newwavelabs/RomancingTheTone.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/SitarVsSitar.ogg b/data/sounds/newwavelabs/SitarVsSitar.ogg
index 0b421b8..cfe9c80 100644
--- a/data/sounds/newwavelabs/SitarVsSitar.ogg
+++ b/data/sounds/newwavelabs/SitarVsSitar.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/SpringyJalopy.ogg b/data/sounds/newwavelabs/SpringyJalopy.ogg
index d4c596e..b837aff 100644
--- a/data/sounds/newwavelabs/SpringyJalopy.ogg
+++ b/data/sounds/newwavelabs/SpringyJalopy.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/Terminated.ogg b/data/sounds/newwavelabs/Terminated.ogg
index 1b780b9..b980053 100644
--- a/data/sounds/newwavelabs/Terminated.ogg
+++ b/data/sounds/newwavelabs/Terminated.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/TwirlAway.ogg b/data/sounds/newwavelabs/TwirlAway.ogg
index faa685d..eeff7f0 100644
--- a/data/sounds/newwavelabs/TwirlAway.ogg
+++ b/data/sounds/newwavelabs/TwirlAway.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/VeryAlarmed.ogg b/data/sounds/newwavelabs/VeryAlarmed.ogg
index 22b3ae1..bfb63f4 100644
--- a/data/sounds/newwavelabs/VeryAlarmed.ogg
+++ b/data/sounds/newwavelabs/VeryAlarmed.ogg
Binary files differ
diff --git a/data/sounds/newwavelabs/World.ogg b/data/sounds/newwavelabs/World.ogg
index 03cafe6..e226166 100644
--- a/data/sounds/newwavelabs/World.ogg
+++ b/data/sounds/newwavelabs/World.ogg
Binary files differ
diff --git a/data/sounds/test.mid b/data/sounds/testfiles/test.mid
index d4ead53..d4ead53 100755
--- a/data/sounds/test.mid
+++ b/data/sounds/testfiles/test.mid
Binary files differ
diff --git a/docs/docs-redirect.html b/docs/docs-redirect.html
index 3d2b8a0..4e0743e 100644
--- a/docs/docs-redirect.html
+++ b/docs/docs-redirect.html
@@ -1,8 +1,8 @@
<html>
<head>
-<meta http-equiv="refresh" content="0;url=docs/index.html">
+<meta http-equiv="refresh" content="0;url=docs/offline.html">
</head>
<body>
-<a href="docs/index.html">click here if you are not redirected</a>
+<a href="docs/offline.html">click here if you are not redirected</a>
</body>
</html>
diff --git a/docs/html/_build_id.cs b/docs/html/_build_id.cs
deleted file mode 100644
index 139c216..0000000
--- a/docs/html/_build_id.cs
+++ /dev/null
@@ -1,2 +0,0 @@
-<?cs # appears on the right side of the blue bar at the bottom of every page
-?><div id="jd-build-id"> Build <?cs var:page.build ?> - <?cs var:page.now ?> </div>
diff --git a/docs/html/about.jd b/docs/html/about.jd
deleted file mode 100755
index a129916..0000000
--- a/docs/html/about.jd
+++ /dev/null
@@ -1,13 +0,0 @@
-about=true
-page.title=About
-@jd:body
-
- <div id="mainBodyFixed">
- <h2 id="searchTitle">About</h2>
- <img src="{@docRoot}assets/images/hr_gray_main.jpg" />
- <div><br /></div>
- <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
- <br /><br /><br /><br /><br /><br /><br /><br />
- <br /><br /><br /><br /><br /><br /><br /><br />
- <br /><br /><br /><br /><br /><br /><br /><br />
- </div> \ No newline at end of file
diff --git a/docs/html/app.yaml b/docs/html/app.yaml
index c63791e..9ffb775 100644
--- a/docs/html/app.yaml
+++ b/docs/html/app.yaml
@@ -3,9 +3,36 @@ version: 1
runtime: python
api_version: 1
+# This file defines two mutually exclusive
+# hander blocks:
+# - a handler for use on a local dev_appserver
+# during development or non-production doc build
+# - a handler for use on a production gae
+# instance. This handler requires that the
+# docs files in the app have been compressed
+# with divide_and_compress.py and that main.py
+# and gae_shell/ are present.
+#
+# Only one of the handler blocks should be
+# uncommented at any given time. By default,
+# the development handler is exposed.
+
handlers:
+# DEVELOPMENT HANDLER
+# (this handler block *must* be commented
+# out before pushing to a production server)
- url: /
static_dir: /
-
+# PRODUCTION GAE HANDLER
+#- url: /gae_shell/static
+# static_dir: gae_shell/static
+# expiration: 1d
+#
+#- url: /gae_shell/.*
+# script: /gae_shell/shell.py
+# login: admin
+#
+#- url: .*
+# script: main.py
diff --git a/docs/html/community/index.jd b/docs/html/community/index.jd
index 284afe3..2df4c01 100644
--- a/docs/html/community/index.jd
+++ b/docs/html/community/index.jd
@@ -4,53 +4,115 @@ page.title=Community
<div id="mainBodyFluid">
<h1>Community</h1>
- <p>Welcome to the Android community! We're glad you're here and invite you to participate in these discussions. Before posting, please red the <a href="#">Groups Charter</a> that covers the community guidelines.</p>
- <p>To get the most out of this group, please do the following before you post:</p>
- <ol>
- <li><a href="{@docRoot}guide/appendix/faq/index.html">Read the FAQs</a> The most common questions are addressed in this frequently updated list.</li>
- <li><strong>Type in keywords of your questions in the main Android site's search bar</strong> (such as the one above). This search encompasses all previous discussions, across all groups, as well as the full contents of the site, documentation, and blogs. Chances are good that somebody has run into the same issue before.</li>
- <li><strong>Be very clear</strong> about your question in the subject - it helps everyone, both those trying to answer your question as well as those who may be looking for information in the future. Also <strong>give plenty of details</strong> in your post to help others understand your problem. Code or log snippets, as well as pointers to screenshots, may also be helpful.</li>
- </ol>
- <p>For a great guide to phrasing your questions, please read: <a href="#">How to Ask Questions The Smart Way</a>.</p>
-
-<h2>Subscribe to a Group</h2>
-<p>You can subscribe to these groups in one of two ways:</p>
- <ul>
- <li>Follow the web access link (in the first column below) and then click "Join this group" on the right-side of the Groups page. If you'd rather read posts via email, sign in to Groups and click "edit my membership" on the right hand side. Select "email" under "How do you want to read this group?".</li>
- <li>Or simply subscribe via email by clicking the subscribe link (in the last column below).</li>
- </ul>
-
-<h3 class="green">Available Groups</h3>
- <table class="groupTable">
- <tr>
- <th>Group - Web Access</th>
- <th>Description</th>
- <th>Subscribe by email</th>
- </tr>
- <tr class="oddRow">
- <td><a href="http://groups.google.com/group/android-beginners">android-beginners</a></td>
- <td>Discuss developing Android applications using the Android framework. Get help with troubleshooting apps, advice on implementation, and strategies for improving your app's speed and user experience.</td>
- <td><a href="mailto:android-beginners-subscribe@googlegroups.com">android-beginners-subscribe@googlegroups.com</a></td>
- </tr>
- <tr class="evenRow">
- <td><a href="http://groups.google.com/group/android-developers">android-developers</a></td>
- <td>New to ANdroid development? Start here. Open to any discussion around beginner-type questions; this is a great way to get up and running with your new App on the Android platform.</td>
- <td><a href="mailto:android-developers-subscribe@googlegroups.com">android-developers-subscribe@googlegroups.com</a></td>
- </tr>
- <tr class="oddRow">
- <td><a href="http://groups.google.com/group/android-discuss">android-discuss</a></td>
- <td>The "water cooler" of Android discussion. Free-wheeling discussion from ideas about the Android platform to your announcements on other Android resources.</td>
- <td><a href="mailto:android-discuss-subscribe@googlegroups.com">android-discuss-subscribe@googlegroups.com</a></td>
- </tr>
- <tr class="evenRow">
- <td><a href="http://groups.google.com/group/android-security-discuss">android-security-discuss</a></td>
- <td>A place for open discussion on secure development, emerging security concerns, and best practices for and by android developers.</td>
- <td><a href="mailto:android-security-discuss-subscribe@googlegroups.com">android-security-discuss-subscribe@googlegroups.com</a></td>
- </tr>
- <tr class="oddRow">
- <td><nobr><a href="http://groups.google.com/group/android-security-announce">android-security-announce</a></nobr></td>
- <td>A low-volume group for security-related announcements by the Android Security Team.</td>
- <td><a href="mailto:android-security-announce-subscribe@googlegroups.com">android-security-announce-subscribe@googlegroups.com</a></td>
- </tr>
- </table>
-</div> \ No newline at end of file
+ <p>Welcome to the Android developers community! We're glad you're here and invite you to participate in these discussions. Before posting, please read the <a href="http://source.android.com/discuss/android-discussion-groups-charter">Groups Charter</a> that covers the community guidelines.</p>
+
+<p class="note"><strong>Note:</strong> If you are seeking discussion about Android source code (not application development),
+then please refer to the <a href="http://source.android.com/discuss">Open Source Project Mailing lists</a>.</p>
+
+<p style="margin-bottom".5em"><strong>Contents</strong></p>
+<ol class="toc">
+ <li><a href="#BeforeYouPost">Before you post</a></li>
+ <li><a href="#ApplicationDeveloperLists">Application developer mailing lists</a></li>
+ <li><a href="#UsingEmail">Using email with the mailing lists</a></li>
+ <li><a href="#UsingIRC">Using IRC</a></li>
+</ol>
+
+<h2 id="BeforeYouPost">Before you post</h2>
+<p>Before writing a post, please try the following:</p>
+
+<ol>
+<li><a href="{@docRoot}guide/appendix/faq/index.html">Read the FAQs</a> The most common questions about developing Android applications are addressed in this frequently updated list.</li>
+<li><strong>Type in keywords of your questions in the main Android site's search bar</strong> (such as the one above). This search encompasses all previous discussions, across all groups, as well as the full contents of the site, documentation, and blogs. Chances are good that somebody has run into the same issue before.</li>
+<li><b>Search the mailing list archives</b> to see whether your questions have already been discussed.
+ </li>
+</ol>
+
+<p>If you can't find your answer, then we encourage you to address the community.
+As you write your post, please do the following:
+<ol>
+<li><b>Read
+the <a href="http://sites.google.com/a/android.com/opensource/discuss/android-discussion-groups-charter">mailing list charter</a></b> that covers the community guidelines.
+</li>
+<li><b>Select the most appropriate mailing list for your question</b>. There are several different lists for
+developers, described below.</li>
+<li>
+ <b>Be very clear</b> about your question
+in the subject -- it helps everyone, both those trying to answer your
+question as well as those who may be looking for information in the
+future.</li>
+<li><b>Give plenty of details</b> in your post to
+help others understand your problem. Code or log snippets, as well as
+pointers to screenshots, may also be helpful. For a great guide to
+phrasing your questions, read <a href="http://www.catb.org/%7Eesr/faqs/smart-questions.html">How To Ask Questions The Smart Way</a>.
+ </li>
+</ol>
+
+
+<h3 id="ApplicationDeveloperLists">Application developer mailing lists</h3>
+<ul>
+<li><b>Android beginners</b> - You're new to Android application development. You want to figure out how to get started with the Android SDK and the basic Android APIs? Start here. This list is open to any discussion around beginner-type questions for developers using the SDK; this is a great way to get up and running with your new application on the Android platform. Ask about getting your development environment set up, get help with the first steps of Android development (your first User Interface, your first permission, your first file on the Android filesystem, your first app on the Android Market...). Be sure to check the archives first before asking new questions. Please avoid advanced subjects, which belong on android-developers, and user questions, which will get a better reception on android-discuss.
+<ul>
+<li>Subscribe using Google Groups:&nbsp;<a href="http://groups.google.com/group/android-beginners">android-beginners</a></li>
+<li>Subscribe via email:&nbsp;<a href="mailto:android-beginners-subscribe@googlegroups.com">android-beginners-subscribe@googlegroups.com</a><a href="mailto:android-platform-subscribe@googlegroups.com">
+</a></li>
+</ul>
+</li>
+
+<li><b>Android developers</b> - You're now an experienced Android application developer. You've grasped the basics of Android app development, you're comfortable using the SDK, now you want to move to advanced topics. Get help here with troubleshooting applications, advice on implementation, and strategies for improving your application's performance and user experience. This is the not the right place to discuss user issues (use android-discuss for that) or beginner questions with the Android SDK (use android-beginners for that).
+<ul>
+<li>Subscribe using Google Groups:&nbsp;<a href="http://groups.google.com/group/android-developers">android-developers</a></li>
+<li>Subscribe via email:&nbsp;<a href="mailto:android-developers-subscribe@googlegroups.com">android-developers-subscribe@googlegroups.com</a><a href="mailto:android-platform-subscribe@googlegroups.com">
+</a></li>
+</ul>
+</li>
+
+<li><b>Android discuss</b> - The "water cooler" of Android discussion. You can discuss just about anything Android-related here, ideas for the Android platform, announcements about your applications, discussions about Android devices, community resources... As long as your discussion is related to Android, it's on-topic here. However, if you have a discussion here that could belong on another list, you are probably not reaching all of your target audience here and may want to consider shifting to a more targeted list.
+<ul>
+<li>Subscribe using Google Groups:&nbsp;<a href="http://groups.google.com/group/android-discuss">android-discuss</a></li>
+<li>Subscribe via email:&nbsp;<a href="mailto:android-discuss-subscribe@googlegroups.com">android-discuss-subscribe@googlegroups.com</a><a href="mailto:android-platform-subscribe@googlegroups.com">
+ </a></li>
+</ul>
+</li>
+
+<li><b>Android security discuss</b> - A place for open discussion on secure development, emerging security concerns, and best practices for and by android developers. Please don't disclose vulnerabilities directly on this list, you'd be putting all Android users at risk.
+<ul>
+<li>Subscribe using Google Groups:&nbsp;<a href="http://groups.google.com/group/android-security-discuss">android-security-discuss</a></li>
+<li>Subscribe via email:&nbsp;<a href="mailto:android-security-discuss@googlegroups.com">android-secuirty-discuss@googlegroups.com</a><a href="mailto:android-platform-subscribe@googlegroups.com">
+ </a></li>
+</ul>
+</li>
+
+<li><b>Android security announce</b> - A low-volume group for security-related announcements by the Android Security Team.
+<ul>
+<li>Subscribe using Google Groups:&nbsp;<a href="http://groups.google.com/group/android-security-announce">android-security-announce</a></li>
+<li>Subscribe via email:&nbsp;<a href="mailto:android-security-announce-subscribe@googlegroups.com">android-security-announce-subscribe@googlegroups.com</a>
+<a href="mailto:android-platform-subscribe@googlegroups.com"> </a></li>
+</ul>
+</li>
+</ul>
+
+
+
+<h2 id="UsingEmail">Using email with the mailing lists</h2>
+<p>Instead of using the <a href="http://groups.google.com/">Google Groups</a> site, you can use your email client of choice to participate in the mailing lists.</p>
+<p>To subscribe to a group without using the Google Groups site, use the link under "subscribe via email" in the lists above.</p>
+<p>To set up how you receive mailing list postings by email:</p>
+
+<ol><li>Sign into the group via the Google Groups site. For example, for the android-framework group you would visit <a href="http://groups.google.com/group/android-framework">http://groups.google.com/group/android-framework</a>.</li>
+<li>Click "Edit
+my membership" on the right side.</li>
+<li>Under "How do
+you want to read this group?" select one of the email options. </li>
+</ol>
+
+<h2 id="UsingIRC">Using IRC</h2>
+<p>The Android community is using the #android channel on the irc.freenode.net server.
+</p>
+
+
+
+
+
+
+
+</div>
diff --git a/docs/html/favicon.ico b/docs/html/favicon.ico
new file mode 100644
index 0000000..d8884b7
--- /dev/null
+++ b/docs/html/favicon.ico
Binary files differ
diff --git a/docs/html/goodies/index.jd b/docs/html/goodies/index.jd
deleted file mode 100644
index c126098..0000000
--- a/docs/html/goodies/index.jd
+++ /dev/null
@@ -1,85 +0,0 @@
-page.title=Goodies
-@jd:body
-
-<h1>Goodies</h1>
-
-<h2>Wallpaper</h2>
-
-<table class="columns">
- <tr>
- <td>
- <ul style="font-size: 85%; list-style: none; margin: 0 0 1em 0;">
- <li><img src="{@docRoot}goodies/wallpaper/android-wallpaper1_thumbnail.png" height="125" width="200" alt="Android Wallpaper #1"></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper1_1024x768.png">1024 x 768</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper1_1280x800.png">1280 x 800</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper1_1440x900.png">1440 x 900</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper1_1600x1200.png">1600 x 1200</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper1_1680x1050.png">1680 x 1050</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper1_1920x1200.png">1920 x 1200</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper1_2560x1600.png">2560 x 1600</a></li>
- </ul>
- </td>
- <td>
- <ul style="font-size: 85%; list-style: none; margin: 0 0 1em 0;">
- <li><img src="{@docRoot}goodies/wallpaper/android-wallpaper2_thumbnail.png" height="125" width="200" alt="Android Wallpaper #2"></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper2_1024x768.png">1024 x 768</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper2_1280x800.png">1280 x 800</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper2_1440x900.png">1440 x 900</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper2_1600x1200.png">1600 x 1200</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper2_1680x1050.png">1680 x 1050</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper2_1920x1200.png">1920 x 1200</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper2_2560x1600.png">2560 x 1600</a></li>
- </ul>
- </td>
- <td>
- <ul style="font-size: 85%; list-style: none; margin: 0 0 1em 0;">
- <li><img src="{@docRoot}goodies/wallpaper/android-wallpaper3_thumbnail.png" height="125" width="200" alt="Android Wallpaper #3"></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper3_1024x768.png">1024 x 768</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper3_1280x800.png">1280 x 800</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper3_1440x900.png">1440 x 900</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper3_1600x1200.png">1600 x 1200</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper3_1680x1050.png">1680 x 1050</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper3_1920x1200.png">1920 x 1200</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper3_2560x1600.png">2560 x 1600</a></li>
- </ul>
- </td>
- <tr>
- </tr>
- <td>
- <ul style="font-size: 85%; list-style: none; margin: 0 0 1em 0;">
- <li><img src="{@docRoot}goodies/wallpaper/android-wallpaper4_thumbnail.png" height="125" width="200" alt="Android Wallpaper #4"></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper4_1024x768.png">1024 x 768</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper4_1280x800.png">1280 x 800</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper4_1440x900.png">1440 x 900</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper4_1600x1200.png">1600 x 1200</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper4_1680x1050.png">1680 x 1050</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper4_1920x1200.png">1920 x 1200</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper4_2560x1600.png">2560 x 1600</a></li>
- </ul>
- </td>
- <td>
- <ul style="font-size: 85%; list-style: none; margin: 0 0 1em 0;">
- <li><img src="{@docRoot}goodies/wallpaper/android-wallpaper5_thumbnail.jpg" height="125" width="200" alt="Android Wallpaper #5"></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper5_1024x768.jpg">1024 x 768</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper5_1280x800.jpg">1280 x 800</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper5_1440x900.jpg">1440 x 900</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper5_1600x1200.jpg">1600 x 1200</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper5_1680x1050.jpg">1680 x 1050</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper5_1920x1200.jpg">1920 x 1200</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper5_2560x1600.jpg">2560 x 1600</a></li>
- </ul>
- </td>
- <td>
- <ul style="font-size: 85%; list-style: none; margin: 0 0 1em 0;">
- <li><img src="{@docRoot}goodies/wallpaper/android-wallpaper6_thumbnail.jpg" height="125" width="200" alt="Android Wallpaper #6"></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper6_1024x768.jpg">1024 x 768</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper6_1280x800.jpg">1280 x 800</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper6_1440x900.jpg">1440 x 900</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper6_1600x1200.jpg">1600 x 1200</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper6_1680x1050.jpg">1680 x 1050</a> / <a href="{@docRoot}goodies/wallpaper/android-wallpaper6_1920x1200.jpg">1920 x 1200</a></li>
- <li><a href="{@docRoot}goodies/wallpaper/android-wallpaper6_2560x1600.jpg">2560 x 1600</a></li>
- </ul>
- </td>
- </tr>
-</table>
-
-<br>
-
-<div class="notice"><div id="notice" style="text-align: center; border: 1em 0em 1em 0em">
- Except as otherwise <a
- href="http://code.google.com/policies.html#restrictions">noted</a>,
- the content of this page is licensed under the <a rel="license"
- href="http://creativecommons.org/licenses/by/3.0/">Creative Commons
- Attribution 3.0 License</a>.
-<!-- <rdf:RDF xmlns="http://web.resource.org/cc/"
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
- <Work rdf:about="">
- <license rdf:resource="http://creativecommons.org/licenses/by/3.0/" />
- </Work>
- <License rdf:about="http://creativecommons.org/licenses/by/3.0/">
- <permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
- <permits rdf:resource="http://web.resource.org/cc/Distribution"/>
- <requires rdf:resource="http://web.resource.org/cc/Notice"/>
- <requires rdf:resource="http://web.resource.org/cc/Attribution"/>
- <permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
- </License>
-</rdf:RDF> -->
-</div>
diff --git a/docs/html/goodies/wallpaper/android-wallpaper1_1024x768.png b/docs/html/goodies/wallpaper/android-wallpaper1_1024x768.png
deleted file mode 100644
index f33b16c..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper1_1024x768.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper1_1280x800.png b/docs/html/goodies/wallpaper/android-wallpaper1_1280x800.png
deleted file mode 100644
index 391eb1a..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper1_1280x800.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper1_1440x900.png b/docs/html/goodies/wallpaper/android-wallpaper1_1440x900.png
deleted file mode 100644
index dcc49b5..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper1_1440x900.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper1_1600x1200.png b/docs/html/goodies/wallpaper/android-wallpaper1_1600x1200.png
deleted file mode 100644
index 3799bd7..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper1_1600x1200.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper1_1680x1050.png b/docs/html/goodies/wallpaper/android-wallpaper1_1680x1050.png
deleted file mode 100644
index 7ed9dca..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper1_1680x1050.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper1_1920x1200.png b/docs/html/goodies/wallpaper/android-wallpaper1_1920x1200.png
deleted file mode 100644
index 74b937c..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper1_1920x1200.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper1_2560x1600.png b/docs/html/goodies/wallpaper/android-wallpaper1_2560x1600.png
deleted file mode 100644
index 1fa8446..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper1_2560x1600.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper1_thumbnail.png b/docs/html/goodies/wallpaper/android-wallpaper1_thumbnail.png
deleted file mode 100644
index 7c9b435..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper1_thumbnail.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper2_1024x768.png b/docs/html/goodies/wallpaper/android-wallpaper2_1024x768.png
deleted file mode 100644
index d3613e9..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper2_1024x768.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper2_1280x800.png b/docs/html/goodies/wallpaper/android-wallpaper2_1280x800.png
deleted file mode 100644
index f0ef459..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper2_1280x800.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper2_1440x900.png b/docs/html/goodies/wallpaper/android-wallpaper2_1440x900.png
deleted file mode 100644
index 99b71f9..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper2_1440x900.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper2_1600x1200.png b/docs/html/goodies/wallpaper/android-wallpaper2_1600x1200.png
deleted file mode 100644
index 4e145e7..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper2_1600x1200.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper2_1680x1050.png b/docs/html/goodies/wallpaper/android-wallpaper2_1680x1050.png
deleted file mode 100644
index eeb7508..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper2_1680x1050.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper2_1920x1200.png b/docs/html/goodies/wallpaper/android-wallpaper2_1920x1200.png
deleted file mode 100644
index ecabf82..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper2_1920x1200.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper2_2560x1600.png b/docs/html/goodies/wallpaper/android-wallpaper2_2560x1600.png
deleted file mode 100644
index cae1607..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper2_2560x1600.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper2_thumbnail.png b/docs/html/goodies/wallpaper/android-wallpaper2_thumbnail.png
deleted file mode 100644
index cac05de..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper2_thumbnail.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper3_1024x768.png b/docs/html/goodies/wallpaper/android-wallpaper3_1024x768.png
deleted file mode 100644
index 18ccd88..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper3_1024x768.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper3_1280x800.png b/docs/html/goodies/wallpaper/android-wallpaper3_1280x800.png
deleted file mode 100644
index dffd997..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper3_1280x800.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper3_1440x900.png b/docs/html/goodies/wallpaper/android-wallpaper3_1440x900.png
deleted file mode 100644
index b62cae9..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper3_1440x900.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper3_1600x1200.png b/docs/html/goodies/wallpaper/android-wallpaper3_1600x1200.png
deleted file mode 100644
index 7f4409b..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper3_1600x1200.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper3_1680x1050.png b/docs/html/goodies/wallpaper/android-wallpaper3_1680x1050.png
deleted file mode 100644
index 5828234c..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper3_1680x1050.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper3_1920x1200.png b/docs/html/goodies/wallpaper/android-wallpaper3_1920x1200.png
deleted file mode 100644
index 7e33515..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper3_1920x1200.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper3_2560x1600.png b/docs/html/goodies/wallpaper/android-wallpaper3_2560x1600.png
deleted file mode 100644
index d948b4e..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper3_2560x1600.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper3_thumbnail.png b/docs/html/goodies/wallpaper/android-wallpaper3_thumbnail.png
deleted file mode 100644
index abd2c92..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper3_thumbnail.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper4_1024x768.png b/docs/html/goodies/wallpaper/android-wallpaper4_1024x768.png
deleted file mode 100644
index 536056d..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper4_1024x768.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper4_1280x800.png b/docs/html/goodies/wallpaper/android-wallpaper4_1280x800.png
deleted file mode 100644
index ba87529..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper4_1280x800.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper4_1440x900.png b/docs/html/goodies/wallpaper/android-wallpaper4_1440x900.png
deleted file mode 100644
index aa88c61..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper4_1440x900.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper4_1600x1200.png b/docs/html/goodies/wallpaper/android-wallpaper4_1600x1200.png
deleted file mode 100644
index cf10a81..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper4_1600x1200.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper4_1680x1050.png b/docs/html/goodies/wallpaper/android-wallpaper4_1680x1050.png
deleted file mode 100644
index 00d19fc..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper4_1680x1050.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper4_1920x1200.png b/docs/html/goodies/wallpaper/android-wallpaper4_1920x1200.png
deleted file mode 100644
index 3df19a9..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper4_1920x1200.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper4_2560x1600.png b/docs/html/goodies/wallpaper/android-wallpaper4_2560x1600.png
deleted file mode 100644
index 4d693ef..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper4_2560x1600.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper4_thumbnail.png b/docs/html/goodies/wallpaper/android-wallpaper4_thumbnail.png
deleted file mode 100644
index f1a1841..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper4_thumbnail.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper5_1024x768.jpg b/docs/html/goodies/wallpaper/android-wallpaper5_1024x768.jpg
deleted file mode 100644
index 68bdee83..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper5_1024x768.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper5_1280x800.jpg b/docs/html/goodies/wallpaper/android-wallpaper5_1280x800.jpg
deleted file mode 100644
index fc441b8..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper5_1280x800.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper5_1440x900.jpg b/docs/html/goodies/wallpaper/android-wallpaper5_1440x900.jpg
deleted file mode 100644
index 7f6bde8..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper5_1440x900.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper5_1600x1200.jpg b/docs/html/goodies/wallpaper/android-wallpaper5_1600x1200.jpg
deleted file mode 100644
index bb577bb..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper5_1600x1200.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper5_1680x1050.jpg b/docs/html/goodies/wallpaper/android-wallpaper5_1680x1050.jpg
deleted file mode 100644
index d28b06b..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper5_1680x1050.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper5_1920x1080.jpg b/docs/html/goodies/wallpaper/android-wallpaper5_1920x1080.jpg
deleted file mode 100644
index 7239e51..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper5_1920x1080.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper5_1920x1200.jpg b/docs/html/goodies/wallpaper/android-wallpaper5_1920x1200.jpg
deleted file mode 100644
index 862b5b6..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper5_1920x1200.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper5_2560x1600.jpg b/docs/html/goodies/wallpaper/android-wallpaper5_2560x1600.jpg
deleted file mode 100644
index 7fc9a08..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper5_2560x1600.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper5_thumbnail.jpg b/docs/html/goodies/wallpaper/android-wallpaper5_thumbnail.jpg
deleted file mode 100644
index 99f22f7..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper5_thumbnail.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper6_1024x768.jpg b/docs/html/goodies/wallpaper/android-wallpaper6_1024x768.jpg
deleted file mode 100644
index 2074065..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper6_1024x768.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper6_1280x800.jpg b/docs/html/goodies/wallpaper/android-wallpaper6_1280x800.jpg
deleted file mode 100644
index d0fe49c..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper6_1280x800.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper6_1440x900.jpg b/docs/html/goodies/wallpaper/android-wallpaper6_1440x900.jpg
deleted file mode 100644
index 52d3b4f..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper6_1440x900.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper6_1600x1200.jpg b/docs/html/goodies/wallpaper/android-wallpaper6_1600x1200.jpg
deleted file mode 100644
index b1b151e..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper6_1600x1200.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper6_1680x1050.jpg b/docs/html/goodies/wallpaper/android-wallpaper6_1680x1050.jpg
deleted file mode 100644
index d0f9c63..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper6_1680x1050.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper6_1920x1200.jpg b/docs/html/goodies/wallpaper/android-wallpaper6_1920x1200.jpg
deleted file mode 100644
index 730ef98..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper6_1920x1200.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper6_2560x1600.jpg b/docs/html/goodies/wallpaper/android-wallpaper6_2560x1600.jpg
deleted file mode 100644
index eb80b5c..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper6_2560x1600.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/goodies/wallpaper/android-wallpaper6_thumbnail.jpg b/docs/html/goodies/wallpaper/android-wallpaper6_thumbnail.jpg
deleted file mode 100644
index eabfe71..0000000
--- a/docs/html/goodies/wallpaper/android-wallpaper6_thumbnail.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/googleb38c1d60b7ba5d19.html b/docs/html/googleb38c1d60b7ba5d19.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/docs/html/googleb38c1d60b7ba5d19.html
diff --git a/docs/html/guide/appendix/faq/commontasks.jd b/docs/html/guide/appendix/faq/commontasks.jd
index 69fddd3..9c79bdd 100644
--- a/docs/html/guide/appendix/faq/commontasks.jd
+++ b/docs/html/guide/appendix/faq/commontasks.jd
@@ -1,4 +1,6 @@
page.title=Common Tasks and How to Do Them in Android
+parent.title=FAQs, Tips, and How-to
+parent.link=index.html
@jd:body
<ul>
@@ -81,7 +83,7 @@ want to look at the sample code included with the Android SDK, in the
and required files and syntax details for each is given in <a href="#filelist">File
List for an Android Application</a>. </li>
<li><strong>Design your user interface</strong> &nbsp;&nbsp;See <a
- href="{@docRoot}guide/topics/views/index.html">Implementing a UI</a> for
+ href="{@docRoot}guide/topics/ui/index.html">User Interface</a> for
details on elements of the Android screen. </li>
<li><strong>Implement your Activity </strong>(this page)<strong>&nbsp;&nbsp; </strong> You
will create one class/file for each screen in your application. Screens will
@@ -200,7 +202,7 @@ startActivity(myIntent); </pre>
<p>Android defines a number of standard values, for instance the action constants
defined by {@link android.content.Intent}. You can define custom values, but
both the caller and handler must use them. See the &lt;intent-filter&gt;
- tag description in <a href="{@docRoot}guide/topics/manifest/manifest.html">The AndroidManifest.xml
+ tag description in <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml
File</a> for more information on the manifest syntax for the handling
application. </p>
<a name="returningaresult" id="returningaresult"></a><h3>Returning a Result from a Screen</h3>
@@ -267,7 +269,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data){
{@link android.app.Activity#finishActivity(int) Activity.finishActivity()}
on any screens that it opens to close them. </p>
<a name="listening" id="listening"></a><h2>Listening for Button Clicks</h2>
-<p>Button click and other UI event capturing are covered in <a href="{@docRoot}guide/topics/views/ui-events.html">Handling UI Events</a> on the UI Design page.</p>
+<p>Button click and other UI event capturing are covered in <a href="{@docRoot}guide/topics/ui/ui-events.html">Handling UI Events</a> on the UI Design page.</p>
<a name="configurewindowproperties" id="configurewindowproperties"></a><h2>Configuring General Window Properties</h2>
<p>You can set a number of general window properties, such as whether to display
a title, whether the window is floating, and whether it displays an icon, by
@@ -527,174 +529,8 @@ focus to the notification before they can interact with it.</p>
which enables a dialog box with an embedded progress bar to send a &quot;I'm working
on it&quot; notification to the user. </p>
<a name="addmenuitems" id="addmenuitems"></a><h2>Adding Items to the Screen Menu</h2>
-<p>Every Android screen has a default menu with default options, such as adding the
- activity to the favorites menu. You can add your own menu entries to the default
- menu options by implementing {@link android.app.Activity#onCreateOptionsMenu(android.view.Menu)
- Activity.onCreateOptionsMenu} or {@link android.app.Activity#onPrepareOptionsMenu(android.view.Menu)
- Activity.onPrepareOptionsMenu()}, and adding {@link android.view.MenuItem Item}
- objects to the {@link android.view.Menu Menu} passed in. To handle clicks
- implement {@link android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
- Activity.onOptionsItemSelected()} to handle the click in your Activity class.
- You may also pass the Item object a handler class that implements the
- Runnable class (a handler) but this is less efficient and discouraged.</p>
-<p>An application receives a callback at startup time to enable it to populate its
- menu. Additionally, it receives callbacks each time the user displays the options
- menu to let you perform some contextual modifications on the menu. To populate
- the menu on startup, override {@link android.app.Activity#onCreateOptionsMenu(android.view.Menu)
- Activity.onCreateOptionsMenu}; to populate it when the menu is called (somewhat
- less efficient), you can override {@link android.app.Activity#onPrepareOptionsMenu(android.view.Menu)
- Activity.onPrepareOptionsMenu()}. Each Activity has its own menu list.</p>
-<p>Menu items are displayed in the order added, though you can group them as described
- in the {@link android.view.Menu#add Menu.add} documentation.
- The following code snippet adds three items to the default menu options and handles
- them through the overridden Activity.onOptionsItemSelected() method.
- You can show or hide menu items by calling {@link android.view.MenuItem#setVisible(
- boolean) setVisible()} or {@link android.view.Menu#setGroupVisible(int,
- boolean) setGroupVisible()}.
-</p>
-</p>
-<pre>// Called only the first time the options menu is displayed.
-// Create the menu entries.
-// Menu adds items in the order shown.
-&#064;Override
-public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
-
- // Parameters for menu.add are:
- // group -- Not used here.
- // id -- Used only when you want to handle and identify the click yourself.
- // title
- menu.add(0, 0, &quot;Zoom&quot;);
- menu.add(0, 1, &quot;Settings&quot;);
- menu.add(0, 2, &quot;Other&quot;);
- return true;
-}
+<p>See <a href="{@docRoot}guide/topics/ui/menus.html">Creating Menus</a>.</p>
-// Activity callback that lets your handle the selection in the class.
-// Return true to indicate that you&#39;ve got it, false to indicate
-// that it should be handled by a declared handler object for that
-// item (handler objects are discouraged for reasons of efficiency).
-&#064;Override
-public boolean onOptionsItemSelected(MenuItem item){
- switch (item.getId()) {
- case 0:
- showAlert(&quot;Menu Item Clicked&quot;, &quot;Zoom&quot;, &quot;ok&quot;, null, false, null);
- return true;
- case 1:
- showAlert(&quot;Menu Item Clicked&quot;, &quot;Settings&quot;, &quot;ok&quot;, null, false, null);
- return true;
- case 2:
- showAlert(&quot;Menu Item Clicked&quot;, &quot;Other&quot;, &quot;ok&quot;, null, false, null);
- return true;
- }
- return false;
-}
-</pre>
-<a name="menukeyshortcuts" id="menukeyshortcuts"></a>
-<p>You can add key shortcuts by calling the
- MenuItem.setAlphabeticShortcut() or
- MenuItem.setNumericShortcut() methods, as demonstrated here to add a &quot;c&quot; shortcut
- to a menu item:</p>
-<pre>thisItem.setAlphabeticShortcut('c'); </pre>
-<h3>Adding Submenus<a name="submenus" id="submenus"></a></h3>
-<p>Add a submenu by calling {@link android.view.Menu#addSubMenu
- Menu.addSubMenu()}, which returns a SubMenu object. You can then add additional
- items to this menu. Menus can only be one level deep, and you can customize the
- appearance of the submenu menu item. </p>
-<pre>
-&#64;Override
-public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
-
- // Parameters for menu.add are:
- // group -- Not used here.
- // id -- Used only when you want to handle and identify the click yourself.
- // title
- menu.add(0, 0, "Send message");
- menu.add(0, 1, "Settings");
- menu.add(0, 2, "Local handler");
- menu.add(0, 3, "Launch contact picker");
-
- // Add our submenu.
- SubMenu sub = menu.addSubMenu(1, 4, "Days of the week");
- sub.add(0, 5, "Monday");
- sub.add(0, 6, "Tuesday");
- sub.add(0, 7, "Wednesday");
- sub.add(0, 8, "Thursday");
- sub.add(0, 9, "Friday");
- sub.add(0, 10, "Saturday");
- sub.add(0, 11, "Sunday");
- return true;
-}
-</pre>
-<h3><strong>Adding yourself to menus on other applications</strong></h3>
-<a name="addingtoothermenus" id="addingtoothermenus"></a>
-<p>You can also advertise your Activity's services so that other Activities can add
- your activity to their own option menu. For example, suppose you implement a
- new image handling tool that shrinks an image to a smaller size
- and you would like to offer this as a menu option to any other Activity that
- handles pictures. To do this, you would exposes your capabilities inside an intent
- filter in your manifest. If another application that handles photos asks Android
- for any Activities that can perform actions on pictures, Android will perform
- intent resolution, find your Activity, and add it to the other Activity's options
- menu. </p>
-<h4><strong>The offering application </strong></h4>
-<p>The application offering the service must include an <code>&lt;intent-filter&gt;</code> element
- in the manifest, inside the <code>&lt;activity&gt;</code> tag of the offering
- Activity. The intent filter includes all the details describing what it can do,
- such as a <code>&lt;type&gt;</code> element that describes the MIME type of data
- that it can handle, a custom <code>&lt;action&gt;</code> value that describes
- what your handling application can do (this is so that when it receives the Intent
- on opening it knows what it is expected to do), and most important, include a <code>&lt;category&gt;</code> filter
- with the value <code>android.intent.category.ALTERNATIVE </code>and/or <code>android.intent.category.SELECTED_ALTERNATIVE</code> (SELECTED_ALTERNATIVE
- is used to handle only the currently selected element on the screen, rather than
- the whole Activity intent.</p>
-<p>Here's an example of a snip of a manifest that advertises picture shrinking technology
- for both selected items and the whole screen. </p>
-<pre>&lt;activity class=&quot;PictureShrink&quot;&gt; &lt;!-- Handling class --&gt;
- &lt;intent-filter label=&quot;Shrink picture&quot;&gt; &lt;!-- Menu label to display --&gt;
- &lt;action android:name=&quot;com.example.sampleapp.SHRINK_IT&quot; /&gt;
- &lt;data android:name=&quot;image/*&quot; /&gt; &lt;!-- MIME type for generic images --&gt;
- &lt;category android:name=&quot;android.intent.category.ALTERNATIVE &quot; /&gt;
- &lt;category android:name=&quot;android.intent.category.SELECTED_ALTERNATIVE&quot; /&gt;
- &lt;/intent-filter&gt;
-&lt;/activity&gt;</pre>
-<h4><strong>The menu-displaying application</strong></h4>
-<p>An application that wants to display a menu that includes any additional external
- services must, first of all, handle its menu creation callback. As part of that
- callback it creates an intent with the category Intent.ALTERNATIVE_CATEGORY and/or
- Intent.SELECTED_ALTERNATIVE, the MIME type currently selected, and any other
- requirements, the same way as it would satisfy an intent filter to open a new
- Activity. It then calls menu.addIntentOptions() to have Android search for and
- add any services meeting those requirements. It can optionally add additional
- custom menu items of its own. </p>
-<p>You should implement SELECTED_ALTERNATIVE in onPrepareOptionsMenu() rather than
- onCreateOptionsMenu(), because the user's selection can change after the application
- is launched. </p>
-<p>Here's a code snippet demonstrating how a picture application would search for
- additional services to display on its menu.</p>
-<pre>&#064;Override public boolean
-onCreateOptionsMenu(Menu menu){
- super.onCreateOptionsMenu(menu);
-
- // Create an Intent that describes the requirements to fulfill to be included
- // in our menu. The offering app must include a category value of Intent.ALTERNATIVE_CATEGORY.
- Intent intent = new Intent(null, getIntent().getData());
- intent.addCategory(Intent.ALTERNATIVE_CATEGORY);
-
- // Search for, and populate the menu with, acceptable offering applications.
- menu.addIntentOptions(
- 0, // Group
- 0, // Any unique IDs we might care to add.
- MySampleClass.class.getName(), // Name of the class displaying the menu--here, its this class.
- null, // No specifics.
- intent, // Previously created intent that describes our requirements.
- 0, // No flags.
- null); // No specifics.
-
- return true;
-}</pre>
-<p>&nbsp;</p>
<a name="webpage" id="webpage"></a><h2>Display a Web Page</h2>
<p>Use the {@link android.webkit.WebView webkit.WebView} object. </p>
<a name="binding" id="binding"></a><h2>Binding to Data</h2>
@@ -878,7 +714,7 @@ If the latitudeSpan, longitudeSpan, and zoomLevel attributes are not consistent,
where they can be launched (from the main program menu or elsewhere),
any content providers it implements and what kind of data they handle,
where the implementation classes are, and other application-wide
- information. Syntax details for this file are described in <a href="{@docRoot}guide/topics/manifest/manifest.html">The AndroidManifest.xml File</a>.</td>
+ information. Syntax details for this file are described in <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a>.</td>
</tr>
<tr>
<td valign="top">&nbsp;&nbsp;&nbsp;&nbsp;src/<br />
@@ -922,7 +758,7 @@ If the latitudeSpan, longitudeSpan, and zoomLevel attributes are not consistent,
<td valign="top">(<em>optional</em>) Holds all the XML files describing screens or parts
of screens. Although you could create a screen in Java, defining them
in XML files is typically easier. A layout file is similar in concept
- to an HTML file that describes the screen layout and components. See <a href="{@docRoot}guide/topics/views/index.html">Views and Layout</a> for more information about designing screens, and <a href="{@docRoot}guide/topics/resources/available-resources.html#layoutresources">Available Resource Types</a> for the syntax of these files.</td>
+ to an HTML file that describes the screen layout and components. See <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> for more information about designing screens, and <a href="{@docRoot}guide/topics/resources/available-resources.html#layoutresources">Available Resource Types</a> for the syntax of these files.</td>
</tr>
<tr>
<td valign="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;values/<br />
diff --git a/docs/html/guide/appendix/faq/framework.jd b/docs/html/guide/appendix/faq/framework.jd
index c5cfcf1..76a19c5 100644
--- a/docs/html/guide/appendix/faq/framework.jd
+++ b/docs/html/guide/appendix/faq/framework.jd
@@ -1,4 +1,6 @@
page.title=Android Application Framework FAQ
+parent.title=FAQs, Tips, and How-to
+parent.link=index.html
@jd:body
<ul>
diff --git a/docs/html/guide/appendix/faq/licensingandoss.jd b/docs/html/guide/appendix/faq/licensingandoss.jd
index 98be91c..c267fe8 100644
--- a/docs/html/guide/appendix/faq/licensingandoss.jd
+++ b/docs/html/guide/appendix/faq/licensingandoss.jd
@@ -1,4 +1,6 @@
page.title=Android Open Source Licensing FAQ
+parent.title=FAQs, Tips, and How-to
+parent.link=index.html
@jd:body
<ul>
diff --git a/docs/html/guide/appendix/faq/security.jd b/docs/html/guide/appendix/faq/security.jd
index 1c66f95..b0d832b 100644
--- a/docs/html/guide/appendix/faq/security.jd
+++ b/docs/html/guide/appendix/faq/security.jd
@@ -1,4 +1,6 @@
page.title=Android Security FAQ
+parent.title=FAQs, Tips, and How-to
+parent.link=index.html
@jd:body
<ul>
diff --git a/docs/html/guide/appendix/faq/troubleshooting.jd b/docs/html/guide/appendix/faq/troubleshooting.jd
index e10f661..7c703e6 100644
--- a/docs/html/guide/appendix/faq/troubleshooting.jd
+++ b/docs/html/guide/appendix/faq/troubleshooting.jd
@@ -1,4 +1,6 @@
page.title=Troubleshooting
+parent.title=FAQs, Tips, and How-to
+parent.link=index.html
@jd:body
@@ -28,9 +30,14 @@ page.title=Troubleshooting
<p>
The "Android Editors" feature of the ADT Plugin requires specific Eclipse components, such as WST. If you
encounter this error message during ADT installation, you need to install the
-required Eclipse components and then try the ADT installation again. The easiest way to install the required components for the
-Android Editors feature of ADT is the following:
-<ul>
+required Eclipse components and then try the ADT installation again. Follow the steps below to install the required components for the
+Android Editors feature, based on the version of Eclipse that you are using.</p>
+
+<table style="font-size:100%">
+<tr><th>Eclipse 3.3 (Europa)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
+<tr>
+<td width="50%">
+<ol>
<li>From the dialog where you select the <strong>Update sites to visit</strong>, select the checkboxes for both the
ADT site, and the Callisto/Europa/Ganymede Discovery Site (you may want to
check <strong>Automatically select mirrors</strong> at the bottom).</li>
@@ -41,6 +48,19 @@ don't do it, it doesn't load the content of the discovery site.</li>
<li>On the right, click <strong>Select required</strong>. This will select all the components
that are required to install the Android plugin (wst, emf, etc...).</li>
<li>Click <strong>Next</strong>, accept the agreement, click <strong>Install All</strong>, and restart Eclipse.</li>
+</ol>
+</td>
+<td>
+<ol>
+ <li>Select <strong>Help</strong> &gt; <strong>Software Updates...</strong></li>
+ <li>Select the <strong>Installed Software</strong> tab.</li>
+ <li>Click <strong>Update...</strong></li>
+ <li>If an update for ADT is available, select it and click <strong>Finish</strong>.</li>
+</ol>
+</td>
+</tr>
+</table>
+
</p>
<a name="nodevice"></a><h2>ADB reports &quot;no device&quot; when an emulator is running</h2>
diff --git a/docs/html/guide/appendix/glossary.jd b/docs/html/guide/appendix/glossary.jd
index 7059643..ef81631 100644
--- a/docs/html/guide/appendix/glossary.jd
+++ b/docs/html/guide/appendix/glossary.jd
@@ -168,7 +168,7 @@ page.title=Glossary
application's package name, version, components (activities, intent
filters, services), imported libraries, and describes the various
activies, and so on. See <a
- href="{@docRoot}guide/topics/manifest/manifest.html">The
+ href="{@docRoot}guide/topics/manifest/manifest-intro.html">The
AndroidManifest.xml File</a> for complete information.</dd>
<dt id="ninepatch">Nine-patch / 9-patch / Ninepatch image</dt>
diff --git a/docs/html/guide/appendix/media-formats.jd b/docs/html/guide/appendix/media-formats.jd
index 41dfd63..5419ad6 100644
--- a/docs/html/guide/appendix/media-formats.jd
+++ b/docs/html/guide/appendix/media-formats.jd
@@ -20,7 +20,7 @@ page.title=Android Supported Media Formats
</tr>
<tr>
-<td rowspan="8">Audio</td>
+<td rowspan="9">Audio</td>
<td>AAC LC/LTP</td>
<td>&nbsp;</td>
<td style="text-align: center;">X</td>
@@ -83,6 +83,14 @@ page.title=Android Supported Media Formats
</tr>
<tr>
+<td>PCM/WAVE</td>
+<td>&nbsp;</td>
+<td style="text-align: center;">X</td>
+<td>8- and 16-bit linear PCM (rates up to limit of hardware)</td>
+<td>WAVE (.wav)</td>
+</tr>
+
+<tr>
<td rowspan="4">Image</td>
<td>JPEG</td>
<td style="text-align: center;">X</td>
diff --git a/docs/html/guide/basics/anatomy.jd b/docs/html/guide/basics/anatomy.jd
deleted file mode 100755
index f4b2ad0..0000000
--- a/docs/html/guide/basics/anatomy.jd
+++ /dev/null
@@ -1,134 +0,0 @@
-page.title=Anatomy of an Android Application
-@jd:body
-<h1>Anatomy of an Android Application</h1>
-
-<p>
-There are four building blocks to an Android application:
-</p>
-
-<ul>
- <li>Activity</li>
- <li>Broadcast Receiver</li>
- <li>Service</li>
- <li>Content Provider</li>
-</ul>
-
-<p>
-Not every application needs to have all four, but your application will be written with some
-combination of these.
-</p>
-
-<p>
-Once you have decided what components you need for your application, you should list them in a file
-called AndroidManifest.xml. This is an XML file where you declare the components of your application
-and what their capabilities and requirements are. See the
-<a href="{@docRoot}devel/bblocks-manifest.html">Android manifest file documentation</a>
-for complete details.
-</p>
-
-<h2>Activity</h2>
-<p>
-Activities are the most common of the four Android building blocks. An activity is usually a single
-screen in your application. Each activity is implemented as a single class that extends the
-{@link android.app.Activity Activity} base class. Your class will display a user interface composed
-of {@link android.view.View Views} and respond to events. Most applications consist of multiple
-screens. For example, a text messaging application might have one screen that shows a list of
-contacts to send messages to, a second screen to write the message to the chosen contact, and other
-screens to review old messages or change settings. Each of these screens would be implemented as an
-activity. Moving to another screen is accomplished by a starting a new activity. In some cases an
-activity may return a value to the previous activity -- for example an activity that lets the user
-pick a photo would return the chosen photo to the caller.
-</p>
-
-<p>
-When a new screen opens, the previous screen is paused and put onto a history stack. The user can
-navigate backward through previously opened screens in the history. Screens can also choose to be
-removed from the history stack when it would be inappropriate for them to remain. Android retains
-history stacks for each application launched from the home screen.
-</p>
-
-<h3>Intent and Intent Filters</h3>
-
-<p>
-Android uses a special class called an {@link android.content.Intent Intent} to move from screen to
-screen. An intent describes what an application wants done. The two most important parts of the
-intent data structure are the action and the data to act upon. Typical values for action are MAIN
-(the front door of the application), VIEW, PICK, EDIT, etc. The data is expressed as a URI.
-For example, to view contact information for a person, you would create an intent with the VIEW
-action and the data set to a URI representing that person.
-</p>
-
-<p>
-There is a related class called an {@link android.content.IntentFilter IntentFilter}. While an
-intent is effectively a request to do something, an intent filter is a description of what intents
- an activity (or broadcast receiver, see below) is capable of handling. An activity that is able to
- display contact information for a person would publish an IntentFilter that said that it knows
- how to handle the action VIEW when applied to data representing a person.
- Activities publish their IntentFilters in the AndroidManifest.xml file.
-</p>
-
-<p>
-Navigating from screen to screen is accomplished by resolving intents. To navigate forward, an
-activity calls <code>{@link android.app.Activity#startActivity startActivity(myIntent)}</code>.
-The system then looks at the intent filters for all installed applications and picks the activity
-whose intent filters best matches <code>myIntent</code>. The new activity is informed of the intent, which causes
-it to be launched. The process of resolving intents happens at run time when startActivity is
-called, which offers two key benefits:
-</p>
-
-<ul>
- <li>Activities can reuse functionality from other components simply by making a request in the form of an Intent</li>
- <li>Activities can be replaced at any time by a new Activity with an equivalent IntentFilter</li>
-</ul>
-
-
-<h2>Broadcast Receiver</h2>
-
-<p>
-You can use a {@link android.content.BroadcastReceiver BroadcastReceiver} when you want code in your
-application to execute in reaction to an external event, for example, when the phone rings, or when
-the data network is available, or when it's midnight. Broadcast receivers do not display a UI, although
-they may use the {@link android.app.NotificationManager NotificationManager} to alert the user if
-something interesting has happened. Broadcast receivers are registered in AndroidManifest.xml, but you
-can also register them from code using
-<code>{@link android.content.Context#registerReceiver Context.registerReceiver()}</code>.
-Your application does not have to be running for its broadcast receivers to be called; the system will
-start your application, if necessary, when a broadcast receiver is triggered. Applications can also send
-their own intent broadcasts to others with
-<code>{@link android.content.Context#sendBroadcast Context.sendBroadcast()}</code>.
-</p>
-
-<h2>Service</h2>
-
-<p>
-A {@link android.app.Service Service} is code that is long-lived and runs without a UI. A good
-example of this is a media player playing songs from a play list. In a media player application,
-there would probably be one or more activities that allow the user to choose songs and start
-playing them. However, the music playback itself should not be handled by an activity because the
-user will expect the music to keep playing even after navigating to a new screen. In this case, the
-media player activity could start a service using
-<code>{@link android.content.Context#startService Context.startService()}</code>
-to run in the background to keep the music going. The system will then keep the music playback
-service running until it has finished. (You can learn more about the priority given to services in
-the system by reading
-<a href="{@docRoot}intro/lifecycle.html">Life Cycle of an Android Application</a>.)
-Note that you can connect to a
-service (and start it if it's not already running) with the
-<code>{@link android.content.Context#bindService Context.bindService() }</code> method.
-When connected to a service, you can communicate with it through an interface exposed by the
-service. For the music service, this might allow you to pause, rewind, etc.
-</p>
-
-<h2>Content Provider</h2>
-<p>
-Applications can store their data in files, an SQLite database, or any other mechanism that makes
-sense. A content provider, however, is useful if you want your application's data to be shared with
-other applications. A content provider is a class that implements a standard set of methods to let
-other applications store and retrieve the type of data that is handled by that content provider.
-</p>
-
-<p>
-To get more details on content providers, see
-<a href="{@docRoot}devel/data/contentproviders.html">Accessing Content Providers</a>.
-</p>
-
diff --git a/docs/html/guide/basics/android-sdk.jd b/docs/html/guide/basics/android-sdk.jd
deleted file mode 100644
index d1f3437..0000000
--- a/docs/html/guide/basics/android-sdk.jd
+++ /dev/null
@@ -1,11 +0,0 @@
-page.title=The Android SDK
-@jd:body
-
-<p>FIXME</p>
-
-<p>The downloadable Android SDK includes the Android API libraries, sample code, documentation,
-and a collection of Android development tools, like the emulator and debugger.</p>
-
-<p>The SDK supports developing on Linux, Mac OS X, and Windows (XP and Vista).</p>
-
-<p>The Java Development Kit is required.</p> \ No newline at end of file
diff --git a/docs/html/guide/basics/app-framework.jd b/docs/html/guide/basics/app-framework.jd
deleted file mode 100644
index 8513884..0000000
--- a/docs/html/guide/basics/app-framework.jd
+++ /dev/null
@@ -1,4 +0,0 @@
-page.title=The Application Framework
-@jd:body
-
-TODO \ No newline at end of file
diff --git a/docs/html/guide/basics/what-is-android.jd b/docs/html/guide/basics/what-is-android.jd
index 9e2801a..b75321b 100644
--- a/docs/html/guide/basics/what-is-android.jd
+++ b/docs/html/guide/basics/what-is-android.jd
@@ -2,7 +2,7 @@ page.title=What is Android?
@jd:body
<p>Android is a software stack for mobile devices that includes an operating
-system, middleware and key applications. This beta version of the <a
+system, middleware and key applications. The <a
href="http://code.google.com/android/download.html">Android SDK</a>
provides the tools and APIs necessary to begin developing applications on the
Android platform using the Java programming language.</p>
diff --git a/docs/html/guide/developing/debug-tasks.jd b/docs/html/guide/developing/debug-tasks.jd
index a604df2..6b7c27a 100644
--- a/docs/html/guide/developing/debug-tasks.jd
+++ b/docs/html/guide/developing/debug-tasks.jd
@@ -53,7 +53,7 @@ D/ActivityManager( 763): Stopping: HistoryRecord{409dbb20 com.android.home.AllAp
graphical reader called Traceview. See the linked topic for more information. </li>
</ul>
<ul>
- <li><a href="#developingwitheclipse"><strong>Eclipse plugin</strong></a> - The ADT Plugin
+ <li><a href="{@docRoot}guide/developing/eclipse-adt.html"><strong>Eclipse plugin</strong></a> - The ADT Plugin
for Eclipse integrates a number of these tools (ADB, DDMS, logcat output,
and other functionality). See the linked topic for more information. </li>
<li><strong>Debug and Test Device Settings</strong> - Android exposes several settings
diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd
index b723797..35c0a1a 100644
--- a/docs/html/guide/developing/device.jd
+++ b/docs/html/guide/developing/device.jd
@@ -7,8 +7,8 @@ page.title=Developing on a Device
<ol>
<li><a href="#devices">Available Devices</a>
<ol>
- <li><a href="g1">T-Mobile G1</a></li>
- <li><a href="dev-phone-1">Android Dev Phone 1</a></li>
+ <li><a href="#g1">T-Mobile G1</a></li>
+ <li><a href="#dev-phone-1">Android Dev Phone 1</a></li>
</ol>
</li>
<li><a href="#setting-up">Setting up a Device for Development</a></li>
@@ -41,8 +41,9 @@ href="http://www.t-mobileg1.com">T-Mobile G1 site</a>. </p>
<h3 id="dev-phone-1">Android Dev Phone 1</h3>
-<div class="sidebox">
-<p>Selected specs for Android Dev Phone 1: </p>
+<div class="sidebox-wrapper">
+<div class="sidebox-inner">
+<p>Selected specs for Android Dev Phone 1:</p>
<ul>
<li>Touch screen</li>
<li>Trackball</li>
@@ -58,7 +59,7 @@ href="http://www.t-mobileg1.com">T-Mobile G1 site</a>. </p>
<li>Includes 1GB MicroSD card (can be replaced with up to 16GB card)</li>
</ul>
</div>
-
+</div>
<p>The Android Dev Phone 1 is a SIM-unlocked and hardware-unlocked device that
is designed for advanced developers. The device ships with a system image that
is fully compatible with Android 1.0, so you can rely on it when developing your
@@ -71,19 +72,19 @@ who live outside of T-Mobile geographies. </p>
<p>To purchase an Android Dev Phone 1 device, you must first register as an
Android developer on the Android Market site, if you haven't done so already.
Once you've logged into your developer account on Android Market, you can
-purchase the device by clicking the "Purchase" link. To accommodate demand,
+purchase the device by following the link to "Development phones." To accommodate demand,
there is a limit of 1 device per developer account, for now.</p>
<p>The device currently costs $399 (USD) (including free shipping in the US),
-and will be available for purchase in 18 international markets, including the
+and is available for purchase in 18 international markets, including the
US, UK, Germany, Japan, India, Canada, France, Taiwan, Spain, Australia,
Singapore, Switzerland, Netherlands, Austria, Sweden, Finland, Poland, and
Hungary. We will continue to expand this program into new geographies over
time. Check this page for updated information.</p>
<p>Note that Android Dev Phone 1 devices are <em>not</em> intended for
-non-developer end users. Since the devices can be configured with system
-software not provided by or supported by Google or any other company, end users
+non-developer end-users. Because the device can be configured with system
+software not provided by or supported by Google or any other company, end-users
operate these devices at their own risk.</p>
<p>For full device specs and more information about obtaining an Android Dev
@@ -109,17 +110,28 @@ would on the emulator. There are just a few things to do before you can start.</
</li>
<li>Setup your system to detect your device.
<ul>
- <li>If you're developing on Windows (32-bit only), you need to install the USB driver for adb:
+ <li>If you're developing on 32-bit Windows, you need to install the 32-bit USB driver for adb.
+ The USB driver is included in the SDK package. To install it, follow these steps:</p>
<ol>
- <li>Download the driver ZIP file
- (<a href="http://dl.google.com/android/android_usb_windows.zip">android_usb_windows.zip</a>)
- and unzip it.</li>
- <li>Connect your Android device via USB. When the <em>Found New Hardware Wizard</em> appears, you'll be asked if you'd like Windows Update to search for software, select <em>No, not this time</em> and click <b>Next</b>.</li>
+ <li>Connect your Android device via USB. When the <em>Found New Hardware Wizard</em> appears,
+ you'll be asked if you'd like Windows Update to search for software. Select <em>No, not this
+ time</em> and click <b>Next</b>.</li>
<li>Select <em>Install from a list or specified location</em> and click <b>Next</b>.</li>
- <li>Select <em>Search for the best driver in these locations</em>. Browse and select the unzipped file.</li>
- <li>Click <b>Finish</b>. You're all set.</li>
+ <li>Select <em>Search for the best driver in these locations</em>. Browse to the <code>usb_driver/x86</code> in the SDK package (<code>&lt;sdk&gt;\usb_driver\x86</code>).</li>
+ <li>Click <b>Finish</b>. The system should install the driver files as necessary. Your machine may require a reboot.</li>
+ </ol>
+ </li>
+ <li>If you're developing on 64-bit Windows Vista, you need to install the 64-bit USB driver for adb.
+ The USB driver is included in the SDK package. To install it, follow these steps:</p>
+ <ol>
+ <li>Connect your Android device via USB. When the <em>Found New Hardware Wizard</em> appears,
+ you'll be asked if you'd like Windows Update to search for software. Select <em>No, not this
+ time</em> and click <b>Next</b>.</li>
+ <li>Select <em>Install from a list or specified location</em> and click <b>Next</b>.</li>
+ <li>Select <em>Search for the best driver in these locations</em>. Browse to the <code>usb_driver/amd64</code> in the SDK package (<code>&lt;sdk&gt;\usb_driver\amd64</code>).</li>
+ <li>Click <b>Finish</b>. The system should install the driver files as necessary. Your machine may require a reboot.</li>
</ol>
</li>
<li>If you're developing on Mac OS X, it just works. Skip this step.</li>
diff --git a/docs/html/guide/developing/eclipse-adt.jd b/docs/html/guide/developing/eclipse-adt.jd
index 7177395..8c482ee 100644
--- a/docs/html/guide/developing/eclipse-adt.jd
+++ b/docs/html/guide/developing/eclipse-adt.jd
@@ -1,17 +1,28 @@
page.title=In Eclipse, with ADT
@jd:body
-<p>To begin developing Android applications in the Eclipse IDE with ADT, you first create an Android
+<p>The Android Development Tools (ADT) plugin for Eclipse adds powerful extensions to the Eclipse integrated development environment. It allows you to create and debug Android applications easier and faster. If you use Eclipse, the ADT plugin gives you an incredible boost in developing Android applications:</p>
+
+<ul>
+ <li>It gives you access to other Android development tools from inside the Eclipse IDE. For example, ADT lets you access the many capabilities of the DDMS tool: take screenshots, manage port-forwarding, set breakpoints, and view thread and process informationd irectly from Eclipse.</li>
+ <li>It provides a New Project Wizard, which helps you quickly create and set up all of the basic files you'll need for a new Android application.</li>
+ <li>It automates and simplifies the process of building your Android application.</li>
+ <li>It provides an Android code editor that helps you write valid XML for your Android manifest and resource files.</li>
+</ul>
+
+<p>To begin developing Android applications in the Eclipse IDE with ADT, you first need to download the Eclipse IDE and then download and install the ADT plugin. To do so, follow the steps given in <a href="{@docRoot}sdk/1.1_r1/installing.html#installingplugin">Installing the ADT Plugin</a>, in the installation documentation included with your SDK package. </p>
+
+<p>Once you've installed the ADT plugin, you begin by creating an Android
project and then set up a launch configuration. After that, you can write, run, and debug
your application. </p>
<p>The sections below provide instructions assuming that you have installed the ADT plugin
in your Eclipse environment. If you haven't installed the ADT plugin, you should do that
-before using the instructions below. For complete information, see the installation documentation included in your SDK package. </p>
+before using the instructions below. </p>
<a name="creatingaproject" id="creatingaproject"></a>
-<h3>Creating an Android Project</h3>
+<h2>Creating an Android Project</h2>
<p>The ADT plugin provides a New Project Wizard that you can use to quickly create an
Eclipse project for new or existing code. To create the project, follow these steps:</p>
@@ -49,7 +60,7 @@ Eclipse project for new or existing code. To create the project, follow these st
<a name="launchconfig" id="launchconfig"></a>
-<h3>Creating a Launch Configuration </h3>
+<h2>Creating a Launch Configuration </h2>
<p>Before you can run and debug your application in Eclipse, you must create a launch configuration for it. A launch configuration specifies the project to launch, the Activity to start, the emulator options to use, and so on. </p>
@@ -78,9 +89,45 @@ Eclipse project for new or existing code. To create the project, follow these st
</ol>
+
+<h2 id="sign_in_adt">Setting Up Application Signing</h2>
+
+<p>As you begin developing Android applications, you should understand that all
+Android applications must be digitally signed before the system will install
+them on the emulator or an actual device. </p>
+
+<p>The ADT plugin helps you get started quickly by signing your .apk files with
+a debug key, prior to installing them on the emulator. This means that you can
+compile your application and install it on the emulator without having to
+generate your own private key. However, please note that if you intend to
+publish your application, you <em>must</em> sign the application with your own
+private key, rather than the debug key generated by the SDK tools. </p>
+
+<p>To sign your applications, the ADT plugin requires the Keytool utility
+included in the JDK. To set up your development environment for
+signing, you need to make sure that Keytool is available on your
+machine that the ADT plugin knows how to find it. </p>
+
+<p>In most cases, you can tell the SDK build tools how to find Keytool by making
+sure that your JAVA_HOME environment variable is set and that it references a
+suitable JDK. Alternatively, you can add the JDK version of Keytool to your
+PATH variable.</p>
+
+<p>If you are developing on a version of Linux that originally came with Gnu
+Compiler for Java, make sure that the system is using the JDK version of
+Keytool, rather than the gcj version. If keytool is already in your PATH, it
+might be pointing to a symlink at /usr/bin/keytool. In this case, check the
+symlink target to make sure that it points to the keytool in the JDK.</p>
+
+<p>In all cases, please read and understand <a
+href="{@docRoot}guide/publishing/app-signing.html">Signing Your
+Applications</a>, which provides an overview of application signing on Android
+and what it means to you as an Android application developer. </p>
+
+
<a name="installingrunningdebugging" id="installingrunningdebugging"></a>
-<h3>Running and Debugging an Application</h3>
+<h2>Running and Debugging an Application</h2>
<p>Once you've set up the project and launch configuration for your application, you can run or debug it as described below.</p>
@@ -98,7 +145,8 @@ From the Eclipse main menu, select <strong>Run</strong> &gt; <strong>Run</strong
</ul>
- <h2 id="tips">Eclipse Tips </h2>
+
+<h2 id="tips">Eclipse Tips </h2>
<h3>Executing arbitrary Java expressions in Eclipse<a name="arbitraryexpressions" id="arbitraryexpressions"></a></h3>
<p>You can execute arbitrary code when paused at a breakpoint in Eclipse. For example,
when in a function with a String argument called &quot;zip&quot;, you can get
diff --git a/docs/html/guide/developing/instrumentation/index.jd b/docs/html/guide/developing/instrumentation/index.jd
deleted file mode 100644
index 7ebd72e..0000000
--- a/docs/html/guide/developing/instrumentation/index.jd
+++ /dev/null
@@ -1,54 +0,0 @@
-page.title=Instrumentation
-@jd:body
-
-<dl>
- <dt><a href="inst-framework.html">Instrumentation Framework</a></dt>
- <dt><a href="inst-testing.html">Instrumentation Testing</a></dt>
-</dl>
-
-<!--
-<p>Android provides an instrumentation framework that lets you create a bundle of instrumentation tests and attach them to your application. When you run the instrumentation from the command line, the Android system d
-
- through an <code>&lt;instrumentation&gt;</code> element in its manifest file. You write your instrumentation tests in a subclass of {@link android.app.Instrumentation}, from which you have access to a variety of methods for managing the state of the application, from within the application's process. For example, you can write instrumentation to
-<ul>
-<li>Instantiate the process's Application object
-<li>Instantiate an Activity and change it's lifecycle state
-<li>Send keypad events to the currently focused window
-<li>Execute a menu item
-<li>Take a performance snapshot, and
-<li>Attach an
-
-When running with instrumentation turned on, the system instantiates class will be instantiated for you before any of the application code, allowing you to monitor all of the interaction the system has with the application. An Instrumentation implementation is described to the system through an AndroidManifest.xml's &lt;instrumentation> tag.
-
-
-<ul>
- <li>
- <a href="hierarchy.html">IntroducHierarchy of Screen Elements</a>
- </li>
- <li>
- <a href="layout.html">Common Layout Objects</a>
- </li>
- <li>
- <a href="ui-xml.html">Declaring a UI in XML</a>
- </li>
- <li>
- <a href="binding.html">Binding to Data with AdapterView</a>
- </li>
- <li>
- <a href="ui-events.html">Handling UI Events</a>
- </li>
- <li>
- <a href="themes.html">Applying Styles and Themes to Your Application</a>
- </li>
- <li>
- <a href="custom-views.html">Building Custom Views</a>
- </li>
- <li>
- <a href="glossary.html">UI Elements and Concepts Glossary</a>
- </li>
- <li>
- <a href="{@docRoot}guide/tutorials/views/index.html">Hello Views</a>
- </li>
-
-</ul>
---> \ No newline at end of file
diff --git a/docs/html/guide/developing/instrumentation/inst-framework.jd b/docs/html/guide/developing/instrumentation/inst-framework.jd
deleted file mode 100644
index 17eea61..0000000
--- a/docs/html/guide/developing/instrumentation/inst-framework.jd
+++ /dev/null
@@ -1,139 +0,0 @@
-page.title=Instrumentation Framework
-@jd:body
-
-<p>This document describes how to use the Android Instrumentation Framework to write test cases. You should have a working knowledge of the following:</p>
-<ul>
- <li> Android Application Framework </li>
- <li> Using <code>adb</code>, <code>am</code> and various logging functionality </li>
- <li> A brief understanding of the application of interest, that is, he names of the classes which handle the intents etc. </li>
- <li> Junit testing. </li>
-</ul>
-<p> Each Android application runs in its own process. Instrumentation kills the application process and restarts the process with Instrumentation. Instrumentation gives a handle to the application context used to poke around the application to validate test assertions, allowing you to write test cases to test applications at a much lower level than UI screen shot tests. Note that Instrumentation cannot catch UI bugs. </p>
-
-<p>This document covers these topics:</p>
-
-<ul>
-<li><a href="#androidInstrumentationFrameworkamCommand">Understanding the am Command</a></li>
-<li><a href="#androidInstrumentationFrameworkWritingRunning">Writing and Running Test Cases</a></li>
-<li><a href="#androidInstrumentationFrameworkTestCase">Exploring a Test Case</a></li>
-<li><a href="#androidInstrumentationFrameworkTroubleshooting">Troubleshooting</a></li>
-</ul>
-
-<a name="androidInstrumentationFrameworkamCommand"></a><h2>Understanding the am Command</h2>
-
-<p><code>am</code> is used to start and instrument activities using the adb shell command, as shown in the snippet below:</p>
-<pre class="prettify">
-&gt; adb shell am
-usage: am [start|instrument]
- am start [-a &lt;ACTION&gt;] [-d &lt;DATA_URI&gt;] [-t &lt;MIME_TYPE&gt;]
- [-c &lt;CATEGORY&gt; [-c &lt;CATEGORY&gt;] ...]
- [-e &lt;EXTRA_KEY&gt; &lt;EXTRA_VALUE&gt; [-e &lt;EXTRA_KEY&gt; &lt;EXTRA_VALUE&gt; ...]
- [-n &lt;COMPONENT&gt;] [-D] [&lt;URI&gt;]
- am instrument [-e &lt;ARG_NAME&gt; &lt;ARG_VALUE&gt;] [-p &lt;PROF_FILE&gt;]
- [-w] &lt;COMPONENT&gt;
-For example, to start the Contacts application you can use
-&gt; adb shell am start -n com.google.android.contacts/.ContactsActivity
-</pre>
-
-
-<a name="androidInstrumentationFrameworkWritingRunning"></a><h2>Writing and Running Test Cases</h2>
-
-<p>Each instrumentation test case is similar to an Android application with the distinction that it starts another application. For example, have a look in the <code>tests/Contacts</code> directory. </p>
-<ul>
- <li> There should be a Makefile and an Android Manifest file. </li>
- <li> Tests are located in <code>tests/Contacts/src/com/google/android/contactstests</code>. </li>
- <li> The Instrumentation Test Runner is located at <code>tests/Contacts/src/com/google/android/contactstests/functional/ContactsInstrumentationTestRunner.java</code>.</li>
-</ul>
-<p>Suppose you have a makefile with <code>Contactstests</code> as the target. </p>
-<ul>
- <li> <code>make Contactstests</code>: Compiles the test cases. </li>
- <li> <code>adb install Contactstests.apk</code>: Installs the apk on the device. </li>
- <li> Use the adb shell <code>am</code> command to run them. </li>
-</ul>
-<p> For options and other details, please see <a href="inst-testing.html">Instrumentation Testing</a>.</p>
-
-
-<a name="androidInstrumentationFrameworkTestCase"></a><h2>Exploring a Test Case</h2>
-
-<p> The test case described in this section adds and tests a new Contact. Note that you can send intents, register broadcast receivers, etc. </p>
-<p><code>Instrumentation.java</code> has helper functions that send key events and string, for example: </p>
-<ul>
- <li><code>getInstrumentation()</code>: Returns the handle to the instrumentation </li>
- <li><code>sendCharacterSync</code>: Sends a character. </li>
- <li><code>sendStringSync</code>: Sends a string to an input box. </li>
- <li><code>sendKeyDownUpSync</code>: Sends a specific keyevent. </li>
- <li><code>sendTrackballEventSync</code>: Send a trackball event.</li>
-</ul>
-<p> You can find the test case below at <code>device/tests/Contacts.</code></p>
-<pre class="prettify">
-private void addNewContact(String name, int star, int phoneType, String number, String label,
- String email, int emailType){
- ContentValues values = new ContentValues();
- Uri phoneUri = null;
- Uri emailUri = null;
-
- values.put(Contacts.People.NAME, name);
- values.put(Contacts.People.STARRED, star);
-
- //Add Phone Numbers
- Uri uri = mActivity.getContentResolver().insert(Contacts.People.CONTENT_URI, values);
- phoneUri = Uri.withAppendedPath(uri, Contacts.People.Phones.CONTENT_DIRECTORY);
-
- values.clear();
- values.put(Contacts.Phones.TYPE, phoneType);
- values.put(Contacts.Phones.NUMBER, number);
- values.put(Contacts.Phones.LABEL, label);
- mActivity.getContentResolver().insert(phoneUri, values);
-
- //Add Email
- emailUri = Uri.withAppendedPath(uri, ContactMethods.CONTENT_DIRECTORY);
-
- values.clear();
- values.put(ContactMethods.KIND, Contacts.KIND_EMAIL);
- values.put(ContactMethods.DATA, email);
- values.put(ContactMethods.LABEL, "");
- values.put(ContactMethods.TYPE, emailType);
- mActivity.getContentResolver().insert(emailUri, values);
-}
-
-
- public void testAddSaveSingleContact(){
- int previousCount = mActivity.getListView().getCount();
- String message;
-
- addNewContact(INPUT_NAME_1 + "1", "5435754532", "1" + INPUT_EMAIL_1, CONFIRM_OPTION);
-
- message = "Added 1 to initial length=" + previousCount + ", but resulted with a count=" +
- mActivity.getListView().getCount();
- assertEquals(message, ++previousCount, mActivity.getListView().getCount());
-
- // Check Content; Name; Num; Starred
- assertEquals(INPUT_NAME_1 + "1", getTextFromView(0, android.R.id.text1));
- assertEquals("5435754532", getTextFromView(0, android.R.id.text2));
-
- //Check email is saved
- //cursor = returnEmailCursorAtId("1");
- Uri uri = Uri.parse("content://contacts/people/1");
- uri = Uri.withAppendedPath(uri, ContactMethods.CONTENT_DIRECTORY);
- Cursor cursor = mActivity.getContentResolver().query(uri, CONTACTS_COLUMNS, null, null, null);
- assertTrue("returnEmailCursorAtId: Moving cursor to first row has failed", cursor.first());
-
- int dataIndex = cursor.getColumnIndexOrThrow("data");
- assertEquals("1" + INPUT_EMAIL_1, cursor.getString(dataIndex));
- cursor.deactivate();
-}
- </pre>
-
-
-<a name="androidInstrumentationFrameworkTroubleshooting"></a><h2>Troubleshooting</h2>
-
-<p>If you run your test cases and nothing appears to happen, have a look at <code>adb logcat</code>. The following is a common problem:</p>
-<pre class="prettify">
-I/dalvikvm( 688): threadid=11: attached from native, name=Binder Thread #1
-I/dalvikvm( 688): threadid=13: attached from native, name=Binder Thread #2
-W/ActivityManager( 469): Unable to find instrumentation info for: ComponentInfo{com.google.android.browser_instrumentation/com.google.android.browser_instrumentation.BrowserWebkitLayoutInstrumentation}
-D/AndroidRuntime( 688): Shutting down VM
-E/AndroidRuntime( 688): ERROR: thread attach failed
-</pre>
-<p>It's possible that the instrumentation apk isn't installed on your device or that the package name is incorrect in the Manifest file. </p>
-
diff --git a/docs/html/guide/developing/instrumentation/inst-testing.jd b/docs/html/guide/developing/instrumentation/inst-testing.jd
deleted file mode 100644
index 6f69344..0000000
--- a/docs/html/guide/developing/instrumentation/inst-testing.jd
+++ /dev/null
@@ -1,207 +0,0 @@
-
-page.title=Instrumentation Testing
-@jd:body
-
-<p>Sometimes you may want to manually interact with your applications to verify that a particular feature or behavior is working properly; why not automate this verification with a JUnit TestCase that can instrument applications?</p>
-<p>Instrumentation testing allows you to verify a particular feature or behavior with an automated JUnit TestCase. You can launch activities and providers within an application, send key events, and make assertions about various UI elements.</p>
-
-This document provides an overview of how to use instrumentation on Android and covers these topics:
-
-<ul>
-<li><a href="#androidInstrumentationTestingClasses">Classes</a></li>
-<li><a href="#androidInstrumentationTestingRunning">Running Tests</a></li>
-<li><a href="#androidInstrumentationTestingCreating">Creating Tests</a></li>
-<li><a href="#androidInstrumentationAliases">Aliases for Running Framework Instrumentation Tests</a></li>
-</ul>
-
-
-
-
-<a name="androidInstrumentationTestingClasses"></a><h2>Classes</h2>
-
-<p> The following classes help glue together <code>Instrumentation</code> with JUnit testing. </p>
-<table>
- <tr>
- <th scope="col">Class</th>
- <th scope="col">Description</th></tr>
- <tr>
- <td valign="top"><code>InstrumentationTestCase</code></td>
- <td valign="top">
- <p>This extends the standard JUnit <code>TestCase</code> and offers access to an <code>Instrumentation</code> class. Write tests inside your instrumentation class any way you see fit. For example, your test might launch activities and send key events. For this to work properly, the instrumentation needs to be injected into the test case.</p>
- </td>
- </tr>
- <tr>
- <td valign="top"><code>InstrumentationTestRunner</code></td>
- <td valign="top">The instrumentation test runner is an instrumentation that runs instrumentation test cases and injects itself into each test case. Instrumentation test cases need to be grouped together with an instrumentation test runner with the appropriate target package.</td>
- </tr>
- <tr>
- <td valign="top"><code>InstrumentationTestSuite</code></td>
- <td valign="top">The instrumentation test suite is a simple extension of the standard JUnit <code>TestSuite</code> that keeps a member <code>Instrumentation</code> variable on hand to inject into each <code>TestCase</code> before running them. It is used by <code>InstrumentationTestRunner</code>.</td>
- </tr>
-</table>
-<p> Three additional base classes extend <code>InstrumentationTestCase</code> to allow you to test <code>Activity</code> and <code>Provider</code> classes:</p>
-<table>
- <tr>
- <th scope="col">Class</th>
- <th scope="col">Description</th>
- </tr>
- <tr>
- <td valign="top"><code>ActivityTestCase</code></td>
- <td valign="top"><p>This class can be used to write tests for a specific activity. An activity is launched in its <code>setUp()</code> method and finished with <code>tearDown</code>. If you write a test case that extends <code>ActivityTestCase</code>, you can write tests that access the activity using <code>getActivity()</code> and assume it has been set up properly.</p></td>
- </tr>
- <tr>
- <td valign="top"><code>SingleLaunchActivityTestCase</code></td>
- <td valign="top">This class is similar to <code>ActivityTestCase</code> except that the activity is launched once per class instead of every time the test case calls setup. </td>
- </tr>
- <tr>
- <td valign="top"><code>ProviderTestCase</code></td>
- <td valign="top">This class is similar to <code>ActivityTestCase</code> except that it will setup, tear down, and provide access to the <code>Provider</code> of your choice.</td>
- </tr>
-</table>
-
-
-<a name="androidInstrumentationTestingRunning"></a><h2>Running Tests</h2>
-
-<p> To run your tests, use the <code>am instrument</code> command with your <code>InstrumentationTestRunner</code> as its argument. Results are printed as a result of the instrumentation. For example, the following snippet displays the output after running the framework tests with one test failing (note the unusual syntax caused by how instrumentations are run via <code>am</code>):</p>
-<pre class="prettify">
-$ adb shell am instrument -w com.google.android.frameworktest/.tests.FrameworkInstrumentationTestRunner
-INSTRUMENTATION_RESULT: test results:=.......F.......
-Time: 6.837
-There was 1 failure:
-1) testSetUpConditions(com.google.android.frameworktest.tests.focus.RequestFocusTest)junit.framework.AssertionFailedError: requestFocus() should work from onCreate.
- at com.google.android.frameworktest.tests.focus.RequestFocusTest.testSetUpConditions(RequestFocusTest.java:66)
- at java.lang.reflect.Method.invokeNative(Native Method)
- at android.test.InstrumentationTestSuite.runTest(InstrumentationTestSuite.java:73)
- at android.test.InstrumentationTestSuite.runTest(InstrumentationTestSuite.java:73)
- at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:151)
- at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1088)
-
-FAILURES!!!
-Tests run: 14, Failures: 1, Errors: 0
-
-&lt;RETURN&gt; to continue
-
-INSTRUMENTATION_CODE: -1
-$
-</pre>
-
-
-<a name="androidInstrumentationTestingRunningAll"></a><h3>All Tests</h3>
-
-<pre class="prettify">
-$ adb shell am instrument -w MyInstrumentationTestRunner
-</pre>
-
-
-<a name="androidInstrumentationTestingRunningSingleTestCase"></a><h3>A Single Test Case</h3>
-
-<pre class="prettify">
-$ adb shell am instrument \
- -e class MyInstrumentationTestCase \
- -w MyInstrumentationTestRunner
-</pre>
-
-
-<a name="androidInstrumentationTestingRunningSingleTest"></a><h3>A Single Test</h3>
-
-<pre class="prettify">
-$ adb shell am instrument \
- -e class MyInstrumentationTestCase#myTestMethod \
- -w MyInstrumentationTestRunner
-</pre>
-
-
-<a name="androidInstrumentationTestingCreating"></a><h2>Creating Tests</h2>
-
-
-
-<a name="androidInstrumentationTestingCreatingTestRunner"></a>
-
-<h3>New Instrumentation TestRunner</h3>
-
-<pre>
-public class FrameworkInstrumentationTestRunner extends InstrumentationTestRunner {
-
- &#64;Override
- public TestSuite getAllTests() {
- InstrumentationTestSuite suite = new InstrumentationTestSuite(this);
-
- suite.addTestSuite(FocusAfterRemovalTest.class);
- suite.addTestSuite(RequestFocusTest.class);
- suite.addTestSuite(RequestRectangleVisibleTest.class);
- return suite;
- }
-
- &#64;Override
- public ClassLoader getLoader() {
- return FrameworkInstrumentationTestRunner.class.getClassLoader();
- }
-}
-</pre>
-
-<p> Next, in an appropriate <code>AndroidManifest.xml</code>, define the instrumentation for the derived class with the appropriate <code>android:targetPackage</code> set. For example, the snippet below defines the instrumentation runner for the framework tests.</p>
-
-<pre>
-&lt;uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /&gt;
-
-&lt;instrumentation android:name="android.tests.FrameworkInstrumentationTestRunner"
- android:targetPackage="com.google.android.frameworktest"
- android:label="framework instrumentation test runner" /&gt;
-</pre>
-
-
-<a name="androidInstrumentationTestingCreatingTestCase"></a>
-
-<h3>New InstrumentationTestCase</h3>
-
-<p> To create a new test case, write a class that extends <code>InstrumentationTestCase</code> in the same application archive as your test runner. The following snippet illustrates an example <code>ActivityTestCase</code> that tests an activity named <code>MyActivity</code>.</p>
-<pre>
-public class ButtonPressTest extends ActivityTestCase&lt;MyActivity&gt; {
-
- Button mLeftButton;
-
- public ButtonPressTest() {
- super("com.example", MyActivity.class);
- }
-
- &#64;Override
- public void setUp() throws Exception {
- super.setUp();
- mLeftButton = (Button) getActivity().findViewById(R.id.leftButton);
- }
-
- public void testFocusMovesToRight() throws Exception {
- assertTrue(mLeftButton.hasFocus());
- getInstrumentation().sendCharacterSync(KeyEvent.KEYCODE_DPAD_RIGHT);
-
- Button rightButton = (Button) getActivity().findViewById(R.id.rightButton);
- assertTrue(rightButton.hasFocus());
- }
-
- // could have several more tests...
-}
-</pre>
-
-
-<a name="androidInstrumentationAliases"></a><h2>Aliases for Running Framework Instrumentation Tests</h2>
-
-<pre class="prettify">
-# compiles and installs FrameworkTests
-alias deploytests="(cd tests/FrameworkTests/ && mm) && adb install out/target/product/dream/system/app/FrameworkTest.apk"
-
-# runs all of FrameworkTests unit tests
-alias runtests="adb shell am instrument -w com.google.android.frameworktest/.tests.FrameworkInstrumentationTestRunner"
-
-# runtest TEST: runs a single unit test, for instance runtest view.VisibilityTest
-# -- for convenience, you don't have to type the com.google.android.frameworktest.tests.
-function runtest {
- adb shell am instrument -e class com.google.android.frameworktest.tests.$1 -w com.google.android.frameworktest/.tests.FrameworkInstrumentationTestRunner
-}
-
-# debugtest TEST: runs a single unit test in debug mode, for instance runtest view.VisibilityTest
-function debugtest {
- adb shell am instrument -e debug true -e class com.google.android.frameworktest.tests.$1 -w com.google.android.frameworktest/.tests.FrameworkInstrumentationTestRunner
-}
-</pre>
-
-
diff --git a/docs/html/guide/developing/other-ide.jd b/docs/html/guide/developing/other-ide.jd
index 78871c5..7bcb509 100644
--- a/docs/html/guide/developing/other-ide.jd
+++ b/docs/html/guide/developing/other-ide.jd
@@ -2,9 +2,9 @@ page.title=In Other IDEs
@jd:body
<p>The recommended way to develop an Android application is to use
- <a href="#developingwitheclipse">Eclipse
- with the ADT plugin</a>. This plugin provides editing, building,
- and debugging functionality integrated right into the IDE. </p>
+ <a href="{@docRoot}guide/developing/eclipse-adt.html">Eclipse with the Android
+ Development Tools (ADT) plugin</a>, provided in the SDK. The ADT plugin
+ provides editing, building,and debugging functionality integrated right into the IDE. </p>
<p>However, if you'd rather develop your application in another IDE, such as IntelliJ,
or use Eclipse without the ADT plugin, you can do that instead. The SDK
@@ -82,6 +82,45 @@ activity_name: ActivityName
latest version of the application for you to deploy.</li>
</ol>
+<h2 id="sign_in_other">Setting Up Application Signing</h2>
+
+<p>As you begin developing Android applications, you should understand that all
+Android applications must be digitally signed before the system will install
+them on the emulator or an actual device. </p>
+
+<p>The Android build tools help you get started quickly by signing your .apk
+files with a debug key, prior to installing them on the emulator. This means
+that you can compile your application and install it on the emulator without
+having to generate your own private key. However, please note that if you intend
+to publish your application, you <em>must</em> sign the application with your
+own private key, rather than the debug key generated by the SDK tools. </p>
+
+<p>To sign your applications, the ADT plugin requires the Keytool utility
+included in the JDK. To set up your development environment for
+signing, all you need to do is make sure that Keytool is available on your
+machine that the build tools know how to find it. </p>
+
+<p>In most cases, you can tell the SDK build tools how to find Keytool by making
+sure that
+your JAVA_HOME environment variable is set and that it references a suitable
+JDK. Alternatively,
+you can add the JDK version of Keytool to your PATH variable.</p>
+
+<p>If you are developing on a version of Linux that originally came with Gnu
+Compiler for Java,
+make sure that the system is using the JDK version of Keytool, rather than the
+gcj version.
+If keytool is already in your PATH, it might be pointing to a symlink at
+/usr/bin/keytool.
+In this case, check the symlink target to make sure that it points to the
+keytool in the JDK.</p>
+
+<p>In all cases, please read and understand <a
+href="{@docRoot}guide/publishing/app-signing.html">Signing Your
+Applications</a>, which provides an overview of application signing on Android
+and what it means to you as an Android application developer. </p>
+
+
<h2>Running an Android Application</h2>
<p>To run a compiled
application, you will upload the .apk file to the <code>/data/app/ </code>directory
@@ -122,7 +161,7 @@ activity_name: ActivityName
can be used without DDMS, such as displaying CPU usage or screen refresh
rate on the emulator.</li>
<li><strong>Configure your IDE to attach to port 8700 for debugging.</strong> We
- include information on <a href="#eclipse">how to set up Eclipse to debug
- your project</a>. </li>
+ include information on <a href="{@docRoot}guide/developing/debug-tasks.html#ide-debug-port">
+ how to set up Eclipse to debug your project</a>. </li>
</ol>
diff --git a/docs/html/guide/developing/tools/adb.jd b/docs/html/guide/developing/tools/adb.jd
index 50fb024..b111047 100644
--- a/docs/html/guide/developing/tools/adb.jd
+++ b/docs/html/guide/developing/tools/adb.jd
@@ -104,7 +104,7 @@ Emulator 2, adb: 5557 ...
<pre>adb [-d|-e|-s &lt;serialNumber&gt;] &lt;command&gt; </pre>
-<p>When you issue a command, the program invokes an adb client. The client is not specifically associated with any emulator instance, so if multiple emulators/devices are running, you need to use the <code>-d</code> option to specify the target instance to which the command should be directed. For more information about using this option, see <a href"#directingcommands">Directing Commands to a Specific Emulator/Device Instance</a>. </p>
+<p>When you issue a command, the program invokes an adb client. The client is not specifically associated with any emulator instance, so if multiple emulators/devices are running, you need to use the <code>-d</code> option to specify the target instance to which the command should be directed. For more information about using this option, see <a href="#directingcommands">Directing Commands to a Specific Emulator/Device Instance</a>. </p>
<a name="devicestatus"></a>
diff --git a/docs/html/guide/developing/tools/adt.jd b/docs/html/guide/developing/tools/adt.jd
index c3bd255..f28b24c 100644
--- a/docs/html/guide/developing/tools/adt.jd
+++ b/docs/html/guide/developing/tools/adt.jd
@@ -90,7 +90,7 @@ If you are having trouble downloading the ADT plugin after following the steps a
If you are still unable to use Eclipse to download the ADT plugin, follow these steps to download and install the plugin from your computer:
</p>
<ol>
-<li><a href="adt_download.html">Download the ADT zip file</a> (do not unpack it).
+<li><a href="{@docRoot}sdk/adt_download.html">Download the ADT zip file</a> (do not unpack it).
<li>Follow steps 1 and 2 in the default install instructions (above).
<li>In Eclipse 3.3, click <strong>New Archive Site...</strong>. <br/>
In Eclipse 3.4, click <strong>Add Site...</strong>, then <strong>Archive...</strong>
diff --git a/docs/html/guide/developing/tools/emulator.jd b/docs/html/guide/developing/tools/emulator.jd
index dd367b7..769491b 100644
--- a/docs/html/guide/developing/tools/emulator.jd
+++ b/docs/html/guide/developing/tools/emulator.jd
@@ -812,7 +812,7 @@ in the default directory, or in a custom location (if you specified a path with
<tr>
<td><code>userdata-qemu.img</code></td>
<td>An image to which the emulator writes runtime user-data for a unique user.</td>
- <td>Override using <code>-data &lt;;filepath&gt;</code>, where <code>&lt;filepath&gt;</code> is the
+ <td>Override using <code>-data &lt;filepath&gt;</code>, where <code>&lt;filepath&gt;</code> is the
path the image, relative to the current working directory. If you supply a filename only,
the emulator looks for the file in the current working directory. If the file at <code>&lt;filepath&gt;</code> does
not exist, the emulator creates an image from the default userdata.img, stores it under the name you
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 3e01172..77d3522 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -3,9 +3,9 @@
<li><h2>Android Basics</h2>
<ul>
<li><a href="<?cs var:toroot ?>guide/basics/what-is-android.html">What Is Android?</a></li>
-<li><a style="color:gray;">The Android SDK</a></li>
-<li><a style="color:gray;">Walkthrough for Developers</a></li>
- <!-- quick overview of what it's like to develop on Android -->
+<!-- <li><a style="color:gray;">The Android SDK</a></li> -->
+<!-- <li><a style="color:gray;">Walkthrough for Developers</a></li> -->
+ <!-- quick overview of what it's like to develop on Android -->
</ul>
</li>
@@ -15,15 +15,16 @@
</ul>
<ul>
<li class="toggle-list">
- <div><a href="<?cs var:toroot ?>guide/topics/views/index.html">Views and Layout</a></div>
+ <div><a href="<?cs var:toroot ?>guide/topics/ui/index.html">User Interface</a></div>
<ul>
- <li><a href="<?cs var:toroot ?>guide/topics/views/layout.html">Common Layout Objects</a></li>
- <li><a href="<?cs var:toroot ?>guide/topics/views/declaring-layout.html">Declaring Layout</a></li>
- <li><a href="<?cs var:toroot ?>guide/topics/views/binding.html">Binding to Data with AdapterView</a></li>
- <li><a href="<?cs var:toroot ?>guide/topics/views/ui-events.html">Handling UI Events</a></li>
- <li><a href="<?cs var:toroot ?>guide/topics/views/themes.html">Applying Styles and Themes</a></li>
- <li><a href="<?cs var:toroot ?>guide/topics/views/custom-components.html">Building Custom Components</a></li>
- <li><a href="<?cs var:toroot ?>guide/topics/views/how-android-draws.html">How Android Draws Views</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/ui/declaring-layout.html">Declaring Layout</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/ui/menus.html">Creating Menus</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/ui/layout-objects.html">Common Layout Objects</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/ui/binding.html">Binding to Data with AdapterView</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/ui/ui-events.html">Handling UI Events</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/ui/themes.html">Applying Styles and Themes</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/ui/custom-components.html">Building Custom Components</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/ui/how-android-draws.html">How Android Draws Views</a></li>
</ul>
</li>
<li class="toggle-list">
@@ -33,14 +34,38 @@
<li><a href="<?cs var:toroot ?>guide/topics/resources/available-resources.html">Available Resource Types</a></li>
</ul>
</li>
- <li><a href="<?cs var:toroot ?>guide/topics/intents/intents-filters.html">Intents and Intent Filtering</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/intents/intents-filters.html">Intents and Intent Filters</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/data/data-storage.html">Data Storage</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/providers/content-providers.html">Content Providers</a></li>
- <li><a style="color:gray;">Notifications</a></li>
+<!-- <li><a style="color:gray;">Notifications</a></li> -->
<li><a href="<?cs var:toroot ?>guide/topics/security/security.html">Security and Permissions</a></li>
<!-- <li><a style="color:gray;">Processes and Threads</a></li> -->
<!-- <li><a style="color:gray;">Interprocess Communication</a></li> -->
- <li><a href="<?cs var:toroot ?>guide/topics/manifest/manifest.html">The Manifest File</a></li>
+ <li class="toggle-list">
+ <div><a href="<?cs var:toroot ?>guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/action-element.html">&lt;action&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/application-element.html">&lt;application&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/category-element.html">&lt;category&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/data-element.html">&lt;data&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/instrumentation-element.html">&lt;instrumentation&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/service-element.html">&lt;service&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk&gt;</a></li>
+ </ul>
+ </li>
</ul>
<ul>
<li class="toggle-list">
@@ -51,22 +76,22 @@
</ul>
</li>
<li><a href="<?cs var:toroot ?>guide/topics/media/index.html">Audio and Video</a></li>
- <li class="toggle-list">
- <div><a href="<?cs var:toroot ?>guide/topics/sensors/index.html">Sensors</a></div>
+<!-- <li class="toggle-list">
+ <div><a style="color:gray;">Sensors</a></div>
<ul>
- <li><a href="<?cs var:toroot ?>guide/topics/sensors/camera.html">Camera</a></li>
- <li><a href="<?cs var:toroot ?>guide/topics/sensors/compass.html">Compass</a></li>
- <li><a href="<?cs var:toroot ?>guide/topics/sensors/accelerometer.html">Accelerometer</a></li>
+ <li><a style="color:gray;">Camera</a></li>
+ <li><a style="color:gray;">Compass</a></li>
+ <li><a style="color:gray;">Accelerometer</a></li>
</ul>
- </li>
+ </li> -->
<li><a href="<?cs var:toroot ?>guide/topics/location/index.html">Location</a></li>
- <li class="toggle-list">
- <div><a href="<?cs var:toroot ?>guide/topics/wireless/index.html">Wireless Controls</a></div>
+<!-- <li class="toggle-list">
+ <div><a style="color:gray;">Wireless Controls</a></div>
<ul>
- <li><a href="<?cs var:toroot ?>guide/topics/wireless/wifi.html">Wi-Fi</a></li>
- <li><a href="<?cs var:toroot ?>guide/topics/wireless/bluetooth.html">Bluetooth</a></li>
+ <li><a style="color:gray;">Wi-Fi</a></li>
+ <li><a style="color:gray;">Bluetooth</a></li>
</ul>
- </li>
+ </li> -->
<!-- <li><a style="color:gray;">Localization</a></li> -->
</ul>
</li>
@@ -86,7 +111,7 @@
<li><a href="<?cs var:toroot ?>guide/developing/tools/aapt.html">aapt</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/adb.html">adb</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/othertools.html#activitycreator">activitycreator</a></li>
- <li><a href="<?cs var:toroot ?>guide/developing/tools/adt.html">ADT Plugin</a></li>
+<!-- <li><a href="<?cs var:toroot ?>guide/developing/tools/adt.html">ADT Plugin</a></li>-->
<li><a href="<?cs var:toroot ?>guide/developing/tools/aidl.html" >aidl</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/ddms.html" >ddms</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/othertools.html#dx">dx</a></li>
@@ -98,8 +123,8 @@
<li><a href="<?cs var:toroot ?>guide/developing/tools/adb.html#sqlite">sqlite3</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/traceview.html" >Traceview</a></li>
</ul></li>
- <li><a href="<?cs var:toroot ?>guide/developing/instrumentation/index.html">Instrumentation</a></li>
- <li><a style="color:gray;">JUnit</a></li>
+<!-- <li><a href="<?cs var:toroot ?>guide/developing/instrumentation/index.html">Instrumentation</a></li>
+ <li><a style="color:gray;">JUnit</a></li> -->
</ul>
</li>
@@ -118,28 +143,34 @@
<li><a href="<?cs var:toroot ?>guide/practices/design/performance.html">Designing for Performance</a></li>
<li><a href="<?cs var:toroot ?>guide/practices/design/responsiveness.html">Designing for Responsiveness</a></li>
<li><a href="<?cs var:toroot ?>guide/practices/design/seamlessness.html">Designing for Seamlessness</a></li>
- <li><a style="color:gray;">User Interface Guidelines</a></li>
+<!-- <li><a style="color:gray;">User Interface Guidelines</a></li> -->
</ul>
</li>
-<!--
-<li><h2>Best Practices (alt)</h2>
- <ul>
- <li><a href="<?cs var:toroot ?>guide/practices/design/index.html">Design Goals</a></li>
- <li><a style="color:gray;">User Interface Guidelines</a></li>
- </ul>
-</li>
--->
-
-<li><h2>Tutorials</h2>
+<li><h2>Tutorials and Sample Code</h2>
<ul>
<li><a href="<?cs var:toroot ?>guide/tutorials/hello-world.html">Hello World</a></li>
<li><a href="<?cs var:toroot ?>guide/tutorials/views/index.html">Hello Views</a></li>
- <li><a href="<?cs var:toroot ?>guide/tutorials/notepad/index.html">Notepad</a></li>
- <li><a href="<?cs var:toroot ?>guide/samples/index.html">Sample Code</a></li>
+ <li><a href="<?cs var:toroot ?>guide/tutorials/notepad/index.html">Notepad Tutorial</a></li>
+ </ul>
+ <ul>
+ <?cs if:android.whichdoc != "online" ?>
+ <li><a href="<?cs var:toroot ?>../samples">Sample Code &raquo;</a></li>
+ <?cs else ?>
+ <li class="toggle-list">
+ <div><a href="<?cs var:toroot ?>guide/samples/index.html">Sample Code</a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/samples/ApiDemos/index.html">API Demos</a></li>
+ <li><a href="<?cs var:toroot ?>guide/samples/LunarLander/index.html">Lunar Lander</a></li>
+ <li><a href="<?cs var:toroot ?>guide/samples/NotePad/index.html">NotePad</a></li>
+ </ul>
+ </li>
+ <?cs /if ?>
</ul>
</li>
+
+
<li><h2>Appendix</h2>
<ul>
<li><a href="<?cs var:toroot ?>guide/appendix/media-formats.html">Supported Media Formats</a></li>
@@ -155,4 +186,4 @@
<!--
buildToggleLists();
//-->
-</script> \ No newline at end of file
+</script>
diff --git a/docs/html/guide/index.jd b/docs/html/guide/index.jd
index e723235..ecbf97b 100644
--- a/docs/html/guide/index.jd
+++ b/docs/html/guide/index.jd
@@ -1,62 +1,84 @@
-page.title=Get Started
+page.title=The Developer's Guide
@jd:body
-<p>Welcome to the Android Developer Guide! The <strong>Dev Guide</strong> is your conceptual and practical
-introduction to developing applications for Android. With this guide, you're free to explore
-which ever topics interest you, based on your goals and experience.</p>
-
-<p>If you're new to Android, you're probably wondering what it takes to
-write a "Hello, World" application. So here it is:</p>
-
-<pre>
-package com.example.hello;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.widget.TextView;
-
-public class HelloWorld extends Activity {
-
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- TextView tv = new TextView(this);
- tv.setText(&quot;Hello, World&quot;);
- setContentView(tv);
- }
-
-}
-</pre>
-
-<p>That's the only code you need to write!</p>
-
-<h2 class="small-header">Not convinced?</h2>
-<p>If you're still shouting "Show me the code!" then take a look at
-more Android code in the <a href="{@docRoot}guide/tutorials/hello-world/index.html">Hello World Samples</a>.</p>
-
-<h2 class="small-header">Ready to start?</h2>
-<p>If you're already convinced you want to develop on Android,
-then we'll teach you how to build and run this "Hello, World" application in the
-<a href="{@docRoot}guide/tutorials/hello-world.html">Hello World Introduction</a>.</p>
-
-<h2 class="small-header">Ready for more?</h2>
-<p>Once you've got your feet wet (or just want to skip to the heart of Android), the following
-sections of the Dev Guide will educate you on the Android ins, outs, idioms and techniques:</p>
-<ul>
- <li><em>Android Basics</em>:
- Learn more about what Android is, what it offers, and how your application fits in.</li>
- <li><em>Framework Topics</em>:
- Become well versed in the practical matters of developing on Android &mdash; from drawing a UI, to storing data,
- to drawing 3D graphics, and much more.</li>
- <li><em>Developing</em>:
- Learn more about developing with IDEs, using Android develop/debug tools, and testing.</li>
- <li><em>Publishing</em>:
- Learn how to get you application out there, for the world to enjoy!</li>
- <li><em>Best Practices</em>:
- Get some recommendations on preferred techniques to write the best applications.</li>
- <li><em>Tutorials</em>:
- Get help doing some of the basics, step by step.</li>
- <li><em>Appendix</em>:
- Flotsam and jetsam. Find some of those spare nuggets of information.</li>
-</ul>
-
-<p>For more help, you should consider joining one or more of the Android discussion groups. See the <a href="{@docRoot}community/index.html">Community</a> for more information.</p>
+<p>
+Welcome to the <i>Android Dev Guide</i>! The Dev Guide is
+a practical introduction to developing applications for Android.
+It explores the concepts behind Android, the framework for
+constructing an application, and the tools for developing,
+testing, and publishing software for the platform.
+</p>
+
+<p>
+The Dev Guide holds most of the documentation for the Android
+platform, except for reference material on the framework API.
+For API specifications, go to the
+<a href="{@docRoot}reference/packages.html">Reference</a> tab above.
+</p>
+
+<p>
+As you can see in the panel on the left, the Dev Guide is
+divided into a handful of sections. They are:
+<p>
+
+<dl>
+<dt><b>Android Basics</b></dt>
+<dd>An initial orientation to Android &mdash; what it is,
+what it offers, and how your application fits in.</dd>
+
+<dt><b>Framework Topics</b></dt>
+<dd>Discussions of particular parts of the Android framework
+and API. For an overview of the framework, begin with
+<a href="{@docRoot}guide/topics/fundamentals.html">Application
+Fundamentals</a>. Then explore other topics &mdash; from
+designing a user interface and setting up resources to storing
+data and using permissions &mdash; as needed.</dd>
+
+<dt><b>Developing</b></dt>
+<dd>Directions for using Android's development and debugging tools,
+and for testing the results.</dd>
+
+<dt><b>Publishing</b></dt>
+<dd>Instructions on how to prepare your application for deployment
+and how to publish it when it's ready.</dd>
+
+<dt><b>Best Practices</b></dt>
+<dd>Recommendations on preferred techniques for writing
+applications that perform efficiently and work well for the
+user.</dd>
+
+<dt><b>Tutorials and Samples</b></dt>
+<dd>Step-by-step tutorials and sample code demonstrating how
+an Android application is constructed.</dd>
+
+<dt><b>Appendix</b></dt>
+<dd>Reference information and specifications, as well as FAQs,
+a glossary of terms, and other information.</dd>
+</dl>
+
+<p>
+The first step in programming for Android is downloading the SDK
+(software development kit). For instructions and information about
+the kit, go to the <a href="{@docRoot}sdk/index.html">SDK</a> tab above.
+</p>
+
+<p>
+After you have the SDK, begin by looking over the Dev Guide.
+If you want to start by getting a quick look at the code, the short
+<a href="{@docRoot}guide/tutorials/hello-world.html">Hello World</a>
+tutorial walks you through a standard "Hello, World" application as
+it would be written for the Android platform. The
+<a href="{@docRoot}guide/topics/fundamentals.html">Application
+Fundamentals</a> document is a good place to start for an
+understanding of the application framework.
+</p>
+
+
+<p>
+For additional help, consider joining one or more of the Android
+discussion groups. Go to the
+<a href="{@docRoot}community/index.html">Community</a> tab above
+for more information.
+</p>
+
+<p>To return to this page later, just click the "Dev Guide" tab while any Dev Guide page is loaded. </p> \ No newline at end of file
diff --git a/docs/html/guide/practices/design/seamlessness.jd b/docs/html/guide/practices/design/seamlessness.jd
index caf0d6a..a6c1641 100644
--- a/docs/html/guide/practices/design/seamlessness.jd
+++ b/docs/html/guide/practices/design/seamlessness.jd
@@ -164,7 +164,7 @@ interface they've come to expect. When designing your UIs, you should try and
avoid rolling your own as much as possible. Instead, use a Theme. You
can override or extend those parts of the theme that you need to, but at least
you're starting from the same UI base as all the other applications. For all
-the details, read <a href="{@docRoot}guide/topics/views/themes.html">Applying Styles and Themes</a>.</p>
+the details, read <a href="{@docRoot}guide/topics/ui/themes.html">Applying Styles and Themes</a>.</p>
<h2 id="flexui">Design Your UI to Work with Multiple Screen Resolutions</h2>
@@ -208,7 +208,6 @@ option</a> when starting the emulator.</p>
<h2 id="keyboard">Don't Assume Touchscreen or Keyboard</h2>
-Keyboad Different Keystrokes for Different Folks</h2>
<p>
Android will support a variety of handset form-factors. That's a fancy way of
saying that some Android devices will have full "QWERTY" keyboards, while
@@ -220,8 +219,6 @@ about specific keyboard layouts -- unless, of course, you're really interested
in restricting your application so that it can only be used on those devices.
</p>
-<h2 id="network">Assume the Network is Slow</h2>
-<h2 id="keyboard">Don't Assume Touchscreen or Keyboard</h2>
<h2 id="battery">Do Conserve the Device Battery</h2>
<p>
A mobile device isn't very mobile if it's constantly plugged into the
diff --git a/docs/html/guide/publishing/app-signing.jd b/docs/html/guide/publishing/app-signing.jd
index 1862b50..28c927a 100644
--- a/docs/html/guide/publishing/app-signing.jd
+++ b/docs/html/guide/publishing/app-signing.jd
@@ -94,7 +94,7 @@ you can run Keytool manually to generate your own keystore/key and then sign you
application with Jarsigner.</li>
</ul>
-<h2 id="strategies">Signing Strategies</h3>
+<h2 id="strategies">Signing Strategies</h2>
<p>Some aspects of application signing may affect how you approach the development
of your application, especially if you are planning to release multiple
diff --git a/docs/html/guide/publishing/preparing.jd b/docs/html/guide/publishing/preparing.jd
index 1f3c624..d355265 100644
--- a/docs/html/guide/publishing/preparing.jd
+++ b/docs/html/guide/publishing/preparing.jd
@@ -18,9 +18,11 @@ page.title=Preparing to Publish: A Checklist
<p>Publishing an application means testing it, packaging it appropriately, and
making it available to users of Android-powered mobile devices.</p>
-<p>If you plan to publish your application for installation on Android-powered devices,
-there are several things you need to do, to get your application ready. This document
-the significant checkpoints for preparing your application for a successful release. </p>
+<p>If you plan to publish your application for installation on
+Android-powered devices, there are several things you need to do, to get
+your application ready. This document highlights the significant
+checkpoints for preparing your application for a successful release.
+</p>
<p>If you will publish your application on Android Market, please also see <a
href="{@docRoot}guide/publishing/publishing.html#market">Publishing on Android Market</a>
@@ -67,7 +69,7 @@ testing classes and tools. You can use
{@link android.app.Instrumentation Instrumentation} to run JUnit and other
test cases, and you can use testing
tools such as the <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application
-Exerciser Monkey</a>. </p>
+Exerciser Monkey</a>. </p>
<ul>
<li>To ensure that your application will run properly for users, you should make
@@ -94,12 +96,12 @@ orientation changes. </li>
</ul>
<h3 id="eula">2. Consider adding an End User License Agreement in your
-application</h4>
+application</h3>
<p>To protect your person, organization, and intellectual property, you may want
to provide an End User License Agreement (EULA) with your application.
-<h3 id="iconlabel">3. Specify an icon and label in the application's manifest</h4>
+<h3 id="iconlabel">3. Specify an icon and label in the application's manifest</h3>
<p>The icon and label that you specify in an application's manifest are
important because they are displayed to users as your application's icon and
@@ -114,7 +116,7 @@ display the icon and label to users. </p>
<p>As regards the design of your icon, you should try to make it match as much
as possible the style used by the built-in Android applications.</p>
-<h3 id="logging">4. Turn off logging and debugging and clean up data/files</h4>
+<h3 id="logging">4. Turn off logging and debugging and clean up data/files</h3>
<p>For release, you should make sure that debug facilities are turned off and
that debug and other unnecessary data/files are removed from your application
@@ -129,9 +131,9 @@ application project.</li>
code.</li>
</ul>
-<h2 id="finalcompile">Before you do the final compile of your application</h3>
+<h2 id="finalcompile">Before you do the final compile of your application</h2>
-<h3 id="versionapp">5. Version Your Application</h4>
+<h3 id="versionapp">5. Version your application</h3>
<p>Before you compile your application, you must make sure that you have defined
a version number for your application, specifying an appropriate value for both
@@ -147,9 +149,10 @@ increment both the <code>android:versionCode</code> and
element in the application's manifest file, using appropriate values. </p>
<p>For detailed information about how to define version information for your
-application, see <a href="{@docRoot}guide/publishing/versioning.html">Versioning Your Applications</a>.</p>
+application, see <a href="{@docRoot}guide/publishing/versioning.html">Versioning
+Your Applications</a>.</p>
-<h3 id="cryptokey">6. Obtain a suitable cryptographic key</h4>
+<h3 id="cryptokey">6. Obtain a suitable cryptographic key</h3>
<p>If you have read and followed all of the preparation steps up to this point,
your application is compiled and ready for signing. Inside the .apk, the
@@ -158,7 +161,8 @@ private data, as described above. </p>
<p>Before you sign your application, you need to make sure that you have a
suitable private key. For complete information about how to obtain (or generate)
-a private key, see <a href="#cert">Obtaining a Private Key</a>.</p>
+a private key, see <a href="{@docRoot}guide/publishing/app-signing.html#cert">
+Obtaining a Suitable Private Key</a>.</p>
<p>Once you have obtained (or generated) a suitable private key, you will use it
to:</p>
@@ -166,20 +170,18 @@ to:</p>
<ul>
<li>Register for a Maps API Key (see below), if your application uses MapView
elements.</li>
-<li>Sign your application for release</li>
+<li>Sign your application for release, later in the preparation process</li>
</ul>
-
<h3 id="mapsApiKey">7. Register for a Maps API Key, if your application is using
MapView elements</h3>
-<div class="sidebox" style="margin-bottom:.5em;"><p>For complete information
-about getting a Maps API Key, see <a
-href="{@docRoot}guide/developing/mapkey.html">Obtaining a Maps API
+<div class="sidebox" style="margin-bottom:.5em;padding:1em;"><p>
+For complete information about getting a Maps API Key, see <a
+href="{@docRoot}guide/topics/location/geo/mapkey.html">Obtaining a Maps API
Key</a>.<br></p></div>
-<p>If your application uses one or more
-{@link-fixme com.google.android.maps.MapView Mapview} elements, you will need to
+<p>If your application uses one or more Mapview elements, you will need to
register your application with the Google
Maps service and obtain a Maps API Key, before your MapView(s) will be able to
retrieve data from Google Maps. To do so, you supply an MD5 fingerprint of your
@@ -222,20 +224,20 @@ to download Maps data. </li>
href="#signing">Signing Your Applications</a>.</p>
-<h2 id="compile">Compile Your Application</h3>
+<h2 id="compile">Compile your application</h2>
<p>When you've prepared your application as described in the previous sections,
you can compile your application for release. </p>
-<h2 id="post-compile">After Compiling Your Application</h3>
+<h2 id="post-compile">After compiling your application</h2>
-<h3 id="signapp">8. Sign Your Application</h4>
+<h3 id="signapp">8. Sign your application</h3>
<p>Sign your application using your private key. Signing your application
correctly is critically important. Please see <a href="#signing">Signing Your
Applications</a> for complete information. </p>
-<h3 id="testapp">9. Test Your Compiled and Signed Application</h4>
+<h3 id="testapp">9. Test your compiled and signed application</h3>
<p>Before you release your compiled application, you should thoroughly test it
on the target mobile device (and target network, if possible). In particular,
diff --git a/docs/html/guide/publishing/publishing.jd b/docs/html/guide/publishing/publishing.jd
index 1a022dd..3aea3cf 100644
--- a/docs/html/guide/publishing/publishing.jd
+++ b/docs/html/guide/publishing/publishing.jd
@@ -21,10 +21,10 @@ page.title=Publishing Your Applications
<li><a href="#marketupgrade">Publishing Upgrades on Android Market</a>
<li><a href="#marketintent">Using Intents to Launch the Market Application</a></li>
</ol></li>
-
+<!--
<li><span style="color:ccc">Publishing on Other Hosted Services</a></li>
<li><span style="color:ccc">Publishing through a Web Server</a></li>
-
+-->
</ol>
<h2>See also</h2>
@@ -84,7 +84,7 @@ that it meets the requirements listed below, which are enforced by the Market
server when you upload the application.</p>
<div class="special">
-<p>Requirements enforced by the Android Market server</p>
+<p>Requirements enforced by the Android Market server:</p>
<ol>
<li>Your application must be signed with a cryptographic private key whose
validity period ends after <span style="color:red">22 October 2033</span>. </li>
diff --git a/docs/html/guide/publishing/versioning.jd b/docs/html/guide/publishing/versioning.jd
index 1f4df0b..d0eafcd 100644
--- a/docs/html/guide/publishing/versioning.jd
+++ b/docs/html/guide/publishing/versioning.jd
@@ -13,12 +13,20 @@ page.title=Versioning Your Applications
<li>Determine your versioning strategy early in the development process, including considerations for future releases.</li>
</ul>
+<h2>In this document</h2>
+
+<ol>
+<li><a href="#appversion">Setting Application Version</a></li>
+<li><a href="#minsdkversion">Specifying Minimum System API Version</a>
+</ol>
+
+
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}guide/publishing/preparing.html">Preparing to Publish Your Application</a></li>
<li><a href="{@docRoot}guide/publishing/publishing.html#market">Publishing On Android Market</a></li>
-<li><a href="{@docRoot}guide/topics/manifest/manifest.html">The Manifest File</a></li>
+<li><a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a></li>
</ol>
</div>
@@ -40,11 +48,17 @@ users. A publishing service may also need to check the application version to
determine compatibility and establish upgrade/downgrade relationships.</li>
</ul>
-<p>The Android system itself <em>does not ever</em> check the version
+<p>The Android system itself <em>does not ever</em> check the application version
information for an application, such as to enforce restrictions on upgrades,
compatibility, and so on. Instead, only users or applications themselves are
-responsible for enforcing any version restrictions. </p>
+responsible for enforcing any version restrictions for applications themselves. </p>
+<p>The Android system <em>does</em> check any system version compatibility expressed
+by an application in its manifest, in the <code>minSdkVersion</code> attribute. This
+allows an application to specify the minimum system API with which is compatible.
+For more information see <a href="#minsdkversion">Specifying Minimum System API Version</a>.
+
+<h2 id="appversioning">Setting Application Version</h2>
<p>To define the version information for your application, you set attributes in
the application's manifest file. Two attributes are available, and you should
always define values for both of them: </p>
@@ -111,8 +125,15 @@ applications use the
{@link android.content.pm.PackageManager#getPackageInfo(java.lang.String, int)}
method of {@link android.content.pm.PackageManager PackageManager}. </p>
+<h2 id="minsdkversion">Specifying Minimum System API Version</h2>
+
<p>If your application requires a specific minimum version of the Android
-platform, you can also specify that in the manifest file: </p>
+platform, you can specify that version as an API Level identifier
+in the application's manifest file. Doing so ensures that your
+application can only be installed on devices that
+are running a compatible version of the Android system. </p>
+
+<p>To specify the minimum system version in the manifest, use this attribute: </p>
<ul>
<li><code>android:minSdkVersion</code> &mdash; An integer value corresponding to
@@ -129,7 +150,6 @@ that your application is compatible with all platform versions.</p></li>
<p>To specify a minimum platform version for your application, add a
<code>&lt;uses-sdk&gt;</code> element as a child of
<code>&lt;manifest&gt;</code>, then define the
-<code>android:minSdkVersion</code> as an attribute. Currently, only one platform
-version has been released for mobile devices &mdash; that version is "1". For
-this reason, you do not need to define this attribute in your application and,
-at this point, defining it is <em>not recommended</em>.</p> \ No newline at end of file
+<code>android:minSdkVersion</code> as an attribute. </p>
+
+<p>For more information, also see the <a href="{@docRoot}sdk/android-1.1.html">Android System Image 1.1 Version Notes</a>.</p>
diff --git a/docs/html/guide/samples/index.jd b/docs/html/guide/samples/index.jd
index c2dbb48..4e665fa 100644
--- a/docs/html/guide/samples/index.jd
+++ b/docs/html/guide/samples/index.jd
@@ -1,11 +1,17 @@
guide=true
-page.title=Android Samples
+page.title=Sample Code
@jd:body
-<p>Sometimes, the best way to learn how things are done is to just look at some code.
-So here we've provided the source code for some simple Android applications.</p>
+<p>Sometimes, the best way to learn how things are done is to just look at some code. So here
+ we've provided links to let you browse the source of some some simple Android applications. </p>
+<p>The source code for these applications is included in the Android SDK, in this location:</p>
+
+<p style="margin-left:2em"><code>&lt;sdk&gt;/samples/</code></p>
+
+<p>You can easily add these applications as projects in your development environment, so that you
+can modify them and watch them execute. </p>
<dl>
<dt><a href="ApiDemos/index.html">API Demos</a></dt>
<dd>A variety of small applications that demonstrate simple views and widgets.</dd>
@@ -14,4 +20,4 @@ So here we've provided the source code for some simple Android applications.</p>
<dt><a href="NotePad/index.html">Note Pad</a></dt>
<dd>An application for saving notes. Similar (but not identical) to the
<a href="{@docRoot}guide/tutorials/notepad/index.html">Notepad tutorial</a>.</dd>
-</dl> \ No newline at end of file
+</dl>
diff --git a/docs/html/guide/topics/fundamentals.jd b/docs/html/guide/topics/fundamentals.jd
index 7118ceb..3c7f419 100644
--- a/docs/html/guide/topics/fundamentals.jd
+++ b/docs/html/guide/topics/fundamentals.jd
@@ -17,6 +17,7 @@ page.title=Application Fundamentals
<li><a href="#appcomp">Application Components</a>
<ol>
<li><a href="#actcomp">Activating components: intents</a></li>
+ <li><a href="#endcomp">Shutting down components</a></li>
<li><a href="#manfile">The manifest file</a></li>
<li><a href="#ifilters">Intent filters</a></li>
</ol></li>
@@ -27,26 +28,34 @@ page.title=Application Fundamentals
<li><a href="#clearstack">Clearing the stack</a></li>
<li><a href="#starttask">Starting tasks</a></li>
</ol></li>
-<li><a href="#procthread">Processes and Threads</a></li>
-<li><a href="#lcycles">Lifecycles</a>
+<li><a href="#procthread">Processes and Threads</a>
+ <ol>
+ <li><a href="#procs">Processes</a></li>
+ <li><a href="#threads">Threads</a></li>
+ <li><a href="#rpc">Remote procedure calls</a></li>
+ <li><a href="#tsafe">Thread-safe methods</a></li>
+ </ol></li>
+<li><a href="#lcycles">Component Lifecycles</a>
<ol>
<li><a href="#actlife">Activity lifecycle</a></li>
<li><a href="#servlife">Service lifecycle</a></li>
<li><a href="#broadlife">Broadcast receiver lifecycle</a></li>
<li><a href="#proclife">Processes and lifecycles</a></li>
</ol></li>
+</ol>
</div>
</div>
<p>
Android applications are written in the Java programming language.
-The compiled Java code &mdash; along with data and
-resource files required by the application and a manifest describing the
-application &mdash; is bundled by the aapt tool into an <i>Android package</i>,
-an archive file marked by an {@code .apk} suffix. This file is the vehicle
-for distributing the application and installing it on mobile devices; it's
-the file users download to their devices. All the code in a single
-{@code .apk} file is considered to be one <i>application</i>.
+The compiled Java code &mdash; along with any data and resource
+files required by the application &mdash; is bundled by the
+<a href="{@docRoot}guide/developing/tools/aapt.html"><code>aapt</code>
+tool</a> into an <i>Android package</i>, an archive file
+marked by an {@code .apk} suffix. This file is the vehicle
+for distributing the application and installing it on mobile devices;
+it's the file users download to their devices. All the code in a
+single {@code .apk} file is considered to be one <i>application</i>.
</p>
<p>
@@ -76,7 +85,7 @@ in the same Linux process, sharing the same VM.
</p>
-<h2><a name="appcomp"></a>Application Components</h2>
+<h2 id="appcomp">Application Components</h2>
<p>
A central feature of Android is that one application can make use of elements
@@ -125,24 +134,31 @@ current activity start the next one.
Each activity is given a default window to draw in. Typically, the window
fills the screen, but it might be smaller than the screen and float on top
of other windows. An activity can also make use of additional windows &mdash;
-for example, a window that presents users with vital information when they
-select a particular item on-screen, or a pop-up dialog that calls for a user
-response in the midst of the activity.
+for example, a pop-up dialog that calls for a user response in the midst of
+the activity, or a window that presents users with vital information when they
+select a particular item on-screen.
</p>
<p>
The visual content of the window is provided by a hierarchy of views &mdash;
objects derived from the base {@link android.view.View} class. Each view
-draws in a particular rectangular space within the window and responds to user
-actions directed at that space. Android has a number of ready-made views that
-you can use &mdash; including buttons, text fields, scroll bars, menu items,
-check boxes, and more. A view hierarchy is placed within the activity's
-window by the <code>{@link android.app.Activity#setContentView
-Activity.setContentView()}</code> method. The <i>content view</i>
-is the View object at the root of the hierarchy.
-(See <a href="{@docRoot}guide/topics/views/index.html">Views and Layout</a>
-for more information on views and the heirarchy.)
-</p></dd>
+controls a particular rectangular space within the window. Parent views
+contain and organize the layout of their children. Leaf views (those at the
+bottom of the hierarchy) draw in the rectangles they control and respond to
+user actions directed at that space. Thus, views are where the activity's
+interaction with the user takes place. For example, a view might display
+a small image and initiate an action when the user taps that image. Android
+has a number of ready-made views that you can use &mdash; including buttons,
+text fields, scroll bars, menu items, check boxes, and more.
+</p>
+
+<p>
+A view hierarchy is placed within an activity's window by the
+<code>{@link android.app.Activity#setContentView Activity.setContentView()}</code>
+method. The <i>content view</i> is the View object at the root of the hierarchy.
+(See the separate <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a>
+document for more information on views and the hierarchy.)
+</p>
<p><dt><b>Services</b></dt>
<dd>A <i>service</i> doesn't have a visual user interface, but rather runs in
@@ -152,13 +168,13 @@ data over the network or calculate something and provide the result to activitie
that need it. Each service extends the {@link android.app.Service} base class.
<p>
-A good example is a media player playing songs from a play list. The player
+A prime example is a media player playing songs from a play list. The player
application would probably have one or more activities that allow the user to
choose songs and start playing them. However, the music playback itself would
not be handled by an activity because users will expect the music to keep
playing even after they leave the player and begin something different.
To keep the music going, the media player activity could start a service to run
-in the background. The system will then keep the music playback service running
+in the background. The system would then keep the music playback service running
even after the activity that started it leaves the screen.
</p>
@@ -180,8 +196,10 @@ user interface, they often spawn another thread for time-consuming tasks
<dd>A <i>broadcast receiver</i> is a component that does nothing but
receive and react to broadcast announcements. Many broadcasts originate in
system code &mdash; for example, announcements that the timezone has changed,
-that the battery is low, that the keyboard has been exposed, or that the user
-changed a language preference.
+that the battery is low, that a picture has been taken, or that the user
+changed a language preference. Applications can also initiate broadcasts
+&mdash; for example, to let other applications know that some data has been
+downloaded to the device and is available for them to use.
<p>
An application can have any number of broadcast receivers to respond to any
@@ -227,19 +245,19 @@ is available, creating the instance if necessary.
</p>
-<h3><a name="actcomp"></a>Activating components: intents</h3>
+<h3 id="actcomp">Activating components: intents</h3>
<p>
Content providers are activated when they're targeted by a request from a
ContentResolver. The other three components &mdash; activities, services,
and broadcast receivers &mdash; are activated by asynchronous messages
called <i>intents</i>. An intent is an {@link android.content.Intent}
-object that holds the content of the message. Among other things, it names
-the action an activity or service is being requested to take and specifies
-the URI of the data to act on. For broadcast receivers, it names the
-action being announced. For example, it might convey a request for
+object that holds the content of the message. For activities and services,
+it names the action being requested and specifies the URI of the data to
+act on, among other things. For example, it might convey a request for
an activity to present an image to the user or let the user edit some
-text. Or it might announce to interested broadcast receivers that the
+text. For broadcast receivers, the Intent object names the action being
+announced. For example, it might announce to interested parties that the
camera button has been pressed.
</p>
@@ -281,13 +299,19 @@ onStart()}</code> method and passes it the Intent object.</p>
Similarly, an intent can be passed to <code>{@link
android.content.Context#bindService Context.bindService()}</code> to
establish an ongoing connection between the calling component and a
-target service. It initiates the service if it's not already running.
-The service receives the Intent object in
+target service. The service receives the Intent object in
an <code>{@link android.app.Service#onBind onBind()}</code> call.
-For example, an activity might establish a connection with the music
-playback service mentioned earlier so that it could provide the user
-with an interface for controlling the playback. The activity would
-call {@code bindService()} to set up that connection.
+(If the service is not already running, {@code bindService()} can
+optionally start it.) For example, an activity might establish a connection
+with the music playback service mentioned earlier so that it can provide
+the user with the means (a user interface) for controlling the playback.
+The activity would call {@code bindService()} to set up that connection,
+and then call methods defined by the service to affect the playback.
+</p>
+
+<p>
+A later section, <a href="#rpc">Remote procedure calls</a>, has more details
+about binding to a service.
</p>
</li>
@@ -304,12 +328,49 @@ android.content.BroadcastReceiver#onReceive onReceive()}</code> methods.</p></li
</ul>
<p>
-For more on intent messages, see the separate article, <a
-href="{@docRoot}guide/topics/intents/intents-filters.html">Intents
+For more on intent messages, see the separate article,
+<a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents
and Intent Filters</a>.
+</p>
+
+
+<h3 id="endcomp">Shutting down components</h3>
+<p>
+A content provider is active only while it's responding to a request from
+a ContentResolver. And a broadcast receiver is active only while it's
+responding to a broadcast message. So there's no need to explicitly shut
+down these components.
+</p>
+
+<p>
+Activities, on the other hand, provide the user interface. They're
+in a long-running conversation with the user and may remain active,
+even when idle, as long as the conversation continues. Similarly, services
+may also remain running for a long time. So Android has methods to shut
+down activities and services in an orderly way:
+</p>
-<h3><a name="manfile"></a>The manifest file</h3>
+<ul>
+<li>An activity can be shut down by calling its
+<code>{@link android.app.Activity#finish finish()}</code> method. One activity can
+shut down another activity (one it started with {@code startActivityForResult()}) by
+calling <code>{@link android.app.Activity#finishActivity finishActivity()}</code>.</li>
+
+<li>A service can be stopped by calling its
+<code>{@link android.app.Service#stopSelf stopSelf()}</code> method, or by calling
+<code>{@link android.content.Context#stopService Context.stopService()}</code>.</li>
+</ul>
+
+<p>
+Components might also be shut down by the system when they are no longer being
+used or when Android must reclaim memory for more active components. A later
+section, <a href="#lcycles">Component Lifecycles</a>, discusses this
+possibility and its ramifications in more detail.
+</p>
+
+
+<h3 id="manfile">The manifest file</h3>
<p>
Before Android can start an application component, it must learn that
@@ -341,11 +402,12 @@ components. For example, an activity might be declared as follows:
&lt;/activity&gt;
. . .
&lt;/application&gt;
-&lt/manifest&gt;</pre>
+&lt;/manifest&gt;</pre>
<p>
-The {@code name} attribute of the {@code &lt;activity&gt;} element
-names the {@link android.app.Activity} subclass that implements the
+The {@code name} attribute of the
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+element names the {@link android.app.Activity} subclass that implements the
activity. The {@code icon} and {@code label} attributes point to
resource files containing an icon and label that can be displayed
to users to represent the activity.
@@ -353,24 +415,28 @@ to users to represent the activity.
<p>
The other components are declared in a similar way &mdash;
-{@code &lt;service&gt;} elements for services, {@code &lt;receiver&gt;}
-elements for broadcast receivers, and {@code &lt;provider&gt;} elements
-for content providers. Activities, services, and content providers that
-are not declared in the manifest are not visible to the system and are
-consequently never run. Broadcast receivers can be declared in the
-manifest, or they can be created dynamically in code (as
-{@link android.content.BroadcastReceiver} objects)
-and registered with the system by calling <code>{@link
-android.content.Context#registerReceiver Context.registerReceiver()}</code>.
+<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
+elements for services,
+<code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>
+elements for broadcast receivers, and
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
+elements for content providers. Activities, services, and content providers
+that are not declared in the manifest are not visible to the system and are
+consequently never run. However, broadcast receivers can either be
+declared in the manifest, or they can be created dynamically in code
+(as {@link android.content.BroadcastReceiver} objects)
+and registered with the system by calling
+<code>{@link android.content.Context#registerReceiver Context.registerReceiver()}</code>.
</p>
<p>
For more on how to structure a manifest file for your application, see
-<a href="{@docRoot}guide/topics/manifest/manifest.html">The Manifest File</a>.
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The
+AndroidManifest.xml File</a>.
</p>
-<h3><a name="ifilters"></a>Intent filters</h3>
+<h3 id="ifilters">Intent filters</h3>
<p>
An Intent object can explicitly name a target component. If it does,
@@ -404,7 +470,7 @@ two intent filters to the activity:
&lt;/activity&gt;
. . .
&lt;/application&gt;
-&lt/manifest&gt;</pre>
+&lt;/manifest&gt;</pre>
<p>
The first filter in the example &mdash; the combination of the action
@@ -442,7 +508,7 @@ and Intent Filters</a>.
</p>
-<h2><a name="acttask"></a>Activities and Tasks</h2>
+<h2 id="acttask">Activities and Tasks</h2>
<p>
As noted earlier, one activity can start another, including one defined
@@ -467,14 +533,14 @@ the one that is the focus for user actions. When one activity starts another,
the new activity is pushed on the stack; it becomes the running activity.
The previous activity remains in the stack. When the user presses the BACK key,
the current activity is popped from the stack, and the previous one resumes as
-the running activity. Activities in the stack are never rearranged, only
-pushed and popped.
+the running activity.
</p>
<p>
The stack contains objects, so if a task has more than one instance of the same
Activity subclass open &mdash; multiple map viewers, for example &mdash; the
-stack has a separate entry for each instance.
+stack has a separate entry for each instance. Activities in the stack are never
+rearranged, only pushed and popped.
</p>
<p>
@@ -505,7 +571,8 @@ The behavior just described is the default behavior for activities and tasks.
But there are ways to modify almost all aspects of it. The association of
activities with tasks, and the behavior of an activity within a task, is
controlled by the interaction between flags set in the Intent object that
-started the activity and attributes set in the activity's {@code &lt;activity&gt;}
+started the activity and attributes set in the activity's
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
element in the manifest. Both requester and respondent have a say in what happens.
</p>
@@ -529,19 +596,19 @@ The principal {@code &lt;activity&gt;} attributes are:
<p>
The following sections describe what some of these flags and attributes do,
-and how they interact.
+how they interact, and what considerations should govern their use.
</p>
-<h3><a name="afftask"></a>Affinities and new tasks</h3>
+<h3 id="afftask">Affinities and new tasks</h3>
<p>
By default, all the activities in an application have an <i>affinity</i> for each
other &mdash; that is, there's a preference for them all to belong to the
same task. However, an individual affinity can be set for each activity
-with the {@code taskAffinity} attribute. Activities defined in different
-applications can share an affinity, or activities defined in the same
-application can be assigned different affinities.
+with the {@code taskAffinity} attribute of the {@code &lt;activity&gt;} element.
+Activities defined in different applications can share an affinity, or activities
+defined in the same application can be assigned different affinities.
The affinity comes into play in two circumstances: When the Intent object
that launches an activity contains the {@code FLAG_ACTIVITY_NEW_TASK} flag,
and when an activity has its {@code allowTaskReparenting} attribute set
@@ -550,26 +617,28 @@ to "{@code true}".
<dl>
<dt>The <code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code> flag</dt>
-<dd>As mentioned earlier, a new activity is, by default, launched into
+<dd>As described earlier, a new activity is, by default, launched into
the task of the activity that called {@code startActivity()}. It's pushed
onto the same stack as the caller. However, if the Intent object passed
to {@code startActivity()} contains the {@code FLAG_ACTIVITY_NEW_TASK}
flag, the system looks for a different task to house the new activity.
Often, as the name of the flag implies, it's a new task. However, it
-doesn't have to be. If there's an existing task with the same affinity
-as the new activity, the activity is launched into that task. If not,
-it begins a new task.</dd>
-
-<dt>The {@code allowTaskReparenting} attribute</dt>
-<dd>If an activity has its {@code allowTaskReparenting} attribute is
-set to "{@code true}", it can move from the task it starts in to the task
+doesn't have to be. If there's already an existing task with the same
+affinity as the new activity, the activity is launched into that task. If
+not, it begins a new task.</dd>
+
+<dt>The <code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">allowTaskReparenting</a></code>
+attribute</dt>
+<dd>If an activity has its {@code allowTaskReparenting} attribute set
+to "{@code true}", it can move from the task it starts in to the task
it has an affinity for when that task comes to the fore. For example,
suppose that an activity that reports weather conditions in selected
cities is defined as part of a travel application. It has the same
affinity as other activities in the same application (the default
affinity) and it allows reparenting. One of your activities
starts the weather reporter, so it initially belongs to the same task as
-your activity. However, when the travel application, next comes forward,
+your activity. However, when the travel application next comes forward,
the weather reporter will be reassigned to and displayed with that task.</dd>
</dl>
@@ -580,65 +649,116 @@ affinities to the activities associated with each of them.
</p>
-<h3><a name="lmodes"></a>Launch modes</h3>
+<h3 id="lmodes">Launch modes</h3>
<p>
There are four different launch modes that can be assigned to an {@code
-&lt;activity&gt;} element's {@code launchMode} attribute:
+&lt;activity&gt;} element's
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#lmode">launchMode</a></code>
+attribute:
</p>
-<p style="margin-left: 2em">"{@code standard}" (the default value)
+<p style="margin-left: 2em">"{@code standard}" (the default mode)
<br>"{@code singleTop}"
<br>"{@code singleTask}"
<br>"{@code singleInstance}"</p>
<p>
-The launch mode determines three things:
+The modes differ from each other on these four points:
</p>
<ul>
-<li>Whether the activity can belong to a task that includes other
-activities. The answer is yes for all the modes except
-"{@code singleInstance}". A "{@code singleInstance}" activity is always
-the only activity in its task. If it tries to launch another activity,
-that activity is assigned to a different task &mdash; as if {@code
-FLAG_ACTIVITY_NEW_TASK} was in the intent.</li>
-
-<li><p>Whether the activity always begins a task. For "{@code singleTask}"
-and "{@code singleInstance}" the answer is yes. They mark activities that
-can only be the root activities of a task; they define a task. In contrast,
-"{@code standard}" and "{@code singleTop}" activities can belong to any task.
+
+<li><b>Which task will hold the activity that responds to the intent</b>.
+For the "{@code standard}" and "{@code singleTop}" modes, it's the task that
+originated the intent (and called
+<code>{@link android.content.Context#startActivity startActivity()}</code>)
+&mdash; unless the Intent object contains the
+<code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code> flag.
+In that case, a different task is chosen as described in the previous
+section, <a href="#afftask">Affinities and new tasks</a>.
+
+<p>
+In contrast, the "{@code singleTask}" and "{@code singleInstance}" modes mark
+activities that are always at the root of a task. They define a task; they're
+never launched into another task.
+</p>
+
+<li><p><b>Whether there can be multiple instances of the activity</b>.
+A "{@code standard}" or "{@code singleTop}" activity can be instantiated
+many times. They can belong to multiple tasks, and a given task can have
+multiple instances of the same activity.
+</p>
+
+<p>
+In contrast, "{@code singleTask}" and "{@code singleInstance}" activities
+are limited to just one instance. Since these activities are at the root
+of a task, this limitation means that there is never more than a single
+instance of the task on the device at one time.
+</p>
+
+<li><p><b>Whether the instance can have other activities in its task</b>.
+A "{@code singleInstance}" activity stands alone as the only activity in its
+task. If it starts another activity, that activity will be launched into a
+different task regardless of its launch mode &mdash; as if {@code
+FLAG_ACTIVITY_NEW_TASK} was in the intent. In all other respects, the
+"{@code singleInstance}" mode is identical to "{@code singleTask}".</p>
+
+<p>
+The other three modes permit multiple activities to belong to the task.
+A "{@code singleTask}" activity will always be the root activity of the task,
+but it can start other activities that will be assigned to its
+task. Instances of "{@code standard}" and "{@code singleTop}"
+activities can appear anywhere in a stack.
</p></li>
-<li><p>Whether an existing instance of the activity can handle new
-intents. The answer is yes for all the modes except "{@code standard}".
-Existing "{@code singleTask}" and "{@code singleInstance}" activities
-handle all new intents that come their way; a new instance is never
-created. In the case of "{@code singleTask}", all other activities in
-the task are popped from the stack, so that the root "{@code singleTask}"
-activity is at the top and in position to respond to the intent.
+<li><b>Whether a new instance of the class will be launched
+to handle a new intent</b>. For the default "{@code standard}" mode, a
+new instance is created to respond to every new intent. Each instance
+handles just one intent. For the "{@code singleTop}" mode, an existing
+instance of the class is re-used to handle a new intent if it resides
+at the top of the activity stack of the target task. If it does not
+reside at the top, it is not re-used. Instead, a new instance
+is created for the new intent and pushed on the stack.
+
+<p>
+For example, suppose a task's activity stack consists of root activity A with
+activities B, C, and D on top in that order, so the stack is A-B-C-D. An intent
+arrives for an activity of type D. If D has the default "{@code standard}" launch
+mode, a new instance of the class is launched and the stack becomes A-B-C-D-D.
+However, if D's launch mode is "{@code singleTop}", the existing instance is
+expected to handle the new intent (since it's at the top of the stack) and the
+stack remains A-B-C-D.
</p>
<p>
-If a "{@code singleTop}" activity is at the
-top of its stack, that object is expected to handle any new intents.
-However, if it's farther down the stack, a new instance is created for
-the intent and pushed on the stack.
+If, on the other hand, the arriving intent is for an activity of type B, a new
+instance of B would be launched no matter whether B's mode is "{@code standard}"
+or "{@code singleTop}" (since B is not at the top of the stack), so the resulting
+stack would be A-B-C-D-B.
</p>
<p>
-In contrast, a new instance of a "{@code standard}" activity is always
-created for each new intent.
+As noted above, there's never more than one instance of a "{@code singleTask}"
+or "{@code singleInstance}" activity, so that instance is expected to handle
+all new intents. A "{@code singleInstance}" activity is always at the top of
+the stack (since it is the only activity in the task), so it is always in
+position to handle the intent. However, a "{@code singleTask}" activity may
+or may not have other activities above it in the stack. If it does, it is not
+in position to handle the intent, and the intent is dropped. (Even though the
+intent is dropped, its arrival would have caused the task to come to the
+foreground, where it would remain.)
</p>
</li>
+
</ul>
<p>
When an existing activity is asked to handle a new intent, the Intent
-object is passed to the activity in an <code>{@link android.app.Activity#onNewIntent
-onNewIntent()}</code> call. (The intent object that originally started the
-activity can be retrieved by calling
-<code>{@link android.app.Activity#getIntent getIntent()}</code>.)
+object is passed to the activity in an
+<code>{@link android.app.Activity#onNewIntent onNewIntent()}</code> call.
+(The intent object that originally started the activity can be retrieved by
+calling <code>{@link android.app.Activity#getIntent getIntent()}</code>.)
</p>
<p>
@@ -650,13 +770,13 @@ return to what that instance was doing before the new intent arrived.
</p>
<p>
-For more on launch modes, see
-<a href="{@docRoot}guide/topics/manifest/manifest.html">The
-AndroidManifest.xml File</a>
+For more on launch modes, see the description of the
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+element.
</p>
-<h3><a name="clearstack"></a>Clearing the stack</h3>
+<h3 id="clearstack">Clearing the stack</h3>
<p>
If the user leaves a task for a long time, the system clears the task of all
@@ -673,24 +793,30 @@ control this behavior and modify it:
</p>
<dl>
-<dt>The {@code alwaysRetainTaskState} attribute</dt>
+<dt>The <code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html#always">alwaysRetainTaskState</a></code>
+attribute</dt>
<dd>If this attribute is set to "{@code true}" in the root activity of a task,
the default behavior just described does not happen.
-Activities are retained in the stack even after a long period.</dd>
+The task retains all activities in its stack even after a long period.</dd>
-<dt>The {@code clearTaskOnLaunch} attribute</dt>
+<dt>The <code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html#clear">clearTaskOnLaunch</a></code>
+attribute</dt>
<dd>If this attribute is set to "{@code true}" in the root activity of a task,
the stack is cleared down to the root activity whenever the user leaves the task
and returns to it. In other words, it's the polar opposite of
{@code alwaysRetainTaskState}. The user always returns to the task in its
initial state, even after a momentary absence.</dd>
-<dt>The {@code finishOnTaskLaunch} attribute</dt>
+<dt>The <code><a
+href="{@docRoot}guide/topics/manifest/activity-element.html#finish">finishOnTaskLaunch</a></code>
+attribute</dt>
<dd>This attribute is like {@code clearTaskOnLaunch}, but it operates on a
single activity, not an entire task. And it can cause any activity to go
away, including the root activity. When it's set to "{@code true}", the
activity remains part of the task only for the current session. If the user
-leaves and then relaunches the task, it no longer is present.</dd>
+leaves and then returns to the task, it no longer is present.</dd>
</dl>
<p>
@@ -700,7 +826,11 @@ android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_CLEAR_TOP}</code>
flag, and the target task already has an instance of the type of activity that
should handle the intent in its stack, all activities above that instance
are cleared away so that it stands at the top of the stack and can respond
-to the intent.
+to the intent.
+If the launch mode of the designated activity is "{@code standard}", it too
+will be removed from the stack, and a new instance will be launched to handle
+the incoming intent. That's because a new instance is always created for
+a new intent when the launch mode is "{@code standard}".
</p>
<p>
@@ -711,7 +841,7 @@ a position where it can respond to the intent.
</p>
-<h3><a name="starttask"></a>Starting tasks</h3>
+<h3 id="starttask">Starting tasks</h3>
<p>
An activity is set up as the entry point for a task by giving it
@@ -731,7 +861,7 @@ and then come back to it later. For this reason, the two launch modes
that mark activities as always initiating a task, "{@code singleTask}"
and "{@code singleInstance}", should be used only when the activity has
a {@code MAIN} and {@code LAUNCHER} filter.
-Imagine, for example, what could happen if the filter is missing.
+Imagine, for example, what could happen if the filter is missing:
An intent launches a "{@code singleTask}" activity, initiating a new task,
and the user spends some time working in that task. The user then presses
the HOME key. The task is now ordered behind and obscured by the home
@@ -760,7 +890,7 @@ See <a href="#clearstack">Clearing the stack</a>, earlier.
</p>
-<h2><a name="procthread"></a>Processes and Threads</h2>
+<h2 id="procthread">Processes and Threads</h2>
<p>
When the first of an application's components needs to be run, Android
@@ -769,12 +899,15 @@ all components of the application run in that process and thread.
</p>
<p>
-However, you can arrange for components to run in other processes as well as
-spawn additional threads:
+However, you can arrange for components to run in other processes, and you
+can spawn additional threads for any process.
</p>
-<ul>
-<li>The process where a component runs is controlled by the manifest file.
+
+<h3 id="procs">Processes</h3>
+
+<p>
+The process where a component runs is controlled by the manifest file.
The component elements &mdash; {@code &lt;activity&gt;},
{@code &lt;service&gt;}, {@code &lt;receiver&gt;}, and {@code &lt;provider&gt;}
&mdash; each have a {@code process} attribute that can specify a process
@@ -784,26 +917,27 @@ while others do not. They can also be set so that components of
different applications run in the same process &mdash; provided that the
applications share the same Linux user ID and are signed by the same authorities.
The {@code &lt;application&gt;} element also has a {@code process} attribute,
-for setting a default value that applies to all components.</li>
-
-<li><p>Threads are created in code using standard Java {@link java.lang.Thread}
-objects. Android provides a number of convenience classes for managing threads
-&mdash; {@link android.os.Looper} for running a message loop within a thread,
-{@link android.os.Handler} for processing messages, and
-{@link android.os.HandlerThread} for setting up a thread with a message loop.</p>
+for setting a default value that applies to all components.
+</p>
<p>
-Even though you may confine your application to a single process, there may be
-times when you will need to spawn a thread to do some background work. Since the
-user interface must always be quick to respond to user actions, the
-thread that hosts an activity should not also host time-consuming operations like
-network downloads, or anything else that may not be completed quickly.
-</p></li>
-</ul>
+All components are instantiated in the main thread of the specified
+process, and system calls to the component are dispatched from that
+thread. Separate threads are not created for each instance. Consequently,
+methods that respond to those calls &mdash; methods like
+<code>{@link android.view.View#onKeyDown View.onKeyDown()}</code> that report
+user actions and the lifecycle notifications discussed later in the
+<a href="#lcycles">Component Lifecycles</a> section &mdash; always run in the
+main thread of the process. This means
+that no component should perform long or blocking operations (such as networking
+operations or computation loops) when called by the system, since this will block
+any other components also in the process. You can spawn separate threads for
+long operations, as discussed under <a href="#threads">Threads</a>, next.
+</p>
<p>
Android may decide to shut down a process at some point, when memory is
-low and required by other applications that are more immediately serving
+low and required by other processes that are more immediately serving
the user. Application components running in the process are consequently
destroyed. A process is restarted for those components when there's again
work for them to do.
@@ -816,17 +950,176 @@ with activities that are no longer visible on screen than a process with
visible activities.
The decision whether to terminate a process, therefore, depends on the state
of the components running in that process. Those states are the subject of
-the next section, <a href="#lcycles">Lifecycles</a>.
+a later section, <a href="#lcycles">Component Lifecycles</a>.
+</p>
+
+
+<h3 id="threads">Threads</h3>
+
+<p>
+Even though you may confine your application to a single process, there will
+likely be times when you will need to spawn a thread to do some background
+work. Since the user interface must always be quick to respond to user actions,
+the thread that hosts an activity should not also host time-consuming operations
+like network downloads. Anything that may not be completed quickly should be
+assigned to a different thread.
+</p>
+
+<p>
+Threads are created in code using standard Java {@link java.lang.Thread}
+objects. Android provides a number of convenience classes for managing
+threads &mdash; {@link android.os.Looper} for running a message loop within
+a thread, {@link android.os.Handler} for processing messages, and
+{@link android.os.HandlerThread} for setting up a thread with a message loop.
</p>
-<h2><a name="lcycles"></a>Lifecycles</h2>
+<h3 id="rpc">Remote procedure calls</h3>
+
+<p>
+Android has a lightweight mechanism for remote procedure calls (RPCs)
+&mdash; where a method is called locally, but executed remotely (in another
+process), with any result returned back to the caller.
+This entails decomposing the method call and all its attendant data to a
+level the operating system can understand, transmitting it from the local
+process and address space to the remote process and address space, and
+reassembling and reenacting the call there. Return values have to be
+transmitted in the opposite direction. Android provides all the code
+to do that work, so that you can concentrate on defining and implementing
+the RPC interface itself.
+</p>
+
+<p>
+An RPC interface can include only methods.
+All methods are executed synchronously (the local method blocks until the
+remote method finishes), even if there is no return value.
+</p>
+
+<p>
+In brief, the mechanism works as follows: You'd begin by declaring the
+RPC interface you want to implement using a simple IDL (interface definition
+language). From that declaration, the
+<code><a href="{@docRoot}guide/developing/tools/aidl.html">aidl</a></code>
+tool generates a Java interface definition that must be made available to
+both the local and the remote process. It contains two inner class, as shown
+in the following diagram:
+</p>
+
+<p style="margin-left: 2em">
+<img src="{@docRoot}images/binder_rpc.png" alt="RPC mechanism." />
+</p>
+
+<p>
+The inner classes have all the code needed to administer remote procedure
+calls for the interface you declared with the IDL.
+Both inner classes implement the {@link android.os.IBinder}
+interface. One of them is used locally and internally by the system;
+the code you write can ignore it.
+The other, called Stub, extends the {@link android.os.Binder}
+class. In addition to internal code for effectuating the IPC calls, it
+contains declarations for the methods in the RPC interface you declared.
+You would subclass Stub to implement those methods, as indicated in the
+diagram.
+</p>
+
+<p>
+Typically, the remote process would be managed by a service (because a
+service can inform the system about the process and its connections to
+other processes). It would have both the interface file generated by
+the {@code aidl} tool and the Stub subclass implementing the
+RPC methods. Clients of the service would have only the interface file
+generated by the {@code aidl} tool.
+</p>
+
+<p>
+Here's how a connection between a service and its clients is set up:
+</p>
+
+<ul>
+<li>Clients of the service (on the local side) would implement
+<code>{@link android.content.ServiceConnection#onServiceConnected
+onServiceConnected()}</code> and
+<code>{@link android.content.ServiceConnection#onServiceDisconnected
+onServiceDisconnected()}</code> methods so they can be notified
+when a successful connection to the remote service is established, and
+when it goes away. They would then call
+<code>{@link android.content.Context#bindService bindService()}</code>
+to set up the connection.
+</li>
+
+<li>
+The service's <code>{@link android.app.Service#onBind onBind()}</code>
+method would be implemented to either accept or reject the connection,
+depending on the intent it receives (the intent passed to
+{@code bindService()}). If the connection is accepted, it returns
+an instance of the Stub subclass.
+</li>
+
+<li>If the service accepts the connection, Android calls the
+client's {@code onServiceConnected()} method and passes it an IBinder
+object, a proxy for the Stub subclass managed by the service. Through
+the proxy, the client can make calls on the remote service.
+</li>
+</ul>
+
+<p>
+This brief description omits some details of the RPC mechanism. For more
+information, see
+<a href="{@docRoot}guide/developing/tools/aidl.html">Designing a Remote
+Interface Using AIDL</a> and the {@link android.os.IBinder IBinder} class
+description.
+</p>
+
+
+<h3 id="tsafe">Thread-safe methods</h3>
+
+<p>
+In a few contexts, the methods you implement may be called from more
+than one thread, and therefore must be written to be thread-safe.
+</p>
+
+<p>
+This is primarily true for methods that can be called remotely &mdash;
+as in the RPC mechanism discussed in the previous section.
+When a call on a method implemented in an IBinder object originates
+in the same process as the IBinder, the method is executed in the
+caller's thread. However, when the call originates in another process,
+the method is executed in a thread chosen from a pool of threads that
+Android maintains in the same process as the IBinder; it's not executed
+in the main thread of the process. For example, whereas a service's
+{@code onBind()} method would be called from the main thread of the
+service's process, methods implemented in the object that {@code onBind()}
+returns (for example, a Stub subclass that implements RPC methods) would
+be called from threads in the pool.
+Since services can have more than one client, more than one pool thread
+can engage the same IBinder method at the same time. IBinder methods
+must, therefore, be implemented to be thread-safe.
+</p>
+
+<p>
+Similarly, a content provider can receive data requests that originate in
+other processes. Although the ContentResolver and ContentProvider classes
+hide the details of how the interprocess communication is managed,
+ContentProvider methods that respond to those requests &mdash; the methods
+<code>{@link android.content.ContentProvider#query query()}</code>,
+<code>{@link android.content.ContentProvider#insert insert()}</code>,
+<code>{@link android.content.ContentProvider#delete delete()}</code>,
+<code>{@link android.content.ContentProvider#update update()}</code>, and
+<code>{@link android.content.ContentProvider#getType getType()}</code>
+&mdash; are called from a pool of threads in the content provider's
+process, not the main thread of the process. Since these methods
+may be called from any number of threads at the same time, they too must
+be implemented to be thread-safe.
+</p>
+
+
+<h2 id="lcycles">Component Lifecycles</h2>
<p>
Application components have a lifecycle &mdash; a beginning when
Android instantiates them to respond to intents through to an end when
the instances are destroyed. In between, they may sometimes be active
-or inactive, or, in the case of activities, visible to the user or
+or inactive,or, in the case of activities, visible to the user or
invisible. This section discusses the lifecycles of activities,
services, and broadcast receivers &mdash; including the states that they
can be in during their lifetimes, the methods that notify you of transitions
@@ -835,7 +1128,7 @@ the process hosting them might be terminated and the instances destroyed.
</p>
-<h3><a name="actlife"></a>Activity lifecycle</h3>
+<h3 id="actlife">Activity lifecycle</h3>
<p>An activity has essentially three states:</p>
@@ -864,12 +1157,10 @@ method), or simply killing its process. When it is displayed again
to the user, it must be completely restarted and restored to its previous state.
</p>
-
-<h4>Lifecycle methods</h4>
-
<p>
As an activity transitions from state to state, it is notified of the change
by calls to the following protected methods:
+</p>
<p style="margin-left: 2em">{@code void onCreate(Bundle <i>savedInstanceState</i>)}
<br/>{@code void onStart()}
@@ -881,15 +1172,15 @@ by calls to the following protected methods:
<p>
All of these methods are hooks that you can override to do appropriate work
-when the state changes.
-All activities must implement <code>{@link android.app.Activity#onCreate
-onCreate()}</code> to do initial setup when the activity is first instantiated.
+when the state changes. All activities must implement
+<code>{@link android.app.Activity#onCreate onCreate()}</code> to do the
+initial setup when the object is first instantiated.
Many will also implement <code>{@link android.app.Activity#onPause onPause()}</code>
to commit data changes and otherwise prepare to stop interacting with the user.
</p>
<div class="sidebox-wrapper">
-<div class="sidebox">
+<div class="sidebox-inner">
<h2>Calling into the superclass</h2>
<p>
An implementation of any activity lifecycle method should always first
@@ -950,19 +1241,19 @@ can be in. The square rectangles represent the callback methods you can impleme
to perform operations when the activity transitions between states.
<p>
-<p><img src="{@docRoot}images/activity_lifecycle.png"
-alt="State diagram for an Android activity lifecycle." border="0" /></p>
+<p style="margin-left: 2em"><img src="{@docRoot}images/activity_lifecycle.png"
+alt="State diagram for an Android activity lifecycle." /></p>
<p>
The following table describes each of these methods in more detail and
locates it within the activity's overall lifecycle:
</p>
-<table border="2" width="85%" align="center" frame="hsides" rules="rows">
-<colgroup align="left" span="3" />
-<colgroup align="left" />
-<colgroup align="center" />
-<colgroup align="center" />
+<table border="2" width="85%" frame="hsides" rules="rows">
+<colgroup align="left" span="3"></colgroup>
+<colgroup align="left"></colgroup>
+<colgroup align="center"></colgroup>
+<colgroup align="center"></colgroup>
<thead>
<tr><th colspan="3">Method</th> <th>Description</th> <th>Killable?</th> <th>Next</th></tr>
@@ -970,7 +1261,7 @@ locates it within the activity's overall lifecycle:
<tbody>
<tr>
- <td colspan="3" align="left" border="0"><code>{@link android.app.Activity#onCreate onCreate()}</code></td>
+ <td colspan="3" align="left"><code>{@link android.app.Activity#onCreate onCreate()}</code></td>
<td>Called when the activity is first created.
This is where you should do all of your normal static set up &mdash;
create views, bind data to lists, and so on. This method is passed
@@ -984,7 +1275,7 @@ locates it within the activity's overall lifecycle:
<tr>
<td rowspan="5" style="border-left: none; border-right: none;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
- <td colspan="2" align="left" border="0"><code>{@link android.app.Activity#onRestart
+ <td colspan="2" align="left"><code>{@link android.app.Activity#onRestart
onRestart()}</code></td>
<td>Called after the activity has been stopped, just prior to it being
started again.
@@ -994,7 +1285,7 @@ onRestart()}</code></td>
</tr>
<tr>
- <td colspan="2" align="left" border="0"><code>{@link android.app.Activity#onStart onStart()}</code></td>
+ <td colspan="2" align="left"><code>{@link android.app.Activity#onStart onStart()}</code></td>
<td>Called just before the activity becomes visible to the user.
<p>Followed by {@code onResume()} if the activity comes
to the foreground, or {@code onStop()} if it becomes hidden.</p></td>
@@ -1004,7 +1295,7 @@ onRestart()}</code></td>
<tr>
<td rowspan="2" style="border-left: none;">&nbsp;&nbsp;&nbsp;&nbsp;</td>
- <td align="left" border="0"><code>{@link android.app.Activity#onResume onResume()}</code></td>
+ <td align="left"><code>{@link android.app.Activity#onResume onResume()}</code></td>
<td>Called just before the activity starts
interacting with the user. At this point the activity is at
the top of the activity stack, with user input going to it.
@@ -1014,7 +1305,7 @@ onRestart()}</code></td>
</tr>
<tr>
- <td align="left" border="0"><code>{@link android.app.Activity#onPause onPause()}</code></td>
+ <td align="left"><code>{@link android.app.Activity#onPause onPause()}</code></td>
<td>Called when the system is about to start resuming another
activity. This method is typically used to commit unsaved changes to
persistent data, stop animations and other things that may be consuming
@@ -1023,24 +1314,24 @@ onRestart()}</code></td>
<p>Followed either by {@code onResume()} if the activity
returns back to the front, or by {@code onStop()} if it becomes
invisible to the user.</td>
- <td align="center"><font color="#800000"><strong>Yes</strong></font></td>
+ <td align="center"><strong style="color:#800000">Yes</strong></td>
<td align="center">{@code onResume()} <br/>or<br/> {@code onStop()}</td>
</tr>
<tr>
- <td colspan="2" align="left" border="0"><code>{@link android.app.Activity#onStop onStop()}</code></td>
+ <td colspan="2" align="left"><code>{@link android.app.Activity#onStop onStop()}</code></td>
<td>Called when the activity is no longer visible to the user. This
may happen because it is being destroyed, or because another activity
(either an existing one or a new one) has been resumed and is covering it.
<p>Followed either by {@code onRestart()} if
the activity is coming back to interact with the user, or by
{@code onDestroy()} if this activity is going away.</p></td>
- <td align="center"><font color="#800000"><strong>Yes</strong></font></td>
+ <td align="center"><strong style="color:#800000">Yes</strong></td>
<td align="center">{@code onRestart()} <br/>or<br/> {@code onDestroy()}</td>
</tr>
<tr>
- <td colspan="3" align="left" border="0"><code>{@link android.app.Activity#onDestroy
+ <td colspan="3" align="left"><code>{@link android.app.Activity#onDestroy
onDestroy()}</code></td>
<td>Called before the activity is destroyed. This is the final call
that the activity will receive. It could be called either because the
@@ -1049,7 +1340,7 @@ onDestroy()}</code></td>
instance of the activity to save space. You can distinguish
between these two scenarios with the <code>{@link
android.app.Activity#isFinishing isFinishing()}</code> method.</td>
- <td align="center"><font color="#800000"><strong>Yes</strong></font></td>
+ <td align="center"><strong style="color:#800000">Yes</strong></td>
<td align="center"><em>nothing</em></td>
</tr>
</tbody>
@@ -1062,7 +1353,7 @@ whether or not the system can kill the process hosting the activity
line of the activity's code</em>. Three methods ({@code onPause()},
{@code onStop()}, and {@code onDestroy()}) are marked "Yes." Because
{@code onPause()} is the first of the three, it's the only one that's
-guaranteed to be called before the process is killed &mdash
+guaranteed to be called before the process is killed &mdash;
{@code onStop()} and {@code onDestroy()} may not be. Therefore, you
should use {@code onPause()} to write any persistent data (such as user
edits) to storage.
@@ -1084,7 +1375,7 @@ extreme and dire circumstances when there is no other recourse.
</p>
-<h4><a name="actstate"></a>Saving activity state</h4>
+<h4 id="actstate">Saving activity state</h4>
<p>
When the system, rather than the user, shuts down an activity to conserve
@@ -1096,7 +1387,7 @@ previous state.
To capture that state before the activity is killed, you can implement
an <code>{@link android.app.Activity#onSaveInstanceState
onSaveInstanceState()}</code> method for the activity. Android calls this
-method before making the activity vulnerable to being destroyed &mdash
+method before making the activity vulnerable to being destroyed &mdash;
that is, before {@code onPause()} is called. It
passes the method a {@link android.os.Bundle} object where you can record
the dynamic state of the activity as name-value pairs. When the activity is
@@ -1118,14 +1409,38 @@ return to the activity, so there's no reason to save its state.
</p>
<p>
-Because {@code onSaveInstanceState()} is not always called, you
-should use it only to record the transient state of the activity,
-not to store persistent data. Use {@code onPause()} for that purpose
-instead.
+Because {@code onSaveInstanceState()} is not always called, you should
+use it only to record the transient state of the activity, not to store
+persistent data. Use {@code onPause()} for that purpose instead.
+</p>
+
+
+<h4 id="coordact">Coordinating activities</h4>
+
+<p>
+When one activity starts another, they both experience lifecycle
+transitions. One pauses and may stop, while the other starts up.
+On occasion, you may need to coordinate these activities, one with
+the other.
+</p>
+
+<p>
+The order of lifecycle callbacks is well defined,
+particularly when the two activities are in the same process:
</p>
+<ol>
+<li>The current activity's {@code onPause()} method is called.</li>
+
+<li>Next, the starting activity's {@code onCreate()}, {@code onStart()},
+and {@code onResume()} methods are called in sequence.</li>
+
+<li>Then, if the starting activity is no longer visible
+on screen, its {@code onStop()} method is called.</li>
+</ol>
+
-<h3><a name="servlife"></a>Service lifecycle</h3>
+<h3 id="servlife">Service lifecycle</h3>
<p>
A service can be used in two ways:
@@ -1243,11 +1558,11 @@ no matter how it's started, can potentially allow clients to bind to it,
so any service may receive {@code onBind()} and {@code onUnbind()} calls.
</p>
-<p><img src="{@docRoot}images/service_lifecycle.png"
-alt="State diagram for Service callbacks." border="0" /></p>
+<p style="margin-left: 2em"><img src="{@docRoot}images/service_lifecycle.png"
+alt="State diagram for Service callbacks." /></p>
-<h3><a name="broadlife"></a>Broadcast receiver lifecycle</h3>
+<h3 id="broadlife">Broadcast receiver lifecycle</h3>
<p>
A broadcast receiver has single callback method:
@@ -1286,15 +1601,16 @@ The next section has more on the vulnerability of processes to being killed.
</p>
-<h3><a name="proclife"></a>Processes and lifecycles</h3>
+<h3 id="proclife">Processes and lifecycles</h3>
<p>The Android system tries to maintain an application process for as
long as possible, but eventually it will need to remove old processes when
memory runs low. To determine which processes to keep and which to kill,
Android places each process into an "importance hierarchy" based on the
-components running in it and the state of those components. There are
-five levels in the hierarchy. The following list presents them in order
-of importance:
+components running in it and the state of those components. Processes
+with the lowest importance are eliminated first, then those with the next
+lowest, and so on. There are five levels in the hierarchy. The following
+list presents them in order of importance:
</p>
<ol>
@@ -1306,7 +1622,7 @@ in the foreground if any of the following conditions hold:
<ul>
<li>It is running an activity that the user is interacting with
(the Activity object's <code>{@link android.app.Activity#onResume
-onResume()}</code> method has been called).</p></li>
+onResume()}</code> method has been called).</li>
<li><p>It hosts a service that's bound
to the activity that the user is interacting with.</p></li>
@@ -1348,16 +1664,15 @@ A visible process is considered extremely important and will not be killed
unless doing so is required to keep all foreground processes running.
</p></li>
-<li><p>A <b>service process</b> is one that is running a service that has
-been started with the
+<li><p>A <b>service process</b> is one that is running a service that
+has been started with the
<code>{@link android.content.Context#startService startService()}</code>
-method. Although service processes are not directly tied to anything the
+method and that does not fall into either of the two higher categories.
+Although service processes are not directly tied to anything the
user sees, they are generally doing things that the user cares about (such
as playing an mp3 in the background or downloading data on the network),
so the system keeps them running unless there's not enough
-memory to retain them along with all foreground and visible processes.
-(Note that a service can be ranked higher than this by virtue of being
-bound to a visible or foreground activity).
+memory to retain them along with all foreground and visible processes.
</p></li>
<li><p>A <b>background process</b> is one holding an activity
@@ -1365,8 +1680,8 @@ that's not currently visible to the user (the Activity object's
<code>{@link android.app.Activity#onStop onStop()}</code> method has been called).
These processes have no direct impact on the user experience, and can be killed
at any time to reclaim memory for a foreground, visible, or service process.
-Usually there are many background processes running,
-so they are kept in an LRU list to ensure that the process with the activity that
+Usually there are many background processes running, so they are kept in an
+LRU (least recently used) list to ensure that the process with the activity that
was most recently seen by the user is the last to be killed.
If an activity implements its lifecycle methods correctly, and captures its current
state, killing its process will not have a deleterious effect on the user experience.
diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd
index 822c66f..befb018 100644
--- a/docs/html/guide/topics/graphics/2d-graphics.jd
+++ b/docs/html/guide/topics/graphics/2d-graphics.jd
@@ -87,6 +87,13 @@ protected void onCreate(Bundle savedInstanceState) {
To do so, create a Drawable from the resource like so:
<pre>Drawable myImage = Resources.getDrawable(R.drawable.my_image);</pre>
+<p class="caution"><strong>Caution:</strong> Each unique resource in your project can maintain only one
+state, no matter how many different objects you may instantiate for it. For example, if you instantiate two
+Drawable objects from the same image resource, then change a property (such as the alpha) for one of the
+Drawables, then it will also affect the other. So when dealing with multiple instances of an image resource,
+instead of directly transforming the Drawable, you should perform a <a href="#tween-animation">tween animation</a>.</p>
+
+
<h4>Example XML</h4>
<p>The XML snippet below shows how to add a resource Drawable to an
{@link android.widget.ImageView} in the XML layout (with some red tint just for fun).
@@ -103,8 +110,8 @@ To do so, create a Drawable from the resource like so:
<h3 id="drawables-from-xml">Creating from resource XML</h3>
-<p>By now, you should be familiar with Android's principles of
-<a href="{@docRoot}guide/topics/views/index.html">Views and Layout</a>. Hence, you understand the power
+<p>By now, you should be familiar with Android's principles of developing a
+<a href="{@docRoot}guide/topics/ui/index.html">User Interface</a>. Hence, you understand the power
and flexibility inherent in defining objects in XML. This philosophy caries over from Views to Drawables.
If there is a Drawable object that you'd like to create, which is not initially dependent on variables defined by
your applicaton code or user interaction, then defining the Drawable in XML is a good option.
@@ -309,15 +316,28 @@ stretches to accommodate it.
<h2 id="tween-animation">Tween Animation</h2>
-<p>A tweened animation can perform a series of simple transformations (position, size, rotation, and transparency) on
+<p>A tween animation can perform a series of simple transformations (position, size, rotation, and transparency) on
the contents of a View object. So, if you have a TextView object, you can move, rotate, grow, or shrink the text.
-If it has a background image, the background image will be transformed along with the text.</p>
+If it has a background image, the background image will be transformed along with the text.
+The {@link android.view.animation animation package} provides all the classes used in a tween animation.</p>
-<p>The animation is achieved with a sequence of animation instructions, defined in either XML or code.
+<p>A sequence of animation instructions defines the twen animation, defined by either XML or Android code.
Like defining a layout, an XML file is recommended because it's more readable, reusable, and swappable
-than hard-coding it. In the example below, we use XML. (To define an animation in code, refer to the
+than hard-coding the animation. In the example below, we use XML. (To learn more about defining an animation
+in your application code, instead of XML, refer to the
{@link android.view.animation.AnimationSet} class and other {@link android.view.animation.Animation} subclasses.)</p>
+<p>The animation instructions define the transformations that you want to occur, when they will occur,
+and how long they should take to apply. Transformations can be sequential or simultaneous &mdash;
+for example, you can have the contents of a TextView move from left to right, and then
+rotate 180 degrees, or you can have the text move and rotate simultaneously. Each transformation
+takes a set of parameters specific for that transformation (starting size and ending size
+for size change, starting angle and ending angle for rotation, and so on), and
+also a set of common parameters (for instance, start time and duration). To make
+several transformations happen simultaneously, give them the same start time;
+to make them sequential, calculate the start time plus the duration of the preceding transformation.
+</p>
+
<p>The animation XML file belongs in the <code>res/anim/</code> directory of your Android project.
The file must have a single root element: this will be either a single <code>&lt;alpha&gt;</code>,
<code>&lt;scale&gt;</code>, <code>&lt;translate&gt;</code>, <code>&lt;rotate&gt;</code>, interpolator element,
@@ -389,22 +409,23 @@ spaceshipImage.startAnimation(hyperspaceJumpAnimation);
<p>As an alternative to <code>startAnimation()</code>, you can define a starting time for the animation with
<code>{@link android.view.animation.Animation#setStartTime(long) Animation.setStartTime()}</code>,
then assign the animation to the View with
-<code>{@link android.view.View#setAnimation(android.view.animation.Animation) View.setAnimation()}</code>.</p>
+<code>{@link android.view.View#setAnimation(android.view.animation.Animation) View.setAnimation()}</code>.
+</p>
<p>For more information on the XML syntax, available tags and attributes, see the discussion on animation
in the <a href="{@docRoot}guide/topics/resources/available-resources.html#animation">Available Resources</a>.</p>
-<p class="note"><strong>Note:</strong> Animations are drawn in the area designated for the View at the start of
-the animation; this area does not change to accommodate size or movement, so if your animation moves or expands
-outside the original boundaries of your object, it will be clipped to the size of the original View, even if
-the object's LayoutParams are set to WRAP_CONTENT (the object will not resize to accommodate moving or
-expanding/shrinking animations).</p>
+<p class="note"><strong>Note:</strong> Regardless of how your animation may move or resize, the bounds of the
+View that holds your animation will not automatically adjust to accomodate it. Even so, the animation will still
+be drawn beyond the bounds of its View and will not be clipped. However, clipping <em>will occur</em>
+if the animation exceeds the bounds of the parent View.</p>
<h2 id="frame-animation">Frame Animation</h2>
<p>This is a traditional animation in the sense that it is created with a sequence of different
-images, played in order, like a roll of film.</p>
+images, played in order, like a roll of film. The {@link android.graphics.drawable.AnimationDrawable}
+class is the basis for frame animations.</p>
<p>While you can define the frames of an animation in your code, using the
{@link android.graphics.drawable.AnimationDrawable} class API, it's more simply accomplished with a single XML
@@ -426,7 +447,7 @@ Here's an example XML file for a frame-by-frame animation:</p>
<p>This animation runs for just three frames. By setting the <code>android:oneshot</code> attribute of the
list to <var>true</var>, it will cycle just once then stop and hold on the last frame. If it is set <var>false</var> then
-the animation will loop. With this XML saved as <code>rocket_thrust.xml</p> in the <code>res/anim/</code> directory
+the animation will loop. With this XML saved as <code>rocket_thrust.xml</code> in the <code>res/anim/</code> directory
of the project, it can be added as the background image to a View and then called to play. Here's an example Activity,
in which the animation is added to an {@link android.widget.ImageView} and then animated when the screen is touched:</p>
<pre>
@@ -454,6 +475,6 @@ called during the <code>onCreate()</code> method of your Activity, because the A
to the window. If you want to play the animation immediately, without
requiring interaction, then you might want to call it from the
<code>{@link android.app.Activity#onWindowFocusChanged(boolean) onWindowFocusChanged()}</code> method in
-your Activity, which will get called when Android brings your window into focus.</p>
+your Activity, which will get called when Android brings your window into focus.</p>
diff --git a/docs/html/guide/topics/graphics/index.jd b/docs/html/guide/topics/graphics/index.jd
index 388acc9..bc2a8bf 100644
--- a/docs/html/guide/topics/graphics/index.jd
+++ b/docs/html/guide/topics/graphics/index.jd
@@ -1,21 +1,203 @@
-page.title=2D and 3D Graphics
+page.title=Graphics
@jd:body
-
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#options">Consider your Options</a></li>
+ <li><a href="#draw-to-view">Simple Graphics Inside a View</a></li>
+ <li><a href="#draw-with-canvas">Draw with a Canvas</a>
+ <ol>
+ <li><a href="#on-view">On a View</a></li>
+ <li><a href="#on-surfaceview">On a SurfaceView</a></li>
+ </ol>
+ </li>
+ </ol>
+ </div>
+</div>
<p>Android graphics are powered by a custom 2D graphics library and OpenGL ES 1.0
-for 3D graphics.</p>
-
-<h2>2D Graphics</h2>
-<p>Android offers a custom 2D graphics library for drawing shapes and images.</p>
-<p>The {@link android.graphics} and {@link android.graphics.drawable}
-packages are where you'll find the classes used for drawing in two-dimensions.
-For common drawing tasks, though, the {@link android.graphics.drawable} package
-is where you'll find what you need.</p>
-<p>For an introduction to drawing shapes and images, read the
-<a href="2d-graphics.html">2D Graphics</a> document.</p>
-
-
-<h2>3D with OpenGL</h2>
-<p>High performance 3D graphic utilities are provided on Android with the OpenGL ES API.
-You'll find the OpenGL APIs in the {@link android.opengl} package.
-Read more about <a href="opengl.html">3D with OpenGL</a>.</p> \ No newline at end of file
+for high performance 3D graphics. The most common 2D graphics APIs can be found in the
+{@link android.graphics.drawable drawable package}. OpenGL APIs are available
+from the Khronos {@link javax.microedition.khronos.opengles OpenGL ES package},
+plus some Android {@link android.opengl OpenGL utilities}.</p>
+
+<p>When starting a project, it's important to consider exactly what your graphical demands will be.
+Varying graphical tasks are best accomplished with varying techniques. For example, graphics and animations
+for a rather static application should be implemented much differently than graphics and animations
+for an interactive game or 3D rendering.</p>
+
+<p>Here, we'll discuss a few of the options you have for drawing graphics on Android,
+and which tasks they're best suited for.</p>
+
+<p>If you're specifically looking for information on drawing 3D graphics, this page won't
+help a lot. However, the information below, on <a href="#drawing-with-canvas">Drawing with a Canvas</a>
+(and the section on SurfaceView),
+will give you a quick idea of how you should draw to the View hierarchy. For more information
+on Android's 3D graphic utilities (provided by the OpenGL ES API),
+read <a href="opengl.html">3D with OpenGL</a> and refer to other OpenGL documentation.</p>
+
+
+<h2 id="options">Consider your Options</h2>
+
+<p>When drawing 2D graphics, you'll typically do so in one of two ways:</p>
+<ol type="a">
+ <li>Draw your graphics or animations into a View object from your layout. In this manner,
+ the drawing (and any animation) of your graphics is handled by the system's
+ normal View hierarchy drawing process &mdash; you simply define the graphics to go inside the View.</li>
+ <li>Draw your graphics directly to a Canvas. This way, you personally call the appropriate class's
+ <code>draw()</code> method (passing it your Canvas), or one of the Canvas <code>draw...()</code> methods (like
+ <code>{@link android.graphics.Canvas#drawPicture(Picture,Rect) drawPicture()}</code>). In doing so, you are also in
+ control of any animation.</li>
+</ol>
+
+<p>Option "a," drawing to a View, is your best choice when you want to draw simple graphics that do not
+need to change dynamically and are not part of a performance-intensive game. For example, you should
+draw your graphics into a View when you want to display a static graphic or predefined animation, within
+an otherwise static application. Read <a href="#draw-to-view">Simple Graphics Inside a View</a>.</li>
+
+<p>Option "b," drawing to a Canvas, is better when you're application needs to regularly re-draw itself.
+Basically, any video game should be drawing to the Canvas on its own. However, there's more than
+one way to do this: </p>
+<ul>
+ <li>In the same thread as your UI Activity, wherein you create a custom View component in
+ your layout, call <code>{@link android.view.View#invalidate()}</code> and then handle the
+ <code>{@link android.view.View#onDraw(Canvas) onDraw()}</code> callback..</li>
+ <li>Or, in a separate thread, wherein you manage a {@link android.view.SurfaceView} and
+ perform draws to the Canvas as fast as your thread is capable
+ (you do not need to request <code>invalidate()</code>).</li>
+</ul>
+<p>...Begin by reading <a href="#draw-with-canvas">Draw with a Canvas</a>.</p>
+
+<h2 id="draw-to-view">Simple Graphics Inside a View</h2>
+
+<p>If you'll be drawing some simple graphics (images, shapes, colors, pre-defined animations, etc.),
+then you should probably just draw to the background of a View or
+to the content of an {@link android.widget.ImageView} in your layout.
+In this case, you can skip the rest of this document and learn how to
+draw graphics and animations in the <a href="2d-graphics.html">2D Graphics</a> document.
+</p>
+
+
+<h2 id="draw-with-canvas">Draw with a Canvas</h2>
+
+<p>When you're writing an application in which you would like to perform specialized drawing
+and/or control the animation of graphics,
+you should do so by drawing through a {@link android.graphics.Canvas}. A Canvas works for you as
+a pretense, or interface, to the actual surface upon which your graphics will be drawn &mdash; it
+holds all of your "draw" calls. Via the Canvas, your drawing is actually performed upon an
+underlying {@link android.graphics.Bitmap}, which is placed into the window.</p>
+
+<p>In the event that you're drawing within the <code>{@link android.view.View#onDraw(Canvas) onDraw()}</code>
+callback method, the Canvas is provided for you and you need only place your drawing calls upon it.
+You can also acquire a Canvas from <code>{@link android.view.SurfaceHolder#lockCanvas() SurfaceHolder.lockCanvas()}</code>,
+when dealing with a SurfaceView object. (Both of these scenarios are discussed in the following sections.)
+However, if you need to create a new Canvas, then you must define the {@link android.graphics.Bitmap}
+upon which drawing will actually be performed. The Bitmap is always required for a Canvas. You can set up
+a new Canvas like this:</p>
+<pre>
+Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
+Canvas c = new Canvas(b);
+</pre>
+
+<p>Now your Canvas will draw onto the defined Bitmap. After drawing upon it with the Canvas, you can then carry your
+Bitmap to another Canvas with one of the <code>{@link android.graphics.Canvas#drawBitmap(Bitmap,Matrix,Paint)
+Canvas.drawBitmap(Bitmap,...)}</code> methods. It's recommended that you ultimately draw your final
+graphics through a Canvas offered to you
+by <code>{@link android.view.View#onDraw(Canvas) View.onDraw()}</code> or
+<code>{@link android.view.SurfaceHolder#lockCanvas() SurfaceHolder.lockCanvas()}</code> (see the following sections).</p>
+
+<p>The {@link android.graphics.Canvas} class has its own set of drawing methods that you can use,
+like <code>drawBitmap(...)</code>, <code>drawRect(...)</code>, <code>drawText(...)</code>, and many more.
+Other classes that you might use also have <code>draw()</code> methods. For example, you'll probably
+have some {@link android.graphics.drawable.Drawable} objects that you want to put on the Canvas. Drawable
+has its own <code>{@link android.graphics.drawable.Drawable#draw(Canvas) draw()}</code> method
+that takes your Canvas as an arguement.</p>
+
+
+<h3 id="on-view">On a View</h3>
+
+<p>If you're application does not require a significant amount of processing or
+frame-rate speed (perhaps for a chess game, a snake game,
+or another slowly-animated application), then you should consider creating a custom View component
+and drawing with a Canvas in <code>{@link android.view.View#onDraw(Canvas) View.onDraw()}</code>.
+The most convenient aspect of doing so is that the Android framework will
+provide you with a pre-defined Canvas to which you will place your drawing calls.</p>
+
+<p>To start, extend the {@link android.view.View} class (or descendent thereof) and define
+the <code>{@link android.view.View#onDraw(Canvas) onDraw()}</code> callback method. This method will be called by the Android
+framework to request that your View draw itself. This is where you will perform all your calls
+to draw through the {@link android.graphics.Canvas}, which is passed to you through the <code>onDraw()</code> callback.</p>
+
+<p>The Android framework will only call <code>onDraw()</code> as necessary. Each time that
+your application is prepared to be drawn, you must request your View be invalidated by calling
+<code>{@link android.view.View#invalidate()}</code>. This indicates that you'd like your View to be drawn and
+Android will then call your <code>onDraw()</code> method (though is not guaranteed that the callback will
+be instantaneous). </p>
+
+<p>Inside your View component's <code>onDraw()</code>, use the Canvas given to you for all your drawing,
+using various <code>Canvas.draw...()</code> methods, or other class <code>draw()</code> methods that
+take your Canvas as an argument. Once your <code>onDraw()</code> is complete, the Android framework will
+use your Canvas to draw a Bitmap handled by the system.</p>
+
+<p class="note"><strong>Note: </strong> In order to request an invalidate from a thread other than your main
+Activity's thread, you must call <code>{@link android.view.View#postInvalidate()}</code>.</p>
+
+<p>Also read <a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a>
+for a guide to extending a View class, and <a href="2d-graphics.html">2D Graphics: Drawables</a> for
+information on using Drawable objects like images from your resources and other primitive shapes.</p>
+
+<p>For a sample application, see the Snake game, in the SDK samples folder:
+<code>&lt;your-sdk-directory>/samples/Snake/</code>.</p>
+
+<h3 id="on-surfaceview">On a SurfaceView</h3>
+
+<p>The {@link android.view.SurfaceView} is a special subclass of View that offers a dedicated
+drawing surface within the View hierarchy. The aim is to offer this drawing surface to
+an application's secondary thread, so that the application isn't required
+to wait until the system's View hierarchy is ready to draw. Instead, a secondary thread
+that has reference to a SurfaceView can draw to its own Canvas at its own pace.</p>
+
+<p>To begin, you need to create a new class that extends {@link android.view.SurfaceView}. The class should also
+implement {@link android.view.SurfaceHolder.Callback}. This subclass is an interface that will notify you
+with information about the underlying {@link android.view.Surface}, such as when it is created, changed, or destroyed.
+These events are important so that you know when you can start drawing, whether you need
+to make adjustments based on new surface properties, and when to stop drawing and potentially
+kill some tasks. Inside your SurfaceView class is also a good place to define your secondary Thread class, which will
+perform all the drawing procedures to your Canvas.</p>
+
+<p>Instead of handling the Surface object directly, you should handle it via
+a {@link android.view.SurfaceHolder}. So, when your SurfaceView is initialized, get the SurfaceHolder by calling
+<code>{@link android.view.SurfaceView#getHolder()}</code>. You should then notify the SurfaceHolder that you'd
+like to receive SurfaceHolder callbacks (from {@link android.view.SurfaceHolder.Callback}) by calling
+{@link android.view.SurfaceHolder#addCallback(SurfaceHolder.Callback) addCallback()}
+(pass it <var>this</var>). Then override each of the
+{@link android.view.SurfaceHolder.Callback} methods inside your SurfaceView class.</p>
+
+<p>In order to draw to the Surface Canvas from within your second thread, you must pass the thread your SurfaceHandler
+and retrieve the Canvas with <code>{@link android.view.SurfaceHolder#lockCanvas() lockCanvas()}</code>.
+You can now take the Canvas given to you by the SurfaceHolder and do your necessary drawing upon it.
+Once you're done drawing with the Canvas, call
+<code>{@link android.view.SurfaceHolder#unlockCanvasAndPost(Canvas) unlockCanvasAndPost()}</code>, passing it
+your Canvas object. The Surface will now draw the Canvas as you left it. Perform this sequence of locking and
+unlocking the canvas each time you want to redraw.</p>
+
+<p class="note"><strong>Note:</strong> On each pass you retrieve the Canvas from the SurfaceHolder,
+the previous state of the Canvas will be retained. In order to properly animate your graphics, you must re-paint the
+entire surface. For example, you can clear the previous state of the Canvas by filling in a color
+with <code>{@link android.graphics.Canvas#drawColor(int) drawColor()}</code> or setting a background image
+with <code>{@link android.graphics.Canvas#drawBitmap(Bitmap,Rect,RectF,Paint) drawBitmap()}</code>. Otherwise,
+you will see traces of the drawings you previously performed.</p>
+
+
+<p>For a sample application, see the Lunar Landar game, in the SDK samples folder:
+<code>&lt;your-sdk-directory>/samples/LunarLander/</code>. Or,
+browse the source in the <a href="{@docRoot}guide/samples/index.html">Sample Code</a> section.</p>
+
+
+
+
+
+
+
+
diff --git a/docs/html/guide/topics/intents/intents-filters.jd b/docs/html/guide/topics/intents/intents-filters.jd
index d49d27e..fd20ca1 100644
--- a/docs/html/guide/topics/intents/intents-filters.jd
+++ b/docs/html/guide/topics/intents/intents-filters.jd
@@ -399,7 +399,7 @@ IntentFilter objects.)
</p>
<div class="sidebox-wrapper">
-<div class="sidebox">
+<div class="sidebox-inner">
<h2>Filters and security</h2>
<p>An intent filter cannot be relied on for security. While it opens a
component to receiving only certain kinds of implicit intents, it does
diff --git a/docs/html/guide/topics/location/geo/mapkey.jd b/docs/html/guide/topics/location/geo/mapkey.jd
index 110876f..9aa824c 100644
--- a/docs/html/guide/topics/location/geo/mapkey.jd
+++ b/docs/html/guide/topics/location/geo/mapkey.jd
@@ -1,28 +1,210 @@
-page.title=Obtaining a MapView API Key
+page.title=Obtaining a Maps API Key
@jd:body
-<p>{@link-fixme com.google.android.maps.MapView} is a very useful class that lets you easily integrate Google Maps into your application. It provides built-in map downloading, rendering, and caching, as well as a variety of display options and controls. It provides a wrapper around the Google Maps API that lets your application request and manipulate Google Maps data through class methods, and it lets you work with Maps data as you would other types of Views. </p>
+<div class="sidebox"><p>To register for a Maps API Key, read this document and then go to the <a href="http://code.google.com/android/maps-api-signup.html">Android Maps API Key Signup</a> page.</p>
-<p>Because MapView gives you access to Google Maps data, you need to register your application with the Google Maps service and agree to the applicable Terms of Service, before your MapView will be able to obtain data from Google Maps. This will apply whether you are developing your application on the emulator or preparing your application for deployment to mobile devices. </p>
+</div>
-<p>Registering your application is simple, and has two parts: </p>
+<p>com.google.android.maps.MapView is a very useful class that lets you easily integrate Google Maps into your application. It provides built-in map downloading, rendering, and caching of Maps tiles, as well as a variety of display options and controls. It provides a wrapper around the Google Maps API that lets your application request and manipulate Google Maps data through class methods, and it lets you work with Maps data as you would other types of Views. </p>
+
+<p>Because MapView gives you access to Google Maps data, you need to register with the Google Maps service and agree to the applicable Terms of Service before your MapView will be able to obtain data from Google Maps. This will apply whether you are developing your application on the emulator or preparing your application for deployment to mobile devices. </p>
+
+<p>Registering for a Maps API Key is simple, free, and has two parts: </p>
<ol>
-<li>Registering a public key fingerprint from the certificate that you will use to sign the .apk. The registration service then provides you a Maps API Key that is associated with your application's signer certificate. </li>
-<li>Adding the Maps API Key to a special attribute of the MapView element &mdash; <code>android:apiKey</code>. You can use the same Maps API Key for any MapView in any application, provided that the application's .apk is signed with the certificate whose fingerprint you registered with the service. </li>
+<li>Registering the MD5 fingerprint of the certificate that you will use to sign your application. The Maps registration service then provides you a Maps API Key that is associated with your application's signer certificate. </li>
+<li>Adding a reference to the Maps API Key in each MapView, whether declared in XML or instantiated directly from code. You can use the same Maps API Key for any MapView in any Android application, provided that the application is signed with the certificate whose fingerprint you registered with the service. </li>
</ol>
-<p>Once you have registered your application as described above, your MapView will be able to retrieve data from the Google Maps servers. </p>
+<p>During registration, you also need to agree to the Maps API Terms of Service, which describe how your application can use the Maps data. In general, the terms of service are permissive and place few restrictions on how you can use the data. For example, the terms allow you to build "friend finder" type applications. </p>
+
+<p>The sections below describe how to obtain your Maps API Key and how to reference it from your MapView elements. </p>
+
+<ul>
+<li><a href="#overview">Overview</a></li>
+<li><a href="#getfingerprint">Getting the MD5 Fingerprint of Your Signing Certificate</a></li>
+<li><a href="#getdebugfingerprint">Getting the MD5 Fingerprint of the SDK Debug Certificate</a></li>
+<li><a href="#registering">Registering the Certificate Fingerprint with the Google Maps Service</a></li>
+<li><a href="#addingkey">Adding the Maps API Key to your Application</a></li>
+<li><a href="#finalsteps">Final Steps to Enable MapView Elements</a></li>
+</ul>
+
+<h2 id="overview">Overview</h2>
+
+<p>MapView objects are views that display Maps tiles downloaded from the Google Maps service. To ensure that applications use Maps data in an appropriate manner, the Google Maps service requires application developers to register with the service, agreeing to the Terms of Service and supplying an MD5 fingerprint of the certificate(s) that they will use to sign applications. For each registered certificate fingerprint, the service then provides the developer with a Maps API Key &mdash; an alphanumeric string that uniquely identifies the certificate and developer registered with the service. </p>
+
+<p>The Google Maps service also requires that each MapView identify itself to the service using a Maps API Key. Before providing Maps tiles to a MapView, the service checks the Maps API Key supplied by the MapView to ensure that it:</p>
+<ul>
+<li>References a certificate/developer registered with the service, and </li>
+<li>References a certificate that matches the certificate with which the application (containing the MapView) was signed. </li>
+</ul>
+
+<p>Unless both conditions are met, the service does not provide Maps tiles to the MapView. </p>
+
+<p>Each MapView object in your application must reference a Maps API Key. Since the Key is associated with a certificate, all Mapview elements in an application should reference the same Key. Going a step further, all MapView elements in all applications that you sign with the same certificate should reference the same Key. </p>
+
+<p>On the other hand, you can register for multiple Maps API Keys, each being associated with a specific certificate. You would want to do this if, for example, you were developing several independent applications that you will sign using different certificates. In this case, note that all MapView elements in a given application can reference the same Maps API Key, but <em>must</em> reference the Key that is associated with the certificate used to sign the application. </p>
+
+<p>Because MapView elements must refer to a Maps API Key, you need to register your certificate and receive a Key before you can make use of MapView elements in your application. To make it easier for you to get started using MapView elements, you are welcome to register the debug certificate generated by the SDK tools and receive a temporary Maps API Key. The details of how to do that are given below. </p>
+
+<p>When you are preparing to release your application, however, note that you <em>must</em> sign your application with a suitable cryptographic key, rather than the SDK debug key. That means that you will also need to register your application's release certificate with the Google Maps service. After you've done so, you will receive a new Maps API Key that is uniquely associated with your release certificate. To enable the MapView elements in your application to work after release, you must remember to change the Maps API Key for all MapViews in your application so that they refer to the Key associated with your release certificate (rather than your debug certificate). </p>
+
+<p>To summarize, the important points to understand about MapViews and the Maps API Key are: </p>
+
+<ul>
+<li>To display Maps data in a MapView, you need to register for a Maps API Key</li>
+<li>Each Maps API Key is uniquely associated with a specific certificate, based on an MD5 fingerprint of the certificate </li>
+<li>Each MapView must reference a Maps API Key, and the Key referenced must be registered to the certificate used to sign the application</li>
+<li>All MapView elements in an application can reference the same Maps API Key</li>
+<li>You can register multiple certificates under your developer identity</li>
+<li>You can get a temporary Maps API Key based on your debug certificate, but before you publish your application, you must register for a new Key based on your release certificate and update references in your MapViews accordingly</li>
+</ul>
+
+<h2 id="getfingerprint">Getting the MD5 Fingerprint of Your Signing Certificate</h2>
+
+<div class="sidebox">
+For more information about using Keytool and Jarsigner to sign your application, see <a href="{@docRoot}guide/publishing/app-signing.html">Signing Your Applications</a>.
+</div>
+
+<p>To register for a Maps API Key, you need to provide an MD5 fingerprint of the certificate that you will use to sign your application. </p>
+
+<p>Before you visit the registration page, use Keytool to generate the fingerprint of the appropriate certificate.
+
+<p>First, determine which key you will use to sign your application at release and make sure of the path to the keystore that contains it.</p>
+
+<p>Next, run Keytool with the <code>-list</code> option, against the target keystore and key alias. The table below lists the options you should use.</p>
+
+<table>
+<tr>
+<th>Keytool Option</th>
+<th>Description</th>
+</tr>
+<tr>
+<td><code>-list</code></td><td>Print an MD5 fingerprint of a certificate.</td>
+</tr>
+<tr>
+<td><code>-keystore&nbsp;&lt;keystore-name&gt;.keystore</code></td><td>The name of the keystore containing the target key.</td>
+</tr>
+<tr>
+<td><code>-storepass &lt;password&gt;</code></td><td><p>A password for the
+keystore.</p><p>As a security precaution, do not include this option
+in your command line unless you are working at a secure computer.
+If not supplied, Keytool prompts you to enter the password. In this
+way, your password is not stored in your shell history.</p></td>
+</tr>
+<tr>
+<td><code>-alias &lt;alias_name&gt;</code></td><td>The alias for the key for which to generate the MD5 certificate fingerprint.</td>
+</tr>
+<tr>
+<td><code>-keypass &lt;password&gt;</code></td><td><p>The password for the key.</p>
+<p>As a security precaution, do not include this option
+in your command line unless you are working at a secure computer.
+If not supplied, Keytool prompts you to enter the password. In this
+way, your password is not stored in your shell history.</p></td>
+</tr>
+</table>
+
+<p>Here's an example of a Keytool command that generates an MD5 certificate fingerprint for the key <code>alias_name</code> in the keystore <code>my-release-key.keystore</code>:</p>
+
+<pre>$ keytool -list -alias alias_name -keystore my-release-key.keystore</pre>
+
+<p>Keytool will prompt you to enter passwords for the keystore and key. As output of the command, Keytool prints the fingerprint to the shell. For example:</p>
+
+<pre>Certificate fingerprint (MD5): 94:1E:43:49:87:73:BB:E6:A6:88:D7:20:F1:8E:B5:98</pre>
+
+<p>Note that, if you happen to forget your Maps API Key, you can repeat the process described above and register the fingerprint again. The server will give you the same key for the specified certificate fingerprint.</p>
+
+<p>Once you have the fingerprint, you can go to the Maps API registration site, described next.</p>
+
+<h2 id="getdebugfingerprint">Getting the MD5 Fingerprint of the SDK Debug Certificate</h2>
-<div class="special">
-<p>The MapView registration service is not yet active and Google Maps is not yet enforcing the Maps API Key requirement. The registration service will be activated soon, so that MapViews in any application deployed to a mobile device will require registration and a valid Maps API Key.</p>
+<p>While you are developing and debugging your application, you will likely be
+sigining your application in debug mode &mdash; that is, the SDK build tools
+will automatically sign your application using the debug certificate. To let
+your MapView elements properly display Maps data during this period, you should
+obtain a temporary Maps API Key registered to the debug certificate. To do so,
+you first need to get the MD5 fingerprint of the debug certificate. When
+you are ready to release your application, you must register your release
+certificate with the Google Maps service and obtain a new Maps API Key. You must
+then change the MapView elements in your application to reference the new API
+key. </p>
-<p>As soon as the registration service becomes available, this page (<a href="http://code.google.com/android/toolbox/apis/mapkey.html">http://code.google.com/android/toolbox/apis/mapkey.html</a>) will be updated with details about how and where to register and how to add your Maps API Key to your application. </p>
+<p>To generate an MD5 fingerprint of the debug certificate, first locate the debug keystore. The location at which the SDK tools create the default debug keystore varies by platform: </p>
-<p>In the meantime, you can continue developing your MapView without registration, provided that you:</p>
-<ol type="a">
-<li>Add the attribute "android:apiKey" to the MapView element in your layout XML, with any value. Or</li>
-<li>Include an arbitrary string in the <code>apikey</code> parameter of the MapView constructor, if creating the MapView programmatically. </li>
+<ul>
+<li>Windows Vista: <code>C:\Users\&lt;user&gt;\AppData\Local\Android\debug.keystore</code></li>
+<li>Windows XP: <code>C:\Documents and Settings\&lt;user&gt;\Local Settings\Application&nbsp;Data\Android\debug.keystore</code></li>
+<li>OS X and Linux: <code>~/.android/debug.keystore</code></li>
+</ul>
+
+<p>If you are using Eclipse/ADT and are unsure where the debug keystore is located, you can select <strong>Windows</strong> &gt; <strong>Prefs</strong> &gt; <strong>Android</strong> &gt; <strong>Build</strong> to check the full path, which you can then paste into a file explorer to locate the directory containing the keystore.</p>
+
+<p>Once you have located the keystore, use this Keytool command to get the MD5 fingerprint of the debug certificate:</p>
+
+<pre>$ keytool -list -alias androiddebugkey \
+-keystore &lt;path_to_debug_keystore&gt;.keystore \
+-storepass android -keypass android</pre>
+
+<h2 id="registering">Registering the Certificate Fingerprint with the Google Maps Service</h2>
+
+<p>When you are ready to register for a Maps API Key, load this page in a browser: </p>
+
+<p><a href="http://code.google.com/android/maps-api-signup.html">http://code.google.com/android/maps-api-signup.html</a></p>
+
+<p>To register for a Maps API Key, follow these steps:</p>
+
+<ol>
+<li>If you don't have a Google account, use the link on the page to set one up. </li>
+<li>Read the Android Maps API Terms of Service carefully. If you agree to the terms, indicate so using the checkbox on the screen. </li>
+<li>Paste the MD5 certificate fingerprint of the certificate that you are registering into the appropriate form field.</li>
+<li>Click "Generate API Key"</li>
</ol>
-<p>When the Maps API Key checking is activated in the service, any MapViews that do not have a properly registered apiKey will stop working. The map data (tile images) of the MapView will never load (even if the device is on the network). In this case, go to the page linked above and read about how to register your certificate fingerprint and obtain a Maps API Key. </p>
+<p>The server will handle your request, associating the fingerprint with your developer identity and generating a unique Maps API Key, then returning a results page that gives you your Key string. </p>
+
+<p>To use the Maps API Key string, copy and paste it into your code as described in the next section.</p>
+
+<h2 id="addingkey">Adding the Maps API Key to your Application</h2>
+
+<p>Once you've registered with the Google Maps service and have obtained a Maps API Key, you must add it to your application's MapView objects, so that the Maps server will allow them to download Maps tiles. </p>
+
+<p>For <code>&lt;MapView&gt;</code> elements declared in XML layout files, add the Maps API Key as the value of a special attribute &mdash; <code>android:apiKey</code>. For example: </li>
+
+<pre>&lt;com.google.android.maps.MapView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:enabled="true"
+ android:clickable="true"
+ android:apiKey="example_Maps_ApiKey_String"
+ /&gt;</pre>
+</li>
+
+<p>For MapView objects instantiated directly from code, pass the Maps API Key string as a parameter in the constructor. For example: </p>
+
+<pre>mMapView = new MapView(this, "example_Maps_ApiKey_String");</pre>
+
+<p>For more information about MapView, see the MapView class Documentation. </p>
+
+<h2 id="finalsteps">Final Steps to Enable MapView Elements</h2>
+
+<p>If you've added the Maps API Key to the MapViews in your application, here are the final steps to enable the MapView elements to run properly:</p>
+
+<ul>
+<li>Make sure that you added a <code>&lt;uses-library&gt;</code> element referencing the external <code>com.google.android.maps</code> library. The element must be a child of the <code>&lt;application&gt;</code> element in the application's manifest. For example:
+
+<p><pre>&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.package.name"&gt;
+ ...
+ &lt;application android:name="MyApplication" &gt;
+ &lt;uses-library android:name="com.google.android.maps" /&gt;
+ ...
+ &lt;/application&gt;</pre></p></li>
+
+<li>Sign your application with the certificate that corresponds to the Maps API Key referenced in your MapView elements. </li>
+
+</ul>
+
+<div class="special"><p>Note that, when you are ready to publish your application, you must get a Maps API Key that is based on the certificate that you will use to sign the application for release. You must then change the Maps API Key string referenced by all of your MapView elements, so that they reference the new Key. </p></div>
+
+
+
diff --git a/docs/html/guide/topics/location/index.jd b/docs/html/guide/topics/location/index.jd
index eeaab39..53f1d29 100644
--- a/docs/html/guide/topics/location/index.jd
+++ b/docs/html/guide/topics/location/index.jd
@@ -95,7 +95,7 @@ MapView must extend {@link-fixme com.google.android.maps.MapActivity}. </p>
<p>Also note that you must obtain a MapView API Key from the Google Maps
service, before your MapView can load maps data. For more information, see
-<a href="{@docRoot}guide/developing/mapkey.html">Obtaining a MapView API Key</a>.</p>
+<a href="{@docRoot}guide/topics/location/geo/mapkey.html">Obtaining a MapView API Key</a>.</p>
<p>Once you've created a MapView, you'll probably want to use
{@link-fixme com.google.android.maps.MapView#getController()} to
diff --git a/docs/html/guide/topics/manifest/action-element.jd b/docs/html/guide/topics/manifest/action-element.jd
new file mode 100644
index 0000000..bc2e1d3
--- /dev/null
+++ b/docs/html/guide/topics/manifest/action-element.jd
@@ -0,0 +1,46 @@
+page.title=&lt;action&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;action android:<a href="#nm">name</a>="<i>string</i>" /&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code></dd>
+
+<p>
+<dt>description:</dt>
+<dd>Adds an action to an intent filter.
+An <code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> element must contain
+one or more {@code &lt;action&gt;} elements. If it doesn't contain any, no
+Intent objects will get through the filter. See
+<a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and
+Intent Filters</a> for details on intent filters and the role of action
+specifications within a filter.
+</dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The name of the action. Some standard actions are defined in the
+{@link android.content.Intent#ACTION_CHOOSER Intent} class as
+{@code ACTION_<i>string</i>} constants. To assign one of these actions to
+this attribute, prepend "{@code android.intent.action.}" to the
+{@code <i>string</i>} that follows {@code ACTION_}.
+For example, for {@code ACTION_MAIN}, use "{@code android.intent.action.MAIN}"
+and for {@code ACTION_WEB_SEARCH}, use "{@code android.intent.action.WEB_SEARCH}".
+
+<p>
+For actions you define, it's best to use the package name as a prefix to
+ensure uniqueness. For example, a {@code TRANSMOGRIFY} action might be specified
+as follows:
+</p>
+
+<pre>&lt;action android:name="com.example.project.TRANSMOGRIFY" /&gt;</pre>
+</dd>
+</dl></dd>
+
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code></dd>
+
+</dl> \ No newline at end of file
diff --git a/docs/html/guide/topics/manifest/activity-alias-element.jd b/docs/html/guide/topics/manifest/activity-alias-element.jd
new file mode 100644
index 0000000..9d81d50
--- /dev/null
+++ b/docs/html/guide/topics/manifest/activity-alias-element.jd
@@ -0,0 +1,129 @@
+page.title=&lt;activity-alias&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;activity-alias android:<a href="#enabled">enabled</a>=["true" | "false"]
+ android:<a href="#exported">exported</a>=["true" | "false"]
+ android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+ android:<a href="#label">label</a>="<i>string resource</i>"
+ android:<a href="#nm">name</a>="<i>string</i>"
+ android:<a href="#prmsn">permission</a>="<i>string</i>"
+ android:<a href="#trgt">targetActivity</a>="<i>string</i>" &gt;
+ . . .
+&lt;/activity-alias&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code></dd>
+
+<dt>can contain:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>An alias for an activity, named by the {@code targetActivity}
+attribute. The target must be in the same application as the
+alias and it must be declared before the alias in the manifest.
+
+<p>
+The alias presents the target activity as a independent entity.
+It can have its own set of intent filters, and they, rather than the
+intent filters on the target activity itself, determine which intents
+can activate the target through the alias and how the system
+treats the alias. For example, the intent filters on the alias may
+specify the "<code>{@link android.content.Intent#ACTION_MAIN
+android.intent.action.MAIN}</code>"
+and "<code>{@link android.content.Intent#CATEGORY_LAUNCHER
+android.intent.category.LAUNCHER}</code>" flags, causing it to be
+represented in the application launcher, even though none of the
+filters on the target activity itself set these flags.
+</p>
+
+<p>
+With the exception of {@code targetActivity}, {@code &lt;activity-alias&gt;}
+attributes are a subset of <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> attributes.
+For attributes in the subset, none of the values set for the target carry over
+to the alias. However, for attributes not in the subset, the values set for
+the target activity also apply to the alias.
+</p></dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="enabled"></a>{@code android:enabled}</dt>
+<dd>Whether or not the target activity can be instantiated by the system through
+this alias &mdash; "{@code true}" if it can be, and "{@code false}" if not.
+The default value is "{@code true}".
+
+<p>
+The <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element has its own
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#enabled">enabled</a></code> attribute that applies to all
+application components, including activity aliases. The
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> and {@code &lt;activity-alias&gt;}
+attributes must both be "{@code true}" for the system to be able to instantiate
+the target activity through the alias. If either is "{@code false}", the alias
+does not work.
+</p></dd>
+
+<dt><a name="exported"></a>{@code android:exported}</dt>
+<dd>Whether or not components of other applications can launch the target activity
+through this alias &mdash; "{@code true}" if they can, and "{@code false}" if not.
+If "{@code false}", the target activity can be launched through the alias only by
+components of the same application as the alias or applications with the same user ID.
+
+<p>
+The default value depends on whether the alias contains intent filters. The
+absence of any filters means that the activity can be invoked through the alias
+only by specifying the exact name of the alias. This implies that the alias
+is intended only for application-internal use (since others would not know its name)
+&mdash; so the default value is "{@code false}".
+On the other hand, the presence of at least one filter implies that the alias
+is intended for external use &mdash; so the default value is "{@code true}".
+</p></dd>
+
+<dt><a name="icon"></a>{@code android:icon}</dt>
+<dd>An icon for the target activity when presented to users through the alias.
+See the <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#icon">icon</a></code> attribute for more information.
+
+<dt><a name="label"></a>{@code android:label}</dt>
+<dd>A user-readable label for the alias when presented to users through the alias.
+See the the <code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#label">label</a></code> attribute for more information.
+</p></dd>
+
+<dt><a name="nm">{@code android:name}</dt>
+<dd>A unique name for the alias. The name should resemble a fully
+qualified class name. But, unlike the name of the target activity,
+the alias name is arbitrary; it does not refer to an actual class.
+</p></dd>
+
+<dt><a name="prmsn"></a>{@code android:permission}</dt>
+<dd>The name of a permission that clients must have to launch the target activity
+or get it to do something via the alias. If a caller of
+<code>{@link android.content.Context#startActivity startActivity()}</code> or
+<code>{@link android.app.Activity#startActivityForResult startActivityForResult()}</code>
+has not been granted the specified permission, the target activity will not be
+activated.
+
+<p>This attribute supplants any permission set for the target activity itself. If
+it is not set, a permission is not needed to activate the target through the alias.
+</p>
+
+<p>
+For more information on permissions, see the
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#perms">Permissions</a>
+section in the introduction.
+</p></dd>
+
+<dt><a name="trgt"></a>{@code android:targetActivity}</dt>
+<dd>The name of the activity that can be activated through the alias.
+This name must match the {@code name} attribute of an
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> element that precedes
+the alias in the manifest.
+</p></dd>
+</dl></dd>
+
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code></dd>
+
+</dl> \ No newline at end of file
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
new file mode 100644
index 0000000..aba89d7
--- /dev/null
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -0,0 +1,565 @@
+page.title=&lt;activity&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;activity android:<a href="#reparent">allowTaskReparenting</a>=["true" | "false"]
+ android:<a href="#always">alwaysRetainTaskState</a>=["true" | "false"]
+ android:<a href="#clear">clearTaskOnLaunch</a>=["true"" | "false"]
+ android:<a href="#config">configChanges</a>=[<i>one or more of</i>: "mcc" "mnc" "locale"
+ "touchscreen" "keyboard" "keyboardHidden"
+ "navigation" "orientation" "fontScale"]
+ android:<a href="#enabled">enabled</a>=["true" | "false"]
+ android:<a href="#exclude">excludeFromRecents</a>=["true" | "false"]
+ android:<a href="#exported">exported</a>=["true" | "false"]
+ android:<a href="#finish">finishOnTaskLaunch</a>=["true" | "false"]
+ android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+ android:<a href="#label">label</a>="<i>string resource</i>"
+ android:<a href="#lmode">launchMode</a>=["multiple" | "singleTop" |
+ "singleTask" | "singleInstance"]
+ android:<a href="#multi">multiprocess</a>=["true" | "false"]
+ android:<a href="#nm">name</a>="<i>string</i>"
+ android:<a href="#prmsn">permission</a>="<i>string</i>"
+ android:<a href="#proc">process</a>="<i>string</i>"
+ android:<a href="#screen">screenOrientation</a>=["unspecified" | "user" | "behind" |
+ "landscape" | "portrait" |
+ "sensor" | "nonsensor"]
+ android:<a href="#state">stateNotNeeded</a>=["true" | "false"]
+ android:<a href="#aff">taskAffinity</a>="<i>string</i>"
+ android:<a href="#theme">theme</a>="<i>resource or theme</i>" &gt;
+ . . .
+&lt;/activity&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code></dd>
+
+<dt>can contain:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Declares an activity (an {@link android.app.Activity} subclass) that
+implements part of the application's visual user interface. All activities
+must be represented by {@code &lt;activity&gt;}
+elements in the manifest file. Any that are not declared there will not be seen
+by the system and will never be run.
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a href name="reparent"></a>{@code android:allowTaskReparenting}</dt>
+<dd>Whether or not the activity can move from the task that started it to
+the task it has an affinity for when that task is next brought to the
+front &mdash; "{@code true}" if it can move, and "{@code false}" if it
+must remain with the task where it started.
+
+<p>
+If this attribute is not set, the value set by the corresponding
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#reparent">allowTaskReparenting</a></code>
+attribute of the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element
+applies to the activity. The default value is "{@code false}".
+</p>
+
+<p>
+Normally when an activity is started, it's associated with the task of
+the activity that started it and it stays there for its entire lifetime.
+You can use this attribute to force it to be re-parented to the task it
+has an affinity for when its current task is no longer displayed.
+Typically, it's used to cause the activities of an application to move
+to the main task associated with that application.
+</p>
+
+<p>
+For example, if an e-mail message contains a link to a web page, clicking
+the link brings up an activity that can display the page. That activity
+is defined by the browser application, but is launched as part of the e-mail
+task. If it's reparented to the browser task, it will be shown when the
+browser next comes to the front, and will be absent when the e-mail task
+again comes forward.
+</p>
+
+<p>
+The affinity of an activity is defined by the
+<code><a href="#aff">taskAffinity</a></code> attribute. The affinity
+of a task is determined by reading the affinity of its root activity.
+Therefore, by definition, a root activity is always in a task with the
+same affinity. Since activities with "{@code singleTask}" or
+"{@code singleInstance}" launch modes can only be at the root of a task,
+re-parenting is limited to the "{@code standard}" and "{@code singleTop}"
+modes. (See also the <code><a href="#lmode">launchMode</a></code>
+attribute.)
+</p></dd>
+
+<dt><a name="always"></a>{@code android:alwaysRetainTaskState}</dt>
+<dd>Whether or not the state of the task that the activity is in will always
+be maintained by the system &mdash; "{@code true}" if it will be, and
+"{@code false}" if the system is allowed to reset the task to its initial
+state in certain situations. The default value is "{@code false}". This
+attribute is meaningful only for the root activity of a task; it's ignored
+for all other activities.
+
+<p>
+Normally, the system clears a task (removes all activities from the stack
+above the root activity) in certain situations when the user re-selects that
+task from the home screen. Typically, this is done if the user hasn't visited
+the task for a certain amount of time, such as 30 minutes.
+</p>
+
+<p>
+However, when this attribute is "{@code true}", users will always return
+to the task in its last state, regardless of how they get there. This is
+useful, for example, in an application like the web browser where there is
+a lot of state (such as multiple open tabs) that users would not like to lose.
+</p></dd>
+
+<dt><a name="clear"></a>{@code android:clearTaskOnLaunch}</dt>
+<dd>Whether or not all activities will be removed from the task, except for
+the root activity, whenever it is re-launched from the home screen &mdash;
+"{@code true}" if the task is always stripped down to its root activity, and
+"{@code false}" if not. The default value is "{@code false}". This attribute
+is meaningful only for activities that start a new task (the root activity);
+it's ignored for all other activities in the task.
+
+<p>
+When the value is "{@code true}", every time users start the task again, they
+are brought to its root activity, regardless of what they were last doing in
+the task and regardless of whether they used BACK or HOME to last leave it.
+When the value is "{@code false}", the task may be cleared of activities in
+some situations (see the
+<code><a href="#always">alwaysRetainTaskState</a></code> attribute), but not always.
+</p>
+
+<p>
+Suppose, for example, that someone launches activity P from the home screen,
+and from there goes to activity Q. The user next presses HOME, and then returns
+to activity P. Normally, the user would see activity Q, since that is what they
+were last doing in P's task. However, if P set this flag to "{@code true}", all
+of the activities on top of it (Q in this case) were removed when the user pressed
+HOME and the task went to the background. So the user sees only P when returning
+to the task.
+</p>
+
+<p>
+If this attribute and <code><a href="#reparent">allowTaskReparenting</a></code>
+are both "{@code true}", any activities that can be re-parented are moved to
+the task they share an affinity with; the remaining activities are then dropped,
+as described above.
+</p></dd>
+
+<dt><a name="config"></a>{@code android:configChanges}</dt>
+<dd>Lists configuration changes that the activity will handle itself. When
+changes that are not listed occur, the activity is shut down and restarted.
+When a listed change occurs, the activity remains running and its <code>{@link android.app.Activity#onConfigurationChanged onConfigurationChanged()}</code>
+method is called.
+
+<p>
+Any or all of the following strings can be used to set this attribute. Values are
+separated by '{@code |}' &mdash; for example, "{@code locale|navigation|orientation}".
+</p>
+
+<table>
+<tr>
+ <td><b>Value</b></td>
+ <td><b>Description</b></td>
+</tr><tr>
+ <td>"{@code mcc}"</td>
+ <td>The IMSI mobile country code (MCC) has changed &mdash;
+ that is, a SIM has been detected and updated the MCC.</td>
+</tr><tr>
+ <td>"{@code mnc}"</td>
+ <td>The IMSI mobile network code (MNC) has changed &mdash;
+ that is, a SIM has been detected and updated the MNC.</td>
+</tr><tr>
+ <td>"{@code locale}"</td>
+ <td>The locale has changed &mdash; for example, the user has selected a new
+ language that text should be displayed in.</td>
+</tr><tr>
+ <td>"{@code touchscreen}"</td>
+ <td>The touchscreen has changed. (This should never normally happen.)</td>
+</tr><tr>
+ <td>"{@code keyboard}"</td>
+ <td>The keyboard type has changed &mdash; for example, the user has
+ plugged in an external keyboard.</td>
+</tr><tr>
+ <td>"{@code keyboardHidden}"</td>
+ <td>The keyboard accessibility has changed &mdash; for example, the
+ user has slid the keyboard out to expose it.</td>
+</tr><tr>
+ <td>"{@code navigation}"</td>
+ <td>The navigation type has changed. (This should never normally happen.)</td>
+</tr><tr>
+ <td>"{@code orientation}"</td>
+ <td>The screen orientation has changed &mdash; that is, the user has rotated
+ the device.</td>
+ </tr><tr>
+ <td>"{@code fontScale}"</td>
+ <td>The font scaling factor has changed &mdash; that is, the user has selected
+ a new global font size.</td>
+</tr>
+</table>
+
+<p>
+All of these configuration changes can impact the resource values seen by the
+application. Therefore, when <code>{@link android.app.Activity#onConfigurationChanged
+onConfigurationChanged()}</code> is called, it will generally be necessary to again
+retrieve all resources (including view layouts, drawables, and so on) to correctly
+handle the change.
+</p></dd>
+
+<dt><a name="enabled"></a>{@code android:enabled}</dt>
+<dd>Whether or not the activity can be instantiated by the system &mdash;
+"{@code true}" if it can be, and "{@code false}" if not. The default value
+is "{@code true}".
+
+<p>
+The <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element has its own
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#enabled">enabled</a></code> attribute that applies to all
+application components, including activities. The
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> and {@code &lt;activity&gt;}
+attributes must both be "{@code true}" (as they both are by default) for
+the system to be able to instantiate the activity. If either is
+"{@code false}", it cannot be instantiated.
+</p></dd>
+
+<dt><a name="exclude"></a>{@code android:excludeFromRecents}</dt>
+<dd>Whether or not the activity should be excluded from the list of recently
+launched activities that can be displayed to users &mdash; "{@code true}" if
+it should be excluded, and "{@code false}" if it should be included.
+The default value is "{@code false}".
+</p></dd>
+
+<dt><a name="exported"></a>{@code android:exported}</dt>
+<dd>Whether or not the activity can be launched by components of other
+applications &mdash; "{@code true}" if it can be, and "{@code false}" if not.
+If "{@code false}", the activity can be launched only by components of the
+same application or applications with the same user ID.
+
+<p>
+The default value depends on whether the activity contains intent filters. The
+absence of any filters means that the activity can be invoked only by specifying
+its exact class name. This implies that the activity is intended only for
+application-internal use (since others would not know the class name). So in
+this case, the default value is "{@code false}".
+On the other hand, the presence of at least one filter implies that the activity
+is intended for external use, so the default value is "{@code true}".
+</p>
+
+<p>
+This attribute is not the only way to limit an activity's exposure to other
+applications. You can also use a permission to limit the external entities that
+can invoke the activity (see the <code><a href="{@docRoot}guide/topics/manifest/activity-element.html#prmsn">permission</a></code>
+attribute).
+</p></dd>
+
+<dt><a name="finish"></a>{@code android:finishOnTaskLaunch}</dt>
+<dd>Whether or not an existing instance of the activity should be shut down
+(finished) whenever the user again launches its task (chooses the task on the
+home screen) &mdash; "{@code true}" if it should be shut down, and "{@code false}"
+if not. The default value is "{@code false}".
+
+<p>
+If this attribute and <code><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">allowTaskReparenting</a></code>
+are both "{@code true}", this attribute trumps the other. The affinity of the
+activity is ignored. The activity is not re-parented, but destroyed.
+</p>
+
+<dt><a name="icon"></a>{@code android:icon}</dt>
+<dd>An icon representing the activity. The icon is displayed to users when
+a representation of the activity is required on-screen. For example, icons
+for activities that initiate tasks are displayed in the launcher window.
+The icon is often accompanied by a label (see the {@code label} attribute).
+</p>
+
+<p>
+This attribute must be set as a reference to a drawable resource containing
+the image definition. If it is not set, the icon specified for the application
+as a whole is used instead (see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+element's <code><a href="{@docRoot}guide/topics/manifest/application-element.html#icon">icon</a></code> attribute).
+</p>
+
+<p>
+The activity's icon &mdash; whether set here or by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element &mdash; is also the
+default icon for all the activity's intent filters (see the
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html#icon">icon</a></code> attribute).
+</p></dd>
+
+<dt><a name="label"></a>{@code android:label}</dt>
+<dd>A user-readable label for the activity. The label is displayed on-screen
+when the activity must be represented to the user. It's often displayed along
+with the activity icon.
+
+<p>
+If this attribute is not set, the label set for the application as a whole is
+used instead (see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#label">label</a></code> attribute).
+</p>
+
+<p>
+The activity's label &mdash; whether set here or by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element &mdash; is also the
+default label for all the activity's intent filters (see the
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html#label">label</a></code> attribute).
+</p>
+
+<p>
+The label should be set as a reference to a string resource, so that
+it can be localized like other strings in the user interface.
+However, as a convenience while you're developing the application,
+it can also be set as a raw string.
+</p></dd>
+
+<dt><a name="lmode"></a>{@code android:launchMode}</dt>
+<dd>An instruction on how the activity should be launched. There are four modes
+that work in conjunction with activity flags ({@code FLAG_ACTIVITY_*} constants)
+in {@link android.content.Intent} objects to determine what should happen when
+the activity is called upon to handle an intent. They are:
+
+<p style="margin-left: 2em">"{@code standard}"
+<br>"{@code singleTop}"
+<br>"{@code singleTask}"
+<br>"{@code singleInstance}"</p>
+
+<p>
+The default mode is "{@code standard}".
+</p>
+
+<p>
+The modes fall into two main groups, with "{@code standard}" and
+"{@code singleTop}" activities on one side, and "{@code singleTask}" and
+"{@code singleInstance}" activities on the other. An activity with the
+"{@code standard}" or "{@code singleTop}" launch mode can be instantiated
+multiple times. The instances can belong to any task and can be located
+anywhere in the activity stack. Typically, they're launched into the task
+that called
+<code>{@link android.content.Context#startActivity startActivity()}</code>
+(unless the Intent object contains a
+<code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code>
+instruction, in which case a different task is chosen &mdash; see the
+<a href="#aff">taskAffinity</a> attribute).
+</p>
+
+<p>
+In contrast, "{@code singleTask}" and "{@code singleInstance}" activities
+can only begin a task. They are always at the root of the activity stack.
+Moreover, the device can hold only one instance of the activity at a time
+&mdash; only one such task.
+</p>
+
+<p>
+The "{@code standard}" and "{@code singleTop}" modes differ from each other
+in just one respect: Every time there's new intent for a "{@code standard}"
+activity, a new instance of the class is created to respond to that intent.
+Each instance handles a single intent.
+Similarly, a new instance of a "{@code singleTop}" activity may also be
+created to handle a new intent. However, if the target task already has an
+existing instance of the activity at the top of its stack, that instance
+will receive the new intent (in an
+<code>{@link android.app.Activity#onNewIntent onNewIntent()}</code> call);
+a new instance is not created.
+In other circumstances &mdash; for example, if an existing instance of the
+"{@code singleTop}" activity is in the target task, but not at the top of
+the stack, or if it's at the top of a stack, but not in the target task
+&mdash; a new instance would be created and pushed on the stack.
+</p>
+
+<p>
+The "{@code singleTask}" and "{@code singleInstance}" modes also differ from
+each other in only one respect: A "{@code singleTask}" activity allows other
+activities to be part of its task. It's at the root of the activity stack,
+but other activities (necessarily "{@code standard}" and "{@code singleTop}"
+activities) can be launched into the same task. A "{@code singleInstance}"
+activity, on the other hand, permits no other activities to be part of its
+task. It's the only activity in the task. If it starts another activity,
+that activity is assigned to a different task &mdash; as if {@code
+FLAG_ACTIVITY_NEW_TASK} was in the intent.
+</p>
+
+<p>For more information on launch modes and their interaction with Intent
+flags, see the
+<a href="{@docRoot}guide/topics/fundamentals.html#acttask">Activities and
+Tasks</a> section of the
+<a href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a>
+document.
+</p>
+</dd>
+
+<dt><a name="multi"></a>{@code android:multiprocess}</dt>
+<dd>Whether an instance of the activity can be launched into the process of the component
+that started it &mdash; "{@code true}" if it can be, and "{@code false}" if not.
+The default value is "{@code false}".
+
+<p>
+Normally, a new instance of an activity is launched into the process of the
+application that defined it, so all instances of the activity run in the same
+process. However, if this flag is set to "{@code true}", instances of the
+activity can run in multiple processes, allowing the system to create instances
+wherever they are used (provided permissions allow it), something that is almost
+never necessary or desirable.
+</p></dd>
+
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The name of the class that implements the activity, a subclass of
+{@link android.app.Activity}. The attribute value should be a fully qualified
+class name (such as, "{@code com.example.project.ExtracurricularActivity}").
+However, as a shorthand, if the first character of the name is a period
+(for example, "{@code .ExtracurricularActivity}"), it is appended to the
+package name specified in the
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
+element.
+
+<p>
+There is no default. The name must be specified.
+</p></dd>
+
+<dt><a name="prmsn"></a>{@code android:permission}</dt>
+<dd>The name of a permission that clients must have to launch the activity
+or otherwise get it to respond to an intent. If a caller of
+<code>{@link android.content.Context#startActivity startActivity()}</code> or
+<code>{@link android.app.Activity#startActivityForResult startActivityForResult()}</code>
+has not been granted the specified permission, its intent will not be
+delivered to the activity.
+
+<p>
+If this attribute is not set, the permission set by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#prmsn">permission</a></code> attribute applies
+to the activity. If neither attribute is set, the activity is
+not protected by a permission.
+</p>
+
+<p>
+For more information on permissions, see the
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#sectperm">Permissions</a>
+section in the introduction and another document,
+<a href="{@docRoot}guide/topics/security/security.html">Security and
+Permissions</a>.
+</p></dd>
+
+<dt><a name="proc"></a>{@code android:process}</dt>
+<dd>The name of the process in which the activity should run. Normally,
+all components of an application run in the default process created for the
+application. It has the same name as the application package. The <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#proc">process</a></code> attribute can set a different
+default for all components. But each component can override the default,
+allowing you to spread your application across multiple processes.
+
+<p>
+If the name assigned to this attribute begins with a colon (':'), a new
+process, private to the application, is created when it's needed and
+the activity runs in that process.
+If the process name begins with a lowercase character, the activity will run
+in a global process of that name, provided that it has permission to do so.
+This allows components in different applications to share a process, reducing
+resource usage.
+</p></dd>
+
+<dt><a name="screen"></a>{@code android:screenOrientation}</dt>
+<dd>The orientation of the activity's display on the device.
+The value can be any one of the following strings:
+
+<table>
+<tr>
+ <td>"{@code unspecified}"</td>
+ <td>The default value. The system chooses the orientation. The policy it
+ uses, and therefore the choices made in specific contexts, may differ
+ from device to device.</td>
+</tr><tr>
+ <td>"{@code landscape}"</td>
+ <td>Landscape orientation (the display is wider than it is tall).</td>
+</tr><tr>
+ <td>"{@code portrait}"</td>
+ <td>Portrait orientation (the display is taller than it is wide).</td>
+</tr><tr>
+ <td>"{@code user}"</td>
+ <td>The user's current preferred orientation.</td>
+</tr><tr>
+ <td>"{@code behind}"</td>
+ <td>The same orientation as the activity that's immediately beneath it in
+ the activity stack.</td>
+</tr><tr>
+ <td>"{@code sensor}"</td>
+ <td>The orientation determined by a physical orientation sensor. The
+ orientation of the display depends on how the user is holding the device;
+ it changes when the user rotates the device.</td>
+</tr><tr>
+ <td>"{@code nosensor}"</td>
+ <td>An orientation determined without reference to a physical orientation sensor.
+ The sensor is ignored, so the display will not rotate based on how the user
+ moves the device. Except for this distinction, the system chooses the
+ orientation using the same policy as for the "{@code unspecified}" setting.</td>
+</tr>
+</table></dd>
+
+<dt><a name="state"></a>{@code android:stateNotNeeded}</dt>
+<dd>Whether or not the activity can be killed and successfully restarted
+without having saved its state &mdash; "{@code true}" if it can be restarted
+without reference to its previous state, and "{@code false}" if its previous
+state is required. The default value is "{@code false}".
+
+<p>
+Normally, before an activity is temporarily shut down to save resources, its
+<code>{@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}</code>
+method is called. This method stores the current state of the activity in a
+{@link android.os.Bundle} object, which is then passed to
+<code>{@link android.app.Activity#onCreate onCreate()}</code> when the activity
+is restarted. If this attribute is set to "{@code true}",
+{@code onSaveInstanceState()} may not be called and {@code onCreate()} will
+be passed {@code null} instead of the Bundle &mdash; just as it was when the
+activity started for the first time.
+</p>
+
+<p>
+A "{@code true}" setting ensures that the activity can be restarted in the
+absence of retained state. For example, the activity that displays the
+home screen uses this setting to make sure that it does not get removed if it
+crashes for some reason.
+</p></dd>
+
+<dt><a name="aff"></a>{@code android:taskAffinity}</dt>
+<dd>The task that the activity has an affinity for. Activities with
+the same affinity conceptually belong to the same task (to the same
+"application" from the user's perspective). The affinity of a task
+is determined by the affinity of its root activity.
+
+<p>
+The affinity determines two things &mdash; the task that the activity is re-parented
+to (see the <code><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">allowTaskReparenting</a></code>
+attribute) and the task that will house the activity when it is launched
+with the <code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code>
+flag.
+</p>
+
+<p>
+By default, all activities in an application have the same affinity. You
+can set this attribute to group them differently, and even place
+activities defined in different applications within the same task. To
+specify that the activity does not have an affinity for any task, set
+it to an empty string.
+
+<p>
+If this attribute is not set, the activity inherits the affinity set
+for the application (see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+element's <code><a href="{@docRoot}guide/topics/manifest/application-element.html#aff">taskAffinity</a></code> attribute).
+The name of the default affinity for an application is the package name set
+by the <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> element.
+</p>
+
+<dt><a name="theme"></a>{@code android:theme}</dt>
+<dd>A reference to a style resource defining an overall theme for the activity.
+This automatically sets the activity's context to use this theme (see
+<code>{@link android.content.Context#setTheme setTheme()}</code>, and may also
+cause "starting" animations prior to the activity being launched (to better
+match what the activity actually looks like).
+
+<p>
+If this attribute is not set, the activity inherits the theme set for the
+application as a whole &mdash; see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+element's <code><a href="{@docRoot}guide/topics/manifest/application-element.html#theme">theme</a></code> attribute. If that attribute is
+also not set, the default system theme is used.
+</p>
+<dd>
+</dl></dd>
+
+</dl> \ No newline at end of file
diff --git a/docs/html/guide/topics/manifest/application-element.jd b/docs/html/guide/topics/manifest/application-element.jd
new file mode 100644
index 0000000..362c205
--- /dev/null
+++ b/docs/html/guide/topics/manifest/application-element.jd
@@ -0,0 +1,226 @@
+page.title=&lt;application&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;application android:<a href="#clear">allowClearUserData</a>=["true" | "false"]
+ android:<a href="#reparent">allowTaskReparenting</a>=["true" | "false"]
+ android:<a href="#debug">debuggable</a>=["true" | "false"]
+ android:<a href="#desc">description</a>="<i>string resource</i>"
+ android:<a href="#enabled">enabled</a>=["true" | "false"]
+ android:<a href="#code">hasCode</a>=["true" | "false"]
+ android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+ android:<a href="#label">label</a>="<i>string resource</i>"
+ android:<a href="#space">manageSpaceActivity</a>="<i>string</i>"
+ android:<a href="#nm">name</a>="<i>string</i>"
+ android:<a href="#prmsn">permission</a>="<i>string</i>"
+ android:<a href="#persistent">persistent</a>=["true" | "false"]
+ android:<a href="#proc">process</a>="<i>string</i>"
+ android:<a href="#aff">taskAffinity</a>="<i>string</i>"
+ android:<a href="#theme">theme</a>="<i>resource or theme</i>" &gt;
+ . . .
+&lt;/application&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code></dd>
+
+<dt>can contain:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>The declaration of the application. This element contains subelements
+that declare each of the application's components and has attributes
+that can affect all the components. Many of these attributes (such as
+{@code icon}, {@code label}, {@code permission}, {@code process},
+{@code taskAffinity}, and {@code allowTaskReparenting}) set default values
+for corresponding attributes of the component elements. Others (such as
+{@code debuggable}, {@code enabled}, {@code description}, and
+{@code allowClearUserData}) set values for the application as a whole and
+cannot be overridden by the components.</dd>
+
+<dt>attributes</dt>
+<dd><dl class="attr">
+<dt><a name="clear"></a>{@code android:allowClearUserData}</dt>
+<dd>Whether or not users are given the option to remove user data &mdash;
+"{@code true}" if they are, and "{@code false}" if not. If the value is
+"{@code true}", as it is by default, the application manager includes an
+option that allows users to clear the data.</dd>
+
+<dt><a name="reparent"></a>{@code android:allowTaskReparenting}</dt>
+<dd>Whether or not activities that the application defines can move from
+the task that started them to the task they have an affinity for when that task
+is next brought to the front &mdash; "{@code true}" if they can move, and
+"{@code false}" if they must remain with the task where they started.
+The default value is "{@code false}".
+
+<p>
+The
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+element has its own
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">allowTaskReparenting</a></code>
+attribute that can override the value set here. See that attribute for more
+information.
+</p></dd>
+
+<dt><a name="debug"></a>{@code android:debuggable}</dt>
+<dd>Whether or not the application can be debugged, even when running
+on a device in user mode &mdash; "{@code true}" if it can be, and "{@code false}"
+if not. The default value is "{@code false}".</dd>
+
+<dt><a name="desc"></a>{@code android:description}</dt>
+<dd>User-readable text about the application, longer and more descriptive than the application label. The value must be set as a reference to a string resource. Unlike the label, it cannot be a raw string. There is no default value.</dd>
+
+<dt><a name="enabled"></a>{@code android:enabled}</dt>
+<dd>Whether or not the Android system can instantiate components of
+the application &mdash; "{@code true}" if it can, and "{@code false}"
+if not. If the value is "{@code true}", each component's
+{@code enabled} attribute determines whether that component is enabled
+or not. If the value is "{@code false}", it overrides the
+component-specific values; all components are disabled.
+
+<p>
+The default value is "{@code true}".
+</p></dd>
+
+<dt><a name="code"></a>{@code android:hasCode}</dt>
+<dd>Whether or not the application contains any code &mdash; "{@code true}"
+if it does, and "{@code false}" if not. When the value is "{@code false}",
+the system does not try to load any application code when launching components.
+The default value is "{@code true}".
+
+<p>
+An application would not have any code of its own only if it's using nothing
+but built-in component classes, such as an activity that uses the {@link
+android.app.AliasActivity} class, a rare occurrence.
+
+<dt><a name="icon"></a>{@code android:icon}</dt>
+<dd>An icon for the application as whole, and the default icon for
+each of the application's components. See the individual
+{@code icon} attributes for
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>,
+<code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>,
+<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>,
+<code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>, and
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code> elements.
+
+<p>
+This attribute must be set as a reference to a drawable resource containing
+the image definition. There is no default icon.
+</p></dd>
+
+<dt><a name="label"></a>{@code android:label}</dt>
+<dd>A user-readable label for the application as a whole, and a default
+label for each of the application's components. See the individual
+{@code label} attributes for
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>,
+<code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>,
+<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>,
+<code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>, and
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code> elements.
+
+<p>
+The label should be set as a reference to a string resource, so that
+it can be localized like other strings in the user interface.
+However, as a convenience while you're developing the application,
+it can also be set as a raw string.
+</p></dd>
+
+<dt><a name="space"></a>{@code android:manageSpaceActivity}</dt>
+<dd>The fully qualified name of an Activity subclass that the system
+can launch to let users manage the memory occupied by the application
+on the device. The activity should also be declared with an
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> element.
+</dd>
+
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The fully qualified name of an {@link android.app.Application}
+subclass implemented for the application. When the application process
+is started, this class is instantiated before any of the application's
+components.
+
+<p>
+The subclass is optional; most applications won't need one.
+In the absence of a subclass, Android uses an instance of the base
+Application class.
+</p></dd>
+
+<dt><a name="prmsn"></a>{@code android:permission}</dt>
+<dd>The name of a permission that clients must have in order to interact
+with the application. This attribute is a convenient way to set a
+permission that applies to all of the application's components. It can
+be overwritten by setting the {@code permission} attributes of individual
+components.
+
+<p>
+For more information on permissions, see the
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#sectperm">Permissions</a>
+section in the introduction and another document,
+<a href="{@docRoot}guide/topics/security/security.html">Security and
+Permissions</a>.
+</p></dd>
+
+<dt><a name="persistent"></a>{@code android:persistent}</dt>
+<dd>Whether or not the application should remain running at all times &mdash;
+"{@code true}" if it should, and "{@code false}" if not. The default value
+is "{@code false}". Applications should not normally set this flag;
+persistence mode is intended only for certain system applications.</dd>
+
+<dt><a name="proc"></a>{@code android:process}</dt>
+<dd>The name of a process where all components of the application should run.
+Each component can override this default by setting its own {@code process}
+attribute.
+
+<p>
+By default, Android creates a process for an application when the first
+of its components needs to run. All components then run in that process.
+The name of the default process matches the package name set by the
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> element.
+</p>
+
+<p>By setting this attribute to a process name that's shared with another
+application, you can arrange for components of both applications to run in
+the same process &mdash; but only if the two applications also share a
+user ID and be signed with the same certificate.
+</p>
+
+<p>
+If the name assigned to this attribute begins with a colon (':'), a new
+process, private to the application, is created when it's needed.
+If the process name begins with a lowercase character, a global process
+of that name is created. A global process can be shared with other
+applications, reducing resource usage.
+</p></dd>
+
+<dt><a href name="aff"></a>{@code android:taskAffinity}</dt>
+<dd>An affinity name that applies to all activities within the application,
+except for those that set a different affinity with their own
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">taskAffinity</a></code>
+attributes. See that attribute for more information.
+
+<p>
+By default, all activities within an application share the same
+affinity. The name of that affinity is the same as the package name
+set by the
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> element.
+</p></dd>
+
+<dt><a name="theme"></a>{@code android:theme}</dt>
+<dd>A reference to a style resource defining a default theme for all
+activities in the application. Individual activities can override
+the default by setting their own <code><a href="{@docRoot}guide/topics/manifest/activity-element.html#theme">theme</a></code>
+attributes; see that attribute for more information.</dd>
+
+</dl></dd>
+
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/category-element.jd b/docs/html/guide/topics/manifest/category-element.jd
new file mode 100644
index 0000000..50ea576
--- /dev/null
+++ b/docs/html/guide/topics/manifest/category-element.jd
@@ -0,0 +1,38 @@
+page.title=&lt;category&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;category android:<a href="#nm">name</a>="<i>string</i>" /&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Adds a category name to an intent filter. See
+<a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and
+Intent Filters</a> for details on intent filters and the role of category
+specifications within a filter.</dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The name of the category. Standard categories are defined in the
+{@link android.content.Intent} class as {@code CATEGORY_<i>name</i>}
+constants. The name assigned here can be derived from those constants
+by prefixing "{@code android.intent.category.}" to the
+{@code <i>name</i>} that follows {@code CATEGORY_}. For example,
+the string value for {@code CATEGORY_LAUNCHER} is
+"{@code android.intent.category.LAUNCHER}".
+
+<p>
+Custom categories should use the package name as a prefix, to ensure
+that they are unique.
+</p></dd>
+</dl></dd>
+
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd
new file mode 100644
index 0000000..5d8fde2
--- /dev/null
+++ b/docs/html/guide/topics/manifest/data-element.jd
@@ -0,0 +1,148 @@
+page.title=&lt;data&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;data android:<a href="#host">host</a>="<i>string</i>"
+ android:<a href="#mime">mimeType</a>="<i>string</i>"
+ android:<a href="#path">path</a>="<i>string</i>"
+ android:<a href="#path">pathPattern</a>="<i>string</i>"
+ android:<a href="#path">pathPrefix</a>="<i>string</i>"
+ android:<a href="#port">port</a>="<i>string</i>"
+ android:<a href="#scheme">scheme</a>="<i>string</i>" /&gt;</pre></dd>
+
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Adds a data specification to an intent filter. The specification can
+be just a data type (the <code><a href="{@docRoot}guide/topics/manifest/data-element.html#mime">mimeType</a></code> attribute),
+just a URI, or both a data type and a URI. A URI is specified by separate
+attributes for each of its parts:
+
+<p style="margin-left: 2em">{@code scheme://host:port/path} <i>or</i>
+{@code pathPrefix} <i>or</i> {@code pathPattern}</p>
+
+<p>
+These attributes are optional, but also mutually dependent:
+If a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#scheme">scheme</a></code> is not specified for the
+intent filter, all the other URI attributes are ignored. If a
+<code><a href="{@docRoot}guide/topics/manifest/data-element.html#host">host</a></code> is not specified for the filer,
+the {@code port} attribute and all the path attributes are ignored.
+</p>
+
+<p>
+All the {@code &lt;data&gt;} elements contained within the same
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> element contribute to
+the same filter. So, for example, the following filter specification,
+</p>
+
+<pre>&lt;intent-filter . . . &gt;
+ &lt;data android:scheme="something" android:host="project.example.com" /&gt;
+ . . .
+&lt;/intent-filter&gt;</pre>
+
+<p>is equivalent to this one:</p>
+
+<pre>&lt;intent-filter . . . &gt;
+ &lt;data android:scheme="something" /&gt
+ &lt;data android:host="project.example.com" /&gt;
+ . . .
+&lt;/intent-filter&gt;</pre>
+
+<p>
+You can place any number of &lt;data&gt; elements inside an
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> to give it multiple data
+options. None of its attributes have default values.
+</p>
+
+<p>
+Information on how intent filters work, including the rules for how Intent objects
+are matched against filters, can be found in another document,
+<a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and
+Intent Filters</a>. See also the
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#ifs">Intent Filters</a>
+section in the introduction.
+</p></dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="host"></a>{@code android:host}</dt>
+<dd>The host part of a URI authority. This attribute is meaningless
+unless a <code><a href="{@docRoot}guide/topics/manifest/data-element.html#scheme">scheme</a></code> attribute is also
+specified for the filter.
+</dd>
+
+<dt><a name="mime"></a>{@code android:mimeType}</dt>
+<dd>A MIME media type, such as {@code image/jpeg} or {@code audio/mpeg4-generic}.
+The subtype can be the asterisk wildcard ({@code *}) to indicate that any
+subtype matches.</dd>
+
+<dt><a name="path"></a>{@code android:path}
+<br/>{@code android:pathPrefix}
+<br/>{@code android:pathPattern}</dt>
+<dd>The path part of a URI. The {@code path} attribute specifies a complete
+path that is matched against the complete path in an Intent object. The
+{@code pathPrefix} attribute specifies a partial path that is matched against
+only the initial part of the path in the Intent object. The {@code pathPattern}
+attribute specifies a complete path that is matched against the complete path
+in the Intent object, but it can contain the following wildcards:
+
+<ul>
+<li>An asterisk ('{@code *}') matches a sequence of 0 to many occurrences of
+the immediately preceding character.</li>
+
+<li>A period followed by an asterisk ("{@code .*}") matches any sequence of
+0 to many characters.</li>
+</ul>
+
+<p>
+Because '{@code \}' is used as an escape character when the string is read
+from XML (before it is parsed as a pattern), you will need to double-escape:
+For example, a literal '{@code *}' would be written as "{@code \\*}" and a
+literal '{@code \}' would be written as "{@code \\\\}". This is basically
+the same as what you would need to write if constructing the string in Java code.
+</p>
+
+<p>
+For more information on these three types of patterns, see the descriptions of
+{@link android.os.PatternMatcher#PATTERN_LITERAL},
+{@link android.os.PatternMatcher#PATTERN_PREFIX}, and
+{@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB} in the
+{@link android.os.PatternMatcher} class.
+</p>
+
+<p>These attributes are meaningful only if the
+<code><a href="#scheme">scheme</a></code> and <code><a href="#host">host</a></code>
+attributes are also specified for the filter.
+</p></dd>
+
+<dt><a name="port"></a>{@code android:port}</dt>
+<dd>The port part of a URI authority. This attribute is meaningful only
+if the <code><a href="#scheme">scheme</a></code> and
+<code><a href="#host">host</a></code> attributes are also specified for
+the filter.</dd>
+
+<dt><a name="scheme"></a>{@code android:scheme}</dt>
+<dd>The scheme part of a URI. This is the minimal essential attribute for
+specifying a URI; at least one {@code scheme} attribute must be set
+for the filter, or none of the other URI attributes are meaningful.
+
+<p>
+A scheme is specified without the trailing colon (for example,
+{@code http}, rather than {@code http:}).
+</p>
+
+<p>
+If the filter has a data type set (the <code><a href="{@docRoot}guide/topics/manifest/data-element.html#mime">mimeType</a></code>
+attribute) but no scheme, the {@code content:} and {@code file:} schemes are
+assumed.
+</p></dd>
+</dl></dd>
+
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category&gt;</a></code></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/grant-uri-permission-element.jd b/docs/html/guide/topics/manifest/grant-uri-permission-element.jd
new file mode 100644
index 0000000..f5b37b5
--- /dev/null
+++ b/docs/html/guide/topics/manifest/grant-uri-permission-element.jd
@@ -0,0 +1,85 @@
+page.title=&lt;grant-uri-permission&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;grant-uri-permission android:<a href="#path">path</a>="<i>string</i>"
+ android:<a href="#path">pathPattern</a>="<i>string</i>"
+ android:<a href="#path">pathPrefix</a>="<i>string</i>" /&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Specifies which data subsets of the parent content provider permission
+can be granted for. Data subsets are indicated by the path part of a
+{@code content:} URI. (The authority part of the URI identifies the
+content provider.)
+Granting permission is a way of enabling clients of the provider that don't
+normally have permission to access its data to overcome that restriction on
+a one-time basis.
+
+<p>
+If a content provider's <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmns">grantUriPermissions</a></code>
+attribute is "{@code true}", permission can be granted for any the data under
+the provider's purview. However, if that attribute is "{@code false}", permission
+can be granted only to data subsets that are specified by this element.
+A provider can contain any number of {@code &lt;grant-uri-permission&gt;} elements.
+Each one can specify only one path (only one of the three possible attributes).
+</p>
+
+<p>
+For information on how permission is granted, see the
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">grantUriPermissions</a></code> attribute.
+</p></dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="path"></a>{@code android:path}
+<br/>{@code android:pathPrefix}
+<br/>{@code android:pathPattern}</dt>
+<dd>A path identifying the data subset or subsets that permission can be
+granted for. The {@code path} attribute specifies a complete path;
+permission can be granted only to the particular data subset identified
+by that path.
+The {@code pathPrefix} attribute specifies the initial part of a path;
+permission can be granted to all data subsets with paths that share that
+initial part.
+The {@code pathPattern} attribute specifies a complete path, but one
+that can contain the following wildcards:
+
+<ul>
+<li>An asterisk ('{@code *}') matches a sequence of 0 to many occurrences of
+the immediately preceding character.</li>
+
+<li><p>A period followed by an asterisk ("{@code .*}") matches any sequence of
+0 to many characters.</p></li>
+</ul>
+
+<p>
+Because '{@code \}' is used as an escape character when the string is read
+from XML (before it is parsed as a pattern), you will need to double-escape:
+For example, a literal '{@code *}' would be written as "{@code \\*}" and a
+literal '{@code \}' would be written as "{@code \\\\}". This is basically
+the same as what you would need to write if constructing the string in Java code.
+</p>
+
+<p>
+For more information on these types of patterns, see the descriptions of
+{@link android.os.PatternMatcher#PATTERN_LITERAL},
+{@link android.os.PatternMatcher#PATTERN_PREFIX}, and
+{@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB} in the
+{@link android.os.PatternMatcher} class.
+</p></dd>
+</dl></dd>
+
+<dt>see also:</dt>
+<dd>the
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmns">grantUriPermissions</a></code>
+attribute of the
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
+element</dd>
+
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/instrumentation-element.jd b/docs/html/guide/topics/manifest/instrumentation-element.jd
new file mode 100644
index 0000000..fdec949
--- /dev/null
+++ b/docs/html/guide/topics/manifest/instrumentation-element.jd
@@ -0,0 +1,61 @@
+page.title=&lt;instrumentation&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;instrumentation android:<a href="#ftest">functionalTest</a>=["true" | "false"]
+ android:<a href="#hprof">handleProfiling</a>=["true" | "false"]
+ android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+ android:<a href="#label">label</a>="<i>string resource</i>"
+ android:<a href="#nm">name</a>="<i>string</i>"
+ android:<a href="#trgt">targetPackage</a>="<i>string</i>" /&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Declares an {@link android.app.Instrumentation} class that enables you
+to monitor an application's interaction with the system. The Instrumentation
+object is instantiated before any of the application's components.</dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="ftest"></a>{@code android:functionalTest}</dt>
+<dd>Whether or not the Instrumentation class should run as a functional test
+&mdash; "{@code true}" if it should, and "{@code false}" if not. The
+default value is "{@code false}".</dd>
+
+<dt><a name="hprof"></a>{@code android:handleProfiling}</dt>
+<dd>Whether or not the Instrumentation object will turn profiling on and
+off &mdash; "{@code true}" if it determines when profiling starts and
+stops, and "{@code false}" if profiling continues the entire time it is
+running. A value of "{@code true}" enables the object to target profiling
+at a specific set of operations. The default value is "{@code false}".</dd>
+
+<dt><a name="icon"></a>{@code android:icon}</dt>
+<dd>An icon that represents the Instrumentation class. This attribute must
+be set as a reference to a drawable resource.</dd>
+
+<dt><a name="label"></a>{@code android:label}</dt>
+<dd>A user-readable label for the Instrumentation class. The label can
+be set as a raw string or a reference to a string resource.</dd>
+
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The name of the {@link android.app.Instrumentation} subclass.
+This should be a fully qualified class name (such as,
+"{@code com.example.project.StringInstrumentation}"). However, as a shorthand,
+if the first character of the name is a period, it is appended to the package
+name specified in the <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> element.
+
+<p>
+There is no default. The name must be specified.
+</p></dd>
+
+<dt><a name="trgt"></a>{@code android:targetPackage}</dt>
+<dd>The application that the Instrumentation object will run against.
+An application is identified by the package name assigned in its manifest
+file by the <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> element.</dd>
+
+</dl></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/intent-filter-element.jd b/docs/html/guide/topics/manifest/intent-filter-element.jd
new file mode 100644
index 0000000..58d1f91
--- /dev/null
+++ b/docs/html/guide/topics/manifest/intent-filter-element.jd
@@ -0,0 +1,130 @@
+page.title=&lt;intent-filter&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;intent-filter android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+ android:<a href="#label">label</a>="<i>string resource</i>"
+ android:<a href="#priority">priority</a>="<i>integer</i>" &gt;
+ . . .
+&lt;/intent-filter&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code></dd>
+
+<dt>must contain:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action&gt;</a></code></dd>
+
+<dt>can contain:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Specifies the types of intents that an activity, service, or broadcast
+receiver can respond to. An intent filter declares the capabilities of its
+parent component &mdash; what an activity or service can do and what types
+of broadcasts a receiver can handle. It opens the component to receiving
+intents of the advertised type, while filtering out those that are not
+meaningful for the component.
+
+<p>
+Most of the contents of the filter are described by its
+<code><a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action&gt;</a></code>,
+<code><a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category&gt;</a></code>, and
+<code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code> subelements.
+</p>
+
+<p>
+For a more detailed discussion of filters, see the separate
+<a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents
+and Intent Filters</a> document, as well as the
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#ifs">Intents Filters</a>
+section in the introduction.
+</p></dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="icon"></a>{@code android:icon}</dt>
+<dd>An icon that represents the parent activity, service, or broadcast
+receiver when that component is presented to the user as having the
+capability described by the filter.
+
+<p>
+This attribute must be set as a reference to a drawable resource
+containing the image definition. The default value is the icon set
+by the parent component's {@code icon} attribute. If the parent
+does not specify an icon, the default is the icon set by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element.
+</p>
+
+<p>
+For more on intent filter icons, see
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#iconlabel">Icons and Labels</a>
+in the introduction.
+</p></dd>
+
+<dt><a name="label"></a>{@code android:label}</dt>
+<dd>A user-readable label for the parent component. This label, rather than
+the one set by the parent component, is used when the component is presented
+to the user as having the capability described by the filter.
+
+<p>
+The label should be set as a reference to a string resource, so that
+it can be localized like other strings in the user interface.
+However, as a convenience while you're developing the application,
+it can also be set as a raw string.
+</p>
+
+<p>
+The default value is the label set by the parent component. If the
+parent does not specify a label, the default is the label set by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#label"> label</a></code> attribute.
+</p>
+
+<p>
+For more on intent filter labels, see
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#iconlabel">Icons and Labels</a>
+in the introduction.
+</p></dd>
+
+<dt><a name="priority"></a>{@code android:priority}</dt>
+<dd>The priority that should be given to the parent component with regard
+to handling intents of the type described by the filter. This attribute has
+meaning for both activities and broadcast receivers:
+
+<ul>
+<li>It provides information about how able an activity is to respond to
+an intent that matches the filter, relative to other activities that could
+also respond to the intent. When an intent could be handled by multiple
+activities with different priorities, Android will consider only those with
+higher priority values as potential targets for the intent.</li>
+
+<li><p>It controls the order in which broadcast receivers are executed to
+receive broadcast messages. Those with higher priority
+values are called before those with lower values. (The order applies only
+to synchronous messages; it's ignored for asynchronous messages.)</p></li>
+</ul>
+
+<p>
+Use this attribute only if you really need to impose a specific order in
+which the broadcasts are received, or want to force Android to prefer
+one activity over others.
+</p>
+
+<p>
+The value must be an integer, such as "{@code 100}". Higher numbers have a
+higher priority.
+</p></dd>
+
+</dl></dd>
+
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
new file mode 100644
index 0000000..2669487
--- /dev/null
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -0,0 +1,94 @@
+page.title=&lt;manifest&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;manifest xmlns:<a href="#nspace">android</a>="http://schemas.android.com/apk/res/android"
+ <a href="#package">package</a>="<i>string</i>"
+ android:<a href="#uid">sharedUserId</a>="<i>string</i>"
+ android:<a href="#vcode">versionCode</a>="<i>integer</i>"
+ android:<a href="#vname">versionName</a>="<i>string</i>" &gt;
+ . . .
+&lt;/manifest&gt;</pre></dd>
+
+<p>
+<dt>contained in:</dt>
+<dd><i>none</i></dd>
+
+<p>
+<p>
+<dt>must contain:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code></dd>
+
+<dt>can contain:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/instrumentation-element.html">&lt;instrumentation&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code></dd>
+
+<p>
+<dt>description:</dt>
+<dd>The root element of the AndroidManifest.xml file. It must
+contain an <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element
+and specify {@code xlmns:android} and {@code package} attributes.</dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="nspace"></a>{@code xmlns:android}</dt>
+<dd>Defines the Android namespace. This attribute should always be set
+to "{@code http://schemas.android.com/apk/res/android}".</dd>
+
+<dt><a name="package"></a>{@code package}</dt>
+<dd>A full Java package name for the application. The name should
+be unique. For example, applications published by Google could have
+names in the form <code>com.google.app.<i>application_name</i></code>.
+
+<p>
+The package name serves as a unique identifier for the application.
+It's also the default name for the application process (see the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#aff">process</a></code>
+process</a></code> attribute) and the default task affinity of an activity
+(see the
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+element's
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">taskAffinity</a></code> attribute).
+</p></dd>
+
+<dt><a name="uid"></a>{@code android:sharedUserId}</dt>
+<dd>The name of a Linux user ID that will be shared with other applications.
+By default, Android assigns each application its own unique user ID.
+However, if this attribute is set to the same value for two or more applications,
+they will all share the same ID &mdash; provided that they are also signed
+by the same certificate. Application with the same user ID can access each
+other's data and, if desired, run in the same process.</dd>
+
+<dt><a name="vcode"></a>{@code android:versionCode}</dt>
+<dd>An internal version number. This number is used only to determine whether
+one version is more recent than another, with higher numbers indicating more
+recent versions. This is not the version number shown to users; that number
+is set by the {@code versionName} attribute.
+
+<p>
+The value must be set as an integer, such as "100". You can define it however
+you want, as long as each successive version has a higher number. For example,
+it could be a build number. Or you could translate a version number in "x.y"
+format to an integer by encoding the "x" and "y" separately in the lower and
+upper 16 bits. Or you could simply increase the number by one each time a new
+version is released.
+</p></dd>
+
+<dt><a name="vname"></a>{@code android:versionName}</dt>
+<dd>The version number shown to users. This attribute can be set as a raw
+string or as a reference to a string resource. The string has no other purpose
+than to be displayed to users. The {@code versionCode} attribute holds
+the significant version number used internally.
+</dl></dd>
+
+<p>
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/manifest-intro.jd b/docs/html/guide/topics/manifest/manifest-intro.jd
new file mode 100644
index 0000000..aa14308
--- /dev/null
+++ b/docs/html/guide/topics/manifest/manifest-intro.jd
@@ -0,0 +1,511 @@
+page.title=The AndroidManifest.xml File
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+<li><a href="#filestruct">Structure of the Manifest File</a></li>
+<li><a href="#filec">File Conventions</a>
+<li><a href="#filef">File Features</a>
+ <ol>
+ <li><a href="#ifs">Intent Filters</a></li>
+ <li><a href="#iconlabel">Icons and Labels</a></li>
+ <li><a href="#perms">Permissions</a></li>
+ <li><a href="#libs">Libraries</a></li>
+ </ol></li>
+</ol>
+</div>
+</div>
+
+<p>
+Every application must have an AndroidManifest.xml file (with precisely that
+name) in its root directory. The manifest presents essential information about
+the application to the Android system, information the system must have before
+it can run any of the application's code. Among other things, the manifest
+does the following:
+</p>
+
+<ul>
+<li>It names the Java package for the application.
+The package name serves as a unique identifier for the application.</li>
+
+<li>It describes the components of the application &mdash; the activities,
+services, broadcast receivers, and content providers that the application is
+composed of. It names the classes that implement each of the components and
+publishes their capabilities (for example, which {@link android.content.Intent
+Intent} messages they can handle). These declarations let the Android system
+know what the components are and under what conditions they can be launched.</li>
+
+<li>It determines which processes will host application components.</li>
+
+<li>It declares which permissions the application must have in order to
+access protected parts of the API and interact with other applications.</li>
+
+<li>It also declares the permissions that others are required to have in
+order to interact with the application's components.</li>
+
+<li>It lists the {@link android.app.Instrumentation} classes that provide
+profiling and other information as the application is running. These declarations
+are present in the manifest only while the application is being developed and
+tested; they're removed before the application is published.</li>
+
+<li>It declares the minimum level of the Android API that the application
+requires.</li>
+
+<li>It lists the libraries that the application must be linked against.</li>
+</ul>
+
+
+<h2 id="filestruct">Structure of the Manifest File</h2>
+
+<p>
+The diagram below shows the general structure of the manifest file and
+every element that it can contain. Each element, along with all of its
+attributes, is documented in full in a separate file. To view detailed
+information about any element, click on the element name in the diagram,
+in the alphabetical list of elements that follows the diagram, or on any
+other mention of the element name.
+</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+
+<a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group /&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/instrumentation-element.html">&lt;instrumentation /&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk /&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;/activity&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;/activity-alias&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data/&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;/service&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a> . . . <a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;/intent-filter&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;/receiver&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data /&gt;</a>
+ <a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;/provider&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library /&gt;</a>
+
+ <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;/application&gt;</a>
+
+<a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;/manifest&gt;</a>
+</pre>
+
+<p>
+All the elements that can appear in the manifest file are listed below
+in alphabetical order. These are the only legal elements; you cannot
+add your own elements or attributes.
+</p>
+
+<p style="margin-left: 2em">
+<code><a href="{@docRoot}guide/topics/manifest/action-element.html">&lt;action&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/category-element.html">&lt;category&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/data-element.html">&lt;data&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/instrumentation-element.html">&lt;instrumentation&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk&gt;</a></code>
+</p>
+
+
+
+<h2 id="filec">File Conventions</h2>
+
+<p>
+Some conventions and rules apply generally to all elements and attributes
+in the manifest:
+</p>
+
+<dl>
+<dt><b>Elements</b></dt>
+<dd>Only the
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> and
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+elements are required, they each must be present and can occur only once.
+Most of the others can occur many times or not at all &mdash; although at
+least some of them must be present for the manifest to accomplish anything
+meaningful.
+
+<p>
+If an element contains anything at all, it contains other elements.
+All values are set through attributes, not as character data within an element.
+</p>
+
+<p>
+Elements at the same level are generally not ordered. For example,
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>,
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>, and
+<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
+elements can be intermixed in any sequence. (An
+<code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
+element is the exception to this rule: It must follow the
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+it is an alias for.)
+</p></dd>
+
+<dt><b>Attributes</b></dt>
+<dd>In a formal sense, all attributes are optional. However, there are some
+that must be specified for an element to accomplish its purpose. Use the
+documentation as a guide. For truly optional attributes, it mentions a default
+value or states what happens in the absence of a specification.
+
+<p>Except for some attributes of the root
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
+element, all attribute names begin with an {@code android:} prefix &mdash;
+for example, {@code android:alwaysRetainTaskState}. Because the prefix is
+universal, the documentation generally omits it when referring to attributes
+by name.</p></dd>
+
+<dt><b>Declaring class names</b></dt>
+<dd>Many elements correspond to Java objects, including elements for the
+application itself (the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+element) and its principal components &mdash; activities
+(<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>),
+services
+(<code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>),
+broadcast receivers
+(<code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code>),
+and content providers
+(<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>).
+
+<p>
+If you define a subclass, as you almost always would for the component classes
+({@link android.app.Activity}, {@link android.app.Service},
+{@link android.content.BroadcastReceiver}, and {@link android.content.ContentProvider}),
+the subclass is declared through a {@code name} attribute. The name must include
+the full package designation.
+For example, an {@link android.app.Service} subclass might be declared as follows:
+</p>
+
+<pre>&lt;manifest . . . &gt;
+ &lt;application . . . &gt;
+ &lt;service android:name="com.example.project.SecretService" . . . &gt;
+ . . .
+ &lt;/service&gt;
+ . . .
+ &lt;/application&gt;
+&lt;/manifest&gt;</pre>
+
+<p>
+However, as a shorthand, if the first character of the string is a period, the
+string is appended to the application's package name (as specified by the
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
+element's
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html#package">package</a></code>
+attribute). The following assignment is the same as the one above:
+</p>
+
+<pre>&lt;manifest package="com.example.project" . . . &gt;
+ &lt;application . . . &gt;
+ &lt;service android:name=".SecretService" . . . &gt;
+ . . .
+ &lt;/service&gt;
+ . . .
+ &lt;/application&gt;
+&lt;/manifest&gt;</pre>
+
+<p>
+When starting a component, Android creates an instance of the named subclass.
+If a subclass isn't specified, it creates an instance of the base class.
+</p></dd>
+
+<dt><b>Multiple values</b></dt>
+<dd>If more than one value can be specified, the element is almost always
+repeated, rather than listing multiple values within a single element.
+For example, an intent filter can list several actions:
+
+<pre>&lt;intent-filter . . . &gt;
+ &lt;action android:name="android.intent.action.EDIT" /&gt;
+ &lt;action android:name="android.intent.action.INSERT" /&gt;
+ &lt;action android:name="android.intent.action.DELETE" /&gt;
+ . . .
+&lt;/intent-filter&gt;</pre></dd>
+
+<dt><b>Resource values</b></dt>
+<dd>Some attributes have values that can be displayed to users &mdash; for
+example, a label and an icon for an activity. The values of these attributes
+should be localized and therefore set from a resource or theme. Resource
+values are expressed in the following format,</p>
+
+<p style="margin-left: 2em">{@code @[<i>package</i>:]<i>type</i>:<i>name</i>}</p>
+
+<p>
+where the <i>package</i> name can be omitted if the resource is in the same package
+as the application, <i>type</i> is a type of resource &mdash; such as "string" or
+"drawable" &mdash; and <i>name</i> is the name that identifies the specific resource.
+For example:
+</p>
+
+<pre>&lt;activity android:icon="@drawable/smallPic" . . . &gt</pre>
+
+<p>
+Values from a theme are expressed in a similar manner, but with an initial '{@code ?}'
+rather than '{@code @}':
+</p>
+
+<p style="margin-left: 2em">{@code ?[<i>package</i>:]<i>type</i>:<i>name</i>}
+</p></dd>
+
+<dt><b>String values</b></dt>
+<dd>Where an attribute value is a string, double backslashes ('{@code \\}')
+must be used to escape characters &mdash; for example, '{@code \\n}' for
+a newline or '{@code \\uxxxx}' for a Unicode character.</dd>
+</dl>
+
+
+<h2 id="filef">File Features</h2>
+
+<p>
+The following sections describe how some Android features are reflected
+in the manifest file.
+</p>
+
+
+<h3 id="ifs">Intent Filters</h3>
+
+<p>
+The core components of an application (its activities, services, and broadcast
+receivers) are activated by <i>intents</i>. An intent is a
+bundle of information (an {@link android.content.Intent} object) describing a
+desired action &mdash; including the data to be acted upon, the category of
+component that should perform the action, and other pertinent instructions.
+Android locates an appropriate component to respond to the intent, launches
+a new instance of the component if one is needed, and passes it the
+Intent object.
+</p>
+
+<p>
+Components advertise their capabilities &mdash; the kinds of intents they can
+respond to &mdash; through <i>intent filters</i>. Since the Android system
+must learn which intents a component can handle before it launches the component,
+intent filters are specified in the manifest as
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
+elements. A component may have any number of filters, each one describing
+a different capability.
+</p>
+
+<p>
+An intent that explicitly names a target component will activate that component;
+the filter doesn't play a role. But an intent that doesn't specify a target by
+name can activate a component only if it can pass through one of the component's
+filters.
+</p>
+
+<p>
+For information on how Intent objects are tested against intent filters,
+see a separate document,
+<a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents
+and Intent Filters</a>.
+</p>
+
+
+<h3 id="iconlabel">Icons and Labels</h3>
+
+<p>
+A number of elements have {@code icon} and {@code label} attributes for a
+small icon and a text label that can be displayed to users. Some also have a
+{@code description} attribute for longer explanatory text that can also be
+shown on-screen. For example, the
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+element has all three of these attributes, so that when the user is asked whether
+to grant the permission to an application that has requested it, an icon representing
+the permission, the name of the permission, and a description of what it
+entails can all be presented to the user.
+</p>
+
+<p>
+In every case, the icon and label set in a containing element become the default
+{@code icon} and {@code label} settings for all of the container's subelements.
+Thus, the icon and label set in the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+element are the default icon and label for each of the application's components.
+Similarly, the icon and label set for a component &mdash; for example, an
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+element &mdash; are the default settings for each of the component's
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code>
+elements. If an
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+element sets a label, but an activity and its intent filter do not,
+the application label is treated as the label for both the activity and
+the intent filter.
+</p>
+
+<p>
+The icon and label set for an intent filter are used to represent a component
+whenever the component is presented to the user as fulfilling the function
+advertised by the filter. For example, a filter with
+"{@code android.intent.action.MAIN}" and
+"{@code android.intent.category.LAUNCHER}" settings advertises an activity
+as one that initiates an application &mdash; that is, as
+one that should be displayed in the application launcher. The icon and label
+set in the filter are therefore the ones displayed in the launcher.
+</p>
+
+
+<h3 id="perms">Permissions</h3>
+
+<p>
+A <i>permission</i> is a restriction limiting access to a part of the code
+or to data on the device. The limitation is imposed to protect critical
+data and code that could be misused to distort or damage the user experience.
+</p>
+
+<p>
+Each permission is identified by a unique label. Often the label indicates
+the action that's restricted. For example, here are some permissions defined
+by Android:
+</p>
+
+<p style="margin-left: 2em">{@code android.permission.CALL_EMERGENCY_NUMBERS}
+<br/>{@code android.permission.READ_OWNER_DATA}
+<br/>{@code android.permission.SET_WALLPAPER}
+<br/>{@code android.permission.DEVICE_POWER}</p>
+
+<p>
+A feature can be protected by at most one permission.
+</p>
+
+<p>
+If an application needs access to a feature protected by a permission,
+it must declare that it requires that permission with a
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+element in the manifest. Then, when the application is installed on
+the device, the installer determines whether or not to grant the requested
+permission by checking the authorities that signed the application's
+certificates and, in some cases, asking the user.
+If the permission is granted, the application is able to use the protected
+features. If not, its attempts to access those features will simply fail
+without any notification to the user.
+</p>
+
+<p>
+An application can also protect its own components (activities, services,
+broadcast receivers, and content providers) with permissions. It can employ
+any of the permissions defined by Android (listed in
+{@link android.Manifest.permission android.Manifest.permission}) or declared
+by other applications. Or it can define its own. A new permission is declared
+with the
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+element. For example, an activity could be protected as follows:
+</p>
+
+<pre>
+&lt;manifest . . . &gt;
+ &lt;permission android:name="com.example.project.DEBIT_ACCT" . . . /&gt;
+ . . .
+ &lt;application . . .&gt;
+ &lt;activity android:name="com.example.project.FreneticActivity" . . . &gt;
+ android:permission="com.example.project.DEBIT_ACCT"
+ . . . &gt;
+ . . .
+ &lt;/activity&gt;
+ &lt;/application&gt;
+ . . .
+ &lt;uses-permission android:name="com.example.project.DEBIT_ACCT" /&gt;
+ . . .
+&lt;/manifest&gt;
+</pre>
+
+<p>
+Note that, in this example, the {@code DEBIT_ACCT} permission is not only
+declared with the
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+element, its use is also requested with the
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+element. Its use must be requested in order for other components of the
+application to launch the protected activity, even though the protection
+is imposed by the application itself.
+</p>
+
+<p>
+If, in the same example, the {@code permission} attribute was set to a
+permission declared elsewhere
+(such as {@code android.permission.CALL_EMERGENCY_NUMBERS}, it would not
+have been necessary to declare it again with a
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+element. However, it would still have been necessary to request its use with
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>.
+</p>
+
+<p>
+The
+<code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
+element declares a namespace for a group of permissions that will be defined in
+code. And
+<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
+defines a label for a set of permissions (both those declared in the manifest with
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+elements and those declared elsewhere). It affects only how the permissions are
+grouped when presented to the user. The
+<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
+element does not specify which permissions belong to the group;
+it just gives the group a name. A permission is placed in the group
+by assigning the group name to the
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+element's
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html#pgroup">permissionGroup</a></code>
+attribute.
+</p>
+
+
+<h3 id="libs">Libraries</h3>
+
+<p>
+Every application is linked against the default Android library, which
+includes the basic packages for building applications (with common classes
+such as Activity, Service, Intent, View, Button, Application, ContentProvider,
+and so on).
+</p>
+
+<p>
+However, some packages reside in their own libraries. If your application
+uses code from any of these packages, it must explicitly asked to be linked
+against them. The manifest must contain a separate
+<code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html">&lt;uses-library&gt;</a></code>
+element to name each of the libraries. (The library name can be found in the
+documentation for the package.)
+</p>
diff --git a/docs/html/guide/topics/manifest/manifest.jd b/docs/html/guide/topics/manifest/manifest.jd
deleted file mode 100644
index bf9194c..0000000
--- a/docs/html/guide/topics/manifest/manifest.jd
+++ /dev/null
@@ -1,3063 +0,0 @@
-page.title=The AndroidManifest.xml File
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<h2>In this document</h2>
-<ol>
-<li><a href="#filestruct">Structure of the Manifest File</a></li>
-<li><a href="#filef">File Features</a>
- <ol>
- <li><a href="#ifs">Intent Filter</a></li>
- <li><a href="#iconlabel">Icons and Labels</a></li>
- <li><a href="#perms">Using Permissions</a></li>
- <li><a href="#libs">Libraries</a></li>
- </ol></li>
-<li><a href="#elems">Elements of the Manifest File</a></li>
-</ol>
-</div>
-</div>
-
-<p>
-Every application must have an AndroidManifest.xml file (with precisely that
-name) in its root directory. The manifest presents essential information about
-the application to the Android system, information the system must have before
-it can run any of the application's code. Among other things, the manifest
-does the following:
-</p>
-
-<ul>
-<li>It names the Java package for the application.
-The package name serves as a unique identifier for the application.</li>
-
-<li>It describes the components of the application &mdash; the activities,
-services, broadcast receivers, and content providers that the application is
-composed of. It names the classes that implement each of the components and
-publishes their capabilities (for example, which {@link android.content.Intent
-Intent} messages they can handle). These declarations let the Android system
-know what the components are and under what conditions they can be launched.</li>
-
-<li>It determines which processes will host application components.</li>
-
-<li>It declares which permissions the application must have in order to
-access protected parts of the API and interact with other applications.</li>
-
-<li>It also declares the permissions that others are required to have in
-order to interact with the application's components.</li>
-
-<li>It lists the {@link android.app.Instrumentation} classes that provide
-profiling and other information as the application is running. These declarations
-are present in the manifest only while the application is being developed and
-tested; they're removed before the application is published.</li>
-
-<li>It declares the minimum version of the Android API that the application
-requires.</li>
-
-<li>It lists the libraries that the application must be linked against.</li>
-</ul>
-
-
-<h2 id="filestruct">Structure of the Manifest File</h2>
-
-<p>
-A later section of this document, <a href="#elems">"Elements of the Manifest
-File"</a>, describes all of the elements that can appear in the manifest file
-and each of their attributes. The diagram below shows the general structure of
-the file and every element it can contain.
-</p>
-
-<pre>
-&lt;?xml version="1.0" encoding="utf-8"?&gt;
-
-<a href="#manf">&lt;manifest&gt;</a>
-
- <a href="#usesp">&lt;uses-permission /&gt;</a>
- <a href="#prmsn">&lt;permission /&gt;</a>
- <a href="#ptree">&lt;permission-tree /&gt;</a>
- <a href="#pgroup">&lt;permission-group /&gt;</a>
-
- <a href="#instru">&lt;instrumentation /&gt;</a>
-
- <a href="#usess">&lt;uses-sdk /&gt;</a>
-
- <a href="#app">&lt;application&gt;</a>
-
- <a href="#actv">&lt;activity&gt;</a>
- <a href="#ifilt">&lt;intent-filter&gt;</a>
- <a href="#actn">&lt;action /&gt;</a>
- <a href="#catg">&lt;category /&gt;</a>
- <a href="#data">&lt;data /&gt;</a>
- <a href="#ifilt">&lt;/intent-filter&gt;</a>
- <a href="#meta">&lt;meta-data /&gt;</a>
- <a href="#actv">&lt;/activity&gt;</a>
-
- <a href="#alias">&lt;activity-alias&gt;</a>
- <a href="#ifilt">&lt;intent-filter&gt;</a> . . . <a href="#ifilt">&lt;/intent-filter&gt;</a>
- <a href="#meta">&lt;meta-data /&gt;</a>
- <a href="#alias">&lt;/activity-alias&gt;</a>
-
- <a href="#srvc">&lt;service&gt;</a>
- <a href="#ifilt">&lt;intent-filter&gt;</a> . . . <a href="#ifilt">&lt;/intent-filter&gt;</a>
- <a href="#meta">&lt;meta-data/&gt;</a>
- <a href="#srvc">&lt;/service&gt;</a>
-
- <a href="#rcvr">&lt;receiver&gt;</a>
- <a href="#ifilt">&lt;intent-filter&gt;</a> . . . <a href="#ifilt">&lt;/intent-filter&gt;</a>
- <a href="#meta">&lt;meta-data /&gt;</a>
- <a href="#rcvr">&lt;/receiver&gt;</a>
-
- <a href="#pvdr">&lt;provider&gt;</a>
- <a href="#grantp">&lt;grant-uri-permission /&gt;</a>
- <a href="#meta">&lt;meta-data /&gt;</a>
- <a href="#pvdr">&lt;/provider&gt;</a>
-
- <a href="#usesl">&lt;uses-library /&gt;</a>
-
- <a href="#app">&lt;/application&gt;</a>
-
-<a href="#manf">&lt;/manifest&gt;</a>
-</pre>
-
-<p>
-Some conventions and rules apply generally to all elements and attributes
-in the manifest:
-</p>
-
-<dl>
-<dt><b>Elements</b></dt>
-<dd>Only the {@code <a href="#manf">&lt;manifest&gt;</a>} and
-{@code <a href="#app">&lt;application&gt;</a>} elements are required, they each
-must be present and can occur only once. Most of the others can occur many times
-or not at all &mdash; although at least some of them must be present for the
-manifest to accomplish anything meaningful.
-
-<p>
-If an element contains anything at all, it contains other elements.
-All values are set through attributes, not as character data within an element.
-</p>
-
-<p>
-Elements at the same level are generally not ordered. For example,
-{@code <a href="#actv">&lt;activity&gt;</a>},
-{@code <a href{@code <a href="#pvdr">&lt;provider&gt;</a>}, and
-{@code <a href="#srvc">&lt;service&gt;</a>} elements can be intermixed in
-any sequence. (An {@code <a href="#alias">&lt;activity-alias&gt;</a>} is the
-exception to this rule: It must follow the {@code <a href="#actv">&lt;activity&gt;</a>}
-it is an alias for.)</p></dd>
-
-<dt><b>Attributes</b></dt>
-<dd>In a formal sense, all attributes are optional. However, there are some
-that must be specified for an element to accomplish its purpose. Use the
-documentation as a guide. For truly optional attributes, it mentions a default
-value or states what happens in the absence of a specification.
-
-<p>Except for some attributes of
-the root {@code <a href="#manf">&lt;manifest&gt;</a>} element,
-all attribute names begin with an {@code android:} prefix &mdash;
-for example, {@code android:alwaysRetainTaskState}. Because the prefix is
-universal, this documentation generally omits it when referring to attributes
-by name.</p></dd>
-
-<dt><b>Declaring class names</b></dt>
-<dd>Many elements correspond to Java objects, including elements for the
-application itself (the {@code <a href="#app">&lt;application&gt;</a>} element)
-and its principal components &mdash;
-activities ({@code <a href="#actv">&lt;activity&gt;</a>}),
-services ({@code <a href="#srvc">&lt;service&gt;</a>}),
-broadcast receivers ({@code <a href="#rcvr">&lt;receiver&gt;</a>}),
-and content providers ({@code <a href="#pvdr">&lt;provider&gt;</a>}).
-
-<p>
-If you define a subclass, as you almost always would for the component classes
-({@link android.app.Activity}, {@link android.app.Service},
-{@link android.content.BroadcastReceiver},
-and {@link android.content.ContentProvider}), the subclass is declared through
-a {@code name} attribute. The name must include the full package designation.
-For example, an {@link android.app.Service} subclass might be declared as follows:
-</p>
-
-<pre>&lt;manifest . . . &gt;
- &lt;application . . . &gt;
- &lt;service android:name="com.example.project.SecretService" . . . &gt;
- . . .
- &lt;/service&gt;
- . . .
- &lt;/application&gt;
-&lt;/manifest&gt;</pre>
-
-<p>
-However, as a shorthand, if the first character of the string is a period, the
-string is appended to the application's package name (as specified by the
-{@code <a href="#manf">&lt;manifest&gt;</a>} element's
-{@code <a href="#manf_package">package</a>} attribute). The following assignment
-is the same as the one above:
-</p>
-
-<pre>&lt;manifest package="com.example.project" . . . &gt;
- &lt;application . . . &gt;
- &lt;service android:name=".SecretService" . . . &gt;
- . . .
- &lt;/service&gt;
- . . .
- &lt;/application&gt;
-&lt;/manifest&gt;</pre>
-
-<p>
-When starting a component, Android creates an instance of the named subclass.
-If a subclass isn't specified, it creates an instance of the base class.
-</p></dd>
-
-<dt><b>Multiple values</b></dt>
-<dd>If more than one value can be specified, the element is almost always repeated,
-rather than listing multiple values within a single element.
-For example, an intent filter can list several actions:
-
-<pre>&lt;intent-filter . . . &gt;
- &lt;action android:name="android.intent.action.EDIT" /&gt;
- &lt;action android:name="android.intent.action.INSERT" /&gt;
- &lt;action android:name="android.intent.action.DELETE" /&gt;
- . . .
-&lt;/intent-filter&gt;</pre></dd>
-
-<dt><b>Resource values</b></dt>
-<dd>Some attributes have values that can be displayed to users &mdash; for
-example, a label and an icon for an activity. The values of these attributes
-should be localized and therefore set from a resource or theme. Resource values
-are expressed in the following format,</p>
-
-<p style="margin-left: 2em">{@code @[<i>package</i>:]<i>type</i>:<i>name</i>}</p>
-
-<p>
-where the <i>package</i> name can be omitted if the resource is in the same package
-as the application, <i>type</i> is a type of resource &mdash; such as "string" or
-"drawable" &mdash; and <i>name</i> is the name that identifies the specific resource.
-For example:
-</p>
-
-<pre>&lt;activity android:icon="@drawable/smallPic" . . . &gt</pre>
-
-<p>
-Values from a theme are expressed in a similar manner, but with an initial '?'
-rather than '@':
-</p>
-
-<p style="margin-left: 2em">{@code ?[<i>package</i>:]<i>type</i>:<i>name</i>}
-</p></dd>
-
-<dt><b>String values</b></dt>
-<dd>Where an attribute value is a string, double backslashes ('{@code \\}')
-must be used to escape characters &mdash; for example, '{@code \\n}' for
-a newline or '{@code \\uxxxx}' for a Unicode character.</dd>
-</dl>
-
-
-<h2 id="filef">File Features</h2>
-
-<p>
-The following sections describe how some Android features are reflected
-in the manifest file.
-</p>
-
-
-<h3 id="ifs">Intent Filters</h3>
-
-<p>
-The core components of an application (its activities, services, and broadcast
-receivers) are activated by <i>intents</i>. An intent is a
-bundle of information (an {@link android.content.Intent} object) describing a
-desired action &mdash; including the data to be acted upon, the category of
-component that should perform the action, and other pertinent instructions.
-Android locates an appropriate component to respond to the intent, launches
-a new instance of the component if one is needed, and passes it the
-Intent object.
-</p>
-
-<p>
-Components advertise their capabilities &mdash; the kinds of intents they can
-respond to &mdash; through <i>intent filters</i>. Since the Android system
-must learn which intents a component can handle before it launches the component,
-intent filters are specified in the manifest as
-{@code <a href="#ifilt">&lt;intent-filter&gt;</a>} elements. A component may
-have any number of filters, each one describing a different capability.
-</p>
-
-<p>
-An intent that explicitly names a target component will activate that component;
-the filter doesn't play a role. But an intent that doesn't specify a target by
-name can activate a component only if it can pass through one of the component's
-filters.
-</p>
-
-<p>
-For information on how Intent objects are tested against intent filters,
-a separate document,
-<a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents
-and Intent Filters</a>.
-</p>
-
-
-<h3 id="iconlabel">Icons and Labels</h3>
-
-<p>
-A number of elements have {@code icon} and {@code label} attributes for an
-icon and a text label that can displayed to users. Some also have a
-{@code description} attribute for longer explanatory text that can also be
-shown on-screen. For example, the {@code <a href="#prmsn">&lt;permission&gt;</a>}
-element has all three of these attributes, so that when the user is asked whether
-to grant the permission to an application that has requested it, an icon representing
-the permission, the name of the permission, and a description of what it
-entails can all be presented to the user.
-</p>
-
-<p>
-In every case, the icon and label set in a containing element become the default
-{@code icon} and {@code label} settings for all of the container's subelements.
-Thus, the icon and label set in the {@code <a href="#app">&lt;application&gt;</a>}
-element are the default icon and label for each of the application's components.
-Similarly, the icon and label set for a component &mdash; for example, an
-{@code <a href="#actv">&lt;activity&gt;</a>} element &mdash; are the default
-settings for each of the component's
-{@code <a href="#ifilt">&lt;intent-filter&gt;</a>} elements. If an
-{@code <a href="#app">&lt;application&gt;</a>} element sets a label, but
-an activity and its intent filter do not, the application label is treated
-as the label for both the activity and the intent filter.
-</p>
-
-<p>
-The icon and label set for an intent filter are used to represent a component
-whenever the component is presented to the user as fulfilling the function
-advertised by the filter. For example, a filter with
-"{@code android.intent.action.MAIN}" and
-"{@code android.intent.category.LAUNCHER}" settings advertises an activity
-as one that initiates an application &mdash; that is, as
-one that should be displayed in the application launcher. The icon and label
-set in the filter are therefore the ones displayed in the launcher.
-</p>
-
-
-<h3 id="perms">Permissions</h3>
-
-<p>
-A <i>permission</i> is a restriction limiting access to a part of the code
-or to data on the device. The limitation is imposed to protect critical
-data and code that could be misused to distort or damage the user experience.
-</p>
-
-<p>
-Each permission is identified
-by a unique label. Often the label indicates the action that's restricted.
-For example, here are some permissions defined by Android:
-</p>
-
-<p style="margin-left: 2em">{@code android.permission.CALL_EMERGENCY_NUMBERS}
-<br/>{@code android.permission.READ_OWNER_DATA}
-<br/>{@code android.permission.SET_WALLPAPER}
-<br/>{@code android.permission.DEVICE_POWER}</p>
-
-<p>
-A feature can be protected by at most one permission.
-</p>
-
-<p>
-If an application needs access to a feature protected by a permission, it must
-declare that it requires that permission with a
-{@code <a href="#usesp">&lt;uses-permission&gt;</a>} element in the manifest.
-Then, when the application is installed on the device, the installer determines
-whether or not to grant the requested permission by checking the authorities that
-signed the application's certificates and, in some cases, asking the user.
-If the permission is granted, the application is able to use the protected
-features. If not, its attempts to access those features will simply fail
-without any notification to the user.
-</p>
-
-<p>
-An application can also protect its own components (activities, services,
-broadcast receivers, and content providers) with permissions. It can employ
-any of the permissions defined by Android (listed in
-{@link android.Manifest.permission android.Manifest.permission}) or declared
-by other applications. Or it can define its own. A new permission is declared
-with the {@code <a href="#prmsn">&lt;permission&gt;</a>} element.
-For example, an activity could be protected as follows:
-</p>
-
-<pre>
-&lt;manifest . . . &gt;
- &lt;permission android:name="com.example.project.DEBIT_ACCT" . . . /&gt;
- . . .
- &lt;application . . .&gt;
- &lt;activity android:name="com.example.project.FreneticActivity" . . . &gt;
- android:permission="com.example.project.DEBIT_ACCT"
- . . . &gt;
- . . .
- &lt;/activity&gt;
- &lt;/application&gt;
- . . .
- &lt;uses-permission android:name="com.example.project.DEBIT_ACCT" /&gt;
- . . .
-&lt;/manifest&gt;
-</pre>
-
-<p>
-Note that, in this example, the {@code DEBIT_ACCT} permission is not only
-declared with the {@code <a href="#prmsn">&lt;permission&gt;</a>}
-element, its use is also requested with
-the {@code <a href="#usesp">&lt;uses-permission&gt;</a>} element. Its use
-must be requested in order for other components of the application to launch
-the protected activity, even though the protection is imposed by the
-application itself.
-</p>
-
-<p>
-If, in the same example, the {@code permission} attribute was set to a
-permission declared elsewhere
-(such as {@code android.permission.CALL_EMERGENCY_NUMBERS}, it would not
-have been necessary to declare it again with the
-{@code <a href="#prmsn">&lt;permission&gt;</a>} element.
-However, it would still have been necessary to request its use with
-{@code <a href="#usesp">&lt;uses-permission&gt;</a>}.
-</p>
-
-<p>
-The {@code <a href="#ptree">&lt;permission-tree&gt;</a>} element declares
-a namespace for a group of permissions that will be defined in code.
-And {@code <a href="#pgroup">&lt;permission-group&gt;</a>}
-defines a label for a set of permissions (both those declared in the
-manifest with {@code <a href="#prmsn">&lt;permission&gt;</a>} elements and
-those declared elsewhere). It affects only how the permissions are grouped
-when presented to the user.
-</p>
-
-
-<h3 id="libs">Libraries</h3>
-
-<p>
-Every application is linked against the default Android library, which
-includes the basic packages for building applications (with common classes
-such as Activity, Service, Intent, View, Button, Application, ContentProvider,
-and so on).
-</p>
-
-<p>
-However, some packages reside in their own libraries. If your application
-uses code from any of these packages, it must explicitly asked to be linked
-against them. The manifest must contain a separate
-{@code <a href="#usesl">&lt;uses-library&gt;</a>} element to name each
-of the libraries. (The library name can be found in the documentation
-for the package.)
-</p>
-
-
-<h2 id="elems">Elements of the Manifest File</h2>
-
-<p>
-This section describes all the elements that can appear in the manifest and each
-of their attributes in more detail. Only the elements listed here are legal.
-The list is alphabetical.
-</p>
-
-
-<h3 id="actn">&lt;action&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;action android:name="<i>string</i>" /&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#ifilt">&lt;intent-filter&gt;</a>}</dd>
-
-<p>
-<dt>description:</dt>
-<dd>Adds an action to an intent filter.
-An {@code <a href="#ifilt">&lt;intent-filter&gt;</a>} element must contain
-one or more {@code &lt;action&gt;} elements. If it doesn't contain any, no
-Intent objects will get through the filter. See
-<a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and
-Intent Filters</a> for details on intent filters and the role of action
-specifications within a filter.
-</dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:name}</dt>
-<dd>The name of the action. Some standard actions are defined in the
-{@link android.content.Intent#ACTION_CHOOSER Intent} class as
-{@code ACTION_<i>string</i>} constants. To assign one of these actions to
-this attribute, prepend "{@code android.intent.action.}" to the
-{@code <i>string</i>} that follows {@code ACTION_}.
-For example, for {@code ACTION_MAIN}, use "{@code android.intent.action.MAIN}"
-and for {@code ACTION_WEB_SEARCH}, use "{@code android.intent.action.WEB_SEARCH}".
-
-<p>
-For actions you define, it's best to use the package name as a prefix to
-ensure uniqueness. For example, a {@code TRANSMOGRIFY} action might be specified
-as follows:
-</p>
-
-<pre>&lt;action android:name="com.example.project.TRANSMOGRIFY" /&gt;</pre>
-</dd>
-</dl></dd>
-
-<dt>see also:</dt>
-<dd>{@code <a href="#ifilt">&lt;intent-filter&gt;</a>}</dd>
-
-</dl>
-<hr>
-
-<h3 id="actv">&lt;activity&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;activity android:allowTaskReparenting=["true" | "false"]
- android:alwaysRetainTaskState=["true" | "false"]
- android:clearTaskOnLaunch=["true"" | "false"]
- android:configChanges=["mcc" | "mnc" | "locale" |
- "touchscreen" | "keyboard" |
- "keyboardHidden" | "navigation" |
- "orientation" | "fontScale"]
- android:enabled=["true" | "false"]
- android:excludeFromRecents=["true" | "false"]
- android:exported=["true" | "false"]
- android:finishOnTaskLaunch=["true" | "false"]
- android:icon="<i>drawable resource</i>"
- android:label="<i>string resource</i>"
- android:launchMode=["multiple" | "singleTop" |
- "singleTask" | "singleInstance"]
- android:multiprocess=["true" | "false"]
- android:name="<i>string</i>"
- android:permission="<i>string</i>"
- android:process="<i>string</i>"
- android:screenOrientation=["unspecified" | "user" | "behind" |
- "landscape" | "portrait" |
- "sensor" | "nonsensor"]
- android:stateNotNeeded=["true" | "false"]
- android:taskAffinity="<i>string</i>"
- android:theme="<i>resource or theme</i>" &gt;
- . . .
-&lt;/activity&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#app">&lt;application&gt;</a>}</dd>
-
-<dt>can contain:</dt>
-<dd>{@code <a href="#ifilt">&lt;intent-filter&gt;</a>}
-<br/>{@code <a href="#meta">&lt;meta-data&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Declares an activity (an {@link android.app.Activity} subclass) that
-implements part of the application's visual user interface. All activities
-must be represented by {@code &lt;activity&gt;}
-elements in the manifest file. Any that are not declared there will not be seen
-by the system and will never be run.
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt><a href name="actv_reparent"></a>{@code android:allowTaskReparenting}</dt>
-<dd>Whether or not the activity can move from the task that started it to
-the task it has an affinity for when that task is next brought to the
-front &mdash; "{@code true}" if it can move, and "{@code false}" if it
-must remain with the task where it started.
-
-<p>
-If this attribute is not set, the value set by the corresponding
-{@code <a href="#app_reparent">allowTaskReparenting</a>}
-attribute of the {@code <a href="#app">&lt;application&gt;</a>} element
-applies to the activity. The default value is "{@code false}".
-</p>
-
-<p>
-Normally when an activity is started, it's associated with the task of
-the activity that started it and it stays there for its entire lifetime.
-You can use this attribute to force it to be re-parented to the task it
-has an affinity for when its current task is no longer displayed.
-Typically, it's used to cause the activities of an application to move
-to the main task associated with that application.
-</p>
-
-<p>
-For example, if an e-mail message contains a link to a web page, clicking
-the link brings up an activity that can display the page. That activity
-is defined by the browser application, but is launched as part of the e-mail
-task. If it's reparented to the browser task, it will be shown when the
-browser next comes to the front, and will be absent when the e-mail task
-again comes forward.
-</p>
-
-<p>
-The affinity of an activity is defined by the
-{@code <a href="#actv_aff">taskAffinity</a>} attribute. The affinity
-of a task is determined by reading the affinity of its root activity.
-Therefore, by definition, a root activity is always in a task with the
-same affinity. Since activities with "{@code singleTask}" or
-"{@code singleInstance}" launch modes can only be at the root of a task,
-re-parenting is limited to the "{@code standard}" and "{@code singleTop}"
-modes. (See also the {@code <a href="#actv_lmode">launchMode</a>}
-attribute.)
-</p></dd>
-
-<dt>{@code android:alwaysRetainTaskState}</dt>
-<dd>Whether or not the state of the task that the activity is in will always
-be maintained by the system &mdash; "{@code true}" if it will be, and
-"{@code false}" if the system is allowed to reset the task to its initial
-state in certain situations. The default value is "{@code false}". This
-attribute is meaningful only for the root activity of a task; it's ignored
-for all other activities.
-
-<p>
-Normally, the system clears a task (removes all activities from the stack
-above the root activity) in certain situations when the user re-selects that
-task from the home screen. Typically, this is done if the user hasn't visited
-the task for a certain amount of time, such as 30 minutes.
-</p>
-
-<p>
-However, when this attribute is "{@code true}", users will always return
-to the task in its last state, regardless of how they get there. This is
-useful, for example, in an application like the web browser where there is
-a lot of state (such as multiple open tabs) that users would not like to lose.
-</p></dd>
-
-<dt>{@code android:clearTaskOnLaunch}</dt>
-<dd>Whether or not all activities will be removed from the task, except for
-the root activity, whenever it is re-launched from the home screen &mdash;
-"{@code true}" if the task is always stripped down to its root activity, and
-"{@code false}" if not. The default value is "{@code false}". This attribute
-is meaningful only for activities that start a new task (the root activity);
-it's ignored for all other activities in the task.
-
-<p>
-When the value is "{@code true}", every time users start the task again, they
-are brought to its root activity, regardless of what they were last doing in
-the task and regardless of whether they used BACK or HOME to last leave it.
-When the value is "{@code false}", the task may be cleared of activities in
-some situations (see the {@code alwaysRetainTaskState} attribute), but not always.
-</p>
-
-<p>
-Suppose, for example, that someone launches activity P from the home screen,
-and from there goes to activity Q. The user next presses HOME, and then returns
-to activity P. Normally, the user would see activity Q, since that is what they
-were last doing in P's task. However, if P set this flag to "{@code true}", all
-of the activities on top of it (Q in this case) were removed when the user pressed
-HOME and the task went to the background. So the user sees only P when returning
-to the task.
-</p>
-
-<p>
-If this attribute and {@code allowTaskReparenting} are both "{@code true}",
-any activities that can be re-parented are moved to the task they share an
-affinity with; the remaining activities are then dropped, as described above.
-</p></dd>
-
-<dt>{@code android:configChanges}</dt>
-<dd>Lists configuration changes that the activity will handle itself. When
-changes that are not listed occur, the activity is shut down and restarted.
-When a listed change occurs, the activity remains running and its <code>{@link android.app.Activity#onConfigurationChanged onConfigurationChanged()}</code>
-method is called.
-
-<p>
-Any or all of the following strings can be used to set this attribute. Values are
-separated by '{@code |}' &mdash; for example, "{@code locale|navigation|orientation}".
-</p>
-
-<table>
-<tr>
- <td><b>Value</b></td>
- <td><b>Description</b></td>
-</tr><tr>
- <td>"{@code mcc}"</td>
- <td>The IMSI mobile country code (MCC) has changed &mdash;
- that is, a SIM has been detected and updated the MCC.</td>
-</tr><tr>
- <td>"{@code mnc}"</td>
- <td>The IMSI mobile network code (MNC) has changed &mdash;
- that is, a SIM has been detected and updated the MNC.</td>
-</tr><tr>
- <td>"{@code locale}"</td>
- <td>The locale has changed &mdash; for example, the user has selected a new
- language that text should be displayed in.</td>
-</tr><tr>
- <td>"{@code touchscreen}"</td>
- <td>The touchscreen has changed. (This should never normally happen.)</td>
-</tr><tr>
- <td>"{@code keyboard}"</td>
- <td>The keyboard type has changed &mdash; for example, the user has
- plugged in an external keyboard.</td>
-</tr><tr>
- <td>"{@code keyboardHidden}"</td>
- <td>The keyboard accessibility has changed &mdash; for example, the
- user has slid the keyboard out to expose it.</td>
-</tr><tr>
- <td>"{@code navigation}"</td>
- <td>The navigation type has changed. (This should never normally happen.)</td>
-</tr><tr>
- <td>"{@code orientation}"</td>
- <td>The screen orientation has changed &mdash; that is, the user has rotated
- the device.</td>
- </tr><tr>
- <td>"{@code fontScale}"</td>
- <td>The font scaling factor has changed &mdash; that is, the user has selected
- a new global font size.</td>
-</tr>
-</table>
-
-<p>
-All of these configuration changes can impact the resource values seen by the
-application. Therefore, when <code>{@link android.app.Activity#onConfigurationChanged
-onConfigurationChanged()}</code> is called, it will generally be necessary to again
-retrieve all resources (including view layouts, drawables, and so on) to correctly
-handle the change.
-</p></dd>
-
-<dt>{@code android:enabled}</dt>
-<dd>Whether or not the activity can be instantiated by the system &mdash;
-"{@code true}" if it can be, and "{@code false}" if not. The default value
-is "{@code true}".
-
-<p>
-The {@code <a href="#app">&lt;application&gt;</a>} element has its own
-{@code <a href="#app_enabled">enabled</a>} attribute that applies to all
-application components, including activities. The
-{@code <a href="#app">&lt;application&gt;</a>} and {@code &lt;activity&gt;}
-attributes must both be "{@code true}" (as they both are by default) for
-the system to be able to instantiate the activity. If either is
-"{@code false}", it cannot be instantiated.
-</p></dd>
-
-<dt>{@code android:excludeFromRecents}</dt>
-<dd>Whether or not the activity should be excluded from the list of recently
-launched activities that can be displayed to users &mdash; "{@code true}" if
-it should be excluded, and "{@code false}" if it should be included.
-The default value is "{@code false}".
-</p></dd>
-
-<dt>{@code android:exported}</dt>
-<dd>Whether or not the activity can be launched by components of other
-applications &mdash; "{@code true}" if it can be, and "{@code false}" if not.
-If "{@code false}", the activity can be launched only by components of the
-same application or applications with the same user ID.
-
-<p>
-The default value depends on whether the activity contains intent filters. The
-absence of any filters means that the activity can be invoked only by specifying
-its exact class name. This implies that the activity is intended only for
-application-internal use (since others would not know the class name). So in
-this case, the default value is "{@code false}".
-On the other hand, the presence of at least one filter implies that the activity
-is intended for external use, so the default value is "{@code true}".
-</p>
-
-<p>
-This attribute is not the only way to limit an activity's exposure to other
-applications. You can also use a permission to limit the external entities that
-can invoke the activity (see the {@code <a href="#actv_prmsn">permission</a>}
-attribute).
-</p></dd>
-
-<dt>{@code android:finishOnTaskLaunch}</dt>
-<dd>Whether or not an existing instance of the activity should be shut down
-(finished) whenever the user again launches its task (chooses the task on the
-home screen) &mdash; "{@code true}" if it should be shut down, and "{@code false}"
-if not. The default value is "{@code false}".
-
-<p>
-If this attribute and {@code <a href="#actv_reparent">allowTaskReparenting</a>}
-are both "{@code true}", this attribute trumps the other. The affinity of the
-activity is ignored. The activity is not re-parented, but destroyed.
-</p>
-
-<dt><a name="actv_icon"></a>{@code android:icon}</dt>
-<dd>An icon representing the activity. The icon is displayed to users when
-a representation of the activity is required on-screen. For example, icons
-for activities that initiate tasks are displayed in the launcher window.
-The icon is often accompanied by a label (see the {@code label} attribute).
-</p>
-
-<p>
-This attribute must be set as a reference to a drawable resource containing
-the image definition. If it is not set, the icon specified for the application
-as a whole is used instead (see the {@code <a href="#app">&lt;application&gt;</a>}
-element's {@code <a href="#app_icon">icon</a>} attribute).
-</p>
-
-<p>
-The activity's icon &mdash; whether set here or by the
-{@code <a href="#app">&lt;application&gt;</a>} element &mdash; is also the
-default icon for all the activity's intent filters (see the
-{@code <a href="#ifilt">&lt;intent-filter&gt;</a>} element's
-{@code <a href="#ifilt_icon">icon</a>} attribute).
-</p></dd>
-
-<dt>{@code android:label}</dt>
-<dd>A user-readable label for the activity. The label is displayed on-screen
-when the activity must be represented to the user. It's often displayed along
-with the activity icon.
-
-<p>
-If this attribute is not set, the label set for the application as a whole is
-used instead (see the {@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_label">label</a>} attribute).
-</p>
-
-<p>
-The activity's label &mdash; whether set here or by the
-{@code <a href="#app">&lt;application&gt;</a>} element &mdash; is also the
-default label for all the activity's intent filters (see the
-{@code <a href="#ifilt">&lt;intent-filter&gt;</a>} element's
-{@code <a href="#ifilt_label">label</a>} attribute).
-</p>
-
-<p>
-The label should be set as a reference to a string resource, so that
-it can be localized like other strings in the user interface.
-However, as a convenience while you're developing the application,
-it can also be set as a raw string.
-</p></dd>
-
-<dt><a name="actv_lmode"></a>{@code android:launchMode}</dt>
-<dd>An instruction on how the activity should be launched. There are four modes
-that work in conjunction with activity flags ({@code FLAG_ACTIVITY_*} constants)
-in {@link android.content.Intent} objects to determine what should happen when
-the activity is called upon to handle an intent:
-
-<p style="margin-left: 2em">"{@code standard}"
-<br>"{@code singleTop}"
-<br>"{@code singleTask}"
-<br>"{@code singleInstance}"</p>
-
-<p>
-The default mode is "{@code standard}".
-The modes differ from each other on three points:
-</p>
-
-<ol>
-
-<li><p><b>Whether or not a new instance of the class will be launched</b>. For
-the default "{@code standard}" mode, every time a new intent is received, a new
-instance of the class is created to handle that intent. For all the other modes,
-an existing instance is re-used if it resides at the top of the activity stack.
-As we'll see below, if there's an existing instance of a "{@code singleTask}" or
-"{@code singleInstance}" activity, it will always be (or come to be) at the top
-of the stack, so this condition will always be met for those two modes. However,
-an existing "{@code singleTop}" instance may or may not be at the top of the stack.
-If it is, it will be re-used. If not, a new instance is created.</p>
-
-<p>
-For example, suppose a task's activity stack consists of root activity A with
-activities B, C, and D on top in that order, so the stack is A-B-C-D. An intent
-arrives for an activity of type D. If D has the default "{@code standard}" launch
-mode, a new instance of the class is launched and the stack becomes A-B-C-D-D.
-However, if D's launch mode is "{@code singleTop}", the existing instance is
-expected to handle the new intent (since it's at the top of the stack) and the
-stack remains A-B-C-D.
-</p>
-
-<p>
-If, on the other hand, the arriving intent is for an activity of type B, a new
-instance of B would be launched no matter whether B's mode is "{@code standard}"
-or "{@code singleTop}" (since B is not at the top of the stack), so the resulting
-stack would be A-B-C-D-B.
-</p>
-
-<p>
-Now, suppose again that the stack is A-B-C-D and that the intent that arrives for
-B has the <code>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</code> flag set. Since
-the intent is destined for an activity of type B and the stack already has an object
-of that type, the flag causes activities C and D to be shut down and removed from
-the stack. If B's launch mode is "{@code standard}", it too will be removed, and
-a new instance of B launched to handle the incoming intent. That's because a new
-instance is always created for a new intent when the launch mode is "{@code standard}".
-However, if B's launch mode is "{@code singleTop}", the current instance would remain
-in the stack and receive the intent.
-</p>
-
-<p>
-Whenever an existing "{@code singleTop}", "{@code singleTask}", or
-"{@code singleInstance}" object is expected to handle an incoming intent, its
-<code>{@link android.app.Activity#onNewIntent onNewIntent()}</code> method is called with the
-{@link android.content.Intent} object passed as an argument.
-</p>
-</li>
-
-<li><p><b>Which task will hold the activity that responds to the intent</b>.
-For the "{@code standard}" and "{@code singleTop}" modes, it's the task that
-originated the intent (and called <code>{@link android.content.Context#startActivity
-startActivity()}</code>) &mdash; unless the Intent object contains the
-<code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code> flag. In that case,
-a different task is chosen as follows:</p>
-
-<ul>
-<li>If there's an existing task with the same affinity as the target activity,
-that task will hold the instance that responds to the intent. (As noted above,
-it could be an existing instance for a "{@code singleTop}" activity, but will
-always be a new instance for a "{@code standard}" activity.)</li>
-
-<li>Otherwise, the activity is launched as the root of a new task.</li>
-</ul>
-
-<p>
-In contrast, the "{@code singleTask}" and "{@code singleInstance}" modes mark
-activities that will always be at the root of a task; they can never be launched
-as part of another task. Moreover, once a "{@code singleTask}" or
-"{@code singleInstance}" activity has been launched, that instance is re-used
-to handle all new intents, so there is never more than one instance of the
-activity on the device.
-</p>
-
-<p>
-When a new intent arrives for an existing "{@code singleTask}" activity, all
-other activities are removed from its stack, so that only the root activity
-remains; it's as if the Intent object included the
-<code>{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}</code> flag. The activity
-is then at the top of its stack, and in a position to receive the new intent
-in an <code>{@link android.app.Activity#onNewIntent onNewIntent()}</code> call.
-</p></li>
-
-<li><p><b>Whether the instance can have other activities in its task</b>.
-A "{@code singleInstance}" activity stands alone as the only activity in its
-task. If it starts another activity, that activity will be launched in a
-different task regardless of its launch mode. In all other respects, the
-"{@code singleInstance}" mode is identical to "{@code singleTask}".</p>
-
-<p>
-All modes other than "{@code singleInstance}" permit multiple activities
-to belong to the task.
-</p></li>
-</ol>
-</dd>
-
-<dt>{@code android:multiprocess}</dt>
-<dd>Whether an instance of the activity can be launched into the process of the component
-that started it &mdash; "{@code true}" if it can be, and "{@code false}" if not.
-The default value is "{@code false}".
-
-<p>
-Normally, a new instance of an activity is launched into the process of the
-application that defined it, so all instances of the activity run in the same
-process. However, if this flag is set to "{@code true}", instances of the
-activity can run in multiple processes, allowing the system to create instances
-wherever they are used (provided permissions allow it), something that is almost
-never necessary or desirable.
-</p></dd>
-
-<dt>{@code android:name}</dt>
-<dd>The name of the class that implements the activity, a subclass of
-{@link android.app.Activity}. The attribute value should be a fully qualified
-class name (such as, "{@code com.example.project. ExtracurricularActivity}").
-However, as a shorthand, if the first character of the name is a period
-(for example, "{@code . ExtracurricularActivity}"), it is appended to the
-package name specified in the {@code <a href="#manf">&lt;manifest&gt;</a>}
-element.
-
-<p>
-There is no default. The name must be specified.
-</p></dd>
-
-<dt><a name="actv_prmsn"></a>{@code android:permission}</dt>
-<dd>The name of a permission that clients must have to launch the activity
-or otherwise get it to respond to an intent. If a caller of
-<code>{@link android.content.Context#startActivity startActivity()}</code> or
-<code>{@link android.app.Activity#startActivityForResult startActivityForResult()}</code>
-has not been granted the specified permission, its intent will not be
-delivered to the activity.
-
-<p>
-If this attribute is not set, the permission set by the
-{@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_prmsn">permission</a>} attribute applies
-to the activity. If neither attribute is set, the activity is
-not protected by a permission.
-</p>
-
-<p>
-For more information on permissions, see the <a href="#sectperm">Permissions</a>
-section earlier in this document and a separate document,
-<a href="{@docRoot}guide/topics/security/security.html">Security and
-Permissions</a>.
-</p></dd>
-
-<dt>{@code android:process}</dt>
-<dd>The name of the process in which the activity should run. Normally,
-all components of an application run in the default process created for the
-application. It has the same name as the application package. The {@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_proc">process</a>} attribute can set a different
-default for all components. But each component can override the default,
-allowing you to spread your application across multiple processes.
-
-<p>
-If the name assigned to this attribute begins with a colon (':'), a new
-process, private to the application, is created when it's needed and
-the activity runs in that process.
-If the process name begins with a lowercase character, the activity will run
-in a global process of that name, provided that it has permission to do so.
-This allows components in different applications to share a process, reducing
-resource usage.
-</p></dd>
-
-<dt>{@code android:screenOrientation}</dt>
-<dd>The orientation of the activity's display on the device.
-The value can be any one of the following strings:
-
-<table>
-<tr>
- <td>"{@code unspecified}"</td>
- <td>The default value. The system chooses the orientation. The policy it
- uses, and therefore the choices made in specific contexts, may differ
- from device to device.</td>
-</tr><tr>
- <td>"{@code landscape}"</td>
- <td>Landscape orientation (the display is wider than it is tall).</td>
-</tr><tr>
- <td>"{@code portrait}"</td>
- <td>Portrait orientation (the display is taller than it is wide).</td>
-</tr><tr>
- <td>"{@code user}"</td>
- <td>The user's current preferred orientation.</td>
-</tr><tr>
- <td>"{@code behind}"</td>
- <td>The same orientation as the activity that's immediately beneath it in
- the activity stack.</td>
-</tr><tr>
- <td>"{@code sensor}"</td>
- <td>The orientation determined by a physical orientation sensor. The
- orientation of the display depends on how the user is holding the device;
- it changes when the user rotates the device.</td>
-</tr><tr>
- <td>"{@code nosensor}"</td>
- <td>An orientation determined without reference to a physical orientation sensor.
- The sensor is ignored, so the display will not rotate based on how the user
- moves the device. Except for this distinction, the system chooses the
- orientation using the same policy as for the "{@code unspecified}" setting.</td>
-</tr>
-</table></dd>
-
-<dt>{@code android:stateNotNeeded}</dt>
-<dd>Whether or not the activity can be killed and successfully restarted
-without having saved its state &mdash; "{@code true}" if it can be restarted
-without reference to its previous state, and "{@code false}" if its previous
-state is required. The default value is "{@code false}".
-
-<p>
-Normally, before an activity is temporarily shut down to save resources, its
-<code>{@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}</code>
-method is called. This method stores the current state of the activity in a
-{@link android.os.Bundle} object, which is then passed to
-<code>{@link android.app.Activity#onCreate onCreate()}</code> when the activity
-is restarted. If this attribute is set to "{@code true}",
-{@code onSaveInstanceState()} may not be called and {@code onCreate()} will
-be passed {@code null} instead of the Bundle &mdash; just as it was when the
-activity started for the first time.
-</p>
-
-<p>
-A "{@code true}" setting ensures that the activity can be restarted in the
-absence of retained state. For example, the activity that displays the
-home screen uses this setting to make sure that it does not get removed if it
-crashes for some reason.
-</p></dd>
-
-<dt><a name="actv_aff"></a>{@code android:taskAffinity}</dt>
-<dd>The task that the activity has an affinity for. Activities with
-the same affinity conceptually belong to the same task (to the same
-"application" from the user's perspective). The affinity of a task
-is determined by the affinity of its root activity.
-
-<p>
-The affinity determines two things &mdash; the task that the activity is re-parented
-to (see the {@code <a href="#actv_reparent">allowTaskReparenting</a>}
-attribute) and the task that will house the activity when it is launched
-with the <code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code>
-flag.
-</p>
-
-<p>
-By default, all activities in an application have the same affinity. You
-can set this attribute to group them differently, and even place
-activities defined in different applications within the same task. To
-specify that the activity does not have an affinity for any task, set
-it to an empty string.
-
-<p>
-If this attribute is not set, the activity inherits the affinity set
-for the application (see the {@code <a href="#app">&lt;application&gt;</a>}
-element's {@code <a href="#app_aff">taskAffinity</a>} attribute).
-The name of the default affinity for an application is the package name set
-by the {@code <a href="#manf">&lt;manifest&gt;</a>} element.
-</p>
-
-<dt><a name="actv_theme"></a>{@code android:theme}</dt>
-<dd>A reference to a style resource defining an overall theme for the activity.
-This automatically sets the activity's context to use this theme (see
-<code>{@link android.content.Context#setTheme setTheme()}</code>, and may also
-cause "starting" animations prior to the activity being launched (to better
-match what the activity actually looks like).
-
-<p>
-If this attribute is not set, the activity inherits the theme set for the
-application as a whole &mdash; see the {@code <a href="#app">&lt;application&gt;</a>}
-element's {@code <a href="#app_theme">theme</a>} attribute. If that attribute is
-also not set, the default system theme is used.
-</p>
-<dd>
-</dl></dd>
-
-</dl>
-<hr>
-
-
-<h3 id="alias">&lt;activity-alias&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;activity-alias android:enabled=["true" | "false"]
- android:exported=["true" | "false"]
- android:icon="<i>drawable resource</i>"
- android:label="<i>string resource</i>"
- android:name="<i>string</i>"
- android:permission="<i>string</i>"
- android:targetActivity="<i>string</i>" &gt;
- . . .
-&lt;/activity-alias&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#app">&lt;application&gt;</a>}</dd>
-
-<dt>can contain:</dt>
-<dd>{@code <a href="#ifilt">&lt;intent-filter&gt;</a>}
-<br/>{@code <a href="#meta">&lt;meta-data&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>An alias for an activity, named by the {@code targetActivity}
-attribute. The target must be in the same application as the
-alias and it must be declared before the alias in the manifest.
-
-<p>
-The alias presents the target activity as a independent entity.
-It can have its own set of intent filters, and they, rather than the
-intent filters on the target activity itself, determine which intents
-can activate the target through the alias and how the system
-treats the alias. For example, the intent filters on the alias may
-specify the "<code>{@link android.content.Intent#ACTION_MAIN
-android.intent.action.MAIN}</code>"
-and "<code>{@link android.content.Intent#CATEGORY_LAUNCHER
-android.intent.category.LAUNCHER}</code>" flags, causing it to be
-represented in the application launcher, even though none of the
-filters on the target activity itself set these flags.
-</p>
-
-<p>
-With the exception of {@code targetActivity}, {@code &lt;activity-alias&gt;}
-attributes are a subset of {@code <a href="#actv">&lt;activity&gt;</a>} attributes.
-For attributes in the subset, none of the values set for the target carry over
-to the alias. However, for attributes not in the subset, the values set for
-the target activity also apply to the alias.
-</p></dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:enabled}</dt>
-<dd>Whether or not the target activity can be instantiated by the system through
-this alias &mdash; "{@code true}" if it can be, and "{@code false}" if not.
-The default value is "{@code true}".
-
-<p>
-The {@code <a href="#app">&lt;application&gt;</a>} element has its own
-{@code <a href="#app_enabled">enabled</a>} attribute that applies to all
-application components, including activity aliases. The
-{@code <a href="#app">&lt;application&gt;</a>} and {@code &lt;activity-alias&gt;}
-attributes must both be "{@code true}" for the system to be able to instantiate
-the target activity through the alias. If either is "{@code false}", the alias
-does not work.
-</p></dd>
-
-<dt>{@code android:exported}</dt>
-<dd>Whether or not components of other applications can launch the target activity
-through this alias &mdash; "{@code true}" if they can, and "{@code false}" if not.
-If "{@code false}", the target activity can be launched through the alias only by
-components of the same application as the alias or applications with the same user ID.
-
-<p>
-The default value depends on whether the alias contains intent filters. The
-absence of any filters means that the activity can be invoked through the alias
-only by specifying the exact name of the alias. This implies that the alias
-is intended only for application-internal use (since others would not know its name)
-&mdash; so the default value is "{@code false}".
-On the other hand, the presence of at least one filter implies that the alias
-is intended for external use &mdash; so the default value is "{@code true}".
-</p></dd>
-
-<dt>{@code android:icon}</dt>
-<dd>An icon for the target activity when presented to users through the alias.
-See the {@code <a href="#actv">&lt;activity&gt;</a>} element's
-{@code <a href="#actv_icon">icon</a>} attribute for more information.
-
-<dt>{@code android:label}</dt>
-<dd>A user-readable label for the alias when presented to users through the alias.
-See the the {@code <a href="#actv">&lt;activity&gt;</a>} element's
-{@code <a href="#actv_label">label</a>} attribute for more information.
-</p></dd>
-
-<dt>{@code android:name}</dt>
-<dd>A unique name for the alias. The name should resemble a fully
-qualified class name. But, unlike the name of the target activity,
-the alias name is arbitrary; it does not refer to an actual class.
-</p></dd>
-
-<dt>{@code android:permission}</dt>
-<dd>The name of a permission that clients must have to launch the target activity
-or get it to do something via the alias. If a caller of
-<code>{@link android.content.Context#startActivity startActivity()}</code> or
-<code>{@link android.app.Activity#startActivityForResult startActivityForResult()}</code>
-has not been granted the specified permission, the target activity will not be
-activated.
-
-<p>This attribute supplants any permission set for the target activity itself. If
-it is not set, a permission is not needed to activate the target through the alias.
-</p>
-
-<p>
-For more information on permissions, see the {@code <a href="#perms">Permissions</a>
-section earlier in this document.
-</p></dd>
-
-<dt>{@code android:targetActivity}</dt>
-<dd>The name of the activity that can be activated through the alias.
-This name must match the {@code name} attribute of an
-{@code <a href="#actv">&lt;activity&gt;</a>} element that precedes
-the alias in the manifest.
-</p></dd>
-</dl></dd>
-
-<dt>see also:</dt>
-<dd>{@code <a href="#actv">&lt;activity&gt;</a>}</dd>
-
-</dl>
-<hr>
-
-<h3 id="app">&lt;application&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;application android:allowClearUserData=["true" | "false"]
- android:allowTaskReparenting=["true" | "false"]
- android:debuggable=["true" | "false"]
- android:description="<i>string resource</i>"
- android:enabled=["true" | "false"]
- android:hasCode=["true" | "false"]
- android:icon="<i>drawable resource</i>"
- android:label="<i>string resource</i>"
- android:manageSpaceActivity="<i>string</i>"
- android:name="<i>string</i>"
- android:permission="<i>string</i>"
- android:persistent=["true" | "false"]
- android:process="<i>string</i>"
- android:taskAffinity="<i>string</i>"
- android:theme="<i>resource or theme</i>" &gt;
- . . .
-&lt;/application&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#manf">&lt;manifest&gt;</a>}</dd>
-
-<dt>can contain:</dt>
-<dd>{@code <a href="#actv">&lt;activity&gt;</a>}
-<br/>{@code <a href="#alias">&lt;activity-alias&gt;</a>}
-<br/>{@code <a href="#srvc">&lt;service&gt;</a>}
-<br/>{@code <a href="#rcvr">&lt;receiver&gt;</a>}
-<br/>{@code <a href="#pvdr">&lt;provider&gt;</a>}
-<br/>{@code <a href="#usesl">&lt;uses-library&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>The declaration of the application. This element contains subelements
-that declare each of the application's components and has attributes
-that can affect all the components. Many of these attributes (such as
-{@code icon}, {@code label}, {@code permission}, {@code process},
-{@code taskAffinity}, and {@code allowTaskReparenting}) set default values
-for corresponding attributes of the component elements. Others (such as
-{@code debuggable}, {@code enabled}, {@code description}, and
-{@code allowClearUserData}) set values for the application as a whole and
-cannot be overridden by the components.</dd>
-
-<dt>attributes</dt>
-<dd><dl class="attr">
-<dt>{@code android:allowClearUserData}</dt>
-<dd>Whether or not users are given the option to remove user data &mdash;
-"{@code true}" if they are, and "{@code false}" if not. If the value is
-"{@code true}", as it is by default, the application manager includes an
-option that allows users to clear the data.</dd>
-
-<dt><a name="app_reparent"></a>{@code android:allowTaskReparenting}</dt>
-<dd>Whether or not activities that the application defines can move from
-the task that started them to the task they have an affinity for when that task
-is next brought to the front &mdash; "{@code true}" if they can move, and
-"{@code false}" if they must remain with the task where they started.
-The default value is "{@code false}".
-
-<p>
-The {@code <a href="#actv">&lt;activity&gt;</a>} element has its own
-{@code <a href="#act_reparent">allowTaskReparenting</a>} attribute
-that can override the value set here. See that attribute for more
-information.
-</p></dd>
-
-<dt>{@code android:debuggable}</dt>
-<dd>Whether or not the application can be debugged, even when running
-on a device in user mode &mdash; "{@code true}" if it can be, and "{@code false}"
-if not. The default value is "{@code false}".</dd>
-
-<dt>{@code android:description}</dt>
-<dd>User-readable text about the application, longer and more descriptive than the application label. The value must be set as a reference to a string resource. Unlike the label, it cannot be a raw string. There is no default value.</dd>
-
-<dt><a name="app_enabled"></a>{@code android:enabled}</dt>
-<dd>Whether or not the Android system can instantiate components of
-the application &mdash; "{@code true}" if it can, and "{@code false}"
-if not. If the value is "{@code true}", each component's
-{@code enabled} attribute determines whether that component is enabled
-or not. If the value is "{@code false}", it overrides the
-component-specific values; all components are disabled.
-
-<p>
-The default value is "{@code true}".
-</p></dd>
-
-<dt>{@code android:hasCode}</dt>
-<dd>Whether or not the application contains any code &mdash; "{@code true}"
-if it does, and "{@code false}" if not. When the value is "{@code false}",
-the system does not try to load any application code when launching components.
-The default value is "{@code true}".
-
-<p>
-An application would not have any code of its own only if it's using nothing
-but built-in component classes, such as an activity that uses the {@link
-android.app.AliasActivity} class, a rare occurrence.
-
-<dt><a name="app_icon"></a>{@code android:icon}</dt>
-<dd>An icon for the application as whole, and the default icon for
-each of the application's components. See the individual
-{@code icon} attributes for
-{@code <a href="#actv">&lt;activity&gt;</a>},
-{@code <a href="#alias">&lt;activity-alias&gt;</a>},
-{@code <a href="#srvc">&lt;service&gt;</a>},
-{@code <a href="#rcvr">&lt;receiver&gt;</a>}, and
-{@code <a href="#pvdr">&lt;provider&gt;</a>} elements.
-
-<p>
-This attribute must be set as a reference to a drawable resource containing
-the image definition. There is no default icon.
-</p></dd>
-
-<dt><a name="app_label"></a>{@code android:label}</dt>
-<dd>A user-readable label for the application as a whole, and a default
-label for each of the application's components. See the individual
-{@code label} attributes for
-{@code <a href="#actv">&lt;activity&gt;</a>},
-{@code <a href="#alias">&lt;activity-alias&gt;</a>},
-{@code <a href="#srvc">&lt;service&gt;</a>},
-{@code <a href="#rcvr">&lt;receiver&gt;</a>}, and
-{@code <a href="#pvdr">&lt;provider&gt;</a>} elements.
-
-<p>
-The label should be set as a reference to a string resource, so that
-it can be localized like other strings in the user interface.
-However, as a convenience while you're developing the application,
-it can also be set as a raw string.
-</p></dd>
-
-<dt>{@code android:manageSpaceActivity}</dt>
-<dd>The fully qualified name of an Activity subclass that the system
-can launch to let users manage the memory occupied by the application
-on the device. The activity should also be declared with an
-{@code <a href="#actv">&lt;activity&gt;</a>} element.
-</dd>
-
-<dt>{@code android:name}</dt>
-<dd>The fully qualified name of an {@link android.app.Application}
-subclass implemented for the application. When the application process
-is started, this class is instantiated before any of the application's
-components.
-
-<p>
-The subclass is optional; most applications won't need one.
-In the absence of a subclass, Android uses an instance of the base
-Application class.
-</p></dd>
-
-<dt><a name="app_prmsn"></a>{@code android:permission}</dt>
-<dd>The name of a permission that clients must have in order to interact
-with the application. This attribute is a convenient way to set a
-permission that applies to all of the application's components. It can
-be overwritten by setting the {@code permission} attributes of individual
-components.
-
-<p>
-For more information on permissions, see the <a href="#sectperm">Permissions</a>
-section earlier in this document and a separate document,
-<a href="{@docRoot}guide/topics/security/security.html">Security and
-Permissions</a>.
-</p></dd>
-
-<dt>{@code android:persistent}</dt>
-<dd>Whether or not the application should remain running at all times &mdash;
-"{@code true}" if it should, and "{@code false}" if not. The default value
-is "{@code false}". Applications should not normally set this flag;
-persistence mode is intended only for certain system applications.</dd>
-
-<dt><a name="app_proc"></a>{@code android:process}</dt>
-<dd>The name of a process where all components of the application should run.
-Each component can override this default by setting its own {@code process}
-attribute.
-
-<p>
-By default, Android creates a process for an application when the first
-of its components needs to run. All components then run in that process.
-The name of the default process matches the package name set by the
-{@code <a href="#manf">&lt;manifest&gt;</a>} element.
-</p>
-
-<p>By setting this attribute to a process name that's shared with another
-application, you can arrange for components of both applications to run in
-the same process &mdash; but only if the two applications also share a
-user ID and be signed with the same certificate.
-</p>
-
-<p>
-If the name assigned to this attribute begins with a colon (':'), a new
-process, private to the application, is created when it's needed.
-If the process name begins with a lowercase character, a global process
-of that name is created. A global process can be shared with other
-applications, reducing resource usage.
-</p></dd>
-
-<dt><a href name="app_aff"></a>{@code android:taskAffinity}</dt>
-<dd>An affinity name that applies to all activities within the application,
-except for those that set a different affinity with their own {@code
-<a href="#actv_aff">taskAffinity</a>} attributes. See that attribute
-for more information.
-
-<p>
-By default, all activities within an application share the same
-affinity. The name of that affinity is the same as the package name
-set by the {@code <a href="#manf">&lt;manifest&gt;</a>} element.
-</p></dd>
-
-<dt><a name="app_theme"></a>{@code android:theme}</dt>
-<dd>A reference to a style resource defining a default theme for all
-activities in the application. Individual activities can override
-the default by setting their own {@code <a href="#actv_theme">theme</a>}
-attributes; see that attribute for more information.</dd>
-
-</dl></dd>
-
-<dt>see also:</dt>
-<dd>{@code <a href="#actv">&lt;activity&gt;</a>}
-<br/>{@code <a href="#srvc">&lt;service&gt;</a>}
-<br/>{@code <a href="#rcvr">&lt;receiver&gt;</a>}
-<br/>{@code <a href="#pvdr">&lt;provider&gt;</a>}</dd>
-
-</dl>
-<hr>
-
-<h3 id="catg">&lt;category&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;category android:name="<i>string</i>" /&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#ifilt">&lt;intent-filter&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Adds a category name to an intent filter. See
-<a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and
-Intent Filters</a> for details on intent filters and the role of category
-specifications within a filter.</dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:name}</dt>
-<dd>The name of the category. Standard categories are defined in the
-{@link android.content.Intent} class as {@code CATEGORY_<i>name</i>}
-constants. The name assigned here can be derived from those constants
-by prefixing "{@code android.intent.category.}" to the
-{@code <i>name</i>} that follows {@code CATEGORY_}. For example,
-the string value for {@code CATEGORY_LAUNCHER} is
-"{@code android.intent.category.LAUNCHER}".
-
-<p>
-Custom categories should use the package name as a prefix, to ensure
-that they are unique.
-</p></dd>
-</dl></dd>
-
-<dt>see also:</dt>
-<dd>{@code <a href="#actn">&lt;action&gt;</a>}
-<br/>{@code <a href="#data">&lt;data&gt;</a>}</dd>
-
-</dl>
-<hr>
-
-<h3 id="data">&lt;data&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;data android:host="<i>string</i>"
- android:mimeType="<i>string</i>"
- android:path="<i>string</i>"
- android:pathPattern="<i>string</i>"
- android:pathPrefix="<i>string</i>"
- android:port="<i>string</i>"
- android:scheme="<i>string</i>" /&gt;</pre></dd>
-
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#ifilt">&lt;intent-filter&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Adds a data specification to an intent filter. The specification can
-be just a data type (the {@code <a href="#data_mime">mimeType</a>} attribute),
-just a URI, or both a data type and a URI. A URI is specified by separate
-attributes for each of its parts:
-
-<p style="margin-left: 2em">{@code scheme://host:port/path} <i>or</i>
-{@code pathPrefix} <i>or</i> {@code pathPattern}</p>
-
-<p>
-These attributes are optional, but also mutually dependent:
-If a {@code <a href="#data_scheme">scheme</a>} is not specified for the
-intent filter, all the other URI attributes are ignored. If a
-{@code <a href="#data_host">host</a>} is not specified for the filer,
-the {@code port} attribute and all the path attributes are ignored.
-</p>
-
-<p>
-All the {@code &lt;data&gt;} elements contained within the same
-{@code <a href="#ifilt">&lt;intent-filter&gt;</a>} element contribute to
-the same filter. So, for example, the following filter specification,
-</p>
-
-<pre>&lt;intent-filter . . . &gt;
- &lt;data android:scheme="something" android:host="project.example.com" /&gt;
- . . .
-&lt;/intent-filter&gt;</pre>
-
-<p>is equivalent to this one:</p>
-
-<pre>&lt;intent-filter . . . &gt;
- &lt;data android:scheme="something" /&gt
- &lt;data android:host="project.example.com" /&gt;
- . . .
-&lt;/intent-filter&gt;</pre>
-
-<p>
-You can place any number of &lt;data&gt; elements inside an
-{@code <a href="#ifilt">&lt;intent-filter&gt;</a>} to give it multiple data
-options. None of its attributes have default values.
-</p>
-
-<p>
-Information on how intent filters work, including the rules for how Intent objects
-are matched against filters, can be found in another document,
-<a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and
-Intent Filters</a>. See also the <a href="#ifs">Intent Filters</a> section
-earlier in this document.
-</p></dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt><a name="data_host"></a>{@code android:host}</dt>
-<dd>The host part of a URI authority. This attribute is meaningless
-unless a {@code <a href="#data_scheme">scheme</a>} attribute is also
-specified for the filter.
-</dd>
-
-<dt><a name="data_mime"></a>{@code android:mimeType}</dt>
-<dd>A MIME media type, such as {@code image/jpeg} or {@code audio/mpeg4-generic}.
-The subtype can be the asterisk wildcard ({@code *}) to indicate that any
-subtype matches.</dd>
-
-<dt>{@code android:path}
-<br/>{@code android:pathPrefix}
-<br/>{@code android:pathPattern}</dt>
-<dd>The path part of a URI. The {@code path} attribute specifies a complete
-path that is matched against the complete path in an Intent object. The
-{@code pathPrefix} attribute specifies a partial path that is matched against
-only the initial part of the path in the Intent object. The {@code pathPattern}
-attribute specifies a complete path that is matched against the complete path
-in the Intent object, but it can contain the following wildcards:
-
-<ul>
-<li>An asterisk ('{@code *}') matches a sequence of 0 to many occurrences of
-the immediately preceding character.</li>
-
-<li><p>A period followed by an asterisk ("{@code .*}") matches any sequence of
-0 to many characters.</p></li>
-</ul>
-
-<p>
-Because '{@code \}' is used as an escape character when the string is read
-from XML (before it is parsed as a pattern), you will need to double-escape:
-For example, a literal '{@code *}' would be written as "{@code \\*}" and a
-literal '{@code \}' would be written as "{@code \\\\}". This is basically
-the same as what you would need to write if constructing the string in Java code.
-</p>
-
-<p>
-For more information on these three types of patterns, see the descriptions of
-{@link android.os.PatternMatcher#PATTERN_LITERAL},
-{@link android.os.PatternMatcher#PATTERN_PREFIX}, and
-{@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB} in the
-{@link android.os.PatternMatcher} class.
-</p>
-
-<p>These attributes are meaningful only if the
-{@code <a href="#data_scheme">scheme</a>} and
-{@code <a href="#data_host">host</a>}
-attributes are also specified for the filter.
-</p></dd>
-
-<dt>{@code android:port}</dt>
-<dd>The port part of a URI authority. This attribute is meaningful only
-if the {@code <a href="#data_scheme">scheme</a>} and
-{@code <a href="#data_host">host</a>} attributes are also specified for
-the filter.</dd>
-
-<dt><a name="data_scheme"></a>{@code android:scheme}</dt>
-<dd>The scheme part of a URI. This is the minimal essential attribute for
-specifying a URI; at least one {@code scheme} attribute must be set
-for the filter, or none of the other URI attributes are meaningful.
-
-<p>
-A scheme is specified without the trailing colon (for example,
-{@code http}, rather than {@code http:}).
-</p>
-
-<p>
-If the filter has a data type set (the {@code <a href="#data_mime">mimeType</a>}
-attribute) but no scheme, the {@code content:} and {@code file:} schemes are
-assumed.
-</p></dd>
-</dl></dd>
-
-<dt>see also:</dt>
-<dd>{@code <a href="#actn">&lt;action&gt;</a>}
-<br/>{@code <a href="#catg">&lt;category&gt;</a>}</dd>
-
-</dl>
-<hr>
-
-<h3 id="grantp">&lt;grant-uri-permission&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;grant-uri-permission android:path="<i>string</i>"
- android:pathPattern="<i>string</i>"
- android:pathPrefix="<i>string</i>" /&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#pvdr">&lt;provider&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Specifies which data subsets of the parent content provider permission
-can be granted for. Data subsets are indicated by the path part of a
-{@code content:} URI. (The authority part of the URI identifies the
-content provider.)
-Granting permission is a way of enabling clients of the provider that don't
-normally have permission to access its data to overcome that restriction on
-a one-time basis.
-
-<p>
-If a content provider's {@code <a href="#pvdr_gprmsn">grantUriPermissions</a>}
-attribute is "{@code true}", permission can be granted for any the data under
-the provider's purview. However, if that attribute is "{@code false}", permission
-can be granted only to data subsets that are specified by this element.
-A provider can contain any number of {@code &lt;grant-uri-permission&gt;} elements.
-Each one can specify only one path (only one of the three possible attributes).
-</p>
-
-<p>
-For information on how permission is granted, see the
-{@code <a href="#ifilt">&lt;intent-filter&gt;</a>} element's
-{@code <a href="#pvdr_gprmsn">grantUriPermissions</a>} attribute.
-</p></dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:path}
-<br/>{@code android:pathPrefix}
-<br/>{@code android:pathPattern}</dt>
-<dd>A path identifying the data subset or subsets that permission can be
-granted for. The {@code path} attribute specifies a complete path;
-permission can be granted only to the particular data subset identified
-by that path.
-The {@code pathPrefix} attribute specifies the initial part of a path;
-permission can be granted to all data subsets with paths that share that
-initial part.
-The {@code pathPattern} attribute specifies a complete path, but one
-that can contain the following wildcards:
-
-<ul>
-<li>An asterisk ('{@code *}') matches a sequence of 0 to many occurrences of
-the immediately preceding character.</li>
-
-<li><p>A period followed by an asterisk ("{@code .*}") matches any sequence of
-0 to many characters.</p></li>
-</ul>
-
-<p>
-Because '{@code \}' is used as an escape character when the string is read
-from XML (before it is parsed as a pattern), you will need to double-escape:
-For example, a literal '{@code *}' would be written as "{@code \\*}" and a
-literal '{@code \}' would be written as "{@code \\\\}". This is basically
-the same as what you would need to write if constructing the string in Java code.
-</p>
-
-<p>
-For more information on these types of patterns, see the descriptions of
-{@link android.os.PatternMatcher#PATTERN_LITERAL},
-{@link android.os.PatternMatcher#PATTERN_PREFIX}, and
-{@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB} in the
-{@link android.os.PatternMatcher} class.
-</p></dd>
-</dl></dd>
-
-<dt>see also:</dt>
-<dd>the {@code <a href="#pvdr_gprmsn">grantUriPermissions</a>} attribute
-of the {@code <a href="#pvdr">&lt;provider&gt;</a>} element</dd>
-
-
-</dl>
-<hr>
-
-<h3 id="instru">&lt;instrumentation&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;instrumentation android:functionalTest=["true" | "false"]
- android:handleProfiling=["true" | "false"]
- android:icon="<i>drawable resource</i>"
- android:label="<i>string resource</i>"
- android:name="<i>string</i>"
- android:targetPackage="<i>string</i>" /&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#manf">&lt;manifest&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Declares an {@link android.app.Instrumentation} class that enables you
-to monitor an application's interaction with the system. The Instrumentation
-object is instantiated before any of the application's components.</dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:functionalTest}</dt>
-<dd>Whether or not the Instrumentation class should run as a functional test
-&mdash; "{@code true}" if it should, and "{@code false}" if not. The
-default value is "{@code false}".</dd>
-
-<dt>{@code android:handleProfiling}</dt>
-<dd>Whether or not the Instrumentation object will turn profiling on and
-off &mdash; "{@code true}" if it determines when profiling starts and
-stops, and "{@code false}" if profiling continues the entire time it is
-running. A value of "{@code true}" enables the object to target profiling
-at a specific set of operations. The default value is "{@code false}".</dd>
-
-<dt>{@code android:icon}</dt>
-<dd>An icon that represents the Instrumentation class. This attribute must
-be set as a reference to a drawable resource.</dd>
-
-<dt>{@code android:label}</dt>
-<dd>A user-readable label for the Instrumentation class. The label can
-be set as a raw string or a reference to a string resource.</dd>
-
-<dt>{@code android:name}</dt>
-<dd>The name of the {@link android.app.Instrumentation} subclass.
-This should be a fully qualified class name (such as,
-"{@code com.example.project.StringInstrumentation}"). However, as a shorthand,
-if the first character of the name is a period, it is appended to the package
-name specified in the {@code <a href="#manf">&lt;manifest&gt;</a>} element.
-
-<p>
-There is no default. The name must be specified.
-</p></dd>
-
-<dt>{@code android:targetPackage}</dt>
-<dd>The application that the Instrumentation object will run against.
-An application is identified by the package name assigned in its manifest
-file by the {@code <a href="#manf">&lt;manifest&gt;</a>} element.</dd>
-
-</dl></dd>
-
-</dl>
-<hr>
-
-<h3 id="ifilt">&lt;intent-filter&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;intent-filter android:icon="<i>drawable resource</i>"
- android:label="<i>string resource</i>"
- android:priority="<i>integer</i>" &gt;
- . . .
-&lt;/intent-filter&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#actv">&lt;activity&gt;</a>}
-<br/>{@code <a href="#alias">&lt;activity-alias&gt;</a>}
-<br/>{@code <a href="#srvc">&lt;service&gt;</a>}
-<br/>{@code <a href="#rcvr">&lt;receiver&gt;</a>}</dd>
-
-<dt>must contain:</dt>
-<dd>{@code <a href="#actn">&lt;action&gt;</a>}</dd>
-
-<dt>can contain:</dt>
-<dd>{@code <a href="#catg">&lt;category&gt;</a>}
-<br/>{@code <a href="#data">&lt;data&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Specifies the types of intents that an activity, service, or broadcast
-receiver can respond to. An intent filter declares the capabilities of its
-parent component &mdash; what an activity or service can do and what types
-of broadcasts a receiver can handle. It opens the component to receiving
-intents of the advertised type, while filtering out those that are not
-meaningful for the component.
-
-<p>
-Most of the contents of the filter are described by its
-{@code <a href="#actn">&lt;action&gt;</a>},
-{@code <a href="#catg">&lt;category&gt;</a>}, and
-{@code <a href="#data">&lt;data&gt;</a>} subelements.
-</p>
-
-<p>
-For a more detailed discussion of filters, see the separate
-<a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents
-and Intent Filters</a> document, as well as the
-<a href="#ifs">Intents Filters</a> section earlier in this document.
-</p></dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt><a name="ifilt_icon"></a>{@code android:icon}</dt>
-<dd>An icon that represents the parent activity, service, or broadcast
-receiver when that component is presented to the user as having the
-capability described by the filter.
-
-<p>
-This attribute must be set as a reference to a drawable resource
-containing the image definition. The default value is the icon set
-by the parent component's {@code icon} attribute. If the parent
-does not specify an icon, the default is the icon set by the
-{@code <a href="#app">&lt;application&gt;</a>} element.
-</p>
-
-<p>
-For more on intent filter icons, see <a href="#iconlabel">Icons and Labels</a>,
-earlier.
-</p></dd>
-
-<dt>{@code android:label}</dt>
-<dd>A user-readable label for the parent component. This label, rather than
-the one set by the parent component, is used when the component is presented
-to the user as having the capability described by the filter.
-
-<p>
-The label should be set as a reference to a string resource, so that
-it can be localized like other strings in the user interface.
-However, as a convenience while you're developing the application,
-it can also be set as a raw string.
-</p>
-
-<p>
-The default value is the label set by the parent component. If the
-parent does not specify a label, the default is the label set by the
-{@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_label"> label</a>} attribute.
-</p>
-
-<p>
-For more on intent filter labels, see <a href="#iconlabel">Icons and Labels</a>,
-earlier.
-</p></dd>
-
-<dt>{@code android:priority}</dt>
-<dd>The priority that should be given to the parent component with regard
-to handling intents of the type described by the filter. This attribute has
-meaning for both activities and broadcast receivers:
-
-<ul>
-<li>It provides information about how able an activity is to respond to
-an intent that matches the filter, relative to other activities that could
-also respond to the intent. When an intent could be handled by multiple
-activities with different priorities, Android will consider only those with
-higher priority values as potential targets for the intent.</li>
-
-<li><p>It controls the order in which broadcast receivers are executed to
-receive broadcast messages. Those with higher priority
-values are called before those with lower values. (The order applies only
-to synchronous messages; it's ignored for asynchronous messages.)</p></li>
-</ul>
-
-<p>
-Use this attribute only if you really need to impose a specific order in
-which the broadcasts are received, or want to force Android to prefer
-one activity over others.
-</p>
-
-<p>
-The value must be an integer, such as "{@code 100}". Higher numbers have a
-higher priority.
-</p></dd>
-
-</dl></dd>
-
-<dt>see also:</dt>
-<dd>{@code <a href="#actn">&lt;action&gt;</a>}
-<br/>{@code <a href="#catg">&lt;category&gt;</a>}
-<br/>{@code <a href="#data">&lt;data&gt;</a>}</dd>
-
-</dl>
-<hr>
-
-
-<h3 id="manf">&lt;manifest&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="<i>string</i>"
- android:sharedUserId="<i>string</i>"
- android:versionCode="<i>integer</i>"
- android:versionName="<i>string</i>" &gt;
- . . .
-&lt;/manifest&gt;</pre></dd>
-
-<p>
-<dt>contained in:</dt>
-<dd><i>none</i></dd>
-
-<p>
-<p>
-<dt>must contain:</dt>
-<dd>{@code <a href="#app">&lt;application&gt;</a>}</dd>
-
-<dt>can contain:</dt>
-<dd>{@code <a href="#instru">&lt;instrumentation&gt;</a>}
-<br/>{@code <a href="#prmsn">&lt;permission&gt;</a>}
-<br/>{@code <a href="#pgroup">&lt;permission-group&gt;</a>}
-<br/>{@code <a href="#ptree">&lt;permission-tree&gt;</a>}
-<br/>{@code <a href="#usesp">&lt;uses-permission&gt;</a>}</dd>
-
-<p>
-<dt>description:</dt>
-<dd>The root element of the AndroidManifest.xml file. It must
-contain an {@code <a href="#app">&lt;application&gt;</a>} element
-and specify {@code xlmns:android} and {@code package} attributes.</dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code xmlns:android}</dt>
-<dd>Defines the Android namespace. This attribute should always be set
-to "{@code http://schemas.android.com/apk/res/android}".</dd>
-
-<dt><a name="manf_package"></a>{@code package}</dt>
-<dd>A full Java package name for the application. The name should
-be unique. For example, applications published by Google could have
-names in the form <code>com.google.app.<i>application_name</i></code>.
-
-<p>
-The package name serves as a unique identifier for the application.
-It's also the default name for the task affinity of components
-(see the {@code <a href="#app_aff">taskAffinity</a>} attribute).
-</p></dd>
-
-<dt>{@code android:sharedUserId}</dt>
-<dd>The name of a Linux user ID that will be shared with other applications.
-By default, Android assigns each application its own unique user ID.
-However, if this attribute is set to the same value for two or more applications,
-they will all share the same ID &mdash; provided that they are also signed
-by the same certificate. Application with the same user ID can access each
-other's data and, if desired, run in the same process.</dd>
-
-<dt>{@code android:versionCode}</dt>
-<dd>An internal version number. This number is used only to determine whether
-one version is more recent than another, with higher numbers indicating more
-recent versions. This is not the version number shown to users; that number
-is set by the {@code versionName} attribute.
-
-<p>
-The value must be set as an integer, such as "100". You can define it however
-you want, as long as each successive version has a higher number. For example,
-it could be a build number. Or you could translate a version number in "x.y"
-format to an integer by encoding the "x" and "y" separately in the lower and
-upper 16 bits. Or you could simply increase the number by one each time a new
-version is released.
-</p></dd>
-
-<dt>{@code android:versionName}</dt>
-<dd>The version number shown to users. This attribute can be set as a raw
-string or as a reference to a string resource. The string has no other purpose
-than to be displayed to users. The {@code versionCode} attribute holds
-the significant version number used internally.
-</dl></dd>
-
-<p>
-<dt>see also:</dt>
-<dd>{@code <a href="#app">&lt;application&gt;</a>}</dd>
-
-</dl>
-<hr>
-
-<h3 id="meta">&lt;meta-data&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;meta-data android:name="<i>string</i>"
- android:resource="<i>resource specification</i>"
- android:value="<i>string</i>" /&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#actv">&lt;activity&gt;</a>}
-<br/>{@code <a href="#alias">&lt;activity-alias&gt;</a>}
-<br/>{@code <a href="#srvc">&lt;service&gt;</a>}
-<br/>{@code <a href="#rcvr">&lt;receiver&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>A name-value pair for an item of additional, arbitrary data that can
-be supplied to the parent component. A component element can contain any
-number of {@code &lt;meta-data&gt;} subelements. The values from all of
-them are collected in a single {@link android.os.Bundle} object and made
-available to the component as the
-{@link android.content.pm.PackageItemInfo#metaData
-PackageItemInfo.metaData} field.
-
-<p>
-Ordinary values are specified through the {@code <a href="#meta_value">value</a>}
-attribute. However, to assign a resource ID as the value, use the
-{@code <a href="#meta_resource">resource</a>} attribute instead. For example,
-the following code assigns whatever value is stored in the {@code @string/kangaroo}
-resource to the "{@code zoo}" name:
-</p>
-
-<pre>&lt;meta-data android:name="zoo" android:value="@string/kangaroo" /&gt;</pre>
-
-<p>
-On the other hand, using the {@code resource} attribute would assign "{@code zoo}"
-the numeric ID of the resource, not the value stored in the resource:
-</p>
-
-<pre>&lt;meta-data android:name="zoo" android:resource="@string/kangaroo" /&gt;</pre>
-
-<p>
-It is highly recommended that you avoid supplying related data as
-multiple separate {@code &lt;meta-data&gt;} entries. Instead, if you
-have complex data to associate with a component, store it as a resource and
-use the {@code resource} attribute to inform the component of its ID.
-</p></dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:name}</dt>
-<dd>A unique name for the item. To ensure that the name is unique, use a
-Java-style naming convention &mdash; for example,
-"{@code com.example.project.activity.fred}".</dd>
-
-<dt>{@code android:resource}</dt>
-<dd>A reference to a resource. The ID of the resource is the value assigned
-to the item. The ID can be retrieved from the meta-data Bundle by the
-{@link android.os.Bundle#getInt Bundle.getInt()} method.</dd>
-
-<dt>{@code android:value}</dt>
-<dd>The value assigned to the item. The data types that can be assigned as values and the Bundle methods that components use to retrieve those values are listed in the following table:
-
-<table>
-<tr>
- <th>Type</th>
- <th>Bundle method</th>
-</tr><tr>
- <td>String value, using double backslashes ({@code \\}) to escape characters
- &mdash; such as "{@code \\n}" and "{@code \\uxxxxx}" for a Unicode character.</td>
- <td>{@link android.os.Bundle#getString(String) getString()}</td>
-</tr><tr>
- <td>Integer value, such as "{@code 100}"</td>
- <td>{@link android.os.Bundle#getInt(String) getInt()}</td>
-</tr><tr>
- <td>Boolean value, either "{@code true}" or "{@code false}"</td>
- <td>{@link android.os.Bundle#getBoolean(String) getBoolean()}</td>
-</tr><tr>
- <td>Color value, in the form "{@code #rgb}", "{@code #argb}",
- "{@code #rrggbb}", or "{@code #aarrggbb}"</td>
- <td>{@link android.os.Bundle#getString(String) getString()}</td>
-</tr><tr>
- <td>Float value, such as "{@code 1.23}"</td>
- <td>{@link android.os.Bundle#getFloat(String) getFloat()}</td>
-</tr>
-</table>
-</dd>
-</dl></dd>
-
-</dl>
-<hr>
-
-<h3 id="prmsn">&lt;permission&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt></dt>
-<dd><pre class="stx">&lt;permission android:description="<i>string resource</i>"
- android:icon="<i>drawable resource</i>"
- android:label="<i>string resource</i>"
- android:name="<i>string</i>"
- android:permissionGroup="<i>string</i>"
- android:protectionLevel=["normal" | "dangerous" |
- "signature" | "signatureOrSystem"] /&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#manf">&lt;manifest&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Declares a security permission that can be used to limit access
-to specific components or features of this or other applications.
-See the <a href="#perms">Permissions</a>, earlier in this document,
-and the <a href="{@docRoot}guide/topics/security/security.html">Security Model</a>
-document for more information on how permissions work.</dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:description}</dt>
-<dd>A user-readable description of the permission, longer and more
-informative than the label. It may be displayed to explain the
-permission to the user &mdash; for example, when the user is asked
-whether to grant the permission to another application.
-
-<p>
-This attribute must be set as a reference to a string resource;
-unlike the {@code label} attribute, it cannot be a raw string.
-</p></dd>
-
-<dt>{@code android:icon}</dt>
-<dd>A reference to a drawable resource for an icon that represents the
-permission.</dd>
-
-<dt>{@code android:label}</dt>
-<dd>A name for the permission, one that can be displayed to users.
-
-<p>
-As a convenience, the label can be directly set
-as a raw string while you're developing the application. However,
-when the application is ready to be published, it should be set as a
-reference to a string resource, so that it can be localized like other
-strings in the user interface.
-</p></dd>
-
-<dt>{@code android:name}</dt>
-<dd>The name of the permission. This is the name that will be used in
-code to refer to the permission &mdash; for example, in a
-{@code <a href="#usesp">&lt;uses-permission&gt;</a>} element and the
-{@code permission} attributes of application components.</dd>
-
-<p>
-The name must be unique, so it should use Java-style scoping &mdash;
-for example, "{@code com.example.project.PERMITTED_ACTION}".
-</p></dd>
-
-<dt>{@code android:permissionGroup}</dt>
-<dd>Assigns this permission to a group. The value of this attribute is
-the name of the group, which must be declared with the
-{@code <a href="#pgroup">&lt;permission-group&gt;</a>} element in this
-or another application. If this attribute is not set, the permission
-does not belong to a group.</dd>
-
-<dt>{@code android:protectionLevel}</dt>
-<dd>Characterizes the potential risk implied in the permission and
-indicates the procedure the system should follow when determining
-whether or not to grant the permission to an application requesting it.
-The value can be set to one of the following strings:
-
-<table>
-<tr>
- <th>Value</th>
- <th>Meaning</th>
-</tr><tr>
- <td>"{@code normal}"</td>
- <td>The default value. A lower-risk permission that gives requesting
- applications access to isolated application-level features, with
- minimal risk to other applications, the system, or the user.
- The system automatically grants this type
- of permission to a requesting application at installation, without
- asking for the user's explicit approval (though the user always
- has the option to review these permissions before installing).
-</tr><tr>
- <td>"{@code dangerous}"</td>
- <td>A higher-risk permission that would give a requesting application
- access to private user data or control over the device that can
- negatively impact the user. Because this type of permission
- introduces potential risk, the system may not automatically
- grant it to the requesting application. For example, any dangerous
- permissions requested by an application may be displayed to the
- user and require confirmation before proceeding, or some other
- approach may be taken to avoid the user automatically allowing
- the use of such facilities.
-</tr><tr>
- <td>"{@code signature}"</td>
- <td>A permission that the system grants only if the requesting
- application is signed with the same certificate as the application
- that declared the permission. If the certificates match, the system
- automatically grants the permission without notifying the user or
- asking for the user's explicit approval.
-</tr><tr>
- <td>"{@code signatureOrSystem}"</td>
- <td>A permission that the system grants only to applications that are
- in the Android system image <em>or</em> that are signed with the same
- certificates as those in the system image. Please avoid using this
- option, as the {@code signature} protection level should be sufficient
- for most needs and works regardless of exactly where applications are
- installed. The "{@code signatureOrSystem}"
- permission is used for certain special situations where multiple
- vendors have applications built into a system image and need
- to share specific features explicitly because they are being built
- together.
-</tr>
-</table>
-</dd>
-</dl></dd>
-
-<dt>see also:</dt>
-<dd>{@code <a href="#usesp">&lt;uses-permission&gt;</a>}
-<br/>{@code <a href="#ptree">&lt;permission-tree&gt;</a>}
-<br/>{@code <a href="#pgroup">&lt;permission-group&gt;</a>}</dd>
-</dd>
-
-</dl>
-<hr>
-
-<h3 id="pgroup">&lt;permission-group&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;permission-group android:description="<i>string resource</i>"
- android:icon="<i>drawable resource</i>"
- android:label="<i>string resource</i>"
- android:name="<i>string</i>" /&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#manf">&lt;manifest&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Declares a name for a logical grouping of related permissions. Individual
-permission join the group through the {@code permissionGroup} attribute of the
-{@code <a href="#prmsn">&lt;permission&gt;</a>} element. Members of a group are
-presented together in the user interface.
-
-<p>
-Note that this element does not declare a permission itself, only a category in
-which permissions can be placed. See the
-{@code <a href="#prmsn">&lt;permission&gt;</a>} element for element for information
-on declaring permissions and assigning them to groups.
-</p></dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:description}</dt>
-<dd>User-readable text that describes the group. The text should be
-longer and more explanatory than the label. This attribute must be
-set as a reference to a string resource. Unlike the {@code label}
-attribute, it cannot be a raw string.</dd>
-
-<dt>{@code android:icon}</dt>
-<dd>An icon representing the permission. This attribute must be set
-as a reference to a drawable resource containing the image definition.</dd>
-
-<dt>{@code android:label}</dt>
-<dd>A user-readable name for the group. As a convenience, the label can
-be directly set as a raw string while you're developing the application.
-However, when the application is ready to be published, it should be set
-as a reference to a string resource, so that it can be localized like other
-strings in the user interface.</dd>
-
-<dt>{@code android:name}</dt>
-<dd>The name of the group. This is the name that can be assigned to a
-{@code <a href="#prmsn">&lt;permission&gt;</a>} element's
-{@code permissionGroup} attribute.</dd>
-</dl></dd>
-
-<dt>see also:</dt>
-<dd>{@code <a href="#prmsn">&lt;permission&gt;</a>}
-<br/>{@code <a href="#ptree">&lt;permission-tree&gt;</a>}
-<br/>{@code <a href="#usesp">&lt;uses-permission&gt;</a>}</dd>
-
-</dl>
-<hr>
-
-<h3 id="ptree">&lt;permission-tree&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;permission-tree android:icon="<i>drawable resource</i>"
- android:label="<i>string resource</i>" ]
- android:name="<i>string</i>" /&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#manf">&lt;manifest&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Declares the base name for a tree of permissions. The application takes
-ownership of all names within the tree. It can dynamically add new permissions
-to the tree by calling <code>{@link android.content.pm.PackageManager#addPermission PackageManager.addPermission()}</code>. Names within the tree are separated by
-periods ('{@code .}'). For example, if the base name is
-{@code com.example.project.taxes}, permissions like the following might be
-added:
-
-<p style="margin-left: 2em">{@code com.example.project.taxes.CALCULATE}
-<br/>{@code com.example.project.taxes.deductions.MAKE_SOME_UP}
-<br/>{@code com.example.project.taxes.deductions.EXAGGERATE}</p>
-
-<p>
-Note that this element does not declare a permission itself, only a
-namespace in which further permissions can be placed.
-See the {@code <a href="#prmsn">&lt;permission&gt;</a>} element for
-information on declaring permissions.
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:icon}</dt>
-<dd>An icon representing all the permissions in the tree. This attribute
-must be set as a reference to a drawable resource containing the image
-definition.</dd>
-
-<dt>{@code android:label}</dt>
-<dd>A user-readable name for the group. As a convenience, the label can
-be directly set as a raw string for quick and dirty programming. However,
-when the application is ready to be published, it should be set as a
-reference to a string resource, so that it can be localized like other
-strings in the user interface.</dd>
-
-<dt>{@code android:name}</dt>
-<dd>The name that's at the base of the permission tree. It serves as
-a prefix to all permission names in the tree. Java-style scoping should
-be used to ensure that the name is unique. The name must have more than
-two period-separated seqments in its path &mdash; for example,
-{@code com.example.base} is OK, but {@code com.example} is not.</dd>
-
-</dl></dd>
-
-<p>
-<dt>see also:</dt>
-<dd>{@code <a href="#prmsn">&lt;permission&gt;</a>}
-<br/>{@code <a href="#pgroup">&lt;permission-group&gt;</a>}
-<br/>{@code <a href="#usesp">&lt;uses-permission&gt;</a>}
-</dd>
-
-</dl>
-<hr>
-
-<h3 id="pvdr">&lt;provider&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;provider android:authorities="<i>list</i>"
- android:enabled=["true" | "false"]
- android:exported=["true" | "false"]
- android:grantUriPermissions=["true" | "false"]
- android:icon="<i>drawable resource</i>"
- android:initOrder="<i>integer</i>"
- android:label="<i>string resource</i>"
- android:multiprocess=["true" | "false"]
- android:name="<i>string</i>"
- android:permission="<i>string</i>"
- android:process="<i>string</i>"
- android:readPermission="<i>string</i>"
- android:syncable=["true" | "false"]
- android:writePermission="<i>string</i>" &gt;
- . . .
-&lt;/provider&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#app">&lt;application&gt;</a>}</dd>
-
-<dt>can contain:</dt>
-<dd>{@code <a href="#meta">&lt;meta-data&gt;</a>}
-<br/>{@code <a href="#grantp">&lt;grant-uri-permission&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Declares a content provider &mdash; a subclass of
-{@link android.content.ContentProvider} &mdash; that supplies structured
-access to data managed by the application. All content providers that
-are part of the application must be represented by {@code &lt;provider&gt;}
-elements in the manifest file. The system cannot see, and therefore will
-not run, any that are not declared. (You need to declare only
-those content providers that you develop as part of your application,
-not those developed by others that your application uses.)
-
-<p>
-The Android system identifies content providers by the authority part
- of a {@code content:} URI. For example, suppose that the following URI
-is passed to <code>{@link android.content.ContentResolver#query
-ContentResolver.query()}</code>:
-
-<p style="margin-left: 2em">{@code content://com.example.project.healthcareprovider/nurses/rn}</p>
-
-<p>
-The {@code content:} scheme identifies the data as belonging to a content
-provider and the authority ({@code com.example.project.healthcareprovider})
-identifies the particular provider. The authority therefore must be unique.
-Typically, as in this example, it's the fully qualified name of a
-ContentProvider subclass. The path part of a URI may be used by a content
-provider to identify particular data subsets, but those paths are not
-declared in the manifest.
-</p>
-
-<p>
-For information on using and developing content providers, see a separate document,
-<a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.
-</p></dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:authorities}</dt>
-<dd>A list of one or more URI authorities that identify data under the purview
-of the content provider.
-Multiple authorities are listed by separating their names with a semicolon.
-To avoid conflicts, authority names should use a Java-style naming convention
-(such as {@code com.example.provider.cartoonprovider}). Typically, it's the name
-of the ContentProvider subclass.
-
-<p>
-There is no default. At least one authority must be specified.
-</p></dd>
-
-<dt>{@code android:enabled}</dt>
-<dd>Whether or not the content provider can be instantiated by the system &mdash;
-"{@code true}" if it can be, and "{@code false}" if not. The default value
-is "{@code true}".
-
-<p>
-The {@code <a href="#app">&lt;application&gt;</a>} element has its own
-{@code <a href="#app_enabled">enabled</a>} attribute that applies to all
-application components, including content providers. The
-{@code <a href="#app">&lt;application&gt;</a>} and {@code &lt;provider&gt;}
-attributes must both be "{@code true}" (as they both
-are by default) for the content provider to be enabled. If either is
-"{@code false}", the provider is disabled; it cannot be instantiated.
-</p></dd>
-
-<dt>{@code android:exported}</dt>
-<dd>Whether or not the content provider can be used by components of other
-applications &mdash; "{@code true}" if it can be, and "{@code false}" if not.
-If "{@code false}", the provider is available only to components of the
-same application or applications with the same user ID. The default value
-is "{@code true}".
-
-<p>
-You can export a content provider but still limit access to it with the
-{@code <a href="#pvdr_prmsn">permission</a>} attribute.
-</p></dd>
-
-<dt><a name="grantp_gprmns"></a>{@code android:grantUriPermissions}</dt>
-<dd>Whether or not those who ordinarily would not have permission to
-access the content provider's data can be granted permission to do so,
-temporarily overcoming the restriction imposed by the
-{@code <a href="#pvdr_rprmsn">readPermission</a>},
-{@code <a href="#pvdr_wprmsn">writePermission</a>}, and
-{@code <a href="#pvdr_prmsn">permission</a>} attributes
-&mdash;
-"{@code true}" if permission can be granted, and "{@ code false}" if not.
-If "{@code true}", permission can be granted to any of the content
-provider's data. If "{@code false}", permission can be granted only
-to the data subsets listed in
-{@code <a href="#grantp">&lt;grant-uri-permission&gt;</a>} subelements,
-if any. The default value is "{@code false}".
-
-<p>
-Granting permission is a way of giving an application component one-time
-access to data protected by a permission. For example, when an e-mail
-message contains an attachment, the mail application may call upon the
-appropriate viewer to open it, even though the viewer doesn't have general
-permission to look at all the content provider's data.
-</p>
-
-<p>
-In such cases, permission is granted by
-<code>{@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}</code>
-and <code>{@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}</code>
-flags in the Intent object that activates the component. For example, the
-mail application might put {@code FLAG_GRANT_READ_URI_PERMISSION} in the
-Intent passed to {@code Context.startActivity()}. The permission is specific
-to the URI in the Intent.
-</p>
-
-<p>
-If you enable this feature, either by setting this attribute to "{@code true}"
-or by defining {@code <a href="#grantp">&lt;grant-uri-permission&gt;</a>}
-subelements, you must call
-<code>{@link android.content.Context#revokeUriPermission
-Context.revokeUriPermission()}</code> when a covered URI is deleted from
-the provider.
-</p>
-
-<p>
-See also the {@code <a href="#grantp">&lt;grant-uri-permission&gt;</a>}
-element.
-</p></dd>
-
-<dt><a name="pvdr_icon"></a>{@code android:icon}</dt>
-<dd>An icon representing the content provider.
-This attribute must be set as a reference to a drawable resource containing
-the image definition. If it is not set, the icon specified for the application
-as a whole is used instead (see the {@code <a href="#app">&lt;application&gt;</a>}
-element's {@code <a href="#app_icon">icon</a>} attribute).</dd>
-
-<dt>{@code android:initOrder}</dt>
-<dd>The order in which the content provider should be instantiated,
-relative to other content providers hosted by the same process.
-When there are dependencies among content providers, setting this
-attribute for each of them ensures that they are created in the order
-required by those dependencies. The value is a simple integer,
-with higher numbers being initialized first.</dd>
-
-<dt>{@code android:label}</dt>
-<dd>A user-readable label for the content provided.
-If this attribute is not set, the label set for the application as a whole is
-used instead (see the {@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_label">label</a>} attribute).
-
-<p>
-The label should be set as a reference to a string resource, so that
-it can be localized like other strings in the user interface.
-However, as a convenience while you're developing the application,
-it can also be set as a raw string.
-</p></dd>
-
-<dt>{@code android:multiprocess}</dt>
-<dd>Whether or not an instance of the content provider can be created in
-every client process &mdash; "{@code true}" if instances can run in multiple
-processes, and "{@code false}" if not. The default value is "{@code false}".
-
-<p>
-Normally, a content provider is instantiated in the process of the
-application that defined it. However, if this flag is set to "{@code true}",
-the system can create an instance in every process where there's a client
-that wants to interact withit, thus avoiding the overhead of interprocess
-communication.
-</p></dd>
-
-<dt>{@code android:name}</dt>
-<dd>The name of the class that implements the content provider, a subclass of
-{@link android.content.ContentProvider}. This should be a fully qualified
-class name (such as, "{@code com.example.project.TransportationProvider}").
-However, as a shorthand, if the first character of the name is a period,
-it is appended to the package name specified in the
-{@code <a href="#manf">&lt;manifest&gt;</a>} element.
-
-<p>
-There is no default. The name must be specified.
-</p></dd>
-
-
-<dt>{@code android:permission}</dt>
-<dd>The name of a permission that clients must have to read or write the
-content provider's data. This attribute is a convenient way of setting a
-single permission for both reading and writing. However, the
-{@code <a href="#pvdr_rprmsn">readPermission</a>} and
-{@code <a href="#pvdr_wprmsn">writePermission</a>} attributes take precedence
-over this one. If the {@code <a href="#pvdr_rprmsn">readPermission</a>}
-attribute is also set, it controls access for querying the content provider.
-And if the {@code <a href="#pvdr_wprmsn">writePermission</a>} attribute is set,
-it controls access for modifying the provider's data.
-
-<p>
-For more information on permissions, see the <a href="#sectperm">Permissions</a>
-section earlier in this document and a separate document,
-<a href="{@docRoot}guide/topics/security/security.html">Security and
-Permissions</a>.
-</p></dd>
-
-<dt>{@code android:process}</dt>
-<dd>The name of the process in which the content provider should run. Normally,
-all components of an application run in the default process created for the
-application. It has the same name as the application package. The {@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_proc">process</a>} attribute can set a different
-default for all components. But each component can override the default
-with its own {@code process} attribute, allowing you to spread your
-application across multiple processes.
-
-<p>
-If the name assigned to this attribute begins with a colon (':'), a new
-process, private to the application, is created when it's needed and
-the activity runs in that process.
-If the process name begins with a lowercase character, the activity will run
-in a global process of that name, provided that it has permission to do so.
-This allows components in different applications to share a process, reducing
-resource usage.
-</p></dd>
-
-<dt>{@code android:readPermission}</dt>
-<dd>A permission that clients must have to query the content provider.
-See also the {@code <a href="#pvdr_prmsn">permission</a>} and
-{@code <a href="#pvdr_wprmsn">writePermission</a>} attributes.</dd>
-
-<dt>{@code android:syncable}</dt>
-<dd>Whether or not the data under the content provider's control
-is to be synchronized with data on a server &mdash; "{@code true}"
-if it is to be synchronized, and "{@ code false}" if not.</dd>
-
-<dt>{@code android:writePermission}</dt>
-<dd>A permission that clients must have to make changes to the data
-controlled by the content provider.
-See also the {@code <a href="#pvdr_prmsn">permission</a>} and
-{@code <a href="#pvdr_rprmsn">readPermission</a>} attributes.</dd>
-
-</dl></dd>
-
-<p>
-<dt>see also:</dt>
-<dd><a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a></dd>
-
-</dl>
-<hr>
-
-<h3 id="rcvr">&lt;receiver&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;receiver android:enabled=["true" | "false"]
- android:exported=["true" | "false"]
- android:icon="<i>drawable resource</i>"
- android:label="<i>string resource</i>"
- android:name="<i>string</i>"
- android:permission="<i>string</i>"
- android:process="<i>string</i>" &gt;
- . . .
-&lt;/receiver&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#app">&lt;application&gt;</a>}</dd>
-
-<dt>can contain:</dt>
-<dd>{@code <a href="#ifilt">&lt;intent-filer&gt;</a>}
-<br/>{@code <a href="#meta">&lt;meta-data&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Declares a broadcast receiver (a {@link android.content.BroadcastReceiver}
-subclass) as one of the application's components. Broadcast receivers enable
-applications to receive intents that are broadcast by the system or by other
-applications, even when other components of the application are not running.
-
-<p>
-There are two ways to make a broadcast receiver known to the system: One is
-declare it in the manifest file with this element. The other is to create
-the receiver dynamically in code and register it with the <code>{@link
-android.content.Context#registerReceiver Context.registerReceiver()}</code>
-method. See the {@link android.content.BroadcastReceiver} class description
-for more on dynamically created receivers.
-</p></dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:enabled}</dt>
-<dd>Whether or not the broadcast receiver can be instantiated by the system &mdash;
-"{@code true}" if it can be, and "{@code false}" if not. The default value
-is "{@code true}".
-
-<p>
-The {@code <a href="#app">&lt;application&gt;</a>} element has its own
-{@code <a href="#app_enabled">enabled</a>} attribute that applies to all
-application components, including broadcast receivers. The
-{@code <a href="#app">&lt;application&gt;</a>} and
-{@code &lt;receiver&gt;} attributes must both be "{@code true}" for
-the broadcast receiver to be enabled. If either is "{@code false}", it is
-disabled; it cannot be instantiated.
-</p></dd>
-
-<dt>{@code android:exported}</dt>
-<dd>Whether or not the broadcast receiver can receive messages from sources
-outside its application &mdash; "{@code true}" if it can, and "{@code false}"
-if not. If "{@code false}", the only messages the broadcast receiver can
-receive are those sent by components of the same application or applications
-with the same user ID.
-
-<p>
-The default value depends on whether the broadcast receiver contains intent filters.
-The absence of any filters means that it can be invoked only by Intent objects that
-specify its exact class name. This implies that the receiver is intended only for
-application-internal use (since others would not normally know the class name).
-So in this case, the default value is "{@code false}".
-On the other hand, the presence of at least one filter implies that the broadcast
-receiver is intended to receive intents broadcast by the system or other applications,
-so the default value is "{@code true}".
-</p>
-
-<p>
-This attribute is not the only way to limit a broadcast receiver's external exposure.
-You can also use a permission to limit the external entities that can send it messages
-(see the {@code <a href="#rcvr_prmsn">permission</a>} attribute).
-</p></dd>
-
-<dt><a name="rcvr_icon"></a>{@code android:icon}</dt>
-<dd>An icon representing the broadcast receiver. This attribute must be set
-as a reference to a drawable resource containing the image definition.
-If it is not set, the icon specified for the application as a whole is used
-instead (see the {@code <a href="#app">&lt;application&gt;</a>}
-element's {@code <a href="#app_icon">icon</a>} attribute).
-
-<p>
-The broadcast receiver's icon &mdash; whether set here or by the
-{@code <a href="#app">&lt;application&gt;</a>} element &mdash; is also the
-default icon for all the receiver's intent filters (see the
-{@code <a href="#ifilt">&lt;intent-filter&gt;</a>} element's
-{@code <a href="#ifilt_icon">icon</a>} attribute).
-</p></dd>
-
-<dt>{@code android:label}</dt>
-<dd>A user-readable label for the broadcast receiver. If this attribute is not
-set, the label set for the application as a whole is
-used instead (see the {@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_label">label</a>} attribute).
-
-<p>
-The broadcast receiver's label &mdash; whether set here or by the
-{@code <a href="#app">&lt;application&gt;</a>} element &mdash; is also the
-default label for all the receiver's intent filters (see the
-{@code <a href="#ifilt">&lt;intent-filter&gt;</a>} element's
-{@code <a href="#ifilt_label">label</a>} attribute).
-</p>
-
-<p>
-The label should be set as a reference to a string resource, so that
-it can be localized like other strings in the user interface.
-However, as a convenience while you're developing the application,
-it can also be set as a raw string.
-</p></dd>
-
-<dt>{@code android:name}</dt>
-<dd>The name of the class that implements the broadcast receiver, a subclass of
-{@link android.content.BroadcastReceiver}. This should be a fully qualified
-class name (such as, "{@code com.example.project.ReportReceiver}"). However,
-as a shorthand, if the first character of the name is a period (for example,
-"{@code . ReportReceiver}"), it is appended to the package name specified in
-the {@code <a href="#manf">&lt;manifest&gt;</a>} element.
-
-<p>
-There is no default. The name must be specified.
-</p></dd>
-
-<dt><a name="rcvr_prmsn"></a>{@code android:permission}</dt>
-<dd>The name of a permission that broadcasters must have to send a
-message to the broadcast receiver.
-If this attribute is not set, the permission set by the
-{@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_prmsn">permission</a>} attribute applies
-to the broadcast receiver. If neither attribute is set, the receiver
-is not protected by a permission.
-
-<p>
-For more information on permissions, see the <a href="#sectperm">Permissions</a>
-section earlier in this document and a separate document,
-<a href="{@docRoot}guide/topics/security/security.html">Security and
-Permissions</a>.
-</p></dd>
-
-<dt>{@code android:process}</dt>
-<dd>The name of the process in which the broadcast receiver should run.
-Normally, all components of an application run in the default process created
-for the application. It has the same name as the application package. The
-{@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_proc">process</a>} attribute can set a different
-default for all components. But each component can override the default
-with its own {@code process} attribute, allowing you to spread your
-application across multiple processes.
-
-<p>
-If the name assigned to this attribute begins with a colon (':'), a new
-process, private to the application, is created when it's needed and
-the broadcast receiver runs in that process.
-If the process name begins with a lowercase character, the receiver will run
-in a global process of that name, provided that it has permission to do so.
-This allows components in different applications to share a process, reducing
-resource usage.
-</p></dd>
-</dl></dd>
-
-</dl>
-<hr>
-
-<h3 id="srvc">&lt;service&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;service android:enabled=["true" | "false"]
- android:exported[="true" | "false"]
- android:icon="<i>drawable resource</i>"
- android:label="<i>string resource</i>"
- android:name="<i>string</i>"
- android:permission="<i>string</i>"
- android:process="<i>string</i>" &gt;
- . . .
-&lt;/service&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#app">&lt;application&gt;</a>}</dd>
-
-<dt>can contain:</dt>
-<dd>{@code <a href="#ifilt">&lt;intent-filer&gt;</a>}
-<br/>{@code <a href="#meta">&lt;meta-data&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Declares a service (a {@link android.app.Service} subclass) as one
-of the application's components. Unlike activities, services lack a
-visual user interface. They're used to implement long-running background
-operations or a rich communications API that can be called by other
-applications.
-
-<p>
-All services must be represented by {@code &lt;service&gt;} elements in
-the manifest file. Any that are not declared there will not be seen
-by the system and will never be run.
-</p></dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:enabled}</dt>
-<dd>Whether or not the service can be instantiated by the system &mdash;
-"{@code true}" if it can be, and "{@code false}" if not. The default value
-is "{@code true}".
-
-<p>
-The {@code <a href="#app">&lt;application&gt;</a>} element has its own
-{@code <a href="#app_enabled">enabled</a>} attribute that applies to all
-application components, including services. The
-{@code <a href="#app">&lt;application&gt;</a>} and {@code &lt;service&gt;}
-attributes must both be "{@code true}" (as they both
-are by default) for the service to be enabled. If either is
-"{@code false}", the service is disabled; it cannot be instantiated.
-</p></dd>
-
-<dt>{@code android:exported}</dt>
-<dd>Whether or not components of other applications can invoke
-the service or interact with it &mdash; "{@code true}" if they can, and
-"{@code false}" if not. When the value is "{@code false}", only
-components of the same application or applications
-with the same user ID can start the service or bind to it.
-
-<p>
-The default value depends on whether the service contains intent filters. The
-absence of any filters means that it can be invoked only by specifying
-its exact class name. This implies that the service is intended only for
-application-internal use (since others would not know the class name). So in
-this case, the default value is "{@code false}".
-On the other hand, the presence of at least one filter implies that the service
-is intended for external use, so the default value is "{@code true}".
-</p>
-
-<p>
-This attribute is not the only way to limit the exposure of a service to other
-applications. You can also use a permission to limit the external entities that
-can interact with the service (see the {@code <a href="#srvc_prmsn">permission</a>}
-attribute).
-</p></dd>
-
-<dt><a name="srvc_icon"></a>{@code android:icon}</dt>
-<dd>An icon representing the service. This attribute must be set as a
-reference to a drawable resource containing the image definition.
-If it is not set, the icon specified for the application
-as a whole is used instead (see the {@code <a href="#app">&lt;application&gt;</a>}
-element's {@code <a href="#app_icon">icon</a>} attribute).
-</p>
-
-<p>
-The service's icon &mdash; whether set here or by the
-{@code <a href="#app">&lt;application&gt;</a>} element &mdash; is also the
-default icon for all the service's intent filters (see the
-{@code <a href="#ifilt">&lt;intent-filter&gt;</a>} element's
-{@code <a href="#ifilt_icon">icon</a>} attribute).
-</p></dd>
-
-<dt>{@code android:label}</dt>
-<dd>A name for the service that can be displayed to users.
-If this attribute is not set, the label set for the application as a whole is
-used instead (see the {@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_label">label</a>} attribute).
-
-<p>
-The service's label &mdash; whether set here or by the
-{@code <a href="#app">&lt;application&gt;</a>} element &mdash; is also the
-default label for all the service's intent filters (see the
-{@code <a href="#ifilt">&lt;intent-filter&gt;</a>} element's
-{@code <a href="#ifilt_label">label</a>} attribute).
-</p>
-
-<p>
-The label should be set as a reference to a string resource, so that
-it can be localized like other strings in the user interface.
-However, as a convenience while you're developing the application,
-it can also be set as a raw string.
-</p></dd>
-
-<dt>{@code android:name}</dt>
-<dd>The name of the {@link android.app.Service} subclass that implements
-the service. This should be a fully qualified class name (such as,
-"{@code com.example.project.RoomService}"). However, as a shorthand, if
-the first character of the name is a period (for example, "{@code .RoomService}"),
-it is appended to the package name specified in the
-{@code <a href="#manf">&lt;manifest&gt;</a>} element.
-
-<p>
-There is no default. The name must be specified.
-</p></dd>
-
-<dt><a name="srvc_prmsn"></a>{@code android:permission}</dt>
-<dd>The name of a permission that that an entity must have in order to
-launch the service or bind to it. If a caller of
-<code>{@link android.content.Context#startService startService()}</code>,
-<code>{@link android.content.Context#bindService bindService()}</code>, or
-<code>{@link android.content.Context#stopService stopService()}</code>,
-has not been granted this permission, the method will not work and the
-Intent object will not be delivered to the service.
-
-<p>
-If this attribute is not set, the permission set by the
-{@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_prmsn">permission</a>} attribute applies
-to the service. If neither attribute is set, the service is
-not protected by a permission.
-</p>
-
-<p>
-For more information on permissions, see the <a href="#sectperm">Permissions</a>
-section earlier in this document and a separate document,
-<a href="{@docRoot}guide/topics/security/security.html">Security and
-Permissions</a>.
-</p></dd>
-
-<dt>{@code android:process}</dt>
-<dd>The name of the process where the service is to run. Normally,
-all components of an application run in the default process created for the
-application. It has the same name as the application package. The
-{@code <a href="#app">&lt;application&gt;</a>} element's
-{@code <a href="#app_proc">process</a>} attribute can set a different
-default for all components. But component can override the default
-with its own {@code process} attribute, allowing you to spread your
-application across multiple processes.
-
-<p>
-If the name assigned to this attribute begins with a colon (':'), a new
-process, private to the application, is created when it's needed and
-the service runs in that process.
-If the process name begins with a lowercase character, the service will run
-in a global process of that name, provided that it has permission to do so.
-This allows components in different applications to share a process, reducing
-resource usage.
-</p></dd>
-</dl></dd>
-
-<dt>see also:</dt>
-<dd>{@code <a href="#app">&lt;application&gt;</a>}
-<br>{@code <a href="#actv">&lt;activity&gt;</a>}</dd>
-
-</dl>
-<hr>
-
-<h3 id="usesl">&lt;uses-library&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre>&lt;uses-library android:name="<i>string</i>" /&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#app">&lt;application&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Specifies a shared library that the application must be linked against.
-This element tells the system to include the library's code in the class
-loader for the package.
-
-<p>
-All of the {@code android} packages (such as {@link android.app},
-{@link android.content}, {@link android.view}, and {@link android.widget})
-are in the default library that all applications are automatically linked
-against. However, some packages (such as {@code maps} and {@code awt} are
-in separate libraries that are not automatically linked. Consult the
-documentation for the packages you're using to determine which library
-contains the package code.
-</p></dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:name}</dt>
-<dd>The name of the library.</dd>
-</dl></dd>
-
-</dl>
-<hr>
-
-
-<h3 id="usesp">&lt;uses-permission&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;uses-permission android:name="<i>string</i>" /&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#manf">&lt;manifest&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Requests a permission that the application must be granted in
-order for it to operate correctly. Permissions are granted when the
-application is installed, not while it's running.
-
-<p>
-For more information on permissions, see the
-{@code <a href="#perms">Permissions</a>} section earlier in this document
-and the separate <a href="{@docRoot}guide/topics/security/security.html">Security Model</a>
-document.
-A list of permissions defined by the base platform can be found at
-{@link android.Manifest.permission android.Manifest.permission}.
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:name}</dt>
-<dd>The name of the permission. It can be a permission defined by the
-application with the {@code <a href="#prmsn">&lt;permission&gt;</a>}
-element, a permission defined by another application, or one of the
-standard system permissions, such as "{@code android.permission.CAMERA}"
-or "{@code android.permission.READ_CONTACTS}". As these examples show,
-a permission name typically includes the package name as a prefix.</dd>
-
-</dl></dd>
-
-<dt>see also:</dt>
-<dd>{@code <a href="#prmsn">&lt;permission&gt;</a>}</dd>
-
-</dl>
-<hr>
-
-
-<h3 id="usess">&lt;uses-sdk&gt;</h3>
-
-<dl class="xml">
-<dt>syntax:</dt>
-<dd><pre class="stx">&lt;uses-sdk android:minSdkVersion="<i>integer</i>" /&gt;</pre></dd>
-
-<dt>contained in:</dt>
-<dd>{@code <a href="#manf">&lt;manifest&gt;</a>}</dd>
-
-<dt>description:</dt>
-<dd>Declares which versions of the Android SDK (software development kit)
-the application can run against. The version number is incremented when
-there are additions to the API and resource tree, so an application developed
-using version 3 of the SDK may not run against versions 1 or 2, but should
-run against version 3, 4, 5, and above.
-
-<p>
-The default is version 1. The current version is also 1.
-</p></dd>
-
-<dt>attributes:</dt>
-<dd><dl class="attr">
-<dt>{@code android:minSdkVersion}</dt>
-<dd>An integer designating the minimum version of the SDK that's required
-for the application to run.</dd>
-
-</dl></dd>
-
-</dl>
-
-
diff --git a/docs/html/guide/topics/manifest/meta-data-element.jd b/docs/html/guide/topics/manifest/meta-data-element.jd
new file mode 100644
index 0000000..1c91407
--- /dev/null
+++ b/docs/html/guide/topics/manifest/meta-data-element.jd
@@ -0,0 +1,90 @@
+page.title=&lt;meta-data&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;meta-data android:<a href="#nm">name</a>="<i>string</i>"
+ android:<a href="#rsrc">resource</a>="<i>resource specification</i>"
+ android:<a href="#val">value</a>="<i>string</i>" /&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html">&lt;activity-alias&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html">&lt;service&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/receiver-element.html">&lt;receiver&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>A name-value pair for an item of additional, arbitrary data that can
+be supplied to the parent component. A component element can contain any
+number of {@code &lt;meta-data&gt;} subelements. The values from all of
+them are collected in a single {@link android.os.Bundle} object and made
+available to the component as the
+{@link android.content.pm.PackageItemInfo#metaData
+PackageItemInfo.metaData} field.
+
+<p>
+Ordinary values are specified through the <code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#value">value</a></code>
+attribute. However, to assign a resource ID as the value, use the
+<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#resource">resource</a></code> attribute instead. For example,
+the following code assigns whatever value is stored in the {@code @string/kangaroo}
+resource to the "{@code zoo}" name:
+</p>
+
+<pre>&lt;meta-data android:name="zoo" android:value="@string/kangaroo" /&gt;</pre>
+
+<p>
+On the other hand, using the {@code resource} attribute would assign "{@code zoo}"
+the numeric ID of the resource, not the value stored in the resource:
+</p>
+
+<pre>&lt;meta-data android:name="zoo" android:resource="@string/kangaroo" /&gt;</pre>
+
+<p>
+It is highly recommended that you avoid supplying related data as
+multiple separate {@code &lt;meta-data&gt;} entries. Instead, if you
+have complex data to associate with a component, store it as a resource and
+use the {@code resource} attribute to inform the component of its ID.
+</p></dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>A unique name for the item. To ensure that the name is unique, use a
+Java-style naming convention &mdash; for example,
+"{@code com.example.project.activity.fred}".</dd>
+
+<dt><a name="rsrc"></a>{@code android:resource}</dt>
+<dd>A reference to a resource. The ID of the resource is the value assigned
+to the item. The ID can be retrieved from the meta-data Bundle by the
+{@link android.os.Bundle#getInt Bundle.getInt()} method.</dd>
+
+<dt><a name="val"></a>{@code android:value}</dt>
+<dd>The value assigned to the item. The data types that can be assigned as values and the Bundle methods that components use to retrieve those values are listed in the following table:
+
+<table>
+<tr>
+ <th>Type</th>
+ <th>Bundle method</th>
+</tr><tr>
+ <td>String value, using double backslashes ({@code \\}) to escape characters
+ &mdash; such as "{@code \\n}" and "{@code \\uxxxxx}" for a Unicode character.</td>
+ <td>{@link android.os.Bundle#getString(String) getString()}</td>
+</tr><tr>
+ <td>Integer value, such as "{@code 100}"</td>
+ <td>{@link android.os.Bundle#getInt(String) getInt()}</td>
+</tr><tr>
+ <td>Boolean value, either "{@code true}" or "{@code false}"</td>
+ <td>{@link android.os.Bundle#getBoolean(String) getBoolean()}</td>
+</tr><tr>
+ <td>Color value, in the form "{@code #rgb}", "{@code #argb}",
+ "{@code #rrggbb}", or "{@code #aarrggbb}"</td>
+ <td>{@link android.os.Bundle#getString(String) getString()}</td>
+</tr><tr>
+ <td>Float value, such as "{@code 1.23}"</td>
+ <td>{@link android.os.Bundle#getFloat(String) getFloat()}</td>
+</tr>
+</table>
+</dd>
+</dl></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/permission-element.jd b/docs/html/guide/topics/manifest/permission-element.jd
new file mode 100644
index 0000000..6eef081
--- /dev/null
+++ b/docs/html/guide/topics/manifest/permission-element.jd
@@ -0,0 +1,131 @@
+page.title=&lt;permission&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt></dt>
+<dd><pre class="stx">&lt;permission android:<a href="#desc">description</a>="<i>string resource</i>"
+ android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+ android:<a href="#label">label</a>="<i>string resource</i>"
+ android:<a href="#nm">name</a>="<i>string</i>"
+ android:<a href="#pgroup">permissionGroup</a>="<i>string</i>"
+ android:<a href="#plevel">protectionLevel</a>=["normal" | "dangerous" |
+ "signature" | "signatureOrSystem"] /&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Declares a security permission that can be used to limit access
+to specific components or features of this or other applications.
+See the <a href="{@docRoot}guide/topics/manifest/manifest-intro.html#perms">Permissions</a>
+section in the introduction,
+and the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
+document for more information on how permissions work.</dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="desc"></a>{@code android:description}</dt>
+<dd>A user-readable description of the permission, longer and more
+informative than the label. It may be displayed to explain the
+permission to the user &mdash; for example, when the user is asked
+whether to grant the permission to another application.
+
+<p>
+This attribute must be set as a reference to a string resource;
+unlike the {@code label} attribute, it cannot be a raw string.
+</p></dd>
+
+<dt><a name="icon"></a>{@code android:icon}</dt>
+<dd>A reference to a drawable resource for an icon that represents the
+permission.</dd>
+
+<dt><a name="label"></a>{@code android:label}</dt>
+<dd>A name for the permission, one that can be displayed to users.
+
+<p>
+As a convenience, the label can be directly set
+as a raw string while you're developing the application. However,
+when the application is ready to be published, it should be set as a
+reference to a string resource, so that it can be localized like other
+strings in the user interface.
+</p></dd>
+
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The name of the permission. This is the name that will be used in
+code to refer to the permission &mdash; for example, in a
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code> element and the
+{@code permission} attributes of application components.
+
+<p>
+The name must be unique, so it should use Java-style scoping &mdash;
+for example, "{@code com.example.project.PERMITTED_ACTION}".
+</p></dd>
+
+<dt><a name="pgroup"></a>{@code android:permissionGroup}</dt>
+<dd>Assigns this permission to a group. The value of this attribute is
+the name of the group, which must be declared with the
+<code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code> element in this
+or another application. If this attribute is not set, the permission
+does not belong to a group.</dd>
+
+<dt><a name="plevel"></a>{@code android:protectionLevel}</dt>
+<dd>Characterizes the potential risk implied in the permission and
+indicates the procedure the system should follow when determining
+whether or not to grant the permission to an application requesting it.
+The value can be set to one of the following strings:
+
+<table>
+<tr>
+ <th>Value</th>
+ <th>Meaning</th>
+</tr><tr>
+ <td>"{@code normal}"</td>
+ <td>The default value. A lower-risk permission that gives requesting
+ applications access to isolated application-level features, with
+ minimal risk to other applications, the system, or the user.
+ The system automatically grants this type
+ of permission to a requesting application at installation, without
+ asking for the user's explicit approval (though the user always
+ has the option to review these permissions before installing).
+</tr><tr>
+ <td>"{@code dangerous}"</td>
+ <td>A higher-risk permission that would give a requesting application
+ access to private user data or control over the device that can
+ negatively impact the user. Because this type of permission
+ introduces potential risk, the system may not automatically
+ grant it to the requesting application. For example, any dangerous
+ permissions requested by an application may be displayed to the
+ user and require confirmation before proceeding, or some other
+ approach may be taken to avoid the user automatically allowing
+ the use of such facilities.
+</tr><tr>
+ <td>"{@code signature}"</td>
+ <td>A permission that the system grants only if the requesting
+ application is signed with the same certificate as the application
+ that declared the permission. If the certificates match, the system
+ automatically grants the permission without notifying the user or
+ asking for the user's explicit approval.
+</tr><tr>
+ <td>"{@code signatureOrSystem}"</td>
+ <td>A permission that the system grants only to applications that are
+ in the Android system image <em>or</em> that are signed with the same
+ certificates as those in the system image. Please avoid using this
+ option, as the {@code signature} protection level should be sufficient
+ for most needs and works regardless of exactly where applications are
+ installed. The "{@code signatureOrSystem}"
+ permission is used for certain special situations where multiple
+ vendors have applications built into a system image and need
+ to share specific features explicitly because they are being built
+ together.
+</tr>
+</table>
+</dd>
+</dl></dd>
+
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code></dd>
+</dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/permission-group-element.jd b/docs/html/guide/topics/manifest/permission-group-element.jd
new file mode 100644
index 0000000..9cfca6e
--- /dev/null
+++ b/docs/html/guide/topics/manifest/permission-group-element.jd
@@ -0,0 +1,59 @@
+page.title=&lt;permission-group&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;permission-group android:<a href="#desc">description</a>="<i>string resource</i>"
+ android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+ android:<a href="#label">label</a>="<i>string resource</i>"
+ android:<a href="#nm">name</a>="<i>string</i>" /&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Declares a name for a logical grouping of related permissions. Individual
+permission join the group through the {@code permissionGroup} attribute of the
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code> element. Members of a group are
+presented together in the user interface.
+
+<p>
+Note that this element does not declare a permission itself, only a category in
+which permissions can be placed. See the
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code> element for element for information
+on declaring permissions and assigning them to groups.
+</p></dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="desc"></a>{@code android:description}</dt>
+<dd>User-readable text that describes the group. The text should be
+longer and more explanatory than the label. This attribute must be
+set as a reference to a string resource. Unlike the {@code label}
+attribute, it cannot be a raw string.</dd>
+
+<dt><a name="icon"></a>{@code android:icon}</dt>
+<dd>An icon representing the permission. This attribute must be set
+as a reference to a drawable resource containing the image definition.</dd>
+
+<dt><a name="label"></a>{@code android:label}</dt>
+<dd>A user-readable name for the group. As a convenience, the label can
+be directly set as a raw string while you're developing the application.
+However, when the application is ready to be published, it should be set
+as a reference to a string resource, so that it can be localized like other
+strings in the user interface.</dd>
+
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The name of the group. This is the name that can be assigned to a
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+element's
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html#pgroup">&lt;permissionGroup&gt;</a></code>
+attribute.</dd>
+</dl></dd>
+
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/permission-tree-element.jd b/docs/html/guide/topics/manifest/permission-tree-element.jd
new file mode 100644
index 0000000..e2f7474
--- /dev/null
+++ b/docs/html/guide/topics/manifest/permission-tree-element.jd
@@ -0,0 +1,61 @@
+page.title=&lt;permission-tree&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;permission-tree android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+ android:<a href="#label">label</a>="<i>string resource</i>" ]
+ android:<a href="#nm">name</a>="<i>string</i>" /&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Declares the base name for a tree of permissions. The application takes
+ownership of all names within the tree. It can dynamically add new permissions
+to the tree by calling <code>{@link android.content.pm.PackageManager#addPermission PackageManager.addPermission()}</code>. Names within the tree are separated by
+periods ('{@code .}'). For example, if the base name is
+{@code com.example.project.taxes}, permissions like the following might be
+added:
+
+<p style="margin-left: 2em">{@code com.example.project.taxes.CALCULATE}
+<br/>{@code com.example.project.taxes.deductions.MAKE_SOME_UP}
+<br/>{@code com.example.project.taxes.deductions.EXAGGERATE}</p>
+
+<p>
+Note that this element does not declare a permission itself, only a
+namespace in which further permissions can be placed. See the
+<code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+element for information on declaring permissions.
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="icon"></a>{@code android:icon}</dt>
+<dd>An icon representing all the permissions in the tree. This attribute
+must be set as a reference to a drawable resource containing the image
+definition.</dd>
+
+<dt><a name="label"></a>{@code android:label}</dt>
+<dd>A user-readable name for the group. As a convenience, the label can
+be directly set as a raw string for quick and dirty programming. However,
+when the application is ready to be published, it should be set as a
+reference to a string resource, so that it can be localized like other
+strings in the user interface.</dd>
+
+<dt><a name="nm"</a>{@code android:name}</dt>
+<dd>The name that's at the base of the permission tree. It serves as
+a prefix to all permission names in the tree. Java-style scoping should
+be used to ensure that the name is unique. The name must have more than
+two period-separated seqments in its path &mdash; for example,
+{@code com.example.base} is OK, but {@code com.example} is not.</dd>
+
+</dl></dd>
+
+<p>
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+</dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd
new file mode 100644
index 0000000..7359e50
--- /dev/null
+++ b/docs/html/guide/topics/manifest/provider-element.jd
@@ -0,0 +1,267 @@
+page.title=&lt;provider&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;provider android:<a href="#auth">authorities</a>="<i>list</i>"
+ android:<a href="#enabled">enabled</a>=["true" | "false"]
+ android:<a href="#exported">exported</a>=["true" | "false"]
+ android:<a href="#gprmsn">grantUriPermissions</a>=["true" | "false"]
+ android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+ android:<a href="#init">initOrder</a>="<i>integer</i>"
+ android:<a href="#label">label</a>="<i>string resource</i>"
+ android:<a href="#multi">multiprocess</a>=["true" | "false"]
+ android:<a href="#nm">name</a>="<i>string</i>"
+ android:<a href="#prmsn">permission</a>="<i>string</i>"
+ android:<a href="#proc">process</a>="<i>string</i>"
+ android:<a href="#rprmsn">readPermission</a>="<i>string</i>"
+ android:<a href="#sync">syncable</a>=["true" | "false"]
+ android:<a href="#wprmsn">writePermission</a>="<i>string</i>" &gt;
+ . . .
+&lt;/provider&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code></dd>
+
+<dt>can contain:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Declares a content provider &mdash; a subclass of
+{@link android.content.ContentProvider} &mdash; that supplies structured
+access to data managed by the application. All content providers that
+are part of the application must be represented by {@code &lt;provider&gt;}
+elements in the manifest file. The system cannot see, and therefore will
+not run, any that are not declared. (You need to declare only
+those content providers that you develop as part of your application,
+not those developed by others that your application uses.)
+
+<p>
+The Android system identifies content providers by the authority part
+ of a {@code content:} URI. For example, suppose that the following URI
+is passed to <code>{@link android.content.ContentResolver#query
+ContentResolver.query()}</code>:
+
+<p style="margin-left: 2em">{@code content://com.example.project.healthcareprovider/nurses/rn}</p>
+
+<p>
+The {@code content:} scheme identifies the data as belonging to a content
+provider and the authority ({@code com.example.project.healthcareprovider})
+identifies the particular provider. The authority therefore must be unique.
+Typically, as in this example, it's the fully qualified name of a
+ContentProvider subclass. The path part of a URI may be used by a content
+provider to identify particular data subsets, but those paths are not
+declared in the manifest.
+</p>
+
+<p>
+For information on using and developing content providers, see a separate document,
+<a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.
+</p></dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="auth"></a>{@code android:authorities}</dt>
+<dd>A list of one or more URI authorities that identify data under the purview
+of the content provider.
+Multiple authorities are listed by separating their names with a semicolon.
+To avoid conflicts, authority names should use a Java-style naming convention
+(such as {@code com.example.provider.cartoonprovider}). Typically, it's the name
+of the ContentProvider subclass.
+
+<p>
+There is no default. At least one authority must be specified.
+</p></dd>
+
+<dt><a name="enabled"></a>{@code android:enabled}</dt>
+<dd>Whether or not the content provider can be instantiated by the system &mdash;
+"{@code true}" if it can be, and "{@code false}" if not. The default value
+is "{@code true}".
+
+<p>
+The <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element has its own
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#enabled">enabled</a></code> attribute that applies to all
+application components, including content providers. The
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> and {@code &lt;provider&gt;}
+attributes must both be "{@code true}" (as they both
+are by default) for the content provider to be enabled. If either is
+"{@code false}", the provider is disabled; it cannot be instantiated.
+</p></dd>
+
+<dt><a name="exported"></a>{@code android:exported}</dt>
+<dd>Whether or not the content provider can be used by components of other
+applications &mdash; "{@code true}" if it can be, and "{@code false}" if not.
+If "{@code false}", the provider is available only to components of the
+same application or applications with the same user ID. The default value
+is "{@code true}".
+
+<p>
+You can export a content provider but still limit access to it with the
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">permission</a></code> attribute.
+</p></dd>
+
+<dt><a name="gprmsn"></a>{@code android:grantUriPermissions}</dt>
+<dd>Whether or not those who ordinarily would not have permission to
+access the content provider's data can be granted permission to do so,
+temporarily overcoming the restriction imposed by the
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">readPermission</a></code>,
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">writePermission</a></code>, and
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">permission</a></code> attributes
+&mdash;
+"{@code true}" if permission can be granted, and "{@ code false}" if not.
+If "{@code true}", permission can be granted to any of the content
+provider's data. If "{@code false}", permission can be granted only
+to the data subsets listed in
+<code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code> subelements,
+if any. The default value is "{@code false}".
+
+<p>
+Granting permission is a way of giving an application component one-time
+access to data protected by a permission. For example, when an e-mail
+message contains an attachment, the mail application may call upon the
+appropriate viewer to open it, even though the viewer doesn't have general
+permission to look at all the content provider's data.
+</p>
+
+<p>
+In such cases, permission is granted by
+<code>{@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}</code>
+and <code>{@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}</code>
+flags in the Intent object that activates the component. For example, the
+mail application might put {@code FLAG_GRANT_READ_URI_PERMISSION} in the
+Intent passed to {@code Context.startActivity()}. The permission is specific
+to the URI in the Intent.
+</p>
+
+<p>
+If you enable this feature, either by setting this attribute to "{@code true}"
+or by defining <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
+subelements, you must call
+<code>{@link android.content.Context#revokeUriPermission
+Context.revokeUriPermission()}</code> when a covered URI is deleted from
+the provider.
+</p>
+
+<p>
+See also the <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
+element.
+</p></dd>
+
+<dt><a name="icon"></a>{@code android:icon}</dt>
+<dd>An icon representing the content provider.
+This attribute must be set as a reference to a drawable resource containing
+the image definition. If it is not set, the icon specified for the application
+as a whole is used instead (see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+element's <code><a href="{@docRoot}guide/topics/manifest/application-element.html#icon">icon</a></code> attribute).</dd>
+
+<dt><a name="init"></a>{@code android:initOrder}</dt>
+<dd>The order in which the content provider should be instantiated,
+relative to other content providers hosted by the same process.
+When there are dependencies among content providers, setting this
+attribute for each of them ensures that they are created in the order
+required by those dependencies. The value is a simple integer,
+with higher numbers being initialized first.</dd>
+
+<dt><a name="label"></a>{@code android:label}</dt>
+<dd>A user-readable label for the content provided.
+If this attribute is not set, the label set for the application as a whole is
+used instead (see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#label">label</a></code> attribute).
+
+<p>
+The label should be set as a reference to a string resource, so that
+it can be localized like other strings in the user interface.
+However, as a convenience while you're developing the application,
+it can also be set as a raw string.
+</p></dd>
+
+<dt><a name="multi"></a>{@code android:multiprocess}</dt>
+<dd>Whether or not an instance of the content provider can be created in
+every client process &mdash; "{@code true}" if instances can run in multiple
+processes, and "{@code false}" if not. The default value is "{@code false}".
+
+<p>
+Normally, a content provider is instantiated in the process of the
+application that defined it. However, if this flag is set to "{@code true}",
+the system can create an instance in every process where there's a client
+that wants to interact withit, thus avoiding the overhead of interprocess
+communication.
+</p></dd>
+
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The name of the class that implements the content provider, a subclass of
+{@link android.content.ContentProvider}. This should be a fully qualified
+class name (such as, "{@code com.example.project.TransportationProvider}").
+However, as a shorthand, if the first character of the name is a period,
+it is appended to the package name specified in the
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> element.
+
+<p>
+There is no default. The name must be specified.
+</p></dd>
+
+
+<dt><a name="prmsn"></a>{@code android:permission}</dt>
+<dd>The name of a permission that clients must have to read or write the
+content provider's data. This attribute is a convenient way of setting a
+single permission for both reading and writing. However, the
+<code><a href="#rprmsn">readPermission</a></code> and
+<code><a href="#wprmsn">writePermission</a></code> attributes take precedence
+over this one. If the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">readPermission</a></code>
+attribute is also set, it controls access for querying the content provider.
+And if the <code><a href="#wprmsn">writePermission</a></code> attribute is set,
+it controls access for modifying the provider's data.
+
+<p>
+For more information on permissions, see the
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#sectperm">Permissions</a>
+section in the introduction and a separate document,
+<a href="{@docRoot}guide/topics/security/security.html">Security and
+Permissions</a>.
+</p></dd>
+
+<dt><a name="proc"></a>{@code android:process}</dt>
+<dd>The name of the process in which the content provider should run. Normally,
+all components of an application run in the default process created for the
+application. It has the same name as the application package. The
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#proc">process</a></code>
+attribute can set a different
+default for all components. But each component can override the default
+with its own {@code process} attribute, allowing you to spread your
+application across multiple processes.
+
+<p>
+If the name assigned to this attribute begins with a colon (':'), a new
+process, private to the application, is created when it's needed and
+the activity runs in that process.
+If the process name begins with a lowercase character, the activity will run
+in a global process of that name, provided that it has permission to do so.
+This allows components in different applications to share a process, reducing
+resource usage.
+</p></dd>
+
+<dt><a name="rprmsn"></a>{@code android:readPermission}</dt>
+<dd>A permission that clients must have to query the content provider.
+See also the <code><a href="#prmsn">permission</a></code> and
+<code><a href="#wprmsn">writePermission</a></code> attributes.</dd>
+
+<dt><a name="sync"></a>{@code android:syncable}</dt>
+<dd>Whether or not the data under the content provider's control
+is to be synchronized with data on a server &mdash; "{@code true}"
+if it is to be synchronized, and "{@ code false}" if not.</dd>
+
+<dt><a name="wprmsn"></a>{@code android:writePermission}</dt>
+<dd>A permission that clients must have to make changes to the data
+controlled by the content provider.
+See also the <code><a href="#prmsn">permission</a></code> and
+<code><a href="#rprmsn">readPermission</a></code> attributes.</dd>
+
+</dl></dd>
+
+<p>
+<dt>see also:</dt>
+<dd><a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/receiver-element.jd b/docs/html/guide/topics/manifest/receiver-element.jd
new file mode 100644
index 0000000..777d016
--- /dev/null
+++ b/docs/html/guide/topics/manifest/receiver-element.jd
@@ -0,0 +1,164 @@
+page.title=&lt;receiver&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;receiver android:<a href="#enabled">enabled</a>=["true" | "false"]
+ android:<a href="#exported">exported</a>=["true" | "false"]
+ android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+ android:<a href="#label">label</a>="<i>string resource</i>"
+ android:<a href="#nm">name</a>="<i>string</i>"
+ android:<a href="#prmsn">permission</a>="<i>string</i>"
+ android:<a href="#proc">process</a>="<i>string</i>" &gt;
+ . . .
+&lt;/receiver&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code></dd>
+
+<dt>can contain:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filer&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Declares a broadcast receiver (a {@link android.content.BroadcastReceiver}
+subclass) as one of the application's components. Broadcast receivers enable
+applications to receive intents that are broadcast by the system or by other
+applications, even when other components of the application are not running.
+
+<p>
+There are two ways to make a broadcast receiver known to the system: One is
+declare it in the manifest file with this element. The other is to create
+the receiver dynamically in code and register it with the <code>{@link
+android.content.Context#registerReceiver Context.registerReceiver()}</code>
+method. See the {@link android.content.BroadcastReceiver} class description
+for more on dynamically created receivers.
+</p></dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="enabled"></a>{@code android:enabled}</dt>
+<dd>Whether or not the broadcast receiver can be instantiated by the system &mdash;
+"{@code true}" if it can be, and "{@code false}" if not. The default value
+is "{@code true}".
+
+<p>
+The <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element has its own
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#enabled">enabled</a></code> attribute that applies to all
+application components, including broadcast receivers. The
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> and
+{@code &lt;receiver&gt;} attributes must both be "{@code true}" for
+the broadcast receiver to be enabled. If either is "{@code false}", it is
+disabled; it cannot be instantiated.
+</p></dd>
+
+<dt><a name="exported"></a>{@code android:exported}</dt>
+<dd>Whether or not the broadcast receiver can receive messages from sources
+outside its application &mdash; "{@code true}" if it can, and "{@code false}"
+if not. If "{@code false}", the only messages the broadcast receiver can
+receive are those sent by components of the same application or applications
+with the same user ID.
+
+<p>
+The default value depends on whether the broadcast receiver contains intent filters.
+The absence of any filters means that it can be invoked only by Intent objects that
+specify its exact class name. This implies that the receiver is intended only for
+application-internal use (since others would not normally know the class name).
+So in this case, the default value is "{@code false}".
+On the other hand, the presence of at least one filter implies that the broadcast
+receiver is intended to receive intents broadcast by the system or other applications,
+so the default value is "{@code true}".
+</p>
+
+<p>
+This attribute is not the only way to limit a broadcast receiver's external exposure.
+You can also use a permission to limit the external entities that can send it messages
+(see the <code><a href="{@docRoot}guide/topics/manifest/receiver-element.html#prmsn">permission</a></code> attribute).
+</p></dd>
+
+<dt><a name="icon"></a>{@code android:icon}</dt>
+<dd>An icon representing the broadcast receiver. This attribute must be set
+as a reference to a drawable resource containing the image definition.
+If it is not set, the icon specified for the application as a whole is used
+instead (see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+element's <code><a href="{@docRoot}guide/topics/manifest/application-element.html#icon">icon</a></code> attribute).
+
+<p>
+The broadcast receiver's icon &mdash; whether set here or by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element &mdash; is also the
+default icon for all the receiver's intent filters (see the
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html#icon">icon</a></code> attribute).
+</p></dd>
+
+<dt><a name="label"></a>{@code android:label}</dt>
+<dd>A user-readable label for the broadcast receiver. If this attribute is not
+set, the label set for the application as a whole is
+used instead (see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#label">label</a></code> attribute).
+
+<p>
+The broadcast receiver's label &mdash; whether set here or by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element &mdash; is also the
+default label for all the receiver's intent filters (see the
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html#label">label</a></code> attribute).
+</p>
+
+<p>
+The label should be set as a reference to a string resource, so that
+it can be localized like other strings in the user interface.
+However, as a convenience while you're developing the application,
+it can also be set as a raw string.
+</p></dd>
+
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The name of the class that implements the broadcast receiver, a subclass of
+{@link android.content.BroadcastReceiver}. This should be a fully qualified
+class name (such as, "{@code com.example.project.ReportReceiver}"). However,
+as a shorthand, if the first character of the name is a period (for example,
+"{@code . ReportReceiver}"), it is appended to the package name specified in
+the <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> element.
+
+<p>
+There is no default. The name must be specified.
+</p></dd>
+
+<dt><a name="prmsn"></a>{@code android:permission}</dt>
+<dd>The name of a permission that broadcasters must have to send a
+message to the broadcast receiver.
+If this attribute is not set, the permission set by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#prmsn">permission</a></code> attribute applies
+to the broadcast receiver. If neither attribute is set, the receiver
+is not protected by a permission.
+
+<p>
+For more information on permissions, see the
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#sectperm">Permissions</a>
+section in the introduction and a separate document,
+<a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>.
+</p></dd>
+
+<dt><a name="proc"></a>{@code android:process}</dt>
+<dd>The name of the process in which the broadcast receiver should run.
+Normally, all components of an application run in the default process created
+for the application. It has the same name as the application package. The
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#proc">process</a></code> attribute can set a different
+default for all components. But each component can override the default
+with its own {@code process} attribute, allowing you to spread your
+application across multiple processes.
+
+<p>
+If the name assigned to this attribute begins with a colon (':'), a new
+process, private to the application, is created when it's needed and
+the broadcast receiver runs in that process.
+If the process name begins with a lowercase character, the receiver will run
+in a global process of that name, provided that it has permission to do so.
+This allows components in different applications to share a process, reducing
+resource usage.
+</p></dd>
+</dl></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/service-element.jd b/docs/html/guide/topics/manifest/service-element.jd
new file mode 100644
index 0000000..ad65abe
--- /dev/null
+++ b/docs/html/guide/topics/manifest/service-element.jd
@@ -0,0 +1,176 @@
+page.title=&lt;service&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;service android:<a href="#enabled">enabled</a>=["true" | "false"]
+ android:<a href="#exported">exported[</a>="true" | "false"]
+ android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+ android:<a href="#label">label</a>="<i>string resource</i>"
+ android:<a href="#nm">name</a>="<i>string</i>"
+ android:<a href="#prmsn">permission</a>="<i>string</i>"
+ android:<a href="#proc">process</a>="<i>string</i>" &gt;
+ . . .
+&lt;/service&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code></dd>
+
+<dt>can contain:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filer&gt;</a></code>
+<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html">&lt;meta-data&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Declares a service (a {@link android.app.Service} subclass) as one
+of the application's components. Unlike activities, services lack a
+visual user interface. They're used to implement long-running background
+operations or a rich communications API that can be called by other
+applications.
+
+<p>
+All services must be represented by {@code &lt;service&gt;} elements in
+the manifest file. Any that are not declared there will not be seen
+by the system and will never be run.
+</p></dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="enabled"></a>{@code android:enabled}</dt>
+<dd>Whether or not the service can be instantiated by the system &mdash;
+"{@code true}" if it can be, and "{@code false}" if not. The default value
+is "{@code true}".
+
+<p>
+The <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element has its own
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#enabled">enabled</a></code> attribute that applies to all
+application components, including services. The
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> and {@code &lt;service&gt;}
+attributes must both be "{@code true}" (as they both
+are by default) for the service to be enabled. If either is
+"{@code false}", the service is disabled; it cannot be instantiated.
+</p></dd>
+
+<dt><a name="exported"></a>{@code android:exported}</dt>
+<dd>Whether or not components of other applications can invoke
+the service or interact with it &mdash; "{@code true}" if they can, and
+"{@code false}" if not. When the value is "{@code false}", only
+components of the same application or applications
+with the same user ID can start the service or bind to it.
+
+<p>
+The default value depends on whether the service contains intent filters. The
+absence of any filters means that it can be invoked only by specifying
+its exact class name. This implies that the service is intended only for
+application-internal use (since others would not know the class name). So in
+this case, the default value is "{@code false}".
+On the other hand, the presence of at least one filter implies that the service
+is intended for external use, so the default value is "{@code true}".
+</p>
+
+<p>
+This attribute is not the only way to limit the exposure of a service to other
+applications. You can also use a permission to limit the external entities that
+can interact with the service (see the <code><a href="{@docRoot}guide/topics/manifest/service-element.html#prmsn">permission</a></code>
+attribute).
+</p></dd>
+
+<dt><a name="icon"></a>{@code android:icon}</dt>
+<dd>An icon representing the service. This attribute must be set as a
+reference to a drawable resource containing the image definition.
+If it is not set, the icon specified for the application
+as a whole is used instead (see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+element's <code><a href="{@docRoot}guide/topics/manifest/application-element.html#icon">icon</a></code> attribute).
+</p>
+
+<p>
+The service's icon &mdash; whether set here or by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element &mdash; is also the
+default icon for all the service's intent filters (see the
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html#icon">icon</a></code> attribute).
+</p></dd>
+
+<dt><a name="label"></a>{@code android:label}</dt>
+<dd>A name for the service that can be displayed to users.
+If this attribute is not set, the label set for the application as a whole is
+used instead (see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#label">label</a></code> attribute).
+
+<p>
+The service's label &mdash; whether set here or by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element &mdash; is also the
+default label for all the service's intent filters (see the
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">&lt;intent-filter&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html#label">label</a></code> attribute).
+</p>
+
+<p>
+The label should be set as a reference to a string resource, so that
+it can be localized like other strings in the user interface.
+However, as a convenience while you're developing the application,
+it can also be set as a raw string.
+</p></dd>
+
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The name of the {@link android.app.Service} subclass that implements
+the service. This should be a fully qualified class name (such as,
+"{@code com.example.project.RoomService}"). However, as a shorthand, if
+the first character of the name is a period (for example, "{@code .RoomService}"),
+it is appended to the package name specified in the
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> element.
+
+<p>
+There is no default. The name must be specified.
+</p></dd>
+
+<dt><a name="prmsn"></a>{@code android:permission}</dt>
+<dd>The name of a permission that that an entity must have in order to
+launch the service or bind to it. If a caller of
+<code>{@link android.content.Context#startService startService()}</code>,
+<code>{@link android.content.Context#bindService bindService()}</code>, or
+<code>{@link android.content.Context#stopService stopService()}</code>,
+has not been granted this permission, the method will not work and the
+Intent object will not be delivered to the service.
+
+<p>
+If this attribute is not set, the permission set by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#prmsn">permission</a></code>
+attribute applies to the service. If neither attribute is set, the service is
+not protected by a permission.
+</p>
+
+<p>
+For more information on permissions, see the
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#sectperm">Permissions</a>
+section in the introduction and a separate document,
+<a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>.
+</p></dd>
+
+<dt><a name="proc"></a>{@code android:process}</dt>
+<dd>The name of the process where the service is to run. Normally,
+all components of an application run in the default process created for the
+application. It has the same name as the application package. The
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#proc">process</a></code>
+attribute can set a different
+default for all components. But component can override the default
+with its own {@code process} attribute, allowing you to spread your
+application across multiple processes.
+
+<p>
+If the name assigned to this attribute begins with a colon (':'), a new
+process, private to the application, is created when it's needed and
+the service runs in that process.
+If the process name begins with a lowercase character, the service will run
+in a global process of that name, provided that it has permission to do so.
+This allows components in different applications to share a process, reducing
+resource usage.
+</p></dd>
+</dl></dd>
+
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+<br><code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/uses-library-element.jd b/docs/html/guide/topics/manifest/uses-library-element.jd
new file mode 100644
index 0000000..d66da2c
--- /dev/null
+++ b/docs/html/guide/topics/manifest/uses-library-element.jd
@@ -0,0 +1,32 @@
+page.title=&lt;uses-library&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre>&lt;uses-library android:<a href="#nm">name</a>="<i>string</i>" /&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Specifies a shared library that the application must be linked against.
+This element tells the system to include the library's code in the class
+loader for the package.
+
+<p>
+All of the {@code android} packages (such as {@link android.app},
+{@link android.content}, {@link android.view}, and {@link android.widget})
+are in the default library that all applications are automatically linked
+against. However, some packages (such as {@code maps} and {@code awt} are
+in separate libraries that are not automatically linked. Consult the
+documentation for the packages you're using to determine which library
+contains the package code.
+</p></dd>
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The name of the library.</dd>
+</dl></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/uses-permission-element.jd b/docs/html/guide/topics/manifest/uses-permission-element.jd
new file mode 100644
index 0000000..07741b1
--- /dev/null
+++ b/docs/html/guide/topics/manifest/uses-permission-element.jd
@@ -0,0 +1,39 @@
+page.title=&lt;uses-permission&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;uses-permission android:<a href="#nm">name</a>="<i>string</i>" /&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Requests a permission that the application must be granted in
+order for it to operate correctly. Permissions are granted when the
+application is installed, not while it's running.
+
+<p>
+For more information on permissions, see the
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#perms">Permissions</a></code>
+section in the introduction and the separate
+<a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> document.
+A list of permissions defined by the base platform can be found at
+{@link android.Manifest.permission android.Manifest.permission}.
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="nm"></a>{@code android:name}</dt>
+<dd>The name of the permission. It can be a permission defined by the
+application with the <code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
+element, a permission defined by another application, or one of the
+standard system permissions, such as "{@code android.permission.CAMERA}"
+or "{@code android.permission.READ_CONTACTS}". As these examples show,
+a permission name typically includes the package name as a prefix.</dd>
+
+</dl></dd>
+
+<dt>see also:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
new file mode 100644
index 0000000..a88635a
--- /dev/null
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -0,0 +1,49 @@
+page.title=&lt;uses-sdk&gt;
+@jd:body
+
+<dl class="xml">
+<dt>syntax:</dt>
+<dd><pre class="stx">&lt;uses-sdk android:<a href="#min">minSdkVersion</a>="<i>integer</i>" /&gt;</pre></dd>
+
+<dt>contained in:</dt>
+<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code></dd>
+
+<dt>description:</dt>
+<dd>Declares which levels of the Android API the application can run against.
+The level is incremented when there are additions to the API and resource tree,
+so an application developed using level 3 of the API may not run against level
+1 or 2, but should run against level 3, 4, 5, and above.
+</p>
+
+<p>
+The default level is 1.
+</p>
+
+<p>
+For more information on the API level, see the
+<a href="{@docRoot}guide/publishing/versioning.html#minsdkversion">Specifying
+Minimum System API Version</a> section of
+<a href="{@docRoot}guide/publishing/versioning.html">Versioning Your
+Applications</a>.
+</p></dd>
+
+
+<dt>attributes:</dt>
+<dd><dl class="attr">
+<dt><a name="min"></a>{@code android:minSdkVersion}</dt>
+<dd>An integer designating the minimum level of the Android API that's required
+for the application to run.
+
+<p>
+Despite its name, this attribute is set to the API level, <em>not</em> to the
+version number of the SDK (software development kit). The API level is always
+a single integer; the SDK version may be split into major and minor components
+(such as 1.2). You cannot derive the API level from the SDK version number
+(for example, it is not the same as the major version or the sum of the major
+and minor versions). To learn what the API level is, check the notes that
+came with the SDK you're using.
+</p></dd>
+
+</dl></dd>
+
+</dl>
diff --git a/docs/html/guide/topics/resources/available-resources.jd b/docs/html/guide/topics/resources/available-resources.jd
index 7ba9e52..2a6a6ac 100644
--- a/docs/html/guide/topics/resources/available-resources.jd
+++ b/docs/html/guide/topics/resources/available-resources.jd
@@ -853,7 +853,7 @@ of an <code>&lt;item></code> (to create a Sub Menu).</p>
</dl>
<p>For more discussion on how to create menus in XML and inflate them in your application,
-read <a href="{@docRoot}guide/topics/views/menus.html">Creating Menus</a>.</p>
+read <a href="{@docRoot}guide/topics/ui/menus.html">Creating Menus</a>.</p>
@@ -877,7 +877,7 @@ the Android namespace "http://schemas.android.com/apk/res/android" defined in
the root element.</p>
<p>For a complete discussion on creating layouts, see the
-<a href="{@docRoot}guide/topics/views/index.html">Views and Layout</a> topic.</p>
+<a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> topic.</p>
<p> <strong>Source file format:</strong> XML file
requiring a <code>&lt;?xml version="1.0" encoding="utf-8"?&gt;</code>
@@ -971,7 +971,7 @@ res/layout/<em>some_file</em>.xml.</p>
<strong>Attributes exposed by all the superclasses of that element.</strong> For example, the TextView class extends the View class, so the <code>&lt;TextView&gt;</code> element supports all the attributes that the <code>&lt;View&gt;</code> element exposes &mdash; a long list, including <code>View_paddingBottom</code> and <code>View_scrollbars</code>. These too are used without the class name: <code>&lt;TextView android:paddingBottom="20" android:scrollbars="horizontal" /&gt;</code>.
</li>
<li>
- <strong>Attributes of the object's {@link android.view.ViewGroup.LayoutParams} subclass.</strong> All View objects support a LayoutParams member (see <a href="{@docRoot}guide/topics/views/layout.html">LayoutParams in Implementing a UI</a>). To set properties on an element's LayoutParams member, the attribute to use is "android:layout_<em>layoutParamsProperty</em>". For example: <code>android:layout_gravity</code> for an object wrapped by a <code>&lt;LinearLayout&gt;</code> element. Remember that each LayoutParams subclass also supports inherited attributes. Attributes exposed by each subclass are given in the format <em>someLayoutParamsSubclass</em>_Layout_layout_<em>someproperty</em>. This defines an attribute "android:layout_<em>someproperty</em>". Here is an example of how Android documentation lists the properties of the {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams} class:
+ <strong>Attributes of the object's {@link android.view.ViewGroup.LayoutParams} subclass.</strong> All View objects support a LayoutParams member (see <a href="{@docRoot}guide/topics/ui/declaring-layout.html#layout-params">Declaring Layout</a>). To set properties on an element's LayoutParams member, the attribute to use is "android:layout_<em>layoutParamsProperty</em>". For example: <code>android:layout_gravity</code> for an object wrapped by a <code>&lt;LinearLayout&gt;</code> element. Remember that each LayoutParams subclass also supports inherited attributes. Attributes exposed by each subclass are given in the format <em>someLayoutParamsSubclass</em>_Layout_layout_<em>someproperty</em>. This defines an attribute "android:layout_<em>someproperty</em>". Here is an example of how Android documentation lists the properties of the {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams} class:
</li>
</ul>
<ul>
@@ -1032,7 +1032,7 @@ setContentView(R.layout.main_screen);
However, layout elements can also represent repeating elements used as templates.
</p>
-<p>Also see <a href="{@docRoot}guide/topics/views/index.html">Views and Layout</a> for more information on layouts.</p>
+<p>Also see <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> for more information on layouts.</p>
@@ -1078,7 +1078,7 @@ setContentView(R.layout.main_screen);
</p>
<p>For a complete discussion on styles and themes, read
-<a href="{@docRoot}guide/topics/views/themes.html">Applying Styles and Themes</a>.</p>
+<a href="{@docRoot}guide/topics/ui/themes.html">Applying Styles and Themes</a>.</p>
<p>
<strong>Source file format:</strong> XML file requiring a <code>&lt;?xml version="1.0" encoding="utf-8"?&gt;</code> declaration, and a root <code>&lt;resources&gt;</code> element containing one or more <code>&lt;style&gt;</code> tags.
@@ -1132,4 +1132,4 @@ setContentView(R.layout.main_screen);
</dl>
<p>For examples of how to declare and apply styles and themes, read
-<a href="{@docRoot}guide/topics/views/themes.html">Applying Styles and Themes</a>.</p>
+<a href="{@docRoot}guide/topics/ui/themes.html">Applying Styles and Themes</a>.</p>
diff --git a/docs/html/guide/topics/resources/resources-i18n.jd b/docs/html/guide/topics/resources/resources-i18n.jd
index 8a9bd43..b1da4cd 100644
--- a/docs/html/guide/topics/resources/resources-i18n.jd
+++ b/docs/html/guide/topics/resources/resources-i18n.jd
@@ -120,7 +120,7 @@ the containing file.</p>
<tr>
<td><code>res/layout/</code></td>
<td>XML files that are compiled into screen layouts (or part of a screen).
- See <a href="{@docRoot}guide/topics/views/declaring-layout.html">Declaring Layout</a></td>
+ See <a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a></td>
</tr>
<tr>
<td><code>res/values/</code></td>
diff --git a/docs/html/guide/topics/views/binding.jd b/docs/html/guide/topics/ui/binding.jd
index ce57ac4..85aed18 100644
--- a/docs/html/guide/topics/views/binding.jd
+++ b/docs/html/guide/topics/ui/binding.jd
@@ -1,5 +1,5 @@
page.title=Binding to Data with AdapterView
-parent.title=Views and Layout
+parent.title=User Interface
parent.link=index.html
@jd:body
@@ -81,6 +81,9 @@ s2.setAdapter(adapter2);
<p>Note that it is necessary to have the People._ID column in projection used with CursorAdapter
or else you will get an exception.</p>
+<p>If, during the course of your application's life, you change the underlying data that is read by your Adapter,
+you should call {@link android.widget.ArrayAdapter#notifyDataSetChanged()}. This will notify the attached View
+that the data has been changed and it should refresh itself.</p>
<h2 id="HandlingUserSelections">Handling User Selections</h2>
<p>You handle the user's selecction by setting the class's {@link
diff --git a/docs/html/guide/topics/views/custom-components.jd b/docs/html/guide/topics/ui/custom-components.jd
index 9e7943b..eccc2ca 100644
--- a/docs/html/guide/topics/views/custom-components.jd
+++ b/docs/html/guide/topics/ui/custom-components.jd
@@ -1,5 +1,5 @@
page.title=Building Custom Components
-parent.title=Views and Layout
+parent.title=User Interface
parent.link=index.html
@jd:body
@@ -35,7 +35,7 @@ that you can use to construct your UI.</p>
<p>Among the layouts available are {@link android.widget.LinearLayout LinearLayout},
{@link android.widget.FrameLayout FrameLayout}, {@link android.widget.AbsoluteLayout AbsoluteLayout},
-and others. For more examples, see <a href="layout.html">Common Layout Objects</a>.</p>
+and others. For more examples, see <a href="layout-objects.html">Common Layout Objects</a>.</p>
<p>If none of the prebuilt widgets or layouts meets your needs, you can create your own View subclass.
If you only need to make small adjustments to an existing widget or layout, you can simply subclass
diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
new file mode 100644
index 0000000..7ef22a6
--- /dev/null
+++ b/docs/html/guide/topics/ui/declaring-layout.jd
@@ -0,0 +1,275 @@
+page.title=Declaring Layout
+parent.title=User Interface
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+ <h2>Key classes</h2>
+ <ol>
+ <li>{@link android.view.View}</li>
+ <li>{@link android.view.ViewGroup}</li>
+ <li>{@link android.view.ViewGroup.LayoutParams}</li>
+ </ol>
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#write">Write the XML</a></li>
+ <li><a href="#load">Load the XML Resource</a></li>
+ <li><a href="#attributes">Attributes</a>
+ <ol>
+ <li><a href="#id">ID</a></li>
+ <li><a href="#layout-params">Layout Parameters</a></li>
+ </ol>
+ </li>
+ <li><a href="#Position">Position</a></li>
+ <li><a href="#SizePaddingMargin">Size, Padding and Margins</a></li>
+ <li><a href="#example">Example Layout</a></li>
+ </ol>
+</div>
+</div>
+
+<p>Your layout is the architecture for the user interface in an Activity.
+It defines the layout structure and holds all the elements that appear to the user.
+You can declare your layout in two ways:</p>
+<ul>
+<li><strong>Declare UI elements in XML</strong>. Android provides a straightforward XML
+vocabulary that corresponds to the View classes and subclasses, such as those for widgets and layouts.</li>
+<li><strong>Instantiate layout elements at runtime</strong>. Your
+application can create View and ViewGroup objects (and manipulate their properties) programmatically. </li>
+</ul>
+
+<p>The Android framework gives you the flexibility to use either or both of these methods for declaring and managing your application's UI. For example, you could declare your application's default layouts in XML, including the screen elements that will appear in them and their properties. You could then add code in your application that would modify the state of the screen objects, including those declared in XML, at run time. </p>
+
+<div class="sidebox">
+ <p>The <a href="{@docRoot}guide/developing/tools/adt.html">Android Development Tools</a>
+ (ADT) plugin for Eclipse offers a layout preview of your XML &mdash;
+ with the XML file opened, select the <strong>Layout</strong> tab.</p>
+ <p>You should also try the
+ <a href="{@docRoot}guide/developing/tools/hierarchy-viewer.html">Hierarchy Viewer</a> tool,
+ for debugging layouts &mdash; it reveals layout property values,
+ draws wireframes with padding/margin indicators, and full rendered views while
+ you debug on the emulator or device.</p>
+</div>
+
+<p>The advantage to declaring your UI in XML is that it enables you to better separate the presentation of your application from the code that controls its behavior. Your UI descriptions are external to your application code, which means that you can modify or adapt it without having to modify your source code and recompile. For example, you can create XML layouts for different screen orientations, different device screen sizes, and different languages. Additionally, declaring the layout in XML makes it easier to visualize the structure of your UI, so it's easier to debug problems. As such, this document focuses on teaching you how to declare your layout in XML. If you're
+interested in instantiating View objects at runtime, refer to the {@link android.view.ViewGroup} and
+{@link android.view.View} class references.</p>
+
+<p>In general, the XML vocabulary for declaring UI elements closely follows the structure and naming of the classes and methods, where element names correspond to class names and attribute names correspond to methods. In fact, the correspondence is often so direct that you can guess what XML attribute corresponds to a class method, or guess what class corresponds to a given xml element. However, note that not all vocabulary is identical. In some cases, there are slight naming differences. For
+example, the EditText element has a <code>text</code> attribute that corresponds to
+<code>EditText.setText()</code>. </p>
+
+<p class="note"><strong>Tip:</strong> Learn more about different layout types in <a href="{@docRoot}guide/topics/ui/layout-objects.html">Common
+Layout Objects</a>. There are also a collection of tutorials on building various layouts in the
+<a href="{@docRoot}guide/tutorials/views/index.html">Hello Views</a> tutorial guide.</p>
+
+<h2 id="write">Write the XML</h2>
+
+<div class="sidebox"><p>For your convenience, the API reference documentation for UI related classes lists the available XML attributes that correspond to the class methods, including inherited attributes.</p>
+<p>To learn more about the available XML elements and attributes, as well as the format of the XML file, see <a
+href="{@docRoot}guide/topics/resources/available-resources.html#layoutresources">Layout Resources</a>.</p>
+ </div>
+
+<p>Using Android's XML vocabulary, you can quickly design UI layouts and the screen elements they contain, in the same way you create web pages in HTML &mdash; with a series of nested elements. </p>
+
+<p>Each layout file must contain exactly one root element, which must be a View or ViewGroup object. Once you've defined the root element, you can add additional layout objects or widgets as child elements to gradually build a View hierarchy that defines your layout. For example, here's an XML layout that uses a vertical {@link android.widget.LinearLayout}
+to hold a {@link android.widget.TextView} and a {@link android.widget.Button}:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+ &lt;TextView android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Hello, I am a TextView" />
+ &lt;Button android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Hello, I am a Button" />
+&lt;/LinearLayout>
+</pre>
+
+<p>After you've declared your layout in XML, save the file with the <code>.xml</code> extension,
+in your Android project's <code>res/layout/</code> directory, so it will properly compile. </p>
+
+<p>We'll discuss each of the attributes shown here a little later.</p>
+
+<h2 id="load">Load the XML Resource</h2>
+
+<p>When you compile your application, each XML layout file is compiled into a
+{@link android.view.View} resource. You should load the layout resource from your application code, in your
+{@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate()} callback implementation.
+Do so by calling <code>{@link android.app.Activity#setContentView(int) setContentView()}</code>,
+passing it the reference to your layout resource in the form of:
+<code>R.layout.<em>layout_file_name</em></code>
+For example, if your XML layout is saved as <code>main_layout.xml</code>, you would load it
+for your Activity like so:</p>
+<pre>
+public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView.(R.layout.main_layout);
+}
+</pre>
+
+<p>The <code>onCreate()</code> callback method in your Activity is called by the Android framework when
+your Activity is launched (see the discussion on Lifecycles, in the
+<a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application Fundamantals</a>, for more on this).</p>
+
+
+<h2 id="attributes">Attributes</h2>
+
+<p>Every View and ViewGroup object supports their own variety of XML attributes.
+Some attributes are specific to a View object (for example, TextView supports the <code>textSize</code>
+attribute), but these attributes are also inherited by any View objects that may extend this class.
+Some are common to all View objects, because they are inherited from the root View class (like
+the <code>id</code> attribute). And, other attributes are considered "layout parameters," which are
+attributes that describe certain layout orientations of the View object, as defined by that object's
+parent ViewGroup object.</p>
+
+<h3 id="id">ID</h3>
+
+<p>Any View object may have an integer ID associated with it, to uniquely identify the View within the tree.
+When the application is compiled, this ID is referenced as an integer, but the ID is typically
+assigned in the layout XML file as a string, in the <code>id</code> attribute.
+This is an XML attribute common to all View objects
+(defined by the {@link android.view.View} class) and you will use it very often.
+The syntax for an ID, inside an XML tag is:</p>
+<pre>android:id="&#64;+id/my_button"</pre>
+
+<p>The at-symbol (&#64;) at the beginning of the string indicates that the XML parser should parse and expand the rest
+of the ID string and identify it as an ID resource. The plus-symbol (+) means that this is a new resource name that must
+be created and added to our resources (in the <code>R.java</code> file). There are a number of other ID resources that
+are offered by the Android framework. When referencing an Android resource ID, you do not need the plus-symbol,
+but must add the <code>android</code> package namespace, like so:</p>
+<pre>android:id="&#64;android:id/empty"</pre>
+<p>With the <code>android</code> package namespace in place, we're now referencing an ID from the <code>android.R</code>
+resources class, rather than the local resources class.</p>
+
+<p>In order to create views and reference them from the application, a common pattern is to:</p>
+<ol>
+ <li>Define a view/widget in the layout file and assign it a unique ID:
+<pre>
+&lt;Button android:id="&#64;+id/my_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="&#64;string/my_button_text"/>
+</pre>
+ </li>
+ <li>Then create an instance of the view object and capture it from the layout
+(typically in the <code>{@link android.app.Activity#onCreate(Bundle) onCreate()}</code> method):
+<pre>
+Button myButton = (Button) findViewById(R.id.my_button);
+</pre>
+ </li>
+</ol>
+<p>Defining IDs for view objects is important when creating a {@link android.widget.RelativeLayout}.
+In a relative layout, sibling views can define their layout relative to another sibling view,
+which is referenced by the unique ID.</p>
+<p>An ID need not be unique throughout the entire tree, but it should be
+unique within the part of the tree you are searching (which may often be the entire tree, so it's best
+to be completely unique when possible).</p>
+
+
+<h3 id="layout-params">Layout Parameters</h3>
+
+<p>XML layout attributes named <code>layout_<em>something</em></code> define
+layout parameters for the View that are appropriate for the ViewGroup in which it resides.</p>
+
+<p>Every ViewGroup class implements a nested class that extends {@link
+android.view.ViewGroup.LayoutParams}. This subclass
+contains property types that define the size and position for each child view, as
+appropriate for the view group. As you can see in the figure below, the parent
+view group defines layout parameters for each child view (including the child view group).</p>
+
+<img src="{@docRoot}images/layoutparams.png" alt="" height="300" align="center"/>
+
+<p>Note that every LayoutParams subclass has its own syntax for setting
+values. Each child element must define LayoutParams that are appropriate for its parent,
+though it may also define different LayoutParams for its own children. </p>
+
+<p>All view groups include a width and height (<code>layout_width</code> and <code>layout_height</code>),
+and each view is required to define them.
+Many LayoutParams also include optional margins and
+borders. You can specify width and height with exact measurements, though you probably won't want
+to do this often. More often, you will tell your view to size itself either to
+the dimensions required by its content, or to become as big as its parent view group
+will allow (with the <var>wrap_content</var> and <var>fill_parent</var> values, respectively).
+The accepted measurement types are defined in the
+<a href="{@docRoot}guide/topics/resources/available-resources.html#dimension">Available Resources</a> document.</p>
+
+
+<h2 id="Position">Layout Position</h2>
+ <p>
+ The geometry of a view is that of a rectangle. A view has a location,
+ expressed as a pair of <em>left</em> and <em>top</em> coordinates, and
+ two dimensions, expressed as a width and a height. The unit for location
+ and dimensions is the pixel.
+ </p>
+
+ <p>
+ It is possible to retrieve the location of a view by invoking the methods
+ {@link android.view.View#getLeft()} and {@link android.view.View#getTop()}. The former returns the left, or X,
+ coordinate of the rectangle representing the view. The latter returns the
+ top, or Y, coordinate of the rectangle representing the view. These methods
+ both return the location of the view relative to its parent. For instance,
+ when getLeft() returns 20, that means the view is located 20 pixels to the
+ right of the left edge of its direct parent.
+ </p>
+
+ <p>
+ In addition, several convenience methods are offered to avoid unnecessary
+ computations, namely {@link android.view.View#getRight()} and {@link android.view.View#getBottom()}.
+ These methods return the coordinates of the right and bottom edges of the
+ rectangle representing the view. For instance, calling {@link android.view.View#getRight()}
+ is similar to the following computation: <code>getLeft() + getWidth()</code>.
+ </p>
+
+
+<h2 id="SizePaddingMargins">Size, Padding and Margins</h2>
+ <p>
+ The size of a view is expressed with a width and a height. A view actually
+ possess two pairs of width and height values.
+ </p>
+
+ <p>
+ The first pair is known as <em>measured width</em> and
+ <em>measured height</em>. These dimensions define how big a view wants to be
+ within its parent. The
+ measured dimensions can be obtained by calling {@link android.view.View#getMeasuredWidth()}
+ and {@link android.view.View#getMeasuredHeight()}.
+ </p>
+
+ <p>
+ The second pair is simply known as <em>width</em> and <em>height</em>, or
+ sometimes <em>drawing width</em> and <em>drawing height</em>. These
+ dimensions define the actual size of the view on screen, at drawing time and
+ after layout. These values may, but do not have to, be different from the
+ measured width and height. The width and height can be obtained by calling
+ {@link android.view.View#getWidth()} and {@link android.view.View#getHeight()}.
+ </p>
+
+ <p>
+ To measure its dimensions, a view takes into account its padding. The padding
+ is expressed in pixels for the left, top, right and bottom parts of the view.
+ Padding can be used to offset the content of the view by a specific amount of
+ pixels. For instance, a left padding of 2 will push the view's content by
+ 2 pixels to the right of the left edge. Padding can be set using the
+ {@link android.view.View#setPadding(int, int, int, int)} method and queried by calling
+ {@link android.view.View#getPaddingLeft()}, {@link android.view.View#getPaddingTop()},
+ {@link android.view.View#getPaddingRight()} and {@link android.view.View#getPaddingBottom()}.
+ </p>
+
+ <p>
+ Even though a view can define a padding, it does not provide any support for
+ margins. However, view groups provide such a support. Refer to
+ {@link android.view.ViewGroup} and
+ {@link android.view.ViewGroup.MarginLayoutParams} for further information.
+ </p>
+
+<p>For more information about dimensions, see <a href="{@docRoot}guide/topics/resources/available-resources.html#dimension">Dimension Values</a>.</p>
+
+
+
+
diff --git a/docs/html/guide/topics/ui/how-android-draws.jd b/docs/html/guide/topics/ui/how-android-draws.jd
new file mode 100644
index 0000000..a511005
--- /dev/null
+++ b/docs/html/guide/topics/ui/how-android-draws.jd
@@ -0,0 +1,94 @@
+page.title=How Android Draws Views
+parent.title=User Interface
+parent.link=index.html
+@jd:body
+
+
+<p>When an Activity receives focus, it will be requested to draw its layout.
+The Android framework will handle the procedure for drawing, but the Activity must provide
+the root node of its layout hierarchy.</p>
+
+<p>Drawing begins with the root node of the layout. It is requested to measure and
+draw the layout tree. Drawing is handled by walking the tree and rendering each View that
+ intersects the invalid region. In turn, each View group is responsible for requesting
+each of its children to be drawn (with the <code>{@link android.view.View#draw(Canvas) draw()}</code> method)
+and each View is responsible for drawing itself.
+ Because the tree is traversed in-order,
+ this means that parents will be drawn before (i.e., behind) their children, with
+ siblings drawn in the order they appear in the tree.
+ </p>
+
+<div class="sidebox">
+ <p>The framework will not draw Views that are not in the invalid region, and also
+ will take care of drawing the Views background for you.</p>
+ <p>You can force a View to draw, by calling <code>{@link android.view.View#invalidate()}</code>.
+ </p>
+</div>
+
+<p>
+ Drawing the layout is a two pass process: a measure pass and a layout pass. The measuring
+ pass is implemented in <code>{@link android.view.View#measure(int, int)}</code> and is a top-down traversal
+ of the View tree. Each View pushes dimension specifications down the tree
+ during the recursion. At the end of the measure pass, every View has stored
+ its measurements. The second pass happens in
+ <code>{@link android.view.View#layout(int,int,int,int)}</code> and is also top-down. During
+ this pass each parent is responsible for positioning all of its children
+ using the sizes computed in the measure pass.
+ </p>
+
+ <p>
+ When a View's <code>measure()</code> method returns, its <code>{@link android.view.View#getMeasuredWidth()}</code> and
+ <code>{@link android.view.View#getMeasuredHeight()}</code> values must be set, along with those for all of
+ that View's descendants. A View's measured width and measured height values
+ must respect the constraints imposed by the View's parents. This guarantees
+ that at the end of the measure pass, all parents accept all of their
+ children's measurements. A parent View may call <code>measure()</code> more than once on
+ its children. For example, the parent may measure each child once with
+ unspecified dimensions to find out how big they want to be, then call
+ <code>measure()</code> on them again with actual numbers if the sum of all the children's
+ unconstrained sizes is too big or too small (i.e., if the children don't agree among themselves
+ as to how much space they each get, the parent will intervene and set the rules on the second pass).
+ </p>
+
+ <div class="sidebox"><p>
+ To intiate a layout, call <code>{@link android.view.View#requestLayout}</code>. This method is typically
+ called by a View on itself when it believes that is can no longer fit within
+ its current bounds.</p>
+ </div>
+
+ <p>
+ The measure pass uses two classes to communicate dimensions. The
+ {@link android.view.View.MeasureSpec} class is used by Views to tell their parents how they
+ want to be measured and positioned. The base LayoutParams class just
+ describes how big the View wants to be for both width and height. For each
+ dimension, it can specify one of:</p>
+ <ul>
+ <li> an exact number
+ <li><var>FILL_PARENT</var>, which means the View wants to be as big as its parent
+ (minus padding)</li>
+ <li><var>WRAP_CONTENT</var>, which means that the View wants to be just big enough to
+ enclose its content (plus padding).</li>
+ </ul>
+ <p>There are subclasses of LayoutParams for different subclasses of ViewGroup.
+ For example, AbsoluteLayout has its own subclass of LayoutParams which adds
+ an X and Y value.
+ </p>
+
+ <p>
+ MeasureSpecs are used to push requirements down the tree from parent to
+ child. A MeasureSpec can be in one of three modes:</p>
+ <ul>
+ <li><var>UNSPECIFIED</var>: This is used by a parent to determine the desired dimension
+ of a child View. For example, a LinearLayout may call <code>measure()</code> on its child
+ with the height set to <var>UNSPECIFIED</var> and a width of <var>EXACTLY</var> 240 to find out how
+ tall the child View wants to be given a width of 240 pixels.</li>
+ <li><var>EXACTLY</var>: This is used by the parent to impose an exact size on the
+ child. The child must use this size, and guarantee that all of its
+ descendants will fit within this size.</li>
+ <li><var>AT_MOST</var>: This is used by the parent to impose a maximum size on the
+ child. The child must gurantee that it and all of its descendants will fit
+ within this size.</li>
+ </ul>
+
+
+
diff --git a/docs/html/guide/topics/ui/index.jd b/docs/html/guide/topics/ui/index.jd
new file mode 100644
index 0000000..6bd1d15
--- /dev/null
+++ b/docs/html/guide/topics/ui/index.jd
@@ -0,0 +1,235 @@
+page.title=User Interface
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+ <h2>Key classes</h2>
+ <ol>
+ <li>{@link android.view.View}</li>
+ <li>{@link android.view.ViewGroup}</li>
+ <li>{@link android.widget Widget classes}</li>
+ </ol>
+
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#ViewHierarchy">View Hierarchy</a></li>
+ <li><a href="#Layout">Layout</a></li>
+ <li><a href="#Widgets">Widgets</a></li>
+ <li><a href="#Events">UI Events</a></li>
+ <li><a href="#Menus">Menus</a></li>
+ <li><a href="#Advanced">Advanced Topics</a>
+ <ol>
+ <li><a href="#Adapters">Adapters</a></li>
+ <li><a href="#StylesAndThemes">Styles and Themes</a></li>
+ </ol>
+ </li>
+ </ol>
+</div>
+</div>
+
+<p>In an Android application, the user interface is built using {@link android.view.View} and
+{@link android.view.ViewGroup} objects. There are many types of views and view groups, each of which
+is a descendant of the {@link android.view.View} class.</p>
+
+<p>View objects are the basic units of user interface expression on the Android platform.
+The View class serves as the base for subclasses called "widgets," which offer fully implemented
+UI objects, like text fields and buttons. The ViewGroup class serves as the base for subclasses called "layouts,"
+which offer different kinds of layout architecture, like linear, tabular and relative.</p>
+
+<p>A View object is a data structure whose properties store the layout parameters and content for a specific
+rectangular area of the screen. A View object handles its own measurement, layout, drawing, focus change,
+scrolling, and key/gesture interactions for the rectangular area of the screen in which it resides. As an
+object in the user interface, a View is also a point of interaction for the user and the receiver
+of the interaction events.</p>
+
+
+<h2 id="ViewHierarchy">View Hierarchy</h2>
+
+<p>On the Android platform, you define an Activity's UI using a hierarchy of View and ViewGroup nodes,
+as shown in the diagram below. This hierarchy tree can be as simple or complex as you need it to be, and you
+can build it up using Android's set of predefined widgets and layouts, or with custom Views that you
+create yourself.</p>
+
+<img src="{@docRoot}images/viewgroup.png" alt="" width="312" height="211" align="center"/>
+
+<p>
+In order to attach the view hierarchy tree to the screen for rendering, your Activity must call the
+<code>{@link android.app.Activity#setContentView(int) setContentView()}</code>
+method and pass a reference to the root node object. The Android system
+receives this reference and uses it to invalidate, measure, and draw the tree. The root node of the hierarchy requests
+that its child nodes draw themselves &mdash; in turn, each view group node is responsible for calling
+upon each of its own child views to draw themselves.
+The children may request a size and location within the parent, but the parent object has the final
+decision on where how big each child can be. Android parses
+the elements of your layout in-order (from the top of the hierarchy tree), instantiating the Views and
+adding them to their parent(s). Because these are drawn in-order, if there are elements that
+overlap positions, the last one to be drawn will lie on top of others previously drawn to that space.</p>
+
+<p>For a more detailed discussion on how view hierarchies are measured
+and drawn, read <a href="how-android-draws.html">How Android Draws Views</a>.</p>
+
+
+<h2 id="Layout">Layout</h2>
+
+<p>The most common way to define your layout and express the view hierarchy is with an XML layout file.
+XML offers a human-readable structure for the layout, much like HTML. Each element in XML is
+either a View or ViewGroup object (or descendent thereof). View objects are leaves in the tree,
+ViewGroup objects are branches in the tree (see the View Hierarchy figure above).</p>
+<p>The name of an XML element
+is respective to the Java class that it represents. So a <code>&lt;TextView></code> element creates
+a {@link android.widget.TextView} in your UI, and a <code>&lt;LinearLayout></code> element creates
+a {@link android.widget.LinearLayout} view group. When you load a layout resource,
+the Android system initializes these run-time objects, corresponding to the elements in your layout.</p>
+
+<p>For example, a simple vertical layout with a text view and a button looks like this:</p>
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+ &lt;TextView android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Hello, I am a TextView" />
+ &lt;Button android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Hello, I am a Button" />
+&lt;/LinearLayout>
+</pre>
+
+<p>Notice that the LinearLayout element contains both the TextView and the Button. You can nest
+another LinearLayout (or other type of view group) inside here, to lengthen the view hierarchy and create a more
+complex layout.</p>
+
+<p>For more on building a UI layout, read <a href="declaring-layout.html">Declaring Layout</a>.
+
+<div class="sidebox-wrapper">
+<div class="sidebox-inner">
+ <p><b>Tip:</b> You can also draw View and ViewGroups objects in Java code,
+ using the <code>{@link android.view.ViewGroup#addView(View)}</code> methods
+ to dynamically insert new View and ViewGroup objects.</p>
+</div>
+</div>
+
+<p>There are a variety of ways in which you can layout your views. Using more and different kinds of view groups,
+you can structure child views and view groups in an infinite number of ways.
+Some pre-defined view groups offered by Android (called layouts) include LinearLayout, RelativeLayout, AbsoluteLayout,
+TableLayout, GridLayout and others. Each offers a unique set of layout parameters that are used to define the
+positions of child views and layout structure.</p>
+<p>To learn about some of the different kinds of view groups used for a layout,
+read <a href="layout-objects.html">Common Layout Objects</a>.</p>
+
+
+<h2 id="Widgets">Widgets</h2>
+
+<p>A widget is a View object that serves as an interface for interaction with the user.
+Android provides a set of fully implemented
+widgets, like buttons, checkboxes, and text-entry fields, so you can quickly build your UI.
+Some widgets provided by Android are more complex, like a date picker, a clock, and zoom controls.
+But you're not limited to the kinds of widgets provided by the Android platform. If you'd
+like to do something more customized and create your own actionable elements, you can, by defining your own
+View object or by extending and combining existing widgets.</p>
+<p>Read more in <a href="custom-components.html">Building Custom Components</a>.</p>
+
+<p>For a list of the widgets provided by Android, see the {@link android.widget} package.</p>
+
+
+<h2 id="Events">UI Events</h2>
+
+<p>Once you've added some Views/widgets to the UI, you probably want to know about the
+user's interaction with them, so you can perform actions. To be informed of UI events, you need to
+do one of two things:</p>
+<ul>
+ <li><strong>Define an event listener and register it with the View.</strong> More often than not,
+this is how you'll listen for events. The View class contains a collection of nested interfaces named
+On<em>&lt;something></em>Listener, each with a callback method called <code>On<em>&lt;something></em>()</code>.
+For example, {@link android.view.View.OnClickListener} (for handling "clicks" on a View),
+{@link android.view.View.OnTouchListener} (for handling touch screen events in a View), and
+{@link android.view.View.OnKeyListener} (for handling device key presses within a View). So if you want your View
+to be notified when it is "clicked" (such as when a button is selected), implement OnClickListener and define
+its <code>onClick()</code> callback method (where you perform the action upon click), and register it
+to the View with <code>{@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}</code>.
+</li>
+ <li><strong>Override an existing callback method for the View.</strong> This is
+what you should do when you've implemented your own View class and want to listen for specific events
+that occur within it. Example events you can handle include when the
+screen is touched (<code>{@link android.view.View#onTouchEvent(MotionEvent) onTouchEvent()}</code>), when
+the trackball is moved (<code>{@link android.view.View#onTrackballEvent(MotionEvent) onTrackballEvent()}</code>),
+or when a key on the device is pressed (<code>{@link android.view.View#onKeyDown(int, KeyEvent)
+onKeyDown()}</code>). This allows you to define the default behavior for each event inside your custom View and determine
+whether the event should be passed on to some other child View. Again, these are callbacks to the View class,
+so your only chance to define them is when you
+<a href="{@docRoot}guide/topics/ui/custom-components.html">build a custom component</a>.
+</li>
+</ul>
+
+<p>Continue reading about handling user interaction with Views in the <a href="ui-events.html">Handling UI Events</a>
+document.</p>
+
+
+<h2 id="Menus">Menus</h2>
+
+<p>Application menus are another important part of an application's UI. Menus offers a reliable interface that reveals
+application functions and settings. The most common application menu is revealed by pressing
+the MENU key on the device. However, you can also add Context Menus, which may be revealed when the user presses
+and holds down on an item.</p>
+
+<p>Menus are also structured using a View hierarchy, but you don't define this structure yourself. Instead,
+you define the <code>{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}</code> or
+<code>{@link android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenu.ContextMenuInfo) onCreateContextMenu()}</code>
+callback methods for your Activity and declare the items that you want to include in your menu.
+At the appropriate time, Android will automatically create the necessary View hierarchy for the menu and
+draw each of your menu items in it.</p>
+
+<p>Menus also handle their own events, so there's no need to register event listeners on the items in your menu.
+When an item in your menu is selected, the <code>{@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()}</code> or
+<code>{@link android.app.Activity#onContextItemSelected(MenuItem) onContextItemSelected()}</code>
+method will be called by the framework.</p>
+
+<p>And just like your application layout, you have the option to declare the items for you menu in an XML file.</p>
+
+<p>Read <a href="{@docRoot}guide/topics/ui/menus.html">Creating Menus</a> to learn more.</p>
+
+
+<h2 id="Advanced">Advanced Topics</h2>
+
+<p>Once you've grappled the fundamentals of creating a user interface, you can explore
+some advanced features for creating a more complex application interface.</p>
+
+<h3 id="Adapters">Adapters</h3>
+
+<p>Sometimes you'll want to populate a view group with some information that can't be hard-coded, instead,
+you want to bind your view to an external source of data. To do this, you use an AdapterView as
+your view group and each child View is initialized and populated with data from the Adapter.</p>
+<p>The AdapterView object is an implementation of ViewGroup that determines its child views
+based on a given Adapter object. The Adapter acts like a courier between your data source (perhaps an
+array of external strings) and the AdapterView, which displays it. There are several implementations
+of the Adapter class, for specific tasks, such as the CursorAdapter for reading database data from a Cursor,
+or an ArrayAdapter for reading from an arbitrary array.</p>
+<p>To learn more about using an Adapter to populate your views, read
+<a href="binding.html">Binding to Data with AdapterView</a>.</p>
+
+
+<h3 id="StylesAndThemes">Styles and Themes</h3>
+
+<p>Perhaps you're not satisfied with the look of the standard widgets. To revise them, you can create some
+of your own styles and themes.</p>
+
+<ul>
+ <li>A style is a set of one or more formatting attributes that you can apply as a unit to individual elements
+in your layout. For example, you could define a style that specifies a certain text size and color, then
+apply it to only specific View elements.</li>
+ <li>A theme is a set of one or more formatting attributes that you can apply as a unit to all activities in
+an application, or just a single activity. For example, you could define a theme that sets specific colors for
+the window frame and the panel background, and sets text sizes and colors for menus. This theme can then be
+applied to specific activities or the entire application.</li>
+</ul>
+
+<p>Styles and themes are resources. Android provides some default style and theme resources that you can use,
+or you can declare your own custom style and theme resources.</p>
+<p>Learn more about using styles and themes in the
+<a href="themes.html">Applying Styles and Themes</a> document.</p>
diff --git a/docs/html/guide/topics/views/layout.jd b/docs/html/guide/topics/ui/layout-objects.jd
index a6fec35..cf85fd6 100644
--- a/docs/html/guide/topics/views/layout.jd
+++ b/docs/html/guide/topics/ui/layout-objects.jd
@@ -1,5 +1,5 @@
page.title=Common Layout Objects
-parent.title=Views and Layout
+parent.title=User Interface
parent.link=index.html
@jd:body
@@ -20,6 +20,8 @@ parent.link=index.html
<p>This section describes some of the more common types of layout objects
to use in your applications. Like all layouts, they are subclasses of {@link android.view.ViewGroup ViewGroup}.</p>
+<p>Also see the <a href="{@docRoot}guide/tutorials/views/index.html">Hello Views</a> tutorials for
+some guidance on using more Android View layouts.</p>
<h2 id="framelayout">FrameLayout</h2>
<p>{@link android.widget.FrameLayout FrameLayout} is the simplest type of layout
@@ -95,9 +97,42 @@ cells empty, but cells cannot span columns, as they can in HTML.</p>
Each row has zero or more cells, each of which is defined by any kind of other View. So, the cells of a row may be
composed of a variety of View objects, like ImageView or TextView objects.
A cell may also be a ViewGroup object (for example, you can nest another TableLayout as a cell).</p>
-<p>The following image shows a table layout, with the invisible cell borders displayed as dotted lines. </p>
+<p>The following sample layout has two rows and two cells in each. The accompanying screenshot shows the
+result, with cell borders displayed as dotted lines (added for visual effect). </p>
-<img src="{@docRoot}images/table_layout.png" alt="" />
+<table class="columns">
+ <tr>
+ <td>
+ <pre>
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:stretchColumns="1">
+ &lt;TableRow>
+ &lt;TextView
+ android:text="@string/table_layout_4_open"
+ android:padding="3dip" />
+ &lt;TextView
+ android:text="@string/table_layout_4_open_shortcut"
+ android:gravity="right"
+ android:padding="3dip" />
+ &lt;/TableRow>
+
+ &lt;TableRow>
+ &lt;TextView
+ android:text="@string/table_layout_4_save"
+ android:padding="3dip" />
+ &lt;TextView
+ android:text="@string/table_layout_4_save_shortcut"
+ android:gravity="right"
+ android:padding="3dip" />
+ &lt;/TableRow>
+&lt;/TableLayout>
+</pre></td>
+ <td><img src="{@docRoot}images/table_layout.png" alt="" style="margin:0" /></td>
+ </tr>
+</table>
<p>Columns can be hidden, marked to stretch and fill the available screen space,
or can be marked as shrinkable to force the column to shrink until the table
@@ -127,13 +162,54 @@ TableLayout</a> tutorial.</p>
will be aligned relative to screen center. Also, because of this ordering, if using XML to specify this layout,
the element that you will reference (in order to position other view objects) must be listed in the XML
file before you refer to it from the other views via its reference ID. </p>
-<p>Here is an example relative layout with the visible and invisible elements outlined.
- The root screen layout object is a RelativeLayout object. </p>
+<p>The example below shows an XML file and the resulting screen in the UI.
+Note that the attributes that refer to relative elements (e.g., <var>layout_toLeft</var>)
+refer to the ID using the syntax of a relative resource
+(<var>@id/<em>id</em></var>). </p>
+
+<table class="columns">
+ <tr>
+ <td>
+ <pre>
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android
+ android:layout_width=&quot;fill_parent&quot;
+ android:layout_height=&quot;wrap_content&quot;
+ android:background=&quot;@drawable/blue&quot;
+ android:padding=&quot;10px&quot; &gt;
+
+ &lt;TextView android:id=&quot;@+id/label&quot;
+ android:layout_width=&quot;fill_parent&quot;
+ android:layout_height=&quot;wrap_content&quot;
+ android:text=&quot;Type here:&quot; /&gt;
+
+ &lt;EditText android:id=&quot;@+id/entry&quot;
+ android:layout_width=&quot;fill_parent&quot;
+ android:layout_height=&quot;wrap_content&quot;
+ android:background=&quot;@android:drawable/editbox_background&quot;
+ android:layout_below=&quot;@id/label&quot; /&gt;
+
+ &lt;Button android:id=&quot;@+id/ok&quot;
+ android:layout_width=&quot;wrap_content&quot;
+ android:layout_height=&quot;wrap_content&quot;
+ android:layout_below=&quot;@id/entry&quot;
+ android:layout_alignParentRight=&quot;true&quot;
+ android:layout_marginLeft=&quot;10px&quot;
+ android:text=&quot;OK&quot; /&gt;
+
+ &lt;Button android:layout_width=&quot;wrap_content&quot;
+ android:layout_height=&quot;wrap_content&quot;
+ android:layout_toLeftOf=&quot;@id/ok&quot;
+ android:layout_alignTop=&quot;@id/ok&quot;
+ android:text=&quot;Cancel&quot; /&gt;
+&lt;/RelativeLayout&gt;
+</pre></td>
+ <td><img src="{@docRoot}images/designing_ui_layout_example.png" alt="" style="margin:0" /></td>
+ </tr>
+</table>
-<img src="{@docRoot}images/designing_ui_relative_layout.png" alt="" />
-<p>This diagram shows the class names of the screen elements, followed by a list
- of the properties of each. Some of these properties are supported directly by
+<p>Some of these properties are supported directly by
the element, and some are supported by its LayoutParams member (subclass RelativeLayout
for all the elements in this screen, because all elements are children of a RelativeLayout
parent object). The defined RelativeLayout parameters are: <code>width</code>, <code>height</code>,
diff --git a/docs/html/guide/topics/views/menus.jd b/docs/html/guide/topics/ui/menus.jd
index 489cd07..bae94ca 100644
--- a/docs/html/guide/topics/views/menus.jd
+++ b/docs/html/guide/topics/ui/menus.jd
@@ -5,11 +5,17 @@ parent.link=index.html
<div id="qv-wrapper">
<div id="qv">
+ <h2>Key classes</h2>
+ <ol>
+ <li>{@link android.view.Menu}</li>
+ <li>{@link android.view.ContextMenu}</li>
+ <li>{@link android.view.SubMenu}</li>
+ </ol>
<h2>In this document</h2>
<ol>
<li><a href="#options-menu">Options Menu</a></li>
<li><a href="#context-menu">Context Menu</a></li>
- <li><a href="#sub-menu">Sub Menu</a></li>
+ <li><a href="#submenu">Submenu</a></li>
<li><a href="#xml">Define Menus in XML</a></li>
<li><a href="#features">Menu Features</a>
<ol>
@@ -47,9 +53,9 @@ for developers to provide standardized application menus for various situations.
<dt><strong>Context Menu</strong></dt>
<dd>This is a floating list of menu items that may appear when you perform a long-press on a View
(such as a list item). </dd>
- <dt><strong>Sub Menu</strong></dt>
+ <dt><strong>Submenu</strong></dt>
<dd>This is a floating list of menu items that is revealed by an item in the Options Menu
- or a Context Menu. A Sub Menu item cannot support nested Sub Menus. </dd>
+ or a Context Menu. A Submenu item cannot support nested Submenus. </dd>
</dl>
@@ -63,7 +69,7 @@ is automatically added when there are more than six items.</p>
<p>The Options Menu is where you should include basic application functions
and any necessary navigation items (e.g., to a home screen or application settings).
-You can also add <a href="#sub-menu">Sub Menus</a> for organizing topics
+You can also add <a href="#submenu">Submenus</a> for organizing topics
and including extra menu functionality.</p>
<p>When this menu is opened for the first time,
@@ -127,7 +133,7 @@ and we recommend you do it that way for easier localization).</p>
<p class="note"><strong>Tip:</strong>
If you have several menu items that can be grouped together with a title,
-consider organizing them into a <a href="#sub-menu">Sub Menu</a>.</p>
+consider organizing them into a <a href="#submenu">Submenu</a>.</p>
<h3>Adding icons</h3>
<p>Icons can also be added to items that appears in the Icon Menu with
@@ -136,8 +142,8 @@ consider organizing them into a <a href="#sub-menu">Sub Menu</a>.</p>
menu.add(0, MENU_QUIT, 0, "Quit")
.setIcon(R.drawable.menu_quit_icon);</pre>
-<h3>Modifying the options menu</h3>
-<p>If you want to sometimes re-write the options menu as it is opened, override the
+<h3>Modifying the menu</h3>
+<p>If you want to sometimes re-write the Options Menu as it is opened, override the
<code>{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}</code> method, which is
called each time the menu is opened. This will pass you the Menu object, just like the
<code>onCreateOptionsMenu()</code> callback. This is useful if you'd like to add or remove
@@ -225,7 +231,7 @@ in the list is registered to this context menu.</p>
-<h2 id="sub-menu">Sub Menus</h2>
+<h2 id="submenu">Submenus</h2>
<p>A sub menu can be added within any menu, except another sub menu.
These are very useful when your application has a lot of functions that may be
organized in topics, like the items in a PC application's menu bar (File, Edit, View, etc.).</p>
@@ -254,7 +260,7 @@ public boolean onCreateOptionsMenu(Menu menu) {
<p>Callbacks for items selected in a sub menu are made to the parent menu's callback method.
For the example above, selections in the sub menu will be handled by the
<code>onOptionsItemSelected()</code> callback.</p>
-<p>You can also add Sub Menus when you <a href="#xml">define the parent menu in XML</a>.</p>
+<p>You can also add Submenus when you <a href="#xml">define the parent menu in XML</a>.</p>
<h2 id="xml">Define Menus in XML</h2>
@@ -269,7 +275,7 @@ This is where you should keep all XML files that define your application menus.<
three valid elements: <code>&lt;menu></code>, <code>&lt;group></code> and <code>&lt;item></code>. The
<code>item</code> and <code>group</code> elements must be children of a <code>menu</code>, but <code>item</code>
elements may also be the children of a <code>group</code>, and another <code>menu</code> element may be the child
-of an <code>item</code> (to create a Sub Menu). Of course, the root node of any file
+of an <code>item</code> (to create a Submenu). Of course, the root node of any file
must be a <code>menu</code> element.</p>
<p>As an example, we'll define the same menu created in the <a href="#options-menu">Options Menu</a> section,
@@ -302,7 +308,7 @@ passing it a pointer to our menu resource and the Menu object given by the callb
and it keeps your application code clean.</p>
<p>You can define <a href="#groups">menu groups</a> by wrapping <code>item</code> elements in a <code>group</code>
-element, and create Sub Menus by nesting another <code>menu</code> inside an <code>item</code>.
+element, and create Submenus by nesting another <code>menu</code> inside an <code>item</code>.
Each element also supports all the necessary attributes to control features like shortcut keys,
checkboxes, icons, and more. To learn about these attributes and more about the XML syntax, see the Menus
topic in the <a href="{@docRoot}guide/topics/resources/available-resources.html#menus">Available
@@ -367,7 +373,7 @@ assign the same group ID to each menu item
and call <code>{@link android.view.Menu#setGroupCheckable(int,boolean,boolean)
setGroupCheckable()}</code>. In this case, you don't need to call <code>setCheckable()</code>
on each menu items, because the group as a whole is set checkable. Here's an example of
-two mutually exclusive options in a sub-menu:</p>
+two mutually exclusive options in a Submenu:</p>
<pre>
SubMenu subMenu = menu.addSubMenu("Color");
subMenu.add(COLOR_MENU_GROUP, COLOR_RED_ID, 0, "Red");
diff --git a/docs/html/guide/topics/views/themes.jd b/docs/html/guide/topics/ui/themes.jd
index a206a4b..41e8563 100644
--- a/docs/html/guide/topics/views/themes.jd
+++ b/docs/html/guide/topics/ui/themes.jd
@@ -1,11 +1,20 @@
page.title=Applying Styles and Themes
-parent.title=Views and Layout
+parent.title=User Interface
parent.link=index.html
@jd:body
<div id="qv-wrapper">
<div id="qv">
-
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#styles">Styles</a></li>
+ <li><a href="#themes">Themes</a>
+ <ol>
+ <li><a href="#inTheManifest">Set the theme in the manifest</a></li>
+ <li><a href="#fromTheApp">Set the theme from the application</a></li>
+ </ol>
+ </li>
+ </ol>
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style and Theme Resources</a></li>
@@ -27,13 +36,13 @@ parent.link=index.html
<li>Create a file named <code>styles.xml</code> in the your application's <code>res/values</code> directory. Add a root <code>&lt;resources></code> node.</li>
<li>For each style or theme, add a <code>&lt;style&gt;</code> element with a unique <code>name</code> and, optionally, a <code>parent</code> attribute.
The name is used for referencing these styles later, and the parent indicates what style resource to inherit from.</li>
- <li>Inside the <code>style</code> element, declare format values in one or more <code>&lt;item&gt;</code> element.
- Each <code>item</code> identifies its style property with a <code>name</code> attribute and defines its style value inside the element.</li>
+ <li>Inside the <code>&lt;style></code> element, declare format values in one or more <code>&lt;item&gt;</code> element(s).
+ Each <code>&lt;item&gt;</code> identifies its style property with a <code>name</code> attribute and defines its style value inside the element.</li>
<li>You can then reference the custom resources from other XML resources, your manifest or application code.</li>
</ol>
-<h2>Styles</h2>
+<h2 id="styles">Styles</h2>
<p>Here's an example declaration of a style: </p>
@@ -51,7 +60,7 @@ parent.link=index.html
The <code>name</code> attribute in the <code>item</code> can refer to a standard string, a hex color value,
or a reference to any other resource type.</p>
-<p>Note the <code>parent</code> attribute in the <code>style</code> element. This attribute lets you specify a resource from which the current style will inherit values. The style can inherit from any type of resource that contains the style(s) you want. In general, your styles should always inherit (directly or indirectly) from a standard Android style resource. This way, you only have to define the values that you want to change.</p>
+<p>Notice the <code>parent</code> attribute in the <code>&lt;style></code> element. This attribute lets you specify a resource from which the current style will inherit values. The style can inherit from any type of resource that contains the style(s) you want. In general, your styles should always inherit (directly or indirectly) from a standard Android style resource. This way, you only have to define the values that you want to change.</p>
<p>Here's how you would reference the custom style from an XML layout, in this case, for an EditText element:</p>
@@ -63,14 +72,15 @@ or a reference to any other resource type.</p>
android:text="Hello, World!" /&gt;
</pre>
-<p>Now this EditText widget will be styled as defined by the <code>style</code> example above.</p>
+<p>Now this EditText widget will be styled as defined by the XML example above.</p>
-<h2>Themes</h2>
+<h2 id="themes">Themes</h2>
<p>Just like styles, themes are also declared in XML <code>&lt;style&gt;</code> elements, and are referenced in the same manner.
-The difference is that you can add a theme style only to <code>&lt;application&gt;</code> and <code>&lt;activity&gt;</code> elements &mdash;
-they cannot be applied to individual views in the layout.</p>
+The difference is that you add a theme to an entire application or activity, via the <code>&lt;application&gt;</code>
+and <code>&lt;activity&gt;</code> elements in the Android Manifest &mdash;
+themes cannot be applied to individual Views.</p>
<p>Here's an example declaration of a theme:</p>
@@ -100,8 +110,8 @@ is done by referring to a specific <code>&lt;item></code> by its <code>name</cod
This technique can be used only in XML resources.
</p>
-<h3>Set the theme in the Manifest</h3>
-<p>To set this theme for all the activites of your application, open the Manifest file and
+<h3 id="inTheManifest">Set the theme in the manifest</h3>
+<p>To set this theme for all the activites of your application, open the AndroidManifest.xml file and
edit the <code>&lt;application></code> tag to include the <code>android:theme</code> attribute with the
theme name:</p>
@@ -121,32 +131,26 @@ appear like a dialog box. In the manifest, reference an Android theme like so:</
</pre>
<p>If you like a theme, but want to slightly tweak it, just add the theme as the <code>parent</code> of your custom theme.
-For example, we'll modify the <code>Theme.Dialog</code> theme. First, we need to import the parent of the
-<code>Dialog</code> theme: <code>Theme</code>. At the top of the <code>resources</code>, add:</p>
-<pre>
-&lt;style name="Theme" parent="@android:Theme">
- &lt;!-- no modification -->
-&lt;/style>
-</pre>
-<p>Now create a a new theme with <code>Theme.Dialog</code> as the parent:</p>
+For example, we'll modify the <code>Theme.Dialog</code> theme. To do so, create a style
+with <code>Theme.Dialog</code> as the parent:</p>
<pre>
&lt;style name="CustomDialogTheme" parent="@android:style/Theme.Dialog">
</pre>
-<p>There it is. We've inherited the Dialog theme, so we can adjust its styles as we like.
-So, for each item in the Dialog theme that we want to override, we re-define the value under this style and
-then use <var>CustomDialogTheme</var> instead of the <var>Theme.Dialog</var>.</p>
+<p>There it is. We've inherited the Android Dialog theme so we can adjust its styles as we like.
+So, for each item in the Dialog theme that we want to change, we re-define the value here and
+use <var>CustomDialogTheme</var> instead of <var>Theme.Dialog</var> inside the Android Manifest.</p>
-<h3>Set the theme from the application</h3>
+<h3 id="fromTheApp">Set the theme from the application</h3>
<p>You can also load a theme for an Activity programmatically, if needed.
To do so, use the {@link android.app.Activity#setTheme(int) setTheme()}
method. Note that, when doing so, you must be sure to set the theme <em>before</em>
instantiating any Views in the context, for example, before calling
-setContentView(View) or inflate(int, ViewGroup). This ensures that
+<code>setContentView(View)</code> or <code>inflate(int, ViewGroup)</code>. This ensures that
the system applies the same theme for all of your UI screens. Here's an example:</p>
<pre>
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
...
setTheme(android.R.style.Theme_Light);
setContentView(R.layout.linear_layout_3);
@@ -155,14 +159,14 @@ the system applies the same theme for all of your UI screens. Here's an example:
<p>If you are considering loading a theme programmatically for the main
screen of your application, note that the theme would not be applied
-in any animations the system would use to show the activity, which
-would take place before your application starts. In most cases, if
+in any animations the system would use to start the activity, which
+would take place before your application opens. In most cases, if
you want to apply a theme to your main screen, doing so in XML
is a better approach. </p>
<p>For detailed information about custom styles and themes and referencing them from your application, see
-<a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style
-and Theme Resources</a>.</p>
+<a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Available Resource Types:
+Style and Themes</a>.</p>
<p>For information about default themes and styles available, see {@link android.R.style}.</p>
diff --git a/docs/html/guide/topics/ui/ui-events.jd b/docs/html/guide/topics/ui/ui-events.jd
new file mode 100644
index 0000000..f4d114a
--- /dev/null
+++ b/docs/html/guide/topics/ui/ui-events.jd
@@ -0,0 +1,283 @@
+page.title=Handling UI Events
+parent.title=User Interface
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#EventListeners">Event Listeners</a></li>
+ <li><a href="#EventHandlers">Event Handlers</a></li>
+ <li><a href="#TouchMode">Touch Mode</a></li>
+ <li><a href="#HandlingFocus">Handling Focus</a></li>
+ </ol>
+
+ <h2>See also</h2>
+ <ol>
+ <li><a href="{@docRoot}guide/tutorials/views/hello-formstuff.html">Hello Form Stuff tutorial</a></li>
+ </ol>
+</div>
+</div>
+
+<p>On Android, there's more than one way to intercept the events from a user's interaction with your application.
+When considering events within your user interface, the approach is to capture the events from
+the specific View object that the user interacts with. The View class provides the means to do so.</p>
+
+<p>Within the various View classes that you'll use to compose your layout, you may notice several public callback
+methods that look useful for UI events. These methods are called by the Android framework when the
+respective action occurs on that object. For instance, when a View (such as a Button) is touched,
+the <code>onTouchEvent()</code> method is called on that object. However, in order to intercept this, you must extend
+the class and override the method. Obviously, extending every View object
+you want to use (just to handle an event) would be obsurd. This is why the View class also contains
+a collection of nested interfaces with callbacks that you can much more easily define. These interfaces,
+called <a href="#EventListeners">event listeners</a>, are your ticket to capturing the user interaction with your UI.</p>
+
+<p>While you will more commonly use the event listeners to listen for user interaction, there may
+come a time when you do want to extend a View class, in order to build a custom component.
+Perhaps you want to extend the {@link android.widget.Button}
+class to make something more fancy. In this case, you'll be able to define the default event behaviors for your
+class using the class <a href="#EventHandlers">event handlers</a>.</p>
+
+
+<h2 id="EventListeners">Event Listeners</h2>
+
+<p>An event listener is an interface in the {@link android.view.View} class that contains a single
+callback method. These methods will be called by the Android framework when the View to which the listener has
+been registered is triggered by user interaction with the item in the UI.</p>
+
+<p>Included in the event listener interfaces are the following callback methods:</p>
+
+<dl>
+ <dt><code>onClick()</code></dt>
+ <dd>From {@link android.view.View.OnClickListener}.
+ This is called when the user either touches the item
+ (when in touch mode), or focuses upon the item with the navigation-keys or trackball and
+ presses the suitable "enter" key or presses down on the trackball.</dd>
+ <dt><code>onLongClick()</code></dt>
+ <dd>From {@link android.view.View.OnLongClickListener}.
+ This is called when the user either touches and holds the item (when in touch mode), or
+ focuses upon the item with the navigation-keys or trackball and
+ presses and holds the suitable "enter" key or presses and holds down on the trackball (for one second).</dd>
+ <dt><code>onFocusChange()</code></dt>
+ <dd>From {@link android.view.View.OnFocusChangeListener}.
+ This is called when the user navigates onto or away from the item, using the navigation-keys or trackball.</dd>
+ <dt><code>onKey()</code></dt>
+ <dd>From {@link android.view.View.OnKeyListener}.
+ This is called when the user is focused on the item and presses or releases a key on the device.</dd>
+ <dt><code>onTouch()</code></dt>
+ <dd>From {@link android.view.View.OnTouchListener}.
+ This is called when the user performs an action qualified as a touch event, including a press, a release,
+ or any movement gesture on the screen (within the bounds of the item).</dd>
+ <dt><code>onCreateContextMenu()</code></dt>
+ <dd>From {@link android.view.View.OnCreateContextMenuListener}.
+ This is called when a Context Menu is being built (as the result of a sustained "long click"). See the discussion
+ on context menus in <a href="{@docRoot}guide/topics/ui/menus.html#context-menu">Creating Menus</a> for more information.</dd>
+</dl>
+
+<p>These methods are the sole inhabitants of their respective interface. To define one of these methods
+and handle your events, implement the nested interface in your Activity or define it as an anonymous class.
+Then, pass an instance of your implementation
+to the respective <code>View.set...Listener()</code> method. (E.g., call
+<code>{@link android.view.View#setOnClickListener(View.OnClickListener) setOnClickListener()}</code>
+and pass it your implementation of the {@link android.view.View.OnClickListener OnClickListener}.)</p>
+
+<p>The example below shows how to register an on-click listener for a Button. </p>
+
+<pre>
+// Create an anonymous implementation of OnClickListener
+private OnClickListener mCorkyListener = new OnClickListener() {
+ public void onClick(View v) {
+ // do something when the button is clicked
+ }
+};
+
+protected void onCreate(Bundle savedValues) {
+ ...
+ // Capture our button from layout
+ Button button = (Button)findViewById(R.id.corky);
+ // Register the onClick listener with the implementation above
+ button.setOnClickListener(mCorkyListener);
+ ...
+}
+</pre>
+
+<p>You may also find it more conventient to implement OnClickListener as a part of your Activity.
+This will avoid the extra class load and object allocation. For example:</p>
+<pre>
+public class ExampleActivity extends Activity implements OnClickListener {
+ protected void onCreate(Bundle savedValues) {
+ ...
+ Button button = (Button)findViewById(R.id.corky);
+ button.setOnClickListener(this);
+ }
+
+ // Implement the OnClickListener callback
+ public void onClick(View v) {
+ // do something when the button is clicked
+ }
+ ...
+}
+</pre>
+
+<p>Notice that the <code>onClick()</code> callback in the above example has
+no return value, but some other event listener methods must return a boolean. The reason
+depends on the event. For the few that do, here's why:</p>
+<ul>
+ <li><code>{@link android.view.View.OnLongClickListener#onLongClick(View) onLongClick()}</code> -
+ This returns a boolean to indicate whether you have consumed the event and it should not be carried further.
+ That is, return <em>true</em> to indicate that you have handled the event and it should stop here;
+ return <em>false</em> if you have not handled it and/or the event should continue to any other
+ on-click listeners.</li>
+ <li><code>{@link android.view.View.OnKeyListener#onKey(View,int,KeyEvent) onKey()}</code> -
+ This returns a boolean to indicate whether you have consumed the event and it should not be carried further.
+ That is, return <em>true</em> to indicate that you have handled the event and it should stop here;
+ return <em>false</em> if you have not handled it and/or the event should continue to any other
+ on-key listeners.</li>
+ <li><code>{@link android.view.View.OnTouchListener#onTouch(View,MotionEvent) onTouch()}</code> -
+ This returns a boolean to indicate whether your listener consumes this event. The important thing is that
+ this event can have multiple actions that follow each other. So, if you return <em>false</em> when the
+ down action event is received, you indicate that you have not consumed the event and are also
+ not interested in subsequent actions from this event. Thus, you will not be called for any other actions
+ within the event, such as a fingure gesture, or the eventual up action event.</li>
+</ul>
+
+<p>Remember that key events are always delivered to the View currently in focus. They are dispatched starting from the top
+of the View hierarchy, and then down, until they reach the appropriate destination. If your View (or a child of your View)
+currently has focus, then you can see the event travel through the <code>{@link android.view.View#dispatchKeyEvent(KeyEvent)
+dispatchKeyEvent()}</code> method. As an alternative to capturing key events through your View, you can also receive
+all of the events inside your Activity with <code>{@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown()}</code>
+and <code>{@link android.app.Activity#onKeyUp(int,KeyEvent) onKeyUp()}</code>.</p>
+
+<p class="note"><strong>Note:</strong> Android will call event handlers first and then the appropriate default
+handlers from the class definition second. As such, returning <em>true</em> from these event listeners will stop
+the propagation of the event to other event listeners and will also block the callback to the
+default event handler in the View. So be certain that you want to terminate the event when you return <em>true</em>.</p>
+
+
+<h2 id="EventHandlers">Event Handlers</h2>
+
+<p>If you're building a custom component from View, then you'll be able to define several callback methods
+used as default event handlers.
+In the document on <a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a>,
+you'll learn see some of the common callbacks used for event handling, including:</p>
+<ul>
+ <li><code>{@link android.view.View#onKeyDown}</code> - Called when a new key event occurs.</li>
+ <li><code>{@link android.view.View#onKeyUp}</code> - Called when a key up event occurs.</li>
+ <li><code>{@link android.view.View#onTrackballEvent}</code> - Called when a trackball motion event occurs.</li>
+ <li><code>{@link android.view.View#onTouchEvent}</code> - Called when a touch screen motion event occurs.</li>
+ <li><code>{@link android.view.View#onFocusChanged}</code> - Called when the view gains or loses focus.</li>
+</ul>
+<p>There are some other methods that you should be awere of, which are not part of the View class,
+but can directly impact the way you're able to handle events. So, when managing more complex events inside
+a layout, consider these other methods:</p>
+<ul>
+ <li><code>{@link android.app.Activity#dispatchTouchEvent(MotionEvent)
+ Activity.dispatchTouchEvent(MotionEvent)}</code> - This allows your {@link
+ android.app.Activity} to intercept all touch events before they are dispatched to the window.</li>
+ <li><code>{@link android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)
+ ViewGroup.onInterceptTouchEvent(MotionEvent)}</code> - This allows a {@link
+ android.view.ViewGroup} to watch events as they are dispatched to child Views.</li>
+ <li><code>{@link android.view.ViewParent#requestDisallowInterceptTouchEvent(boolean)
+ ViewParent.requestDisallowInterceptTouchEvent(boolean)}</code> - Call this
+ upon a parent View to indicate that it should not intercept touch events with <code>{@link
+ android.view.ViewGroup#onInterceptTouchEvent(MotionEvent)}</code>.</li>
+</ul>
+
+<h2 id="TouchMode">Touch Mode</h2>
+<p>
+When a user is navigating a user interface with directional keys or a trackball, it is
+necessary to give focus to actionable items (like buttons) so the user can see
+what will accept input. If the device has touch capabilities, however, and the user
+begins interacting with the interface by touching it, then it is no longer necessary to
+highlight items, or give focus to a particular View. Thus, there is a mode
+for interaction named "touch mode."
+</p>
+<p>
+For a touch-capable device, once the user touches the screen, the device
+will enter touch mode. From this point onward, only Views for which
+{@link android.view.View#isFocusableInTouchMode} is true will be focusable, such as text editing widgets.
+Other Views that are touchable, like buttons, will not take focus when touched; they will
+simply fire their on-click listeners when pressed.
+</p>
+<p>
+Any time a user hits a directional key or scrolls with a trackball, the device will
+exit touch mode, and find a view to take focus. Now, the user may resume interacting
+with the user interface without touching the screen.
+</p>
+<p>
+The touch mode state is maintained throughout the entire system (all windows and activities).
+To query the current state, you can call
+{@link android.view.View#isInTouchMode} to see whether the device is currently in touch mode.
+</p>
+
+
+<h2 id="HandlingFocus">Handling Focus</h2>
+
+<p>The framework will handle routine focus movement in response to user input.
+This includes changing the focus as Views are removed or hidden, or as new
+Views become available. Views indicate their willingness to take focus
+through the <code>{@link android.view.View#isFocusable()}</code> method. To change whether a View can take
+focus, call <code>{@link android.view.View#setFocusable(boolean) setFocusable()}</code>. When in touch mode,
+you may query whether a View allows focus with <code>{@link android.view.View#isFocusableInTouchMode()}</code>.
+You can change this with <code>{@link android.view.View#setFocusableInTouchMode(boolean) setFocusableInTouchMode()}</code>.
+</p>
+
+<p>Focus movement is based on an algorithm which finds the nearest neighbor in a
+given direction. In rare cases, the default algorithm may not match the
+intended behavior of the developer. In these situations, you can provide
+explicit overrides with the following XML attributes in the layout file:
+<var>nextFocusDown</var>, <var>nextFocusLeft</var>, <var>nextFocusRight</var>, and
+<var>nextFocusUp</var>. Add one of these attributes to the View <em>from</em> which
+the focus is leaving. Define the value of the attribute to be the id of the View
+<em>to</em> which focus should be given. For example:</p>
+<pre>
+&lt;LinearLayout
+ android:orientation="vertical"
+ ... >
+ &lt;Button android:id="@+id/top"
+ android:nextFocusUp="@+id/bottom"
+ ... />
+ &lt;Button android:id="@+id/bottom"
+ android:nextFocusDown="@+id/top"
+ ... />
+&lt;/LinearLayout>
+</pre>
+
+<p>Ordinarily, in this vertical layout, navigating up from the first Button would not go
+anywhere, nor would navigating down from the second Button. Now that the top Button has
+defined the bottom one as the <var>nextFocusUp</var> (and vice versa), the navigation focus will
+cycle from top-to-bottom and bottom-to-top.</p>
+
+<p>If you'd like to declare a View as focusable in your UI (when it is traditionally not),
+add the <code>android:focusable</code> XML attribute to the View, in your layout declaration.
+Set the value <var>true</var>. You can also declare a View
+as focusable while in Touch Mode with <code>android:focusableInTouchMode</code>.</p>
+<p>To request a particular View to take focus, call <code>{@link android.view.View#requestFocus()}</code>.</p>
+<p>To listen for focus events (be notified when a View receives or looses focus), use
+<code>{@link android.view.View.OnFocusChangeListener#onFocusChange(View,boolean) onFocusChange()}</code>,
+as discussed in the <a href="#EventListeners">Event Listeners</a> section, above.</p>
+
+
+
+<!--
+<h2 is="EventCycle">Event Cycle</h2>
+ <p>The basic cycle of a View is as follows:</p>
+ <ol>
+ <li>An event comes in and is dispatched to the appropriate View. The View
+ handles the event and notifies any listeners.</li>
+ <li>If, in the course of processing the event, the View's bounds may need
+ to be changed, the View will call {@link android.view.View#requestLayout()}.</li>
+ <li>Similarly, if in the course of processing the event the View's appearance
+ may need to be changed, the View will call {@link android.view.View#invalidate()}.</li>
+ <li>If either {@link android.view.View#requestLayout()} or {@link android.view.View#invalidate()} were called,
+ the framework will take care of measuring, laying out, and drawing the tree
+ as appropriate.</li>
+ </ol>
+
+ <p class="note"><strong>Note:</strong> The entire View tree is single threaded. You must always be on
+ the UI thread when calling any method on any View.
+ If you are doing work on other threads and want to update the state of a View
+ from that thread, you should use a {@link android.os.Handler}.
+ </p>
+-->
diff --git a/docs/html/guide/topics/views/declaring-layout.jd b/docs/html/guide/topics/views/declaring-layout.jd
deleted file mode 100644
index 43afdf7..0000000
--- a/docs/html/guide/topics/views/declaring-layout.jd
+++ /dev/null
@@ -1,228 +0,0 @@
-page.title=Declaring Layout
-parent.title=Views and Layout
-parent.link=index.html
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
- <h2>In this document</h2>
- <ol>
- <li><a href="#LoadingTheResource">Loading the XML Resource</a></li>
- <li><a href="#Position">Position</a></li>
- <li><a href="#SizePaddingMargin">Size, Padding and Margins</a></li>
- </ol>
-</div>
-</div>
-
-<p>You can create your application's user interface in two ways:
-<ul>
-<li><strong>Declare UI elements statically, in XML</strong>. Android provides a straightforward XML
-vocabulary that corresponds to the View classes and subclasses, such as those for widgets and layouts. </li>
-<li><strong>Instantiate screen elements at runtime</strong>. Your
-application can refer to or create View or other class objects and manipulate their properties programmatically. </li>
-</ul>
-
-<p>One advantage of declaring your UI in XML is that it enables you to better separate the presentation of your application from the code that controls it's behavior. Your UI description is external to your application code, which means that you can modify or adapt it without having to modify your source code and recompile. For example, you can create XML layouts for different screen orientations and for a variety of device screen sizes or languages. Additionally, declaring in XML makes it easier to see the elements and structure of your UI, so it's easier to debug problems. </p>
-
-<div class="sidebox">
- <p>The <a href="{@docRoot}guide/developing/tools/adt.html">Android Development Tools</a>
- (ADT) plugin for Eclipse offers a layout preview of your XML &mdash;
- with the XML file opened, select the <strong>Layout</strong> tab.</p>
- <p>You should also try the
- <a href="{@docRoot}guide/developing/tools/hierarchy-viewer.html">Hierarchy Viewer</a> tool,
- for debugging layouts &mdash; it reveals layout property values,
- draws wireframes with padding/margin indicators, and full rendered views while
- you debug on the emulator or device.</p>
-</div>
-
-<p>The Android framework gives you the flexibility to use either or both of these ways of declaring and managing your application's UI. For example, you could declare your application's default layouts in XML, including the screen elements that will appear in them and their properties. You could then add code in your application that would modify the state of the screen objects, including those declared in XML, at run time. </p>
-
-<p>You build your application's UI in approximately the same way, whether you are declaring it in XML or programmatically. In both cases, your UI will be a tree structure that may include multiple View or Viewgroup subclasses. </p>
-
-<p>In general, the XML vocabulary for declaring UI elements closely follows the structure and naming of the framework's UI-related classes and methods, where element names correspond to class names and attribute names correspond to methods. In fact, the correspondence is often so direct that you can guess what XML attribute corresponds to a class method, or guess what class corresponds to a given xml element. </p>
-
-<p>However, note that the XML vocabulary for defining UI is not entirely identical to the framework's classes and methods. In some cases, there are slight naming differences. For
-example, the EditText element has a <code>text</code> attribute that corresponds to
-<code>EditText.setText()</code>. </p>
-
-<div class="sidebox"><p>For your convenience, the API reference documentation for UI related classes lists the available XML attributes that correspond to the class methods, including inherited attributes.</p>
-
-<p>To learn more about the available XML elements and attributes, as well as the format of the XML file, see <a
-href="{@docRoot}guide/topics/resources/available-resources.html#layoutresources">Layout Resources</a>.</p>
- </div>
-
-<p>Using Android's XML vocabulary, you can quickly design UI layouts and the screen elements they contain, in the same way you create HTML files &mdash; as a series of nested tags. </p>
-
-<p>Each layout file must contain exactly one root element, and the root element must be a View or ViewGroup object. Once you've defined the root element, you can add additional layout objects or controls as child elements of the root element, if needed. In the example below, the tree of XML elements evaluates to the outermost LinearLayout object.
-
-<p>After you've declared your layout in XML, you must save the file, with the <code>.xml</code> extension,
-in your application's <code>res/layout/</code> directory, so it will properly compile. </p>
-
-<p>When you compile your application, each XML layout file is compiled into an
-android.view.View resource. You can then load the layout resource from your application code, by calling <code>setContentView(R.layout.<em>layout_file_name</em>)</code> in your {@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate()}
-implementation.</p>
-
-<p>When you load a layout resource, the Android system initializes run-time objects corresponding to the elements in your layout. It parses the elements of your layout in-order (depth-first), instantiating the Views and adding them to their parent(s).
-See <a href="how-android-draws.html">How Android Draws Views</a> for more information.</p>
-
-<p>Attributes named <code>layout_<em>something</em></code> apply to that
-object's LayoutParams member. <a href="{@docRoot}guide/topics/resources/available-resources.html#layoutresources">Layout
-Resources</a> also describes how to learn the syntax for specifying
-LayoutParams properties. </p>
-
-<p>Also note that Android draws elements in the order in which they
-appear in the XML. Therefore, if elements overlap, the last one in the XML
-file will probably be drawn on top of any previously listed elements in that
-same space.</p>
-
-<p>The following values are supported for dimensions (described in {@link
-android.util.TypedValue TypedValue}):</p>
-
-<ul>
- <li>px (pixels) </li>
- <li>dip (device independent pixels) </li>
- <li>sp (scaled pixels &mdash; best for text size) </li>
- <li>pt (points) </li>
- <li>in (inches) </li>
- <li>mm (millimeters) </li>
-</ul>
-
-<p>Example: <code>android:layout_width=&quot;25px&quot;</code> </p>
-
-<p>For more information about these dimensions, see <a href="{@docRoot}guide/topics/resources/available-resources.html#dimension">Dimension Values</a>.</p>
-
-<p>The example below shows an XML file and the resulting screen in the UI. Note that the text on the
-top of the screen was set by calling {@link
-android.app.Activity#setTitle(java.lang.CharSequence) Activity.setTitle}. Note
-that the attributes that refer to relative elements (i.e., layout_toLeft)
-refer to the ID using the syntax of a relative resource
-(@id/<em>id_number</em>). </p>
-
-<table border="1">
- <tr>
- <td>
- <pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
-&lt;!-- Demonstrates using a relative layout to create a form --&gt;
-&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android
- android:layout_width=&quot;fill_parent&quot;
- android:layout_height=&quot;wrap_content&quot;
- android:background=&quot;@drawable/blue&quot;
- android:padding=&quot;10px&quot;&gt;
-
- &lt;TextView id=&quot;@+id/label&quot;
- android:layout_width=&quot;fill_parent&quot;
- android:layout_height=&quot;wrap_content&quot;
- android:text=&quot;Type here:&quot;/&gt;
-
- &lt;EditText id=&quot;@+id/entry&quot;
- android:layout_width=&quot;fill_parent&quot;
- android:layout_height=&quot;wrap_content&quot;
- android:background=&quot;@android:drawable/editbox_background&quot;
- android:layout_below=&quot;@id/label&quot;/&gt;
-
- &lt;Button id=&quot;@+id/ok&quot;
- android:layout_width=&quot;wrap_content&quot;
- android:layout_height=&quot;wrap_content&quot;
- android:layout_below=&quot;@id/entry&quot;
- android:layout_alignParentRight=&quot;true&quot;
- android:layout_marginLeft=&quot;10px&quot;
- android:text=&quot;OK&quot; /&gt;
-
- &lt;Button android:layout_width=&quot;wrap_content&quot;
- android:layout_height=&quot;wrap_content&quot;
- android:layout_toLeftOf=&quot;@id/ok&quot;
- android:layout_alignTop=&quot;@id/ok&quot;
- android:text=&quot;Cancel&quot; /&gt;
-&lt;/RelativeLayout&gt;</pre></td>
- <td><img src="{@docRoot}images/designing_ui_layout_example.png" alt="Screen shot showing how this layout XML file is rendered." /></td>
- </tr>
-</table>
-
-
-<h2 id="LoadingTheResource">Loading the XML Resource</h2>
-<p>Loading the compiled layout resource is very easy, and done with a single
-call in the activity's <code>onCreate()</code> method, as shown here:</p>
-
-<pre>
-protected void onCreate(Bundle savedInstanceState)
-{
- // Be sure to call the super class.
- super.onCreate(savedInstanceState);
-
- // Load the compiled layout resource into the window's
- // default ViewGroup.
- // The source file is res/layout/hello_activity.xml
- setContentView(R.layout.hello_activity);
-
- // Retrieve any important stored values.
- restoreValues(savedInstanceState);
-} </pre>
-
-<h2 id="Position">Position</h2>
- <p>
- The geometry of a view is that of a rectangle. A view has a location,
- expressed as a pair of <em>left</em> and <em>top</em> coordinates, and
- two dimensions, expressed as a width and a height. The unit for location
- and dimensions is the pixel.
- </p>
-
- <p>
- It is possible to retrieve the location of a view by invoking the methods
- {@link android.view.View#getLeft()} and {@link android.view.View#getTop()}. The former returns the left, or X,
- coordinate of the rectangle representing the view. The latter returns the
- top, or Y, coordinate of the rectangle representing the view. These methods
- both return the location of the view relative to its parent. For instance,
- when getLeft() returns 20, that means the view is located 20 pixels to the
- right of the left edge of its direct parent.
- </p>
-
- <p>
- In addition, several convenience methods are offered to avoid unnecessary
- computations, namely {@link android.view.View#getRight()} and {@link android.view.View#getBottom()}.
- These methods return the coordinates of the right and bottom edges of the
- rectangle representing the view. For instance, calling {@link android.view.View#getRight()}
- is similar to the following computation: <code>getLeft() + getWidth()</code>.
- </p>
-
-
-<h2 id="SizePaddingMargins">Size, Padding and Margins</h2>
- <p>
- The size of a view is expressed with a width and a height. A view actually
- possess two pairs of width and height values.
- </p>
-
- <p>
- The first pair is known as <em>measured width</em> and
- <em>measured height</em>. These dimensions define how big a view wants to be
- within its parent. The
- measured dimensions can be obtained by calling {@link android.view.View#getMeasuredWidth()}
- and {@link android.view.View#getMeasuredHeight()}.
- </p>
-
- <p>
- The second pair is simply known as <em>width</em> and <em>height</em>, or
- sometimes <em>drawing width</em> and <em>drawing height</em>. These
- dimensions define the actual size of the view on screen, at drawing time and
- after layout. These values may, but do not have to, be different from the
- measured width and height. The width and height can be obtained by calling
- {@link android.view.View#getWidth()} and {@link android.view.View#getHeight()}.
- </p>
-
- <p>
- To measure its dimensions, a view takes into account its padding. The padding
- is expressed in pixels for the left, top, right and bottom parts of the view.
- Padding can be used to offset the content of the view by a specific amount of
- pixels. For instance, a left padding of 2 will push the view's content by
- 2 pixels to the right of the left edge. Padding can be set using the
- {@link android.view.View#setPadding(int, int, int, int)} method and queried by calling
- {@link android.view.View#getPaddingLeft()}, {@link android.view.View#getPaddingTop()},
- {@link android.view.View#getPaddingRight()} and {@link android.view.View#getPaddingBottom()}.
- </p>
-
- <p>
- Even though a view can define a padding, it does not provide any support for
- margins. However, view groups provide such a support. Refer to
- {@link android.view.ViewGroup} and
- {@link android.view.ViewGroup.MarginLayoutParams} for further information.
- </p>
- \ No newline at end of file
diff --git a/docs/html/guide/topics/views/how-android-draws.jd b/docs/html/guide/topics/views/how-android-draws.jd
deleted file mode 100644
index f497db7..0000000
--- a/docs/html/guide/topics/views/how-android-draws.jd
+++ /dev/null
@@ -1,90 +0,0 @@
-page.title=How Android Draws Views
-parent.title=Views and Layout
-parent.link=index.html
-@jd:body
-
-
-<p>As mentioned in the introduction to <a href="index.html">Views and Layout</a>,
-drawing begins when the Activity requests the root node of the layout to measure and
-draw the layout tree. Drawing is handled by walking the tree and rendering each view that
- intersects the invalid region. In turn, each view group is responsible for requesting
-each of its children to be drawn and each view is responsible for drawing itself.
- Because the tree is traversed in-order,
- this means that parents will be drawn before (i.e., behind) their children, with
- siblings drawn in the order they appear in the tree.
- </p>
-
-<div class="sidebox">
- <p>The framework will not draw views that are not in the invalid region, and also
- will take care of drawing the views background for you.</p>
- <p>You can force a view to draw, by calling {@link android.view.View#invalidate()}.
- </p>
-</div>
-
-<p>
- Drawing the layout is a two pass process: a measure pass and a layout pass. The measuring
- pass is implemented in {@link android.view.View#measure(int, int)} and is a top-down traversal
- of the view tree. Each view pushes dimension specifications down the tree
- during the recursion. At the end of the measure pass, every view has stored
- its measurements. The second pass happens in
- {@link android.view.View#layout(int,int,int,int)} and is also top-down. During
- this pass each parent is responsible for positioning all of its children
- using the sizes computed in the measure pass.
- </p>
-
- <p>
- When a view's measure() method returns, its {@link android.view.View#getMeasuredWidth()} and
- {@link android.view.View#getMeasuredHeight()} values must be set, along with those for all of
- that view's descendants. A view's measured width and measured height values
- must respect the constraints imposed by the view's parents. This guarantees
- that at the end of the measure pass, all parents accept all of their
- children's measurements. A parent view may call measure() more than once on
- its children. For example, the parent may measure each child once with
- unspecified dimensions to find out how big they want to be, then call
- measure() on them again with actual numbers if the sum of all the children's
- unconstrained sizes is too big or too small (i.e., if the children don't agree among themselves
- as to how much space they each get, the parent will intervene and set the rules on the second pass).
- </p>
-
- <div class="sidebox"><p>
- To intiate a layout, call {@link android.view.View#requestLayout}. This method is typically
- called by a view on itself when it believes that is can no longer fit within
- its current bounds.</p>
- </div>
-
- <p>
- The measure pass uses two classes to communicate dimensions. The
- {@link android.view.View.MeasureSpec} class is used by views to tell their parents how they
- want to be measured and positioned. The base LayoutParams class just
- describes how big the view wants to be for both width and height. For each
- dimension, it can specify one of:</p>
- <ul>
- <li> an exact number
- <li>FILL_PARENT, which means the view wants to be as big as its parent
- (minus padding)</li>
- <li> WRAP_CONTENT, which means that the view wants to be just big enough to
- enclose its content (plus padding).</li>
- </ul>
- <p>There are subclasses of LayoutParams for different subclasses of ViewGroup.
- For example, AbsoluteLayout has its own subclass of LayoutParams which adds
- an X and Y value.
- </p>
-
- <p>
- MeasureSpecs are used to push requirements down the tree from parent to
- child. A MeasureSpec can be in one of three modes:</p>
- <ul>
- <li>UNSPECIFIED: This is used by a parent to determine the desired dimension
- of a child view. For example, a LinearLayout may call measure() on its child
- with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how
- tall the child view wants to be given a width of 240 pixels.</li>
- <li>EXACTLY: This is used by the parent to impose an exact size on the
- child. The child must use this size, and guarantee that all of its
- descendants will fit within this size.</li>
- <li>AT_MOST: This is used by the parent to impose a maximum size on the
- child. The child must gurantee that it and all of its descendants will fit
- within this size.</li>
- </ul>
-
-
-
diff --git a/docs/html/guide/topics/views/index.jd b/docs/html/guide/topics/views/index.jd
deleted file mode 100644
index a246ba1..0000000
--- a/docs/html/guide/topics/views/index.jd
+++ /dev/null
@@ -1,216 +0,0 @@
-page.title=Views and Layout
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
- <h2>Key classes and packages</h2>
- <ol>
- <li>{@link android.view.View}</li>
- <li>{@link android.view.ViewGroup}</li>
- <li>{@link android.widget}</li>
- </ol>
-
- <h2>In this document</h2>
- <ol>
- <li><a href="#ViewHierarchy">View Hierarchy</a></li>
- <li><a href="#Layout">Layout</a></li>
- <li><a href="#Widgets">Widgets</a></li>
- <li><a href="#Events">Events</a></li>
- <li><a href="#Adapters">Adapters</a></li>
- <li><a href="#StylesAndThemes">Styles and Themes</a></li>
- </ol>
-</div>
-</div>
-
-<p>In an Android application, a user interface is built using {@link android.view.View} and
-{@link android.view.ViewGroup} objects. There are many types of views and view groups, each of which
-is a descendant of the {@link android.view.View} class.</p>
-
-<p>View objects are the basic units of user interface expression on the Android platform.
-The View class serves as the base for subclasses called "widgets," which offer fully implemented
-UI objects, like text fields and buttons. The ViewGroup class serves as the base for subclasses called "layouts,"
-which offer different kinds of layout architecture, like linear, tabular and relative.</p>
-
-<p>A View object is a data structure whose properties store the layout properties and content for a specific
-rectangular area of the screen. A View object handles its own measurement, layout, drawing, focus change,
-scrolling, and key/gesture interactions for the rectangular screen area it represents. </p>
-
-
-<h2 id="ViewHierarchy">View Hierarchy</h2>
-
-<p>On the Android platform, you will define an Activity's UI using a hierarchy of view and view group nodes,
-as shown in the diagram below. This hierarchy tree can be as simple or complex as you need it to be, and you
-can build it up using Android's set of predefined widgets and layouts, or with custom view types that you
-create yourself.</p>
-
-<img src="{@docRoot}images/viewgroup.png" alt="" width="312" height="211" align="center"/>
-
-<p>The Android system will notify your Activity when it becomes active and receives focus.
-In order to attach the view hierarchy tree to the screen for rendering, your Activity must call its
-<code>setContentView()</code> method and pass a reference to the root node object. The Android system
-receives this reference so that it can invalidate, measure, and draw the tree. The root node requests
-that its child nodes draw themselves &mdash; in turn, each view group node is responsible for
-calling <code>Draw()</code> on each of its own child views, so that each child view can render itself.
-The children may request a size and location within the parent, but the parent object has the final
-decision on where how big each child can be. To learn more about how a view group and its children are measured
-and drawn, read <a href="how-android-draws.html">How Android Draws Views</a>.</p>
-
-
-<h2 id="Layout">Layout</h2>
-
-<p>The most common way to define your layout and express the view hierarchy is with an XML layout file.
-XML offers a human-readable structure for the layout, much like HTML. Each element in XML is
-(usually a descendant of) either a View or ViewGroup object. View objects are leaves in the tree,
-ViewGroup objects are branches in the tree. The name of an XML element
-is the respective class object name. So a <code>&lt;TextView></code> element creates
-a {@link android.widget.TextView} widget in your UI, and a <code>&lt;LinearLayout></code> element creates
-a {@link android.widget.LinearLayout} layout branch in the tree. To learn more about how to write your layout in XML,
-read <a href="declaring-layout.html">Declaring and Querying Layout</a>.
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
- <p><b>Tip:</b> You can also draw new views and view groups from within your code,
- by adding new View and ViewGroup objects to an
- existing ViewGroup (specifically, you'll use the <code>addView()</code> methods to dynamically insert new views).
- To see how to add views in your code, see the {@link android.view.ViewGroup} reference.</p>
-</div>
-</div>
-
-<p>There are a variety of ways in which you can layout your views, using different view groups.
-Some pre-defined view groups offered by Android (called layouts) include LinearLayout, RelativeLayout, AbsoluteLayout,
-TableLayout, GridLayout and others. Each offers a different mechanisms for arranging child views
-among each other.
-To learn more about how to use some of these view groups for your layout,
-read <a href="layout.html">Common Layout Objects</a>.
-
-<h3 id="IDs">IDs</h3>
-
-<p>Views may have an integer ID associated with them. The ID is written as a string, but once the application is
-compiled, it will be referenced as an integer.
-These IDs are typically assigned in the layout XML file as an attribute of the view,
-and are used to uniquely identify a view within the tree. The usual syntax for an ID, inside an XML tag is:</p>
-<pre>id="&#64;+id/my_button"</pre>
-<p>The at-symbol (&#64;) at the beginning of the string indicates that the XML parser should parse and expand the rest
-of the ID string and identify it as an ID resource. The plus-symbol (+) means that this is a new resource name that must
-be created and added to our resources (in the <code>R.java</code> file). There are a number of other ID resources that
-are offered by the Android framework. When referencing an Android resource ID, you do not need the plus-symbol,
-but must add the <code>android</code> package namespace, like so:</p>
-<pre>id="&#64;android:id/empty"</pre>
-<p>With the <code>android</code> package namespace in place, we're now referencing an ID from the <code>android.R</code>
-resources class, rather than the local resources class.</p>
-
-<p>In order to create views and reference them from the application, a common pattern is to:</p>
-<ol>
- <li>Define a view/widget in the layout file and assign it a unique ID. E.g.:
-<pre>
-&lt;Button id="&#64;+id/my_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="&#64;string/my_button_text"/>
-</pre>
- </li>
- <li>Then create an instance of the view object and capture it from the layout
-(typically in the <code>onCreate()</code> method).
-<pre>
-Button myButton = (Button) findViewById(R.id.my_button);
-</pre>
- </li>
-</ol>
-<p>Defining IDs for view objects is important when creating a {@link android.widget.RelativeLayout}.
-In a relative layout, sibling views can define their layout relative to another sibling view,
-which is referenced by the unique ID.</p>
-<p>An ID need not be unique throughout the entire tree, but it should be
-unique within the part of the tree you are searching (which may often be the entire tree, so it's best
-to be completely unique when possible).</p>
-
-
-<h3>Layout Parameters</h3>
-
-<p>Every ViewGroup class implements a nested class that extends {@link
-android.view.ViewGroup.LayoutParams}. This subclass
-contains property types that define each child view's size and position, as
-appropriate for that type of view group. As you can see in the figure below, the parent
-view group defines layout parameters for each child view (including the child view group).</p>
-
-<img src="{@docRoot}images/layoutparams.png" alt="" height="300" align="center"/>
-
-<p>Note that every LayoutParams subclass has its own syntax for setting
-values. Each child element must define LayoutParams that are appropriate for its parent,
-though it may also define different LayoutParams for its own children. </p>
-
-<p>All view groups include a width and height, and each view is required to define them.
-Many LayoutParams also include optional margins and
-borders. You can specify width and height with exact measurements, though you probably won't want
-to do this often. More often, you will tell your view to size itself either to
-the dimensions required by its content, or to become as big as its parent view group
-will allow (with the <var>wrap_content</var> and <var>fill_parent</var> values, respectively).
-The accepted measurement types are defined in the
-<a href="{@docRoot}guide/topics/resources/available-resources.html#dimension">Available Resources</a> document.</p>
-
-<h2 id="Widgets">Widgets</h2>
-
-
-<p>The View class also serves as a base class for <em>widgets</em> &mdash; a set of fully implemented
-View subclasses that draw interactive screen elements, so you can quickly build your UI.
-Android provides a vast collection of widgets for special actions.
-Some of them are basic interaction elements like buttons and text fields, while others are more complex,
-like a date picker or zoom controls.</p>
-<p>For a list of all built-in widgets, see the {@link android.widget widget}.</p>
-
-<p>You're not limited to the kinds of views, layouts and widgets provided by the Android platform. If you'd
-like to do something more customized, create your own widget or layout, you can.
-Read more in <a href="custom-components.html">Building Custom Components</a>.
-
-
-<h2 id="Events">Events</h2>
-
-<p>Once you've designed and built your UI layout, you need to handle the user interaction with it.
-Obviously, the views that you've implemented in the layout are the
-receptors for such interaction events. Because the View class is built to listen for most interaction events,
-receiving and handling them is pretty straigh-forward. When you want to perform an action upon an event,
-you need to do one of two things:</p>
-<ul>
- <li>Override an existing callback method for the view you've implemented, which will be called when something
-like a touch or focus event occurs.</li>
- <li>Define a listener interface, like {@link android.view.View.OnClickListener} (for handling "clicks" on a View).
-You must then define the listener for your view with the respective <code>set...Listener()</code>
-method (such as {@link android.view.View#setOnClickListener(android.view.View.OnClickListener) setOnCLickListener()}).</li>
-</ul>
-
-<p>To learn more about handling events and writing your own listeners,
-read <a href="ui-events.html">Handling UI Events</a>.</p>
-
-
-<h2 id="Adapters">Adapters</h2>
-
-<p>Sometimes you'll want to populate a view group with some information that can't be hard-coded, instead,
-you want to bind your view to an external source of data. To do this, you use an AdapterView as
-your view group and each child View is initialized and populated with data from the Adapter.</p>
-<p>The AdapterView object is an implementation of ViewGroup that determines its child views
-based on a given Adapter object. The Adapter acts like a courier between your data source (perhaps an
-array of external strings) and the AdapterView, which displays it. There are several implementations
-of the Adapter class, for specific tasks, such as the CursorAdapter for reading database data from a Cursor,
-or an ArrayAdapter for reading from an arbitrary array.</p>
-<p>To learn more about using an Adapter to populate your views, read
-<a href="binding.html">Binding to Data with AdapterView</a>.</p>
-
-
-<h2 id="StylesAndThemes">Styles and Themes</h2>
-
-<p>Perhaps you're not satisfied with the look of the standard widgets. To revise them, you can create some
-of your own styles and themes.</p>
-
-<ul>
- <li>A style is a set of one or more formatting attributes that you can apply as a unit to individual elements
-in your layout. For example, you could define a style that specifies a certain text size and color, then
-apply it to only specific View elements.</li>
- <li>A theme is a set of one or more formatting attributes that you can apply as a unit to all activities in
-an application, or just a single activity. For example, you could define a theme that sets specific colors for
-the window frame and the panel background, and sets text sizes and colors for menus. This theme can then be
-applied to specific activities or the entire application.</li>
-</ul>
-
-<p>Styles and themes are resources. Android provides some default style and theme resources that you can use,
-or you can declare your own custom style and theme resources. Learn more about using styles and themes in the
-<a href="themes.html">Applying Styles and Themes</a> document.</p>
diff --git a/docs/html/guide/topics/views/ui-events.jd b/docs/html/guide/topics/views/ui-events.jd
deleted file mode 100644
index 96136f8..0000000
--- a/docs/html/guide/topics/views/ui-events.jd
+++ /dev/null
@@ -1,113 +0,0 @@
-page.title=Handling UI Events
-parent.title=Views and Layout
-parent.link=index.html
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
- <h2>In this document</h2>
- <ol>
- <li><a href="#TouchMode">Touch Mode</a></li>
- <li><a href="#Scrolling">Scrolling</a></li>
- <li><a href="#EventCycle">Event Cycle</a></li>
- </ol>
-
- <h2>See also</h2>
- <ol>
- <li><a href="{@docRoot}guide/tutorials/views/hello-formstuff.html">Hello Form Stuff tutorial</a></li>
- </ol>
-</div>
-</div>
-
-<p>Many Android classes declare callback methods for handling relevant UI events such as keypresses,
-touch events, focus changes, and so on. For example, {@link android.app.Activity Activity} provides
-the methods <code>onKeyDown()</code> and <code>onKeyUp()</code> and {@link android.widget.TextView TextView}
-provides <code>onFocusChanged()</code>. </p>
-
-<p>In most cases, you can handle events just by overriding the appropriate handler methods.
-When an event is received, the Android system calls your handler method with the event data.</p>
-
-<p>However, some classes do not declare handler methods for specific events. For example,
-{@link android.widget.Button} does not declare an <code>onClick()</code> handler method. So, to handle a click event,
-you need to create an anonymous class to act as a listener for the event, then register the listener with the
-target class object (via the appropriate <code>set...Listener()</code> method). The example below shows how to set
-up a handler for click events in a Button object. </p>
-
-</p>
-<pre>public class ExampleSendResult extends Activity
-{
- protected void onCreate(Bundle savedValues)
- {
- ...
-
- // Capture our button from layout and listen for clicks.
- Button button = (Button)findViewById(R.id.corky);
- button.setOnClickListener(mCorkyListener);
- }
-
- // Create an anonymous class to act as a button click listener.
- private OnClickListener mCorkyListener = new OnClickListener()
- {
- public void onClick(View v)
- {
- //do something when the button is clicked
- }
- };
-}
-</pre>
-
-
-<h2 id="TouchMode">Touch Mode</h2>
- <p>
- When a user is navigating a user interface via directional keys such as a D-pad, it is
- necessary to give focus to actionable items such as buttons so the user can see
- what will take input. If the device has touch capabilities, however, and the user
- begins interacting with the interface by touching it, it is no longer necessary to
- always highlight, or give focus to, a particular view. Thus, there is a mode
- for interaction named "touch mode."
- </p>
- <p>
- For a touch-capable device, once the user touches the screen, the device
- will enter touch mode. From this point onward, only views for which
- {@link android.view.View#isFocusableInTouchMode} is true will be focusable, such as text editing widgets.
- Other views that are touchable, like buttons, will not take focus when touched; they will
- simply fire their on-click listeners when pressed.
- </p>
- <p>
- Any time a user hits a directional key, such as a D-pad direction, the view device will
- exit touch mode, and find a view to take focus, so that the user may resume interacting
- with the user interface without touching the screen.
- </p>
- <p>
- The touch mode state is maintained across {@link android.app.Activity}s. To query the current state, you can call
- {@link android.view.View#isInTouchMode} to see whether the device is currently in touch mode.
- </p>
-
-
-<h2 id="Scrolling">Scrolling</h2>
- <p>
- The framework provides basic support for views that wish to internally
- scroll their content. This includes keeping track of the X and Y scroll
- offset as well as mechanisms for drawing scrollbars. See
- {@link android.view.View#scrollBy(int, int)}, {@link android.view.View#scrollTo(int, int)} for more details.
- </p>
-
-<h2 is="EventCycle">Event Cycle</h2>
- <p>The basic cycle of a view is as follows:</p>
- <ol>
- <li>An event comes in and is dispatched to the appropriate view. The view
- handles the event and notifies any listeners.</li>
- <li>If, in the course of processing the event, the view's bounds may need
- to be changed, the view will call {@link android.view.View#requestLayout()}.</li>
- <li>Similarly, if in the course of processing the event the view's appearance
- may need to be changed, the view will call {@link android.view.View#invalidate()}.</li>
- <li>If either {@link android.view.View#requestLayout()} or {@link android.view.View#invalidate()} were called,
- the framework will take care of measuring, laying out, and drawing the tree
- as appropriate.</li>
- </ol>
-
- <p class="note"><strong>Note:</strong> The entire view tree is single threaded. You must always be on
- the UI thread when calling any method on any view.
- If you are doing work on other threads and want to update the state of a view
- from that thread, you should use a {@link android.os.Handler}.
- </p> \ No newline at end of file
diff --git a/docs/html/guide/tutorials/hello-world.jd b/docs/html/guide/tutorials/hello-world.jd
index c993048..7b9287f 100644
--- a/docs/html/guide/tutorials/hello-world.jd
+++ b/docs/html/guide/tutorials/hello-world.jd
@@ -2,37 +2,40 @@ page.title=Hello, World
@jd:body
<p>As a developer, you know that the first impression
-you get of a development framework is how easy it is to write "Hello,
-World." Well, on Android, it's pretty easy. </p>
-
-<p>It's particularly easy if you're using Eclipse as your IDE, because we've provided a
+of a development framework is how easy it is to write "Hello,
+World." Well, on Android, it's pretty easy.
+It's particularly easy if you're using Eclipse as your IDE, because we've provided a
great plugin that handles your project creation and management to greatly speed up your
-development cycles. Get <a href="http://www.eclipse.org/downloads/">Eclipse</a> and visit the
-<a href="{@docRoot}guide/developing/tools/adt.html">ADT Plugin</a> page to install it.</p>
+development cycles.</p>
<p>If you're not using Eclipse, that's okay. Familiarize yourself with
<a href="{@docRoot}guide/developing/other-ide.html">Developing in Other IDEs</a>.
You can then come back here and ignore anything about Eclipse.</p>
+<p>Before you start, you should already have the latest SDK installed, and if you're using
+Eclipse, you should have installed the ADT plugin as well. See
+<a href="{@docRoot}sdk/1.1_r1/installing.html">Installing the Android SDK</a> to get these
+installed.</p>
+
<p class="note"><strong>Note:</strong>
In some cases, you might want to click the screenshots below to get a bigger view.
</p>
<h2 id="create">Create the Project</h2>
-<ol class="listhead">
- <li>Create a new Android Project.
+<ol>
+ <li><strong>Open a new Android Project.</strong>
<p>From Eclipse, select the <strong>File &gt; New &gt; Project</strong> menu item. If the Android
Plugin for Eclipse has been successfully installed, the resulting dialog
should have a folder labeled "Android" which should contain a single entry:
"Android Project".</p>
+ <p>Selected "Android Project" and click <strong>Next</strong>.</p>
<a href="images/hello_world_0.png"><img src="images/hello_world_0.png" style="height:230px" alt="" /></a>
- <p>Once you've selected "Android Project", click <strong>Next</strong>.</p>
</li>
- <li>Fill out the project details.
+ <li><strong>Fill out the project details.</strong>
<p>The next screen allows you to enter the relevant details for your project:</p>
<ul>
<li><em>Project name:</em> HelloAndroid</li>
@@ -40,7 +43,7 @@ In some cases, you might want to click the screenshots below to get a bigger vie
<li><em>Activity name:</em> HelloAndroid</li>
<li><em>Application name:</em> Hello, Android</li>
</ul>
-
+ <p>Click <strong>Finish</strong>.</p>
<a href="images/hello_world_1.png"><img src="images/hello_world_1.png" style="height:230px" alt="" /></a>
<p>Here's what each field on this screen means:</p>
@@ -74,12 +77,18 @@ In some cases, you might want to click the screenshots below to get a bigger vie
</li>
-<li>Edit the auto-generated source code.
-<p>After the plugin runs, you'll have a class named <code>HelloAndroid</code>
-(found in your package, <em>HelloAndroid > src > com.android.hello</em>). It should look like
+<li><strong>View the auto-generated source code.</strong>
+<p>After the plugin completes your project creations, you'll have a class named <code>HelloAndroid</code>
+(found in your project package, <em>HelloAndroid > src > com.android.hello</em>). It should look like
this:</p>
-<pre>public class HelloAndroid extends Activity {
+<pre>
+package com.example.hello;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class HelloAndroid extends Activity {
/** Called when the activity is first created. */
&#64;Override
public void onCreate(Bundle savedInstanceState) {
@@ -88,9 +97,7 @@ this:</p>
}
}</pre>
-<p>Now, you <em>could</em> run this right away, but let's go a little further,
-so we understand more about what's happening.
-So, the next step is to modify some code! </p>
+<p>Now let's modify some code! </p>
</li>
</ol>
@@ -105,16 +112,16 @@ package com.android.hello;
import android.app.Activity;
import android.os.Bundle;
-import android.widget.TextView;
+<strong>import android.widget.TextView;</strong>
public class HelloAndroid extends Activity {
/** Called when the activity is first created. */
&#64;Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- TextView tv = new TextView(this);
+ <strong>TextView tv = new TextView(this);
tv.setText(&quot;Hello, Android&quot;);
- setContentView(tv);
+ setContentView(tv);</strong>
}
}</pre>
@@ -122,16 +129,21 @@ public class HelloAndroid extends Activity {
press <strong>Ctrl-Shift-O</strong> (<strong>Cmd-Shift-O</strong>, on Mac). This is an Eclipse
shortcut to organize imports&mdash;it identifies missing packages and adds them for you.</p>
-<p>In Android, user interfaces are composed of hierarchies of classes called
-Views. A View is simply a drawable object, such as a radio button, an
+<p>Notice that our class is based on the {@link android.app.Activity} class. An Activity is a
+single application entity that is used to perform actions. An application may have many, but the user
+interacts with them only one at a time. An Activity is not required to actually have a user interface,
+but usually will.</p>
+
+<p>An Android user interface is composed of hierarchies of objects called
+Views. A {@link android.view.View} is simply a drawable object, such as a radio button, an
animation, or (in our case) a text label. The specific name for the View
-subclass that handles text is simply TextView.</p>
+subclass that handles text, which we use here, is {@link android.widget.TextView}.</p>
<p>Here's how you construct a TextView:</p>
<pre>TextView tv = new TextView(this);</pre>
-<p>The argument to TextView's constructor is an Android Context instance. The
+<p>The argument to TextView's constructor is an Android {@link android.content.Context} instance. The
Context is simply a handle to the system; it provides services like
resolving resources, obtaining access to databases and preferences, and so
on. The Activity class inherits from Context. Since our
@@ -189,18 +201,21 @@ simply continue.</p>
<a href="images/hello_world_4.png"><img src="images/hello_world_4.png" style="height:230px" alt="" /></a>
-<p>That's it &mdash; you're done! Click the Run button, and the Android Emulator
-should start. Once it's booted up your application will appear. When all is said and done, you should
+<p>Now click <strong>Run</strong>, and the Android Emulator should start and open the application.
+Once it's booted up your application will appear. (Once booted, you may need to unlock the emulator's phone screen
+by pressing the device MENU key.) When all is said and done, you should
see something like this:</p>
<a href="images/hello_world_5.png"><img src="images/hello_world_5.png" style="height:230px" alt="" /></a>
+
<p>That's "Hello, World" in Android. Pretty straightforward, eh?
The next sections of the tutorial offer more detailed information that you may find valuable as you
learn more about Android.</p>
+
<h2 id="upgrading">Upgrading the UI to an XML Layout</h2>
<p>The "Hello, World" example you just completed uses what we call "programmatic"
@@ -220,12 +235,12 @@ programmatically-constructed example you just completed:</p>
&lt;TextView xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
android:layout_width=&quot;fill_parent&quot;
android:layout_height=&quot;fill_parent&quot;
- android:text=&quot;Hello, Android&quot;/&gt;</pre>
+ android:text=&quot;@string/hello&quot;/&gt;</pre>
<p>The general structure of an Android XML layout file is simple: it's a tree
of XML elements, where each element is the name of a View class
(this example, however, is just one element). You can use the
-name of any class that extends View as an element in your XML layouts,
+name of any class that extends {@link android.view.View} as an element in your XML layouts,
including custom View classes you define in your own code. This
structure makes it very easy to quickly build up UIs, using a more simple
structure and syntax than you would in source code. This model is inspired
@@ -274,14 +289,20 @@ which has four XML attributes. Here's a summary of what they mean:</p>
<code>android:text</code>
</td>
<td>
- This sets the text that the TextView should contain. In this example, it's our usual "Hello, Android" message.
+ This sets the text that the TextView should display. In this example, we use a string
+ resource instead of a hard-coded string value.
+ The <em>hello</em> string is defined in the <em>res/values/strings.xml</em> file. This is the
+ recommended practice for inserting strings to your application, because it makes the localization
+ of your application to other languages graceful, without need to hard-code changes to the layout file.
+ For more information, see <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources
+ and Internationalization</a>.
</td>
</tr>
</tbody>
</table>
-<p>This layout file belongs in the <code>res/layout/</code> directory in your project. The "res" is
+<p>These layout files belong in the <em>res/layout/</em> directory in your project. The "res" is
short for "resources" and that directory contains all the non-code assets that
your application requires. Resources also include things like images, localized
strings, and XML layout files.</p>
@@ -293,17 +314,43 @@ strings, and XML layout files.</p>
Without it the layout will just be stretched.</p>
</div>
-<p>The Eclipse plugin creates one of these XML files for you (<code>main.xml</code>). In our example
-above, we just ignored it and created our layout programmatically. In the Eclipse Package Explorer, expand the
-folder res/layout/, and open the file <code>main.xml</code> (once opened, you might need to click
+<p>The Eclipse plugin automatically creates one of these layout files for you (<code>main.xml</code>). In our example
+above, we just ignored it and created our layout programmatically. We did so just to teach you a little more
+about the framework, but you should almost always define your layout in an XML file instead of in your code.</p>
+
+<p>So, let's put it to use and change the "Hello, Android" sample to use the XML layout.</p>
+
+<ol>
+ <li>In the Eclipse Package Explorer, expand the
+folder <em>res/layout/</em>, and open the file <code>main.xml</code> (once opened, you might need to click
the "main.xml" tab at the bottom to see the XML source). Replace its contents with
-the sample XML above and save your changes.</p>
+the following XML:
+<pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
+&lt;TextView xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+ android:layout_width=&quot;fill_parent&quot;
+ android:layout_height=&quot;fill_parent&quot;
+ android:text=&quot;@string/hello&quot;/&gt;</pre>
+<p>Save the file.</p>
+</li>
-<p>Now open and modify your <code>HelloAndroid</code> class source code to read the
-XML layout, instead of the hard-coded version. Edit the file to look like this:</p>
+<li>Inside the project folder <em>res/values/</em>, open the file <code>strings.xml</code>.
+This is where you should save all default text strings for your user interface. If you're using Eclipse, then
+ADT will have started you with two strings, <em>hello</em> and <em>app_name</em>.
+Revise <em>hello</em> to something else. Perhaps "Hello, Android! I am a string resource!"
+The entire file should now look like this:
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+ &lt;string name="hello">Hello, Android! I am a string resource!&lt;/string>
+ &lt;string name="app_name">Hello, Android&lt;/string>
+&lt;/resources>
+</pre>
+</li>
+<li>Now open and modify your <code>HelloAndroid</code> class source code to read the
+XML layout, instead of the hard-coded version. Edit the file to look like this:
<pre>
-package com.android.hello;
+package com.example.hello;
import android.app.Activity;
import android.os.Bundle;
@@ -319,39 +366,50 @@ public class HelloAndroid extends Activity {
<p>When you make this change, type it by hand to try the code-completion feature on that R class. You'll probably find that it helps a lot.</p>
-<p>The <code>setContentView()</code> method we're now using expects a reference to a layout resource.
-We pass it <code>R.layout.main</code>, which is the reference to the <code>layout/main.xml</code> once it's
-compiled into our R class by the Eclipse plugin. (More about the R class in a moment.)</p>
+<p>Now, instead of passing <code>setContentView()</code> a View object, we give it a reference to our layout resource.
+The resource is identified as <code>R.layout.main</code>, which is actually a compiled object representation of
+the layout defined in <em>layout/main.xml</em>. The Eclipse plugin automatically creates this reference for
+us inside the project's R.java class. If you're not using Eclipse, then the R.java class will be generated for you
+when you run Ant to build the application. (More about the R class in a moment.)</p>
+</li>
+</ol>
<p>Now that you've made this change, go ahead and re-run your application &mdash; all
you need to do is click the green Run arrow icon, or select
-<strong>Run &gt; Run History &gt; Hello, Android</strong> from the menu. You should see.... well, exactly the same thing
+<strong>Run &gt; Run History &gt; Hello, Android</strong> from the menu. You should see pretty much the same thing
you saw before! After all, the point was to show that the two different
layout approaches produce identical results.</p>
-<p>There's a lot more to creating these XML layouts, but that's as far as we'll go
-here. Read the <a href="{@docRoot}guide/topics/views/index.html">Views and Layout</a> documentation for more
-information on creating layouts.</p>
+<p class="note"><strong>Tip:</strong> Use the shortcut <strong>Ctrl-Shift-F11</strong>
+(<strong>Cmd-Shift-F11</strong>, on Mac) to run your currently visible application.</p>
+
+<p>You've just completed your first Android application! Continue reading for an introduction
+to debugging and a little more information on using other IDEs. Once you're ready to move on,
+please begin by reading <a href="{@docRoot}guide/topics/fundamentals.html">Application
+Fundamentals</a>. Also refer to the <a href="{@docRoot}guide/index.html">Developer's Guide</a>
+introduction page for an overview of the <em>Dev Guide</em> documentation.</p>
+
<div class="special">
<h3>R class</h3>
-<p>Open the file named R.java in your source code folder in the Package
+<p>In Eclipse, open the file named R.java in your source code folder in the Package
Explorer. It should look something like this:</p>
<pre>
public final class R {
public static final class attr {
- };
+ }
public static final class drawable {
public static final int icon=0x7f020000;
- };
+ }
public static final class layout {
public static final int main=0x7f030000;
- };
+ }
public static final class string {
- public static final int app_name=0x7f040000;
- };
-};
+ public static final int app_name=0x7f040001;
+ public static final int hello=0x7f040000;
+ }
+}
</pre>
<p>A project's R.java file is an index into all the resources defined in the
@@ -361,10 +419,13 @@ particularly powerful with the code-completion features of IDEs like Eclipse
because it lets you quickly and interactively locate the specific reference
you're looking for.</p>
-<p>For now, notice the inner class named "layout", and its
+<p>It's possible yours looks slighly different than this (perhaps the hexadecimal values are different).
+For now, notice the inner class named "layout", and its
member field "main". The Eclipse plugin noticed the XML
layout file named main.xml and generated a class for it here. As you add other
-resources to your project (in the <code>res/</code> directory), you'll see R.java change to keep up.</p>
+resources to your project (such as strings in the <em>res/values/string.xml</em> file or drawables inside
+the <em>res/drawable/</em> direcory) you'll see R.java change to keep up.</p>
+<p>When not using Eclipse, this class file will be generated for you at build time (with the Ant tool).</p>
<p><em>You should never edit this file by hand.</em></p>
</div>
@@ -436,4 +497,4 @@ just as you would for any other application.</p>
installed and run in your emulator using the 'adb' tool.</p>
<p>For more information on how to use these tools, please read the documentation
- cited above.</p> \ No newline at end of file
+ cited above.</p>
diff --git a/docs/html/guide/tutorials/notepad/codelab/NotepadCodeLab.zip b/docs/html/guide/tutorials/notepad/codelab/NotepadCodeLab.zip
index 86f5e9d..c7dd989 100755..100644
--- a/docs/html/guide/tutorials/notepad/codelab/NotepadCodeLab.zip
+++ b/docs/html/guide/tutorials/notepad/codelab/NotepadCodeLab.zip
Binary files differ
diff --git a/docs/html/guide/tutorials/notepad/notepad-ex1.jd b/docs/html/guide/tutorials/notepad/notepad-ex1.jd
index 45ed97e..b7f42bf 100644
--- a/docs/html/guide/tutorials/notepad/notepad-ex1.jd
+++ b/docs/html/guide/tutorials/notepad/notepad-ex1.jd
@@ -1,4 +1,6 @@
page.title=Notepad Exercise 1
+parent.title=Notepad Tutorial
+parent.link=index.html
@jd:body
@@ -584,5 +586,4 @@ the zip file to compare with your own.</p>
<p>Once you are ready, move on to <a href="notepad-ex2.html">Tutorial
Exercise 2</a> to add the ability to create, edit and delete notes.</p>
-<p><a href="index.html">Back to the Tutorial main page...</a></p>
diff --git a/docs/html/guide/tutorials/notepad/notepad-ex2.jd b/docs/html/guide/tutorials/notepad/notepad-ex2.jd
index b4608fb..3b8fa0b 100644
--- a/docs/html/guide/tutorials/notepad/notepad-ex2.jd
+++ b/docs/html/guide/tutorials/notepad/notepad-ex2.jd
@@ -1,9 +1,12 @@
page.title=Notepad Exercise 2
+parent.title=Notepad Tutorial
+parent.link=index.html
@jd:body
<p><em>In this exercise, you will add a second Activity to your notepad application, to let the user
-create, edit, and delete notes. The new Activity assumes responsibility for creating new notes by
+create and edit notes. You will also allow the user to delete existing notes through a context menu.
+The new Activity assumes responsibility for creating new notes by
collecting user input and packing it into a return Bundle provided by the intent. This exercise
demonstrates:</em></p>
<ul>
@@ -11,6 +14,7 @@ demonstrates:</em></p>
<li><em>Invoking another Activity asynchronously using <code>startActivityForResult()</code></em></li>
<li><em>Passing data between Activity in Bundle objects</em></li>
<li><em>How to use a more advanced screen layout</em></li>
+<li><em>How to create a context menu</em></li>
</ul>
<div style="float:right;white-space:nowrap">
@@ -51,7 +55,8 @@ Tools</strong> &gt; <strong>Fix Project Properties</strong>.</p>
</li>
<li>
There are also a couple of new overridden methods
- (<code>onListItemClick()</code> and <code>onActivityResult()</code>)
+ (<code>onCreateContextMenu()</code>, <code>onContextItemSelected()</code>,
+ <code>onListItemClick()</code> and <code>onActivityResult()</code>)
which we will be filling in below.
</li>
</ul>
@@ -59,59 +64,62 @@ Tools</strong> &gt; <strong>Fix Project Properties</strong>.</p>
<h2>Step 2</h2>
- <p>Add an entry to the menu for deleting a note:</p>
+<div class="sidebox">
+<p>Context menus should always be used when performing actions upon specific elements in the UI.
+When you register a View to a context menu, the context menu is revealed by performing a "long-click"
+on the UI component (press and hold the touchscreen or highlight and hold down the selection key for about two seconds).</p>
+</div>
+
+<p>First, let's create the context menu that will allow users to delete individual notes.
+Open the Notepadv2 class.</p>
+
<ol>
+ <li>In order for each list item in the ListView to register for the context menu, we call
+ <code>registerForContextMenu()</code> and pass it our ListView. So, at the very end of
+ the <code>onCreate()</code> method add this line:
+ <pre>registerForContextMenu(getListView());</pre>
+ <p>Because our Activity extends the ListActivity class, <code>getListView()</code> will return us
+ the local ListView object for the Activity. Now, each list item in this ListView will activate the
+ context menu.
<li>
- In the <code>onCreateOptionsMenu()</code> method, add a new line:
- <pre>menu.add(0, DELETE_ID, 0, R.string.menu_delete);</pre>
- </li>
- <li>
- The whole method should now look like this:<br>
+ Now fill in the <code>onCreateContextMenu()</code> method. This callback is similar to the other
+ menu callback used for the options menu. Here, we add just one line, which will add a menu item
+ to delete a note. Call <code>menu.add()</code> like so:
<pre>
-&#64;Override
-public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- menu.add(0, INSERT_ID, 0, R.string.menu_insert);
+public boolean onCreateContextMenu(Menu menu, View v
+ ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
- return true;
}</pre>
+ <p>The <code>onCreateContextMenu()</code> callback some passes other information in addition to the Menu object,
+ such as the View that has been triggered for the menu and
+ an extra object that may contain additional information about the object selected. However, we don't care about
+ these here, because we only have one kind of object in the Activity that uses context menus. In the next
+ step, we'll handle the menu item selection.</p>
</li>
</ol>
<h2>Step 3</h2>
- <p>In the <code>onMenuItemSelected()</code> method, add a new case for
- <code>DELETE_ID</code>:</p>
- <pre>
-mDbHelper.deleteNote(getListView().getSelectedItemId());
-fillData();
-return true;</pre>
-
- <ol>
- <li>
- Here, we use the <code>deleteNote</code> method to remove the note specified by ID.
- In order to get the ID, we call <code>getListView().getSelectedItemId()</code>.
- </li>
- <li>
- Then we fill the data to keep everything up to date.
- </li>
- </ol>
- <p>
- The whole method should now look like this:</p>
- <pre>
-&#64;Override
-public boolean onMenuItemSelected(int featureId, MenuItem item) {
+ <p>Now that the we've registered our ListView for a context menu and defined our context menu item, we need
+ to handle the callback when it is selected. For this, we need to identify the list ID of the
+ selected item, then delete it. So fill in the
+ <code>onContextItemSelected()</code> method like this:</p>
+<pre>
+public boolean onContextItemSelected(MenuItem item) {
switch(item.getItemId()) {
- case INSERT_ID:
- createNote();
- return true;
case DELETE_ID:
- mDbHelper.deleteNote(getListView().getSelectedItemId());
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+ mDbHelper.deleteNote(info.id);
fillData();
return true;
}
-
- return super.onMenuItemSelected(featureId, item);
+ return super.onContextItemSelected(item);
}</pre>
+<p>Here, we retrieve the {@link android.widget.AdapterView.AdapterContextMenuInfo AdapterContextMenuInfo}
+with {@link android.view.MenuItem#getMenuInfo()}. The <var>id</var> field of this object tells us
+the position of the item in the ListView. We then pass this to the <code>deleteNote()</code>
+method of our NotesDbAdapter and the note is deleted. That's it for the context menu &mdash; notes
+can now be deleted.</p>
<h2 style="clear:right;">Step 4</h2>
<div class="sidebox" style="border:2px solid #FFFFDD;float:right;
@@ -294,8 +302,8 @@ case ACTIVITY_EDIT:
but that doesn't mean it is even close to the kind of sophistication you will be likely to want
in real Android applications.</p>
<p style="padding-left:.5em;font-size:12px;margin:0; padding:.0em .5em .5em 1em;">Creating a
- good UI is part art and part science, and the rest is work. Mastering <a
- href="{@docRoot}guide/topics/views/declaring-layout.html">Android layout</a> is an essential part of creating
+ good UI is part art and part science, and the rest is work. Mastery of <a
+ href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a> is an essential part of creating
a good looking Android application.</p>
<p style="padding-left:.5em;font-size:12px;margin:0;
padding:.0em .5em .5em 1em;">Take a look at the
@@ -570,7 +578,7 @@ protected void onCreate(Bundle savedInstanceState) {
receive, and more. </p>
<p style="padding-left:.5em;font-size:12px;margin:0;
padding:.0em .5em .5em 1em;">For more information, see the reference document
- <a href="{@docRoot}guide/topics/manifest/manifest.html">AndroidManifest.xml</a></p>
+ <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a></p>
</div>
<p>Finally, the new Activity has to be defined in the manifest file:</p>
@@ -636,5 +644,4 @@ Once you are ready, move on to <a href="notepad-ex3.html">Tutorial
Exercise 3</a> where you will fix the problems with the back button and lost
edits by introducing a proper life cycle into the NoteEdit Activity.</p>
-<p><a href="index.html">Back to the Tutorial main page...</a>.</p>
diff --git a/docs/html/guide/tutorials/notepad/notepad-ex3.jd b/docs/html/guide/tutorials/notepad/notepad-ex3.jd
index a2eaa48..8737280 100644
--- a/docs/html/guide/tutorials/notepad/notepad-ex3.jd
+++ b/docs/html/guide/tutorials/notepad/notepad-ex3.jd
@@ -1,4 +1,6 @@
page.title=Notepad Exercise 3
+parent.title=Notepad Tutorial
+parent.link=index.html
@jd:body
@@ -354,4 +356,3 @@ the zip file to compare with your own.</p>
When you are ready, move on to the <a href="notepad-extra-credit.html">Tutorial
Extra Credit</a> exercise, where you can use the Eclipse debugger to
examine the life-cycle events as they happen.</p>
-<p><a href="index.html">Back to the Tutorial main page...</a></p>
diff --git a/docs/html/guide/tutorials/notepad/notepad-extra-credit.jd b/docs/html/guide/tutorials/notepad/notepad-extra-credit.jd
index f64e90e..0d59b56 100644
--- a/docs/html/guide/tutorials/notepad/notepad-extra-credit.jd
+++ b/docs/html/guide/tutorials/notepad/notepad-extra-credit.jd
@@ -1,4 +1,6 @@
-page.title=Tutorial: Extra Credit
+page.title=Notepad Extra Credit
+parent.title=Notepad Tutorial
+parent.link=index.html
@jd:body
@@ -65,6 +67,4 @@ when.</p>
your application development, but also superb profiling support. You can also
try using <a href="{@docRoot}guide/developing/tools/traceview.html">Traceview</a> to profile your application. If your application is running too slow, this can help you
find the bottlenecks and fix them.</p>
-<p><a href="index.html">Back to the Tutorial main
-page...</a></p>
diff --git a/docs/html/guide/tutorials/views/hello-autocomplete.jd b/docs/html/guide/tutorials/views/hello-autocomplete.jd
index de3ba29..fba1ad8 100644
--- a/docs/html/guide/tutorials/views/hello-autocomplete.jd
+++ b/docs/html/guide/tutorials/views/hello-autocomplete.jd
@@ -40,7 +40,7 @@ protected void onCreate(Bundle savedInstanceState) {
AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.edit);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
- android.R.layout.simple_dropdown_item_1line, R.array.planets);
+ android.R.layout.simple_dropdown_item_1line, COUNTRIES);
textView.setAdapter(adapter);
}
</pre>
diff --git a/docs/html/guide/tutorials/views/hello-formstuff.jd b/docs/html/guide/tutorials/views/hello-formstuff.jd
index f858ce3..da4289c 100644
--- a/docs/html/guide/tutorials/views/hello-formstuff.jd
+++ b/docs/html/guide/tutorials/views/hello-formstuff.jd
@@ -32,7 +32,7 @@ We'll make it display a message when pressed.</p>
<ol>
<li><img src="images/android.png" align="right"/>
Drag the Android image on the right (or your own image) into the
- res/drawables/ directory of your project.
+ res/drawable/ directory of your project.
We'll use this for the button.</li>
<li>Open the layout file and, inside the LinearLayout, add the {@link android.widget.ImageButton} element:
<pre>
@@ -43,7 +43,7 @@ We'll make it display a message when pressed.</p>
android:src="@drawable/android" />
</pre>
<p>The source of the button
- is from the res/drawables/ directory, where we've placed the android.png.</p>
+ is from the res/drawable/ directory, where we've placed the android.png.</p>
<p class="note"><strong>Tip:</strong> You can also reference some of the many built-in
images from the Android {@link android.R.drawable} resources,
like <code>ic_media_play</code>, for a "play" button image. To do so, change the source
@@ -52,7 +52,7 @@ We'll make it display a message when pressed.</p>
<li>To make the button to actually do something, add the following
code at the end of the <code>onCreate()</code> method:
<pre>
-ImageButton button = (ImageButton) findViewById(R.id.android_button);
+final ImageButton button = (ImageButton) findViewById(R.id.android_button);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Perform action on clicks
@@ -84,12 +84,12 @@ defines the action to be made when the button is clicked. Here, we show a
<li>To do something with the text that the user enters, add the following code
to the end of the <code>onCreate()</code> method:
<pre>
-EditText edittext = (EditText) findViewById(R.id.edittext);
+final EditText edittext = (EditText) findViewById(R.id.edittext);
edittext.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
// Perform action on key press
- Toast.makeText(HelloImageButton.this, edittext.getText(), Toast.LENGTH_SHORT).show();
+ Toast.makeText(HelloFormStuff.this, edittext.getText(), Toast.LENGTH_SHORT).show();
return true;
}
return false;
@@ -127,9 +127,9 @@ checkbox.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Perform action on clicks
if (checkbox.isChecked()) {
- Toast.makeText(HelloImageButton.this, "Selected", Toast.LENGTH_SHORT).show();
+ Toast.makeText(HelloFormStuff.this, "Selected", Toast.LENGTH_SHORT).show();
} else {
- Toast.makeText(HelloImageButton.this, "Not selected", Toast.LENGTH_SHORT).show();
+ Toast.makeText(HelloFormStuff.this, "Not selected", Toast.LENGTH_SHORT).show();
}
}
});
@@ -183,7 +183,7 @@ OnClickListener radio_listener = new OnClickListener() {
public void onClick(View v) {
// Perform action on clicks
RadioButton rb = (RadioButton) v;
- Toast.makeText(HelloImageButton.this, rb.getText(), Toast.LENGTH_SHORT).show();
+ Toast.makeText(HelloFormStuff.this, rb.getText(), Toast.LENGTH_SHORT).show();
}
};
</pre>
@@ -225,9 +225,9 @@ togglebutton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Perform action on clicks
if (togglebutton.isChecked()) {
- Toast.makeText(HelloImageButton.this, "ON", Toast.LENGTH_SHORT).show();
+ Toast.makeText(HelloFormStuff.this, "ON", Toast.LENGTH_SHORT).show();
} else {
- Toast.makeText(HelloImageButton.this, "OFF", Toast.LENGTH_SHORT).show();
+ Toast.makeText(HelloFormStuff.this, "OFF", Toast.LENGTH_SHORT).show();
}
}
});
diff --git a/docs/html/guide/tutorials/views/hello-gridview.jd b/docs/html/guide/tutorials/views/hello-gridview.jd
index 623a03d..ffb6c93 100644
--- a/docs/html/guide/tutorials/views/hello-gridview.jd
+++ b/docs/html/guide/tutorials/views/hello-gridview.jd
@@ -25,6 +25,7 @@ are acquired from a {@link android.widget.ListAdapter}.</p>
android:stretchMode="columnWidth"
android:gravity="center"
/>
+</pre>
</li>
<li>Open the HelloGridView Java file. Insert the following for the <code>onCreate()</code> method:
<pre>
diff --git a/docs/html/guide/tutorials/views/hello-mapview.jd b/docs/html/guide/tutorials/views/hello-mapview.jd
index fcdf056..976b8ab 100644
--- a/docs/html/guide/tutorials/views/hello-mapview.jd
+++ b/docs/html/guide/tutorials/views/hello-mapview.jd
@@ -16,8 +16,13 @@ First, we'll create a simple Activity that can view and navigate a map. Then we
<pre>&lt;uses-library android:name="com.google.android.maps" /></pre>
</li>
-
- <li>Open the layout file. Define the layout with a MapView inside a RelativeLayout:
+ <li>We also need access to the internet in order to retrieve the Google Maps tiles,
+ so the application must request the {@link android.Manifest.permission#INTERNET INTERNET} permissions.
+ In the manifest file, add the following as a child of the <code>&lt;manifest></code> element:
+ <pre>&lt;uses-permission android:name="android.permission.INTERNET" /></pre>
+ </li>
+ <li>Now open the main layout file for your project. Define a layout with a com.google.android.maps.MapView
+ inside a android.widget.RelativeLayout:
<pre>
&lt;?xml version="1.0" encoding="utf-8"?>
@@ -32,22 +37,21 @@ First, we'll create a simple Activity that can view and navigate a map. Then we
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
- android:apiKey="INSERT YOUR KEY HERE"
+ android:apiKey="<em>Your Maps API Key</em>"
/>
-&lt;RelativeLayout>
+&lt;/RelativeLayout>
</pre>
- <p>Setting <code>clickable</code> is important. Otherwise, the map does not allow any user interaction.</p>
-
- <p>The <code>android:apiKey</code> must contain an authentic Android Maps API key.
- The API key is generated using the MD5 fingerprint of your application certificate. For the purposes of
- this exercise, you should use the fingerprint of your debug certificate (which cannot be used to release
- your application for Android devices, but will work while developing). See how to
- <a href="{@docRoot}guide/topics/geo/mapkey.html#getdebugfingerprint">generate a fingerprint from your
- debug certificate</a>, then <a href="http://code.google.com/android/maps-api-signup.html">register the
- certificate</a> to retieve an API key.
- Insert the API key as the value of the <code>apiKey</code> attribute. If you do not insert a valid
- Maps API key, the application will still run, but no map tiles will load.</p></li>
+ <p>The <code>clickable</code> attribute defines whether you want to allow user-interaction with the map.
+ In this case, we set it "true" so that the user can navigate.</p>
+
+ <p>The <code>apiKey</code> attribute holds the Google Maps API Key that proves your application and signer
+ certificate has been registered with the Google Maps service. Because MapView uses Google Maps data, this key is required
+ in order to receive the map data, even while you are developing. Registration is free and it only takes a couple
+ minutes to register your certificate and receive a Maps API Key. For instructions on getting a key, read
+ <a href="{@docRoot}guide/topics/location/geo/mapkey.html">Obtaining a Maps API Key</a>.
+ (For the purpose of this tutorial, you should register with the fingerprint of the SDK debug certificate.)
+ Once you've acquired the Maps API Key, insert it for the <code>apiKey</code> value.</p></li>
<li>Now open the HelloMapView.java file. For this Activity, we're going to extend the special sub-class of
Activity called MapActivity, so change the class declaration to extend
diff --git a/docs/html/guide/tutorials/views/index.jd b/docs/html/guide/tutorials/views/index.jd
index 6a6ac4b..2248c68 100644
--- a/docs/html/guide/tutorials/views/index.jd
+++ b/docs/html/guide/tutorials/views/index.jd
@@ -30,67 +30,67 @@ your strings.xml file.</p>
<div>
<div class="view">
-<a href="hello-linearlayout.html">LinearLayout<br/>
-<img src="images/hello-linearlayout.png" height="285" width="200" /></a>
+<a href="hello-linearlayout.html">LinearLayout</a><br/>
+<a href="hello-linearlayout.html"><img src="images/hello-linearlayout.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-relativelayout.html">RelativeLayout<br/>
-<img src="images/hello-relativelayout.png" height="285" width="200" /></a>
+<a href="hello-relativelayout.html">RelativeLayout</a><br/>
+<a href="hello-relativelayout.html"><img src="images/hello-relativelayout.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-tablelayout.html">TableLayout<br/>
-<img src="images/hello-tablelayout.png" height="285" width="200" /></a>
+<a href="hello-tablelayout.html">TableLayout</a><br/>
+<a href="hello-tablelayout.html"><img src="images/hello-tablelayout.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-datepicker.html">DatePicker<br/>
-<img src="images/hello-datepicker.png" height="285" width="200" /></a>
+<a href="hello-datepicker.html">DatePicker</a><br/>
+<a href="hello-datepicker.html"><img src="images/hello-datepicker.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-timepicker.html">TimePicker<br/>
-<img src="images/hello-timepicker.png" height="285" width="200" /></a>
+<a href="hello-timepicker.html">TimePicker</a><br/>
+<a href="hello-timepicker.html"><img src="images/hello-timepicker.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-formstuff.html">Form Stuff<br/>
-<img src="images/hello-formstuff.png" height="285" width="200" /></a>
+<a href="hello-formstuff.html">Form Stuff</a><br/>
+<a href="hello-formstuff.html"><img src="images/hello-formstuff.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-spinner.html">Spinner<br/>
-<img src="images/hello-spinner.png" height="285" width="200" /></a>
+<a href="hello-spinner.html">Spinner</a><br/>
+<a href="hello-spinner.html"><img src="images/hello-spinner.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-autocomplete.html">AutoComplete<br/>
-<img src="images/hello-autocomplete.png" height="285" width="200" /></a>
+<a href="hello-autocomplete.html">AutoComplete</a><br/>
+<a href="hello-autocomplete.html"><img src="images/hello-autocomplete.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-listview.html">ListView<br/>
-<img src="images/hello-listview.png" height="285" width="200" /></a>
+<a href="hello-listview.html">ListView</a><br/>
+<a href="hello-listview.html"><img src="images/hello-listview.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-gridview.html">GridView<br/>
-<img src="images/hello-gridview.png" height="285" width="200" /></a>
+<a href="hello-gridview.html">GridView</a><br/>
+<a href="hello-gridview.html"><img src="images/hello-gridview.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-gallery.html">Gallery<br/>
-<img src="images/hello-gallery.png" height="285" width="200" /></a>
+<a href="hello-gallery.html">Gallery</a><br/>
+<a href="hello-gallery.html"><img src="images/hello-gallery.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-tabwidget.html">TabWidget<br/>
-<img src="images/hello-tabwidget.png" height="285" width="200" /></a>
+<a href="hello-tabwidget.html">TabWidget</a><br/>
+<a href="hello-tabwidget.html"><img src="images/hello-tabwidget.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-mapview.html">MapView<br/>
-<img src="images/hello-mapview.png" height="285" width="200" /></a>
+<a href="hello-mapview.html">MapView</a><br/>
+<a href="hello-mapview.html"><img src="images/hello-mapview.png" height="285" width="200" /></a>
</div>
<div class="view">
-<a href="hello-webview.html">WebView<br/>
-<img src="images/hello-webview.png" height="285" width="200" /></a>
+<a href="hello-webview.html">WebView</a><br/>
+<a href="hello-webview.html"><img src="images/hello-webview.png" height="285" width="200" /></a>
</div>
<!--
diff --git a/docs/html/images/adc1r1_deck.pdf b/docs/html/images/adc1r1_deck.pdf
deleted file mode 100644
index e76a554..0000000
--- a/docs/html/images/adc1r1_deck.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/binder_rpc.png b/docs/html/images/binder_rpc.png
new file mode 100644
index 0000000..1021109
--- /dev/null
+++ b/docs/html/images/binder_rpc.png
Binary files differ
diff --git a/docs/html/images/judgebio_charles.jpg b/docs/html/images/judgebio_charles.jpg
deleted file mode 100644
index 2449cfe..0000000
--- a/docs/html/images/judgebio_charles.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/judgebio_dibona.jpg b/docs/html/images/judgebio_dibona.jpg
deleted file mode 100644
index 91869fb..0000000
--- a/docs/html/images/judgebio_dibona.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/judgebio_gadi.jpg b/docs/html/images/judgebio_gadi.jpg
deleted file mode 100644
index d1e40c3..0000000
--- a/docs/html/images/judgebio_gadi.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/judgebio_jens.jpg b/docs/html/images/judgebio_jens.jpg
deleted file mode 100644
index 6f07254..0000000
--- a/docs/html/images/judgebio_jens.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/judgebio_jeremiah.jpg b/docs/html/images/judgebio_jeremiah.jpg
deleted file mode 100644
index c91b43f..0000000
--- a/docs/html/images/judgebio_jeremiah.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/judgebio_kristian.jpg b/docs/html/images/judgebio_kristian.jpg
deleted file mode 100644
index 19e93dd..0000000
--- a/docs/html/images/judgebio_kristian.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/judgebio_leon.jpg b/docs/html/images/judgebio_leon.jpg
deleted file mode 100644
index c648bd3..0000000
--- a/docs/html/images/judgebio_leon.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/options_menu.png b/docs/html/images/options_menu.png
new file mode 100755
index 0000000..ecb9394
--- /dev/null
+++ b/docs/html/images/options_menu.png
Binary files differ
diff --git a/docs/html/images/radio_buttons.png b/docs/html/images/radio_buttons.png
new file mode 100755
index 0000000..b755e42
--- /dev/null
+++ b/docs/html/images/radio_buttons.png
Binary files differ
diff --git a/docs/html/images/table_layout.png b/docs/html/images/table_layout.png
index bc1a47c..e7fae2d 100644
--- a/docs/html/images/table_layout.png
+++ b/docs/html/images/table_layout.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 05ab987..bd681e2 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -1,5 +1,4 @@
home=true
-page.title=Home
@jd:body
@@ -7,14 +6,16 @@ page.title=Home
<div id="mainBodyLeft">
<div id="homeMiddle">
<div id="homeTitle">
- <div style="float:left;">
- <h2>T-Mobile G1 Now Available!</h2>
- </div>
- <div style="float:right;" align="center">
- <a href="http://www.t-mobileg1.com">Learn more &raquo;</a><br />
- <!-- <img src="{@docRoot}assets/images/icon_robot.jpg" style="margin:8px 10px 0 10px; clear:both;" /> -->
- </div>
+ <h2>Developer Announcements</h2>
</div><!-- end homeTitle -->
+ <div id="announcement-block">
+ <!-- total max width is 520px -->
+ <img src="{@docRoot}assets/images/home/IO-logo.png" alt="Google I/O Developer Conference 2009" width="242px" />
+ <div id="announcement" style="width:270px">
+ <p>Google I/O is a two-day developer event that will take place May 27-28 at Moscone Center, San Francisco.</p>
+ <p><a href="http://code.google.com/events/io/">Learn more &raquo;</a></p>
+ </div> <!-- end annoucement -->
+ </div> <!-- end annoucement-block -->
<div id="carouselMain">
<div id="bulletinImg"></div>
<div id="bulletinDesc"></div>
@@ -27,51 +28,32 @@ page.title=Home
<!-- populated by buildCarousel() -->
</div>
</div><!-- end list-clip -->
- <a href="javascript:{}" id="arrow-right" onclick="" class="arrow-right-off"></a>
+ <a href="javascript:page_right()" id="arrow-right" onclick="" class="arrow-right-on"></a>
<div class="clearer"></div>
</div><!-- end app-list container -->
</div><!-- end homeMiddle -->
<div style="clear:both">&nbsp;</div>
-
- <div id="homeBottom">
- <table>
- <tr>
- <td>
- <br />
- <h2>Featured Developer App: BreadCrumbz</h2>
- <p>Amos Yoffe takes navigation to the next level with BreadCrumbz.</p>
- <p><a href="http://www.bcrumbz.com">Learn more about this developer &raquo;</a></p>
- </td>
- <td>
- <img src="{@docRoot}assets/images/logo_breadcrumbz.jpg" />
- </td>
- </tr>
- </table>
- </div><!-- end homeBottom -->
</div><!-- end mainBodyLeft -->
<div id="mainBodyRight">
<table id="rightColumn">
<tr>
- <td class="imageCell"><img src="{@docRoot}assets/images/icon_download.jpg" style="padding:0" /></td>
+ <td class="imageCell"><a href="{@docRoot}sdk/index.html"><img src="{@docRoot}assets/images/icon_download.jpg" style="padding:0" /></a></td>
<td>
<h2 class="green">Download</h2>
- <p>Latest SDK</p>
- <p><a href="{@docRoot}sdk/index.html">Download now</a></p>
+ <p>The Android SDK has the tools, sample code, and docs you need to create great apps. </p>
+ <p><a href="{@docRoot}sdk/1.1_r1/index.html">Learn more &raquo;</a></p>
</td>
</tr>
<tr>
<td colspan="2"><div class="seperator">&nbsp;</div></td>
</tr>
<tr>
- <td class="imageCell"><img src="{@docRoot}assets/images/icon_market.jpg" style="padding:0" /></td>
- <td valign="middle"><br /><h2 class="green">Market</h2></td>
- </tr>
- <tr>
- <td colspan="2">
- <br />
- <p>Android Market is an open service that will give developers the opportunity to distribute applications to handsets.</p>
+ <td class="imageCell"><a href="http://www.android.com/market.html"><img src="{@docRoot}assets/images/icon_market.jpg" style="padding:0" /></a></td>
+ <td>
+ <h2 class="green">Publish</h2>
+ <p>Android Market is an open service that lets you distribute your apps to handsets.</p>
<p><a href="http://www.android.com/market.html">Learn more &raquo;</a></p>
</td>
</tr>
@@ -79,16 +61,25 @@ page.title=Home
<td colspan="2"><div class="seperator">&nbsp;</div></td>
</tr>
<tr>
- <td class="imageCell"><img src="{@docRoot}assets/images/icon_contribute.jpg" style="padding:0" /></td>
+ <td class="imageCell"><a href="http://source.android.com"><img src="{@docRoot}assets/images/icon_contribute.jpg" style="padding:0" /></a></td>
<td>
<h2 class="green">Contribute</h2>
- <p>Create using our open source codebase and help us keep this project growing.</p>
+ <p>Android Open Source Project gives you access to the entire platform source.</p>
<p><a href="http://source.android.com">Learn more &raquo;</a></p>
</td>
</tr>
<tr>
<td colspan="2"><div class="seperator">&nbsp;</div></td>
</tr>
+ <tr>
+ <td class="imageCell"><a href="http://www.youtube.com/user/androiddevelopers"><img src="{@docRoot}assets/images/video-droid.png" style="padding:0" /></a></td>
+ <td>
+ <h2 class="green">Watch</h2>
+ <object width="150" height="140"><param name="movie" value="http://www.youtube.com/v/x1ZZ-R3p_w8&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/x1ZZ-R3p_w8&hl=en&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="150" height="140"></embed></object>
+ <p style="margin-top:1em"><a href="http://www.youtube.com/user/androiddevelopers">More Android videos &raquo;</a></p>
+ </td>
+ </tr>
+
</table>
</div>
</div>
@@ -125,10 +116,10 @@ page.title=Home
'sdk': {
'layout':"imgLeft",
'icon':"sdk-small.png",
- 'name':"SDK 1.0 r1",
+ 'name':"SDK 1.1 r1",
'img':"sdk-large.png",
- 'title':"Android 1.0 SDK r1",
- 'desc': "<p>The first Android 1.0 SDK is available for download. This is the first release guaranteed to operate on the first Android devices. If you want to release an application for Android, you should be developing with this SDK.</p><p><a href='{@docRoot}sdk/index.html'>Download Android 1.0 SDK r1</a></p>"
+ 'title':"Android 1.1 SDK r1",
+ 'desc': "<p>A new Android SDK is available for download. The new SDK includes minor API changes, new UI localizations, bug fixes and some new application features.</p><p><a href='{@docRoot}sdk/1.1_r1/index.html'>Download Android 1.1 SDK r1</a></p>"
},
'mapskey': {
@@ -137,7 +128,7 @@ page.title=Home
'name':"Maps API Key",
'img':"maps-large.png",
'title':"Maps API Key",
- 'desc':"<p>If you're writing an Android application that uses Google Maps (with MapView), you must register your application to obtain a Maps API Key. Without the key, your maps application will not work on Android devices. Obtaining a key requires just a couple of steps.</p><p><a href='{@docRoot}guide/topics/geo/mapkey.html'>Learn how to get a Maps API Key</a></p>"
+ 'desc':"<p>If you're writing an Android application that uses Google Maps (with MapView), you must register your application to obtain a Maps API Key. Without the key, your maps application will not work on Android devices. Obtaining a key requires just a couple of steps.</p><p><a href='{@docRoot}guide/topics/location/geo/mapkey.html'>Learn how to get a Maps API Key</a></p>"
},
'market': {
@@ -147,6 +138,15 @@ page.title=Home
'img':"market-large.png",
'title':"",
'desc': "<p>Android Market helps you get your applications into the hands of users. The beta version of Market is now open and you can begin sharing your applications with users of the first Android-powered phone, the T-Mobile G1.</p><p><a href='http://market.android.com/publish/'>Publish your Android app on Market &raquo;</a></p>"
+ },
+
+ 'devphone': {
+ 'layout':"imgLeft",
+ 'icon':"devphone-small.png",
+ 'name':"Dev Phone 1",
+ 'img':"devphone-large.png",
+ 'title':"Android Dev Phone 1",
+ 'desc': "<p>Run and debug your Android applications directly on this device. Modify and rebuild the Android operating system, and flash it onto the phone. The Android Dev Phone 1 is carrier independent, and available for purchase by any developer registered with <a href='http://market.android.com/publish'>Android Market</a>.</p><p><a href='/guide/developing/device.html#dev-phone-1'>Learn more about the Android Dev Phone 1 &raquo;</a></p>"
}
}
diff --git a/docs/html/license.jd b/docs/html/license.jd
new file mode 100644
index 0000000..88932b6
--- /dev/null
+++ b/docs/html/license.jd
@@ -0,0 +1,143 @@
+page.title=Content License
+hide_license_footer=true
+@jd:body
+
+<div id="mainBodyFluid">
+<h1>Content License</h1>
+
+<p>For the purposes of licensing, the content of this site is divided
+into two categories:</p>
+<ul>
+ <li>Documentation content, found under the "Dev Guide" and "Reference"
+ tabs, including both static content and content extracted from source
+ code modules, as well as sample code, and </li>
+<li>All other site content</li>
+</ul>
+
+<p>The documentation content on this site is made available to
+you as part of the <a href="http://source.android.com">Android Open
+Source Project</a>. This documentation, including any code shown in it,
+is licensed under the <a
+href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0
+license</a>, the preferred license for all parts of the of the Android
+Open Source Project.</p>
+
+<p>Apache 2.0 is a commercial and open-source-friendly software
+license. The majority of the Android platform and documentation is
+licensed under the Apache 2.0 license. While the project strives to
+adhere to the preferred license, there may be exceptions, such as for
+documentation (code comments) extracted from a source code module that
+is licensed under GPLv2 or other license. In those cases, the license
+covering the source code module will apply to the documentation
+extracted from it. </p>
+
+<p>All other content on this site, except the license documents themselves
+and as otherwise noted, is licensed under the <a
+href="http://creativecommons.org/licenses/by/2.5/">Creative Commons
+Attribution 2.5</a> license. </p>
+
+<p>You may use the content of this site in any way that is consistent
+with the specific license that applies to the content, as described
+above. For content licensed under Creative Commons Attribution 2.5, we
+ask that you give proper <a href="#attribution">attribution</a>. </p>
+
+
+<h3 id="terms">Terms of Use</h3>
+
+<p>We are pleased to license the Android documentation and sample code under
+terms that encourage you to take, modify, reuse, re-purpose, and remix the
+content as you see fit. Except as noted in the Restrictions section below, you
+are free to use the documentation content in your own creations. For example,
+you could quote the text in a book, cut-and-paste sections to your blog, record
+it as an audiobook for the visually impaired, or even translate it. </p>
+
+
+<h3 id="restrictions">Restrictions</h3>
+
+<ul>
+<li>While the documentation itself is available to you under the Apache 2.0
+license, note that proprietary trademarks and brand features are not
+included in that license.</li>
+
+<li>Google's trademarks and other brand features (including the
+ANDROID stylized typeface logo) are not included in the license.
+Please see <a href="http://www.google.com/permissions/guidelines.html">
+Guidelines for Third Party Use of Google Brand Features</a> for
+information about this usage. </li>
+
+<li>In some cases, a page may include content, such as an image, that is not
+covered by the license. In that case, we will label the content that is not licensed. </li>
+
+<li>In addition, content linked from a page on this site is not covered
+by the license unless specifically noted. For example, pages may link to videos or
+slide decks that are not covered.</li>
+
+<li>The use of sample source code provided in the SDK or shown in this
+documentation is subject to the conditions detailed in the <a
+href="{@docRoot}sdk/terms.html">SDK Terms and Conditions</a>.</li>
+</ul>
+</h3>
+
+<h3 id="attribution">Attribution</h3>
+<p>
+Proper attribution is required when you reuse or create modified
+versions of content that appears on a page made available under the
+terms of the Creative Commons Attribution license. On this site, the
+requirement for attribution applies only to the non-documentation
+content, as described earlier in this document. The complete
+requirements for attribution can be found in section 4b of the
+<a href="http://creativecommons.org/licenses/by/2.5/legalcode">
+Creative Commons legal code</a>.
+</p>
+<p>
+ In practice we ask that you provide attribution to the Android Open
+ Source project to the best of the ability of the medium in which you
+ are producing the work. There are several typical ways in which this
+ might apply:
+</p>
+<h4>Exact Reproductions</h4>
+<p>
+ If your online work <em>exactly reproduces</em> text or images from this
+ site, in whole or in part, please include a paragraph at the bottom
+ of your page that reads:
+</p>
+<blockquote>
+ Portions of this page are reproduced from work created and <a
+ href="http://code.google.com/policies.html">shared by the Android Open Source Project</a>
+ and used according to terms described in the <a
+ href="http://creativecommons.org/licenses/by/2.5/">Creative Commons
+ 2.5 Attribution License</a>.
+
+</blockquote>
+<p>
+ Also, please link back to the original source page so that readers can
+ refer there for more information.
+</p>
+<h4>Modified Versions</h4>
+<p>
+ If your online work shows <em>modified</em> text or images based on
+ the content from this site, please include a paragraph at the bottom of
+ your page that reads:
+</p>
+<blockquote>
+ Portions of this page are modifications based on work created and <a
+ href="http://code.google.com/policies.html">shared by the Android Open
+ Source Project</a> and used according to terms described in the <a
+ href="http://creativecommons.org/licenses/by/2.5/">Creative Commons
+ 2.5 Attribution License</a>.
+</blockquote>
+<p>
+ Again, please link back to the original source page so that readers can
+ refer there for more information. This is even more important when
+ the content has been modified.
+</p>
+<h4>Other Media</h4>
+<p>
+ If you produce non-hypertext works, such as books, audio, or
+ video, we ask that you make a best effort to include a spoken or
+ written attribution in the spirit of the messages above.
+</p>
+
+</div>
+
+
diff --git a/docs/html/offline.jd b/docs/html/offline.jd
new file mode 100644
index 0000000..d41459b
--- /dev/null
+++ b/docs/html/offline.jd
@@ -0,0 +1,36 @@
+home=true
+page.title=Welcome
+@jd:body
+
+<div id="mainBodyFluid">
+
+<h1>Welcome to the Android SDK!</h1>
+
+<img src="{@docRoot}images/android_icon_125.png" style="float:right; margin:1em 6em 6em;" />
+
+<p>If you've just downloaded the SDK, then continue with
+<a href="{@docRoot}sdk/1.1_r1/installing.html">Installing the Android SDK</a>.</p>
+
+<p>If you're upgrading from a previously installed version, then refer to the
+<a href="{@docRoot}sdk/1.1_r1/upgrading.html">Upgrading</a> guide.</p>
+
+<p>Once you've completed the SDK installation, you can start learning about
+development on the Android framework by reading the <a
+href="{@docRoot}guide/index.html">Developer's Guide</a>. The SDK package
+also includes a wide variety of very helpful <a
+href="{@docRoot}samples/index.html">code samples</a>.</p>
+
+<p>Please note that you are currently viewing a local, offline version of the
+Android developer documentation. The offline documentation offers the same
+content and features as the online documentation, but since the search
+capability is network-based, it will not work while you are offline.
+Autocompletion for API packages and classes, also offered from the search box,
+is available both online and offline and loads the reference documentation for
+the item you select.</p>
+
+<p>For the most current, fully searchable documentation, please visit</p>
+
+<p style="margin-left:2em;"><a href="http://developer.android.com/index.html">
+http://developer.android.com</a>.</p>
+
+</div>
diff --git a/docs/html/resources/bootcamp.pdf b/docs/html/resources/bootcamp.pdf
deleted file mode 100644
index a817b96..0000000
--- a/docs/html/resources/bootcamp.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/roadmap.jd b/docs/html/roadmap.jd
deleted file mode 100644
index 1198638..0000000
--- a/docs/html/roadmap.jd
+++ /dev/null
@@ -1,120 +0,0 @@
-page.title=Developer Roadmap
-@jd:body
-<h1>Android Developer Roadmap</h1>
-<h2>Introduction</h2>
-<p>
-On 12 November, 2007, we made available the first early look at the Android
-SDK to give developers an opportunity to explore Android and build
-applications for the Android Developer Challenge. That was followed by the
-"M5" early look build.
-</p><p>
-Since then, we've been hard at work with our <a
-href="http://www.openhandsetalliance.com/">partners</a> preparing the first
-device for launch and finalizing the APIs and platform. The developer
-feedback we received via the "early look" SDKs has been extremely valuable in
-that process. This Roadmap outlines our plans for
-the coming months, and lets you know what to expect as we near device
-availability.
-</p><p>
-This is the top-level Roadmap. Individual components of Android (such as
-the Dalvik virtual machine, the Android Developer Tools, and so on) will have
-their own roadmaps, once we complete the source code release. Those roadmaps
-will be linked to this page, as they become available.
-</p>
-<h2>Timeline</h2>
-<p>
-To orient yourself, consult this brief timeline. Read on for details on these
-milestones.
-</p><ul>
-<li>12 November, 2007 - "Early Look" SDK released</li>
-<li>January to August, 2008 - Android Developer Challenge I</li>
-<li>18 August, 2008 - Android 0.9 SDK beta released</li>
-<li>28 August, 2008 - Android Market introduced</li>
-<li>23 September, 2008 - Android 1.0 SDK Release 1 available (first actual
-1.0-compatible SDK)</li>
-<li>22 October, 2008 - Android 1.0 devices available at retail</li>
-<li>Q4 2008 - Source code released</li>
-<li>Q4 2008 - Key Announcement on Android Developer Challenge II</li>
-</ul>
-<h2>SDK Naming and Compatibility</h2>
-<p>
-Before we dive into details, here is a quick note on how we name SDKs.
-</p><p>
-We've adopted the following naming convention for Android SDKs:
- "Android &lt;Platform&gt; SDK, release &lt;Release&gt;"
-</p><p>
-The downloadable file names for the SDKs will have this naming convention:
- "android-sdk-&lt;Host-OS&gt;-&lt;Platform&gt;_r&lt;Release&gt;.zip"
-</p><p>
-The "&lt;Platform&gt;" refers to the version of the Android platform with which the
-SDK is compatible. For instance, an SDK that can be used to build
-applications that will run on Android 1.0 is considered to be an "Android 1.0
-SDK". However, since we do expect to release bug fixes and enhancements for
-the various tools included in the SDK (such as the emulator, Eclipse plugin,
-DDMS, and so on) we need to distinguish between releases of the SDK that can
-be used to build for the same Android platform. That's what we will use the
-"&lt;Release&gt;" for.
-</p><p>
-For example, the first SDK that is compatible with Android 1.0 is named
-"Android 1.0 SDK, release 1", and will have file names such as
-"android-sdk-windows-1.0_r1.zip". In the future, after we release a
-hypothetical Android 2.0 platform version, you might see an SDK named "Android
-2.0 SDK, release 3", which would refer to the third released SDK compatible
-with Android 2.0.
-</p>
-<h2>Details of Key Events</h2>
-<h3>Ongoing SDK Releases</h3>
-<p>
-The SDK consists of two general pieces: a version of the Android platform
-itself (that runs in the emulator), and the accompanying developer tools that
-surround it. This means that when we ship SDK releases, all releases within a
-given series (such as all the SDKs for Android 1.0) will consist of
-essentially the same platform image, but with different, updated tools.
-</p><p>
-In August, we released Android 0.9 SDK, beta. The Android
-platform image was not quite 1.0-final (which is why we identified it as 0.9),
-and the tools were not yet final (which is why we referred to it as
-beta.) </p>
-
-<p>For the SDK that includes the Android 1.0 platform and updated tools,
-we've dropped the beta labeling and released "Android 1.0 SDK, release
-1". Applications developed on this SDK version will be compatible with
-devices that run the Android 1.0 platform.</p>
-
-<h3>Device Availability</h3>
-<p>The first Android-powered device, the T-Mobile G1, was announced on 23 September,
-2008. To learn more about the T-Mobile G1, see the <a href="http://www.t-mobileg1.com">T-Mobile G1 site</a>.
-
-<p>Other partners will be releasing Android-powered devices in the future.
-We will update this space with more specific information about each device
-release, as it becomes
-available.</p>
-
-<h3>Source Code Release</h3>
-<p>
-We are currently in the process of preparing for the release of the source
-code. This includes a few key tasks:
-</p><ul>
-<li>Selection of hosting infrastructure</li>
-<li>Updating the build infrastructure for general use</li>
-<li>Creation of a project governance framework</li>
-<li>Final examination of source code for release approval</li>
-<li>Physical upload and release packaging of the source code</li>
-</ul><p>
-This work is already under way, but since Android contains some 8 million
-lines of code, it's a lengthy process. We expect this process to conclude
-(and source code to be released) in Q4 of 2008.
-</p>
-<h3>Android Developer Challenge II</h3>
-<p>
-When Android was announced on 5 November, 2007, Google also announced a $10
-million <a href="{@docRoot}adc.html">Android Developer Challenge</a>, split into two separate $5 million
-events. The first Android Developer Challenge ran from January 2008 through
-August 2008, and was intended to give developers an opportunity to explore
-their ideas using the early look SDK and build prototype applications -- to
-"get in on the ground floor." The second Challenge will give developers a
-chance to build polished applications once hardware is available.
-</p><p>
-We'll be making some interesting announcements regarding ADC II soon, in Q3 or
-Q4.
-</p>
diff --git a/docs/html/robots.txt b/docs/html/robots.txt
new file mode 100644
index 0000000..a872944
--- /dev/null
+++ b/docs/html/robots.txt
@@ -0,0 +1,6 @@
+User-Agent: *
+Allow: /
+Disallow: /gae_shell/
+Disallow: /assets/
+Disallow: /images/
+Sitemap: http://developer.android.com/sitemap.txt
diff --git a/docs/html/samples/index.jd b/docs/html/samples/index.jd
index 6219f9a..c5c0b71 100644
--- a/docs/html/samples/index.jd
+++ b/docs/html/samples/index.jd
@@ -17,7 +17,7 @@ page.onlyfortemplate=codesite
</dl>
<p>To run these samples, you should <a
-href="{@docRoot}intro/installing.html#creatingaproject">import them into
-Eclipse</a> or <a href="{@docRoot}intro/installing.html#otherides">use
+href="{@docRoot}guide/developing/eclipse-adt.html#creatingaproject">import them into
+Eclipse</a> or <a href="{@docRoot}guide/developing/other-ide.html">use
activitycreator.py</a>, as described in the <a
-href="{@docRoot}intro/installing.html">Installing the SDK</a>.</p>
+href="{@docRoot}sdk/1.1_r1/installing.html">Installing the SDK</a>.</p>
diff --git a/docs/html/sdk/1.0_r1/RELEASENOTES.jd b/docs/html/sdk/1.0_r1/RELEASENOTES.jd
deleted file mode 100644
index c6a38bb..0000000
--- a/docs/html/sdk/1.0_r1/RELEASENOTES.jd
+++ /dev/null
@@ -1,100 +0,0 @@
-page.title=Release Notes, 1.0 r1
-@jd:body
-
-
-<p>This SDK release is the first to include the Android 1.0 platform and application API. Applications developed on this SDK will be compatible with mobile devices running the Android 1.0 platform, when such devices are available.</p>
-
-<p>This release includes mainly bug fixes, although some smaller features were added. The Android 1.0 also includes several API changes from the 0.9 version. For more information on API changes, see the <a href="{@docRoot}migrating/0.9-1.0/changes-overview.html">Overview of Changes</a> and the <a href="{@docRoot}migrating/0.9-1.0/changes.html">API Differences Report</a>. For those porting from the M5 release, the SDK also includes the legacy changes overview and API Differences Reports. See the current Overview of Changes for more information. </p>
-
-<h3>ADT Plugin Compatibility</h3>
-
-<p>For this version of the SDK &mdash; Android 1.0 SDK, Release 1 &mdash; the compatible version of the Android Development Tools (ADT) Plugin for Eclipse is <strong>0.8.0</strong>. If you are using a previous version of ADT, you should update to the latest version for use with this SDK. For information about how to update your ADT plugin, see <a href="{@docRoot}intro/upgrading.html">Upgrading the SDK</a>.</p>
-
-<h3>Installation and Upgrade Notes</h3>
-
-<p>If you've been developing an application using a previous SDK version and you want the application to run on Android-powered mobile devices, you must port the application to the Android 1.0 SDK. Please see <a href="{@docRoot}intro/upgrading.html">Upgrading the SDK</a> for detailed instructions on how to make the transition to this release. Be sure to wipe application user data (emulator option <code>-wipe-data</code>) when running your application on the Android 1.0 SDK emulator.</p>
-
-<p>If you're installing the Android SDK for the first time, please see the instructions in <a href="{@docRoot}intro/installing.html">Installing the SDK</a>.
-
-<h3>Other Notes</h3>
-
-<p><strong>MapView API Key</strong></p>
-
-<p>MapView is a class that lets you easily integrate Google Maps into your application. Before you can access the maps data, you will need to register with the Google Maps service and receive a Maps API Key, which you then add to your MapView for authentication to the server.</p>
-
-<p>Currently, the registration service for MapView is not yet active and Google Maps is not yet enforcing the Maps API Key requirement. However, note that the registration service will be activated soon, so that MapViews in any application deployed to a mobile device will require registration and a valid Maps API Key. </p>
-
-<p>As soon as the registration service becomes available, we will update the page at <a href="http://code.google.com/android/toolbox/apis/mapkey.html">http://code.google.com/android/toolbox/apis/mapkey.html</a> with details about how and where to register. Please check that page periodically for registration information, if you are using a MapView.</p>
-
-
-<h3>Resolved Issues, Changes</h3>
-
-<p><strong>Emulator</strong></p>
-<ul>
-<li>Emulator now saves the user image in &lt;android&gt;/SDK1.0/</code></li>
-<li>Fixed EsounD-related freezes on Linux.</li>
-<li>Fixed the documentation in -help-audio. '-audio list' doesn't work, one
- needs to call -help-audio-out and -help-audio-in to get the list of valid
- audio backends.</li>
-<li>Fixed scrollwheel Dpad emulation in rotated mode. before that, using the
- scroll-wheel would always generated Dpad Up/Down events, even when in
- landscape mode.</li>
-<li>Several Obsolete command options were removed.</li>
-<li>Setting the network speed through the console or the -netspeed option will
- properly modify the connectivity icon on the device.</li>
-<li>Setting the GSM voice registration state to 'roaming' in the console will
- properly modify the voice icon on the device</li>
-</ul>
-
-<p><strong>SQLite</strong></p>
-<ul>
-<li>SQLite is now included in the SDK package on all platforms. </li>
-</ul>
-
-<h3>Known Issues</h3>
-
-<p><strong>JUnit and Eclipse/ADT</strong></p>
-<ul>
-<li>If you are developing in Eclipse/ADT and want to add JUnit test
-classes, you can do so. However, you need to set up a custom JUnit configuration
-before your tests will run properly. For detailed information about how to set
-up the JUnit configuration, see the troubleshooting topic <a
-href="{@docRoot}kb/troubleshooting.html#addjunit">Running a Junit test class
-in Eclipse</a>.</li>
-</ul>
-
-<p><strong>Other</strong></p>
-
-<ul>
-<li>It is not possible to send MMS messages between emulator instances. </li>
-<li>In some cases, you may encounter problems when using the browser on an
-emulator started with the command-line option <code>-http-proxy</code>. </li>
-<li>We regret to inform developers that Android 1.0 will not include support for
-dot-matrix printers.</li>
-<li>On the OSX platform, if you manually remove the ~/.android directory
-using <code>rm -rf ~/.android</code>, then try to run
-the emulator, it crashes. This happens because the emulator fails to create
-a new .android directory before attempting to create the child SDK1.0 directory.
-To work around this issue, manually create a new .android directory using
-<code>mkdir ~/.android</code>, then run the emulator. The emulator
-creates the SDK1.0 directory and starts normally. </li>
-<li>The final set of Intent patterns honored by Android 1.0 has not yet been
-fully documented. Documentation will be provided in future releases.</li>
-<li>In ADT Editor, you can add at most ten new resource values at a time,
-in a given res/values/*.xml, using the form in the Android Resources pane.
-If you add more than ten, the Android Resources pane will not display the
-attributes fields for the additional resource entries. To work around this
-problem, you can close the file in the editor and open it again, or you
-can edit the resource entries in the XML text mode. </li>
-<li>The emulator's battery-control commands (<code>power &lt;option&gt</code>)
-are not working in this release.</li>
- <li>We regret to inform developers that Android 1.0 will not support 3.5" floppy disks.
- </li>
- <li>Unfortunately, the ability to play audio streams from memory (such as via an InputStream or Reader) will not be possible in Android 1.0.&nbsp; 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).
- </li>
- <li>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.
- </li>
- <li>We believe that we have eliminated the problem with very long emulator startups on Windows, but had some trouble reproducing the issue.&nbsp; We are interested in feedback from developers, if this issue persists.
- </li>
-</ul>
-
diff --git a/docs/html/sdk/1.0_r1/index.jd b/docs/html/sdk/1.0_r1/index.jd
index 7ad4e88..b6e0e9f 100644
--- a/docs/html/sdk/1.0_r1/index.jd
+++ b/docs/html/sdk/1.0_r1/index.jd
@@ -1,6 +1,8 @@
-page.title=Download 1.0r1
+page.title=Android 1.0 SDK, release 1
-sdk.version=Android 1.0 SDK, release 1
+sdk.not_latest_version=true
+
+sdk.version=1.0_r1
sdk.date=September 23, 2008
sdk.win_download=android-sdk-windows-1.0_r1.zip
@@ -15,4 +17,49 @@ sdk.linux_download=android-sdk-linux_x86-1.0_r1.zip
sdk.linux_bytes=87.8 MB
sdk.linux_checksum=2660b4029039b7d714e59827e9a9a11d
+
@jd:body
+
+<h2>Included in this SDK</h2>
+
+<h4>Development tools</h4>
+
+<p>The SDK includes a variety of tools for developing and debugging application code and designing
+an application UI. You can read about the tools in the documentation included with the SDK.
+You can access the tools in the <code>&lt;sdk&gt;/tools/</code> directory.</p>
+
+<h4 id="system_images">System Images</h4>
+
+<p>The Android system images listed below are included in this SDK.</p>
+
+<table style="margin-right:1em;" width="80%">
+<tr>
+<th><nobr>System Image</nobr></th><th><nobr>API Level</nobr></th><th>Notes</th><th>Description</th>
+</tr>
+
+<tr>
+<td width="5%"><nobr>Android 1.0</nobr></td>
+<td width="5%">1</td>
+<td width="5%"><nobr>N/A</nobr></td>
+<td>Includes the {@code com.google.android.maps} external library and a set of standard development
+applications. </td>
+
+</tr>
+
+</table>
+
+<h4>Sample Code and Applications</h4>
+
+<p>You can look at a variety of tutorials and samples in the
+documentation included with the SDK and access the sample code itself
+in the <code>&lt;sdk&gt;/samples/</code> directory of the SDK package.</p>
+
+<h4>Documentation</h4>
+
+<p>The SDK package provides a full set of local documentation, including installation and upgrade
+instructions. To view it, open the <code>&lt;sdk&gt;/documentation.html</code> file in a web browser.
+If you are developing in an IDE such as Eclipse, you can also view the reference documentation
+directly in the IDE. </p>
+
+
+
diff --git a/docs/html/sdk/1.0_r1/installing.jd b/docs/html/sdk/1.0_r1/installing.jd
index 0f15396..8ac524c 100644
--- a/docs/html/sdk/1.0_r1/installing.jd
+++ b/docs/html/sdk/1.0_r1/installing.jd
@@ -1,29 +1,27 @@
page.title=Installing the SDK
+sdk.version=1.0_r1
@jd:body
+<p>For the current SDK release, see the links under <strong>Current SDK Release</strong> in the side navigation.</p>
-<p>This page describes how to install the Android SDK and set up your development environment. If you haven't
-downloaded the SDK yet, follow the link below.</p>
+<p>This page describes how to install the Android 1.0 SDK, Release 1, and set up your development environment.
+If you haven't downloaded the SDK yet, you can so from the <a href="{@docRoot}sdk/1.0_r1/index.html">Download</a> page.</p>
-<div class="linkbox"><a href="http://developer.android.com/sdk/">Download the SDK</a></div>
+<p>Before you begin, be sure that your development environment meets the SDK
+<a href="{@docRoot}sdk/1.0_r1/requirements.html">System Requirements</a>. If you encounter any problems during installation,
+see the <a href="#installnotes">Installation Notes</a> at the bottom of this page.</p>
-<p>Before you begin, be sure that you're development environment meets the SDK
-<a href="requirements.html">System and Software Requirements</a>.</p>
-
-<div class="special">
<h4 style="margin-top">Upgrading?</h4>
<p>If you have already developed applications using an earlier version of the
SDK, please skip this page and read the
-<b><a href="upgrading.html">Upgrading the SDK</a></b> document.
+<a href="{@docRoot}sdk/1.0_r1/upgrading.html"><strong>Upgrading the SDK</strong></a></b> document instead.
</p>
-</div>
-
<a name="installingsdk"></a>
<a name="setup"></a>
<h2>Installing the SDK</h2>
- <p>After downloading the SDK, unpack the .zip archive to a suitable location on your machine. By default, the SDK files are unpacked into a directory named <code>android_sdk_<em>&lt;platform</em>&gt;_<em>&lt;release&gt;</em>_<em>&lt;build&gt;</em></code>. The directory contains the subdirectories <code>tools/</code>, <code>samples/</code>, and others. </p>
+ <p>After downloading the SDK, unpack the .zip archive to a suitable location on your machine. By default, the SDK files are unpacked into a directory named <code>android_sdk_<em>&lt;platform</em>&gt;_<em>&lt;release&gt;</em>_<em>&lt;build&gt;</em></code>. The directory contains a link to a local copy of the documentation and the subdirectories <code>tools/</code>, <code>samples/</code>, and others. </p>
<p>Make a note of the name and location of the unpacked SDK directory on your system &mdash; you will need to refer to the SDK directory later, when setting up the Android plugin or using SDK tools. </p>
@@ -47,10 +45,86 @@ SDK, please skip this page and read the
<p>Adding <code>tools</code> to your path lets you run Android Debug Bridge (adb) and the other command line <a href="{@docRoot}guide/developing/tools/index.html">tools</a> without needing to supply the full path to the tools directory. Note that, if you update your SDK, you should remember to update your PATH settings to point to the new location, if different.</p>
-<h3>Setting up Eclipse</h3>
-<p>If you'll be developing with the Eclipse IDE, follow the following procedure to setup the IDE
-to use the Android SDK.</p>
-<p>Basically, you just need to update your Eclipse preferences to point to the Android SDK directory:</p>
+
+<p>If you will be using the Eclipse IDE as your environment for developing Android applications, continue reading the next
+section in order to install the Android Development Tools plugin and setup Eclipse. If you choose not to use Eclipse, you can
+develop Android applications using other tools &mdash; read the guide to developing
+<a href="{@docRoot}guide/developing/other-ide.html">In other IDEs</a>.</p>
+
+
+<h2>Setting up Eclipse</h2>
+
+<p>First, you should install a custom plugin called Android Development Tools (ADT), which adds integrated support for Android projects and tools. The ADT plugin includes a variety of powerful extensions that make creating, running, and debugging Android applications faster and easier. Developing in ADT/Eclipse is highly recommended for Eclipse users and those new to Android.</p>
+
+<p>To download and install the ADT plugin, follow the steps below for your respective Eclipse version. </p>
+
+<table style="font-size:100%">
+<tr><th>Eclipse 3.3 (Europa)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
+<tr>
+<td width="45%">
+<ol>
+ <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Software Updates</strong> &gt; <strong>Find
+ and Install...</strong>. </li>
+
+ <li>In the dialog that appears, select <strong>Search for new features to install</strong> and click <strong>Next</strong>. </li>
+ <li>Click <strong>New Remote Site</strong>. </li>
+ <li>In the resulting dialog box, enter a name for the remote site (e.g. Android Plugin) and enter this as its URL:
+ <pre>https://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Alternatively, you can use http in the Location URL, if you are having
+ trouble with https (https is preferred for security reasons).</p>
+ <pre>http://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Click <strong>OK</strong>.</p> </li>
+ <li>You should now see the new site added to the search list (and checked).
+ Click <strong>Finish</strong>. </li>
+ <li>In the subsequent Search Results dialog box, select the checkbox for
+ <strong>Android Plugin</strong> &gt; <strong>Developer Tools</strong>.
+ This will check both features: "Android Developer Tools", and "Android
+ Editors". The Android Editors feature is optional, but recommended. If
+ you choose to install it, you need the WST plugin mentioned earlier in this
+ page. Click <strong>Next</strong>. </li>
+ <li>Read the license agreement and then select <strong>Accept terms of the license agreement</strong>.
+ Click <strong>Next</strong>. </li>
+ <li>Click <strong>Finish</strong>. </li>
+
+ <li>The ADT plugin is not signed; you can accept the installation anyway
+ by clicking <strong>Install All</strong>. </li>
+ <li>Restart Eclipse. </li>
+</ol>
+
+</td>
+<td>
+
+<ol>
+ <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Software Updates...</strong>.
+ </li>
+ <li>In the dialog that appears, click the <strong>Available Software</strong> tab.
+ </li>
+ <li>Click <strong>Add Site...</strong>
+ </li>
+ <li>Enter this as the Location:
+ <pre>https://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Alternatively, you can use http in the Location URL, if you are having
+ trouble with https (https is preferred for security reasons).</p>
+ <pre>http://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Click <strong>OK</strong>.</p></li>
+ <li>Back in the Available Software view, you should see the plugin. Select the checkbox next to
+ <em>Developer Tools</em> and click <strong>Install...</strong>
+ </li>
+ <li>On the subsequent Install window, "Android Developer Tools", and "Android Editors" should both be checked.
+ The Android Editors feature is optional, but recommended. If
+ you choose to install it, you need the WST plugin mentioned earlier in this
+ page. Click <strong>Next</strong>.
+ </li>
+ <li>Accept the license agreement and click <strong>Finish</strong>.</li>
+ <li>Restart Eclipse. </li>
+</ol>
+
+</td>
+</tr>
+</table>
+
+
+<p>Now, you just need to modify your Eclipse preferences to point to the Android SDK directory:</p>
<ol>
<li>Select <strong>Window</strong> &gt; <strong>Preferences...</strong> to open the Preferences
panel. (Mac OS X: <strong>Eclipse</strong> &gt; <strong>Preferences</strong>) </li>
@@ -58,16 +132,55 @@ to use the Android SDK.</p>
<li>For the SDK Location in the main panel, click <strong>Browse...</strong> and locate the SDK directory. </li>
<li>Click <strong>Apply</strong>, then <strong>OK</strong>.</li>
</ol>
-<p>Done! We now recommend that you install the ADT Eclipse plugin, which will provide some much-appreciated assistance in developing Android apps with Eclipse...</p>
-<a name="installingplugin"></a>
-<h2>Installing the Eclipse Plugin (ADT)</h2>
+<p>Done! If you haven't encountered any problems, then you're ready to begin developing Android applications.
+We recommend you begin with the <a href="{@docRoot}guide/tutorials/hello-world.html">Hello World</a> tutorial,
+which will teach you some basics about Android applications and how to create projects using Eclipse.</p>
-<p>If you will be using the Eclipse IDE as your environment for developing Android applications, you can install a custom plugin called Android Development Tools (ADT), which adds integrated support for Android projects and tools. The ADT plugin includes a variety of powerful extensions that make creating, running, and debugging Android applications faster and easier. This plugin is highly recommended for Eclipse users.</p>
-<p>If you <em>will not</em> be using the Eclipse IDE, you do not need to download or install the ADT plugin.</p>
+<h3 id="troubleshooting">Troubleshooting ADT Installation</h3>
+<p>
+If you are having trouble downloading the ADT plugin after following the steps above, here are some suggestions: </p>
-<p><strong>Follow this guide to install the ADT Plugin</strong></p>
+<ul>
+ <li>If Eclipse can not find the remote update site containing the ADT plugin, try changing the remote site URL to use http, rather than https. That is, set the Location for the remote site to:
+ <pre>http://dl-ssl.google.com/android/eclipse/</pre></li>
+ <li>If you are behind a firewall (such as a corporate firewall), make
+ sure that you have properly configured your proxy settings in Eclipse.
+ In Eclipse 3.3/3.4, you can configure proxy information from the main
+ Eclipse menu in <strong>Window</strong> (on Mac, <strong>Eclipse</strong>) &gt; <strong>Preferences</strong> &gt; <strong>General</strong> &gt; <strong>Network Connections</strong>.</li>
+</ul>
+<p>
+If you are still unable to use Eclipse to download the ADT plugin as a remote update site, you can download the ADT files to your local machine using a browser and the install the files in Eclipse from there:
+</p>
+<ol>
+<li><a href="{@docRoot}sdk/adt_download.html">Download the ADT zip file</a> (do not unpack it).
+<li>Follow steps 1 and 2 in the default install instructions (above).
+<li>In Eclipse 3.3, click <strong>New Archive Site...</strong>. <br/>
+ In Eclipse 3.4, click <strong>Add Site...</strong>, then <strong>Archive...</strong>
+<li>Browse and select the downloaded the zip file.
+<li>Follow the remaining procedures, above, starting from steps 5.
+</ol>
+<p>
+Note that to update your plugin, you will have to follow these steps again instead of the default update instructions.</p>
+
+<p>Note that the "Android Editors" feature of ADT requires several optional
+Eclipse components (for example, WST). If you encounter an error when
+installing ADT, your Eclipse installion might not include those components.
+For information about how to quickly add the necessary components to your
+Eclipse installation, see the troubleshooting topic
+<a href="{@docRoot}guide/appendix/faq/troubleshooting.html#installeclipsecomponents">ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui"</a>.</p>
+
+<h4>For Linux users</h4>
+<p>If you encounter this error when installing the ADT Plugin for Eclipse:
+<pre>
+An error occurred during provisioning.
+Cannot connect to keystore.
+JKS</pre>
+<p>
+...then your development machine lacks a suitable Java VM. Installing Sun
+Java 6 will resolve this issue and you can then reinstall the ADT
+Plugin.</p>
<a name="installnotes"></a>
<h2>Installation Notes</h2>
@@ -106,19 +219,3 @@ at the top of this page. In particular, note that some Linux
distributions may include JDK 1.4 or Gnu Compiler for Java, both of
which are not supported for Android development.</li>
</ul>
-
-<a name="developingwitheclipse"></a>
-<a name="existingcode"></a>
-<a name="creatingaproject" id="creatingaproject"></a>
-<a name="launchconfig" id="launchconfig"></a>
-<a name="installingrunningdebugging" id="installingrunningdebugging"></a>
-<a name="otherides" id="otherides"></a>
-<a name="buildingwithant"></a>
-<a name="debugging" id="debugging"></a>
-<a name="additionaldebugging" id="additionaldebugging"></a>
-<a name="toptips" id="toptips"></a>
-<a name="debughelpers"></a>
-<a name="uninstalling" id="uninstalling"></a>
-<a name="tips" id="tips"></a>
-<a name="eclipse" id="eclipse"></a>
-<a name="building"></a>
diff --git a/docs/html/sdk/1.0_r1/terms.jd b/docs/html/sdk/1.0_r1/terms.jd
deleted file mode 100644
index 5c6e6fc..0000000
--- a/docs/html/sdk/1.0_r1/terms.jd
+++ /dev/null
@@ -1,7 +0,0 @@
-page.title=Terms and Conditions
-@jd:body
-
-<?cs include:"terms_body.html" ?>
-
-
-
diff --git a/docs/html/sdk/1.0_r1/upgrading.jd b/docs/html/sdk/1.0_r1/upgrading.jd
index 168f1be..480bff3 100644
--- a/docs/html/sdk/1.0_r1/upgrading.jd
+++ b/docs/html/sdk/1.0_r1/upgrading.jd
@@ -1,37 +1,12 @@
page.title=Upgrading the SDK
+sdk.version=1.0_r1
@jd:body
-<div class="sidebox-wrapper">
- <div class="sidebox-inner">
-
- <h2>Useful Links</h2>
-
- <ul class="noindent">
- <li><a href="migrating/0.9-1.0/changes-overview.html">Overview of Changes</a>
- <p>A high-level look at what's changed in Android, with
- discussion of how the changes may affect your apps.</p></li>
-
- <li><a href="migrating/0.9-1.0/changes.html">API Diff Report</a>
- <p>A detailed report that lists all the specific changes in the latest SDK.</p></li>
-
- <li><a href="RELEASENOTES.html">Release Notes</a>
- <p>Version details, known issues, and resolved issues. </p></li>
-
- <li><a href="http://groups.google.com/group/android-developers">Android Developers Group</a>
- <p>A forum where you can discuss migration issues and learn from other Android developers. </p></li>
-
- <li><a href="http://code.google.com/p/android/issues/list">Android Issue Tracker</a>
- <p>If you think you may have found a bug, use the issue tracker to report it.</p></li>
- </ul>
-
- </div>
-</div><!-- class-sidebox -->
-
+<p>For the current SDK release, see the links under <strong>Current SDK Release</strong> in the side navigation.</p>
<p>This guide will help you migrate your development environment and applications
-to the latest version of the SDK. Use this guide if you've been developing applications
-on a previous version of the Android SDK.
-</p>
+to <strong>version 1.0, release 1</strong>, of the Android SDK. Use this guide if you've been developing applications
+on a different version of the Android SDK.</p>
<p>To ensure that your applications are compliant with the Android 1.0 system available
on mobile devices, you need to install the new SDK and port your existing Android
@@ -39,9 +14,7 @@ applications to the updated API. The sections below guide you through the proces
<h2 id="install-new">Install the new SDK</h2>
-<p><a href="{@docRoot}download.html">Download the SDK</a> and unpack it into a safe location.</p>
-
-<p>After unpacking the new SDK, you should:</p>
+<p>After unpacking the SDK, you should:</p>
<ul>
<li>Wipe your emulator data. <p>Some data formats have changed since the last
@@ -60,27 +33,58 @@ applications to the updated API. The sections below guide you through the proces
<h2 id="update-plugin">Update your ADT Eclipse Plugin</h2>
-<p>If you develop on Eclipse and are using the ADT plugin, follow these steps to install the new plugin that accompanies the latest SDK.</p>
+<p>If you develop on Eclipse and are using the ADT plugin, follow these steps to install the
+plugin that's required for this version of the SDK.</p>
<table style="font-size:100%">
<tr><th>Eclipse 3.3 (Europa)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
<tr>
-<td width="50%">
+<td width="45%">
<ol>
- <li> Select <strong>Help</strong> &gt; <strong>Software Updates</strong> &gt; <strong>Find and Install...</strong>. </li>
- <li> Select <strong>Search for updates of the currently installed features</strong> and click <strong>Finish</strong>. </li>
- <li> If any update for ADT is available, select and install. </li>
- <li> Restart Eclipse.</li>
+ <li><a href="http://dl-ssl.google.com/android/ADT-0.8.0.zip">Download the ADT v0.8.0 zip
+ file</a> (do not unpack it).</li>
+ <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Software Updates</strong> &gt; <strong>Find
+ and Install...</strong>. </li>
+ <li>In the dialog that appears, select <strong>Search for new features to install</strong> and click
+ <strong>Next</strong>. </li>
+ <li>Click <strong>New Archive Site...</strong></li>
+ <li>Browse and select the downloaded the zip file.</li>
+ <li>You should now see the new site added to the search list (and checked).
+ Click <strong>Finish</strong>. </li>
+ <li>In the subsequent Search Results dialog box, select the checkbox for
+ <strong>Android Plugin</strong> &gt; <strong>Developer Tools</strong>.
+ This will check both features: "Android Developer Tools", and "Android
+ Editors". The Android Editors feature is optional, but recommended. If
+ you choose to install it, you need the WST plugin mentioned earlier in this
+ page. Click <strong>Next</strong>. </li>
+ <li>Read the license agreement and then select <strong>Accept terms of the license agreement</strong>.
+ Click <strong>Next</strong>. </li>
+ <li>Click <strong>Finish</strong>. </li>
+ <li>The ADT plugin is not signed; you can accept the installation anyway
+ by clicking <strong>Install All</strong>. </li>
+ <li>Restart Eclipse. </li>
</ol>
+
</td>
<td>
+
<ol>
- <li>Select <strong>Help</strong> &gt; <strong>Software Updates...</strong></li>
- <li>Select the <strong>Installed Software</strong> tab.</li>
- <li>Click <strong>Update...</strong></li>
- <li>If an update for ADT is available, select it and click <strong>Finish</strong>.</li>
- <li>Restart Eclipse.</li>
+ <li><a href="http://dl-ssl.google.com/android/ADT-0.8.0.zip">Download the ADT v0.8.0 zip
+ file</a> (do not unpack it).</li>
+ <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Software Updates...</strong>.</li>
+ <li>In the dialog that appears, click the <strong>Available Software</strong> tab.</li>
+ <li>Click <strong>Add Site...</strong>, then <strong>Archive...</strong>.</li>
+ <li>Browse and select the downloaded the zip file.</li>
+ <li>Back in the Available Software view, you should see the plugin. Select the checkbox next to
+ <em>Developer Tools</em> and click <strong>Install...</strong></li>
+ <li>On the subsequent Install window, "Android Developer Tools", and "Android Editors" should both be checked.
+ The Android Editors feature is optional, but recommended. If
+ you choose to install it, you need the WST plugin mentioned earlier in this
+ page. Click <strong>Next</strong>.</li>
+ <li>Accept the license agreement and click <strong>Finish</strong>.</li>
+ <li>Restart Eclipse. </li>
</ol>
+
</td>
</tr>
</table>
@@ -99,7 +103,7 @@ applications to the updated API. The sections below guide you through the proces
the ADT plugin and the Ant-based build tools support this requirement by signing compiled
.apk files with a debug key. To do so, the build tools use the Keytool utility included
in the JDK to to create a keystore and a key with a known alias and password. For more
-information, see <a href="{@docRoot}guide/publishing/app-signing.html">Signing Your Applications</a>.
+information, see "Signing and Publishing Your App" in the documentation included with the SDK.
<p>To support signing, you should first make sure that Keytool is available to the SDK build
tools. In most cases, you can tell the SDK build tools how to find Keytool by making sure that
@@ -133,10 +137,7 @@ to place 3rd jar files, which are now automatically handled by the Ant script.</
framework and API changes. You'll need to update your code to match changes in the Android APIs.</p>
<p>One way to start is to open your project in Eclipse and see where the ADT
-identifies errors in your application. From there, you can lookup
-respective changes in the
-<a href="migrating/changes-overview.html">Overview of Changes</a>
-and <a href="migrating/changes.html">API Diffs Report</a>.</p>
+identifies errors in your application.</p>
<p>If you have additional trouble updating your code, visit the
<a href="http://groups.google.com/group/android-developers">Android Developers Group</a>
@@ -144,8 +145,4 @@ to seek help from other Android developers.</p>
<p>If you have modified one of the ApiDemos applications and would like to migrate it
to the new SDK, note that you will need to uninstall the version of ApiDemos that comes
-preinstalled in the emulator. For more information, or if you encounter an "reinstallation"
-error when running or installing ApiDemos, see the troubleshooting topic
-<a href="{@docRoot}guide/appendix/faq/troubleshooting.html#apidemosreinstall">I can't install ApiDemos
-apps in my IDE because of a signing error</a> for information about how to solve the problem.</p>
-
+preinstalled in the emulator.</p>
diff --git a/docs/html/sdk/1.0_r2/index.jd b/docs/html/sdk/1.0_r2/index.jd
new file mode 100644
index 0000000..2446c09
--- /dev/null
+++ b/docs/html/sdk/1.0_r2/index.jd
@@ -0,0 +1,65 @@
+page.title=Android 1.0 SDK, release 2
+
+sdk.not_latest_version=true
+
+sdk.version=1.0_r2
+sdk.date=November 2008
+
+sdk.win_download=android-sdk-windows-1.0_r2.zip
+sdk.win_bytes=98360564
+sdk.win_checksum=a5e1af8ac145946b4a9627516ad4a711
+
+sdk.mac_download=android-sdk-mac_x86-1.0_r2.zip
+sdk.mac_bytes=93771410
+sdk.mac_checksum=87b99d5e9f59b78363a63200c11498e8
+
+sdk.linux_download=android-sdk-linux_x86-1.0_r2.zip
+sdk.linux_bytes=94186463
+sdk.linux_checksum=a1f3b6d854596f850f5008856d0f380e
+
+
+@jd:body
+
+<h2>Included in this SDK</h2>
+
+<h4>Development tools</h4>
+
+<p>The SDK includes a variety of tools for developing and debugging application code and designing
+an application UI. You can read about the tools in the documentation included with the SDK.
+You can access the tools in the <code>&lt;sdk&gt;/tools/</code> directory.</p>
+
+<h4 id="system_images">System Images</h4>
+
+<p>The Android system images listed below are included in this SDK.</p>
+
+<table style="margin-right:1em;" width="80%">
+<tr>
+<th><nobr>System Image</nobr></th><th><nobr>API Level</nobr></th><th>Notes</th><th>Description</th>
+</tr>
+
+<tr>
+<td width="5%"><nobr>Android 1.0</nobr></td>
+<td width="5%">1</td>
+<td width="5%"><nobr>N/A</nobr></td>
+<td>Includes the {@code com.google.android.maps} external library and a set of standard development
+applications. </td>
+
+</tr>
+
+</table>
+
+<h4>Sample Code and Applications</h4>
+
+<p>You can look at a variety of tutorials and samples in the
+documentation included with the SDK and access the sample code itself
+in the <code>&lt;sdk&gt;/samples/</code> directory of the SDK package.</p>
+
+<h4>Documentation</h4>
+
+<p>The SDK package provides a full set of local documentation, including installation and upgrade
+instructions. To view it, open the <code>&lt;sdk&gt;/documentation.html</code> file in a web browser.
+If you are developing in an IDE such as Eclipse, you can also view the reference documentation
+directly in the IDE. </p>
+
+
+
diff --git a/docs/html/sdk/1.0_r2/installing.jd b/docs/html/sdk/1.0_r2/installing.jd
new file mode 100644
index 0000000..2c58dfd
--- /dev/null
+++ b/docs/html/sdk/1.0_r2/installing.jd
@@ -0,0 +1,221 @@
+page.title=Installing the SDK
+sdk.version=1.0_r2
+@jd:body
+
+<p>For the current SDK release, see the links under <strong>Current SDK Release</strong> in the side navigation.</p>
+
+<p>This page describes how to install the Android 1.0 SDK, Release 2, and set up your development environment.
+If you haven't downloaded the SDK yet, you can so from the <a href="{@docRoot}sdk/1.0_r2/index.html">Download</a> page.</p>
+
+<p>Before you begin, be sure that your development environment meets the SDK
+<a href="{@docRoot}sdk/1.0_r2/requirements.html">System Requirements</a>. If you encounter any problems during installation,
+see the <a href="#installnotes">Installation Notes</a> at the bottom of this page.</p>
+
+<h4 style="margin-top">Upgrading?</h4>
+<p>If you have already developed applications using an earlier version of the
+SDK, please skip this page and read the
+<a href="{@docRoot}sdk/1.0_r2/upgrading.html"><strong>Upgrading the SDK</strong></a></b> document instead.
+</p>
+
+<a name="installingsdk"></a>
+<a name="setup"></a>
+<h2>Installing the SDK</h2>
+
+ <p>After downloading the SDK, unpack the .zip archive to a suitable location on your machine. By default, the SDK files are unpacked into a directory named <code>android_sdk_<em>&lt;platform</em>&gt;_<em>&lt;release&gt;</em>_<em>&lt;build&gt;</em></code>. The directory contains a link to a local copy of the documentation and the subdirectories <code>tools/</code>, <code>samples/</code>, and others. </p>
+
+ <p>Make a note of the name and location of the unpacked SDK directory on your system &mdash; you will need to refer to the SDK directory later, when setting up the Android plugin or using SDK tools. </p>
+
+ <p>Optionally, you can add the path to the SDK <code>tools</code> directory to your path. As mentioned above, the <code>tools/</code> directory is located in the SDK directory. </p>
+ <ul>
+ <li>On Linux, edit your ~/.bash_profile or ~/.bashrc file. Look
+ for a line that sets the PATH environment variable and add the
+ full path to the <code>tools/</code> directory to it. If you don't
+ see a line setting the path, you can add one:</li>
+
+ <ul><code>export PATH=${PATH}:<em>&lt;your_sdk_dir&gt;</em>/tools</code></ul>
+
+ <li>On a Mac, look in your home directory for .bash_profile and
+ proceed as for Linux. You can create the .bash_profile, if
+ you haven't already set one up on your machine. </li>
+
+ <li>On Windows, right click on My Computer, and select Properties.
+ Under the Advanced tab, hit the Environment Variables button, and in the
+ dialog that comes up, double-click on Path under System Variables. Add the full path to the <code>tools/</code> directory to the path. </li>
+ </ul>
+
+ <p>Adding <code>tools</code> to your path lets you run Android Debug Bridge (adb) and the other command line <a href="{@docRoot}guide/developing/tools/index.html">tools</a> without needing to supply the full path to the tools directory. Note that, if you update your SDK, you should remember to update your PATH settings to point to the new location, if different.</p>
+
+
+<p>If you will be using the Eclipse IDE as your environment for developing Android applications, continue reading the next
+section in order to install the Android Development Tools plugin and setup Eclipse. If you choose not to use Eclipse, you can
+develop Android applications using other tools &mdash; read the guide to developing
+<a href="{@docRoot}guide/developing/other-ide.html">In other IDEs</a>.</p>
+
+
+<h2>Setting up Eclipse</h2>
+
+<p>First, you should install a custom plugin called Android Development Tools (ADT), which adds integrated support for Android projects and tools. The ADT plugin includes a variety of powerful extensions that make creating, running, and debugging Android applications faster and easier. Developing in ADT/Eclipse is highly recommended for Eclipse users and those new to Android.</p>
+
+<p>To download and install the ADT plugin, follow the steps below for your respective Eclipse version. </p>
+
+<table style="font-size:100%">
+<tr><th>Eclipse 3.3 (Europa)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
+<tr>
+<td width="45%">
+<ol>
+ <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Software Updates</strong> &gt; <strong>Find
+ and Install...</strong>. </li>
+
+ <li>In the dialog that appears, select <strong>Search for new features to install</strong> and click <strong>Next</strong>. </li>
+ <li>Click <strong>New Remote Site</strong>. </li>
+ <li>In the resulting dialog box, enter a name for the remote site (e.g. Android Plugin) and enter this as its URL:
+ <pre>https://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Alternatively, you can use http in the Location URL, if you are having
+ trouble with https (https is preferred for security reasons).</p>
+ <pre>http://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Click <strong>OK</strong>.</p> </li>
+ <li>You should now see the new site added to the search list (and checked).
+ Click <strong>Finish</strong>. </li>
+ <li>In the subsequent Search Results dialog box, select the checkbox for
+ <strong>Android Plugin</strong> &gt; <strong>Developer Tools</strong>.
+ This will check both features: "Android Developer Tools", and "Android
+ Editors". The Android Editors feature is optional, but recommended. If
+ you choose to install it, you need the WST plugin mentioned earlier in this
+ page. Click <strong>Next</strong>. </li>
+ <li>Read the license agreement and then select <strong>Accept terms of the license agreement</strong>.
+ Click <strong>Next</strong>. </li>
+ <li>Click <strong>Finish</strong>. </li>
+
+ <li>The ADT plugin is not signed; you can accept the installation anyway
+ by clicking <strong>Install All</strong>. </li>
+ <li>Restart Eclipse. </li>
+</ol>
+
+</td>
+<td>
+
+<ol>
+ <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Software Updates...</strong>.
+ </li>
+ <li>In the dialog that appears, click the <strong>Available Software</strong> tab.
+ </li>
+ <li>Click <strong>Add Site...</strong>
+ </li>
+ <li>Enter this as the Location:
+ <pre>https://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Alternatively, you can use http in the Location URL, if you are having
+ trouble with https (https is preferred for security reasons).</p>
+ <pre>http://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Click <strong>OK</strong>.</p></li>
+ <li>Back in the Available Software view, you should see the plugin. Select the checkbox next to
+ <em>Developer Tools</em> and click <strong>Install...</strong>
+ </li>
+ <li>On the subsequent Install window, "Android Developer Tools", and "Android Editors" should both be checked.
+ The Android Editors feature is optional, but recommended. If
+ you choose to install it, you need the WST plugin mentioned earlier in this
+ page. Click <strong>Next</strong>.
+ </li>
+ <li>Accept the license agreement and click <strong>Finish</strong>.</li>
+ <li>Restart Eclipse. </li>
+</ol>
+
+</td>
+</tr>
+</table>
+
+
+<p>Now, you just need to modify your Eclipse preferences to point to the Android SDK directory:</p>
+<ol>
+ <li>Select <strong>Window</strong> &gt; <strong>Preferences...</strong> to open the Preferences
+ panel. (Mac OS X: <strong>Eclipse</strong> &gt; <strong>Preferences</strong>) </li>
+ <li>Select <strong>Android</strong> from the left panel. </li>
+ <li>For the SDK Location in the main panel, click <strong>Browse...</strong> and locate the SDK directory. </li>
+ <li>Click <strong>Apply</strong>, then <strong>OK</strong>.</li>
+</ol>
+
+<p>Done! If you haven't encountered any problems, then you're ready to begin developing Android applications.
+We recommend you begin with the <a href="{@docRoot}guide/tutorials/hello-world.html">Hello World</a> tutorial,
+which will teach you some basics about Android applications and how to create projects using Eclipse.</p>
+
+
+<h3 id="troubleshooting">Troubleshooting ADT Installation</h3>
+<p>
+If you are having trouble downloading the ADT plugin after following the steps above, here are some suggestions: </p>
+
+<ul>
+ <li>If Eclipse can not find the remote update site containing the ADT plugin, try changing the remote site URL to use http, rather than https. That is, set the Location for the remote site to:
+ <pre>http://dl-ssl.google.com/android/eclipse/</pre></li>
+ <li>If you are behind a firewall (such as a corporate firewall), make
+ sure that you have properly configured your proxy settings in Eclipse.
+ In Eclipse 3.3/3.4, you can configure proxy information from the main
+ Eclipse menu in <strong>Window</strong> (on Mac, <strong>Eclipse</strong>) &gt; <strong>Preferences</strong> &gt; <strong>General</strong> &gt; <strong>Network Connections</strong>.</li>
+</ul>
+<p>
+If you are still unable to use Eclipse to download the ADT plugin as a remote update site, you can download the ADT files to your local machine using a browser and the install the files in Eclipse from there:
+</p>
+<ol>
+<li><a href="{@docRoot}sdk/adt_download.html">Download the ADT zip file</a> (do not unpack it).
+<li>Follow steps 1 and 2 in the default install instructions (above).
+<li>In Eclipse 3.3, click <strong>New Archive Site...</strong>. <br/>
+ In Eclipse 3.4, click <strong>Add Site...</strong>, then <strong>Archive...</strong>
+<li>Browse and select the downloaded the zip file.
+<li>Follow the remaining procedures, above, starting from steps 5.
+</ol>
+<p>
+Note that to update your plugin, you will have to follow these steps again instead of the default update instructions.</p>
+
+<p>Note that the "Android Editors" feature of ADT requires several optional
+Eclipse components (for example, WST). If you encounter an error when
+installing ADT, your Eclipse installion might not include those components.
+For information about how to quickly add the necessary components to your
+Eclipse installation, see the troubleshooting topic
+<a href="{@docRoot}guide/appendix/faq/troubleshooting.html#installeclipsecomponents">ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui"</a>.</p>
+
+<h4>For Linux users</h4>
+<p>If you encounter this error when installing the ADT Plugin for Eclipse:
+<pre>
+An error occurred during provisioning.
+Cannot connect to keystore.
+JKS</pre>
+<p>
+...then your development machine lacks a suitable Java VM. Installing Sun
+Java 6 will resolve this issue and you can then reinstall the ADT
+Plugin.</p>
+
+<a name="installnotes"></a>
+<h2>Installation Notes</h2>
+<h4>Ubuntu Linux Notes</h4>
+<ul>
+ <li>If you need help installing and configuring Java on your
+development machine, you might find these resources helpful:
+ <ul>
+ <li><a href="https://help.ubuntu.com/community/Java">https://help.ubuntu.com/community/Java </a></li>
+ <li><a href="https://help.ubuntu.com/community/Java">https://help.ubuntu.com/community/JavaInstallation </a></li>
+ </ul>
+ </li>
+<li>Here are the steps to install Java and Eclipse, prior to installing
+the Android SDK and ADT Plugin.
+<ol>
+ <li>If you are running a 64-bit distribution on your development
+machine, you need to install the <code>ia32-libs</code> package using
+<code>apt-get:</code>:
+ <pre>apt-get install ia32-libs</pre></li>
+ <li>Next, install Java:
+ <pre>apt-get install sun-java6-bin</pre></li>
+ <li>The Ubuntu package manager does not currently offer an Eclipse 3.3
+ version for download, so we recommend that you download Eclipse from
+eclipse.org (<a
+href="http://www.eclipse.org/downloads/">http://www.eclipse.org/
+downloads/</a>). A Java or RCP version of Eclipse is recommended.</li>
+<li>Follow the steps given in previous sections to install the SDK
+and the ADT plugin. </li>
+</ol>
+</ul>
+<h4>Other Linux Notes</h4>
+<ul>
+ <li>If JDK is already installed on your development computer, please
+take a moment to make sure that it meets the version requirements listed
+at the top of this page. In particular, note that some Linux
+distributions may include JDK 1.4 or Gnu Compiler for Java, both of
+which are not supported for Android development.</li>
+</ul>
diff --git a/docs/html/sdk/1.0_r2/requirements.jd b/docs/html/sdk/1.0_r2/requirements.jd
new file mode 100644
index 0000000..74d90ef
--- /dev/null
+++ b/docs/html/sdk/1.0_r2/requirements.jd
@@ -0,0 +1,44 @@
+page.title=System Requirements
+sdk.version=1.0_r2
+
+
+@jd:body
+
+<p>The sections below describe the system and software requirements for developing Android applications using the Android SDK tools included in Android 1.0 SDK, Release 2. </p>
+
+<h2>System and Software Requirements</h2>
+<p>The following systems and development environments are supported by this SDK.</p>
+
+<h4>Supported Operating Systems:</h4>
+<ul>
+ <li>Windows XP or Vista</li>
+ <li>Mac OS X 10.4.8 or later (x86 only)</li>
+ <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+</ul>
+
+<h4>Supported Development Environments:</h4>
+<ul>
+ <li>Eclipse IDE
+ <ul>
+ <li><a href="http://www.eclipse.org/downloads/">Eclipse</a> 3.3 (Europa), 3.4 (Ganymede)
+ <ul>
+ <li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included in most Eclipse IDE packages) </li>
+ <li><a href="http://www.eclipse.org/webtools">WST</a> (optional, but needed for the Android Editors feature; included in <a href="http://www.eclipse.org/downloads/moreinfo/compare.php">most Eclipse IDE packages</a>)</li>
+ </ul>
+ </li>
+ <li><a href="http://java.sun.com/javase/downloads/index.jsp">JDK 5 or JDK 6</a> (JRE alone is not sufficient)</li>
+ <li><a href="installing.html#installingplugin">Android Development Tools plugin</a> (optional)</li>
+ <li><strong>Not</strong> compatible with Gnu Compiler for Java (gcj)</li>
+ </ul>
+ </li>
+ <li>Other development environments or IDEs
+ <ul>
+ <li><a href="http://java.sun.com/javase/downloads/index.jsp">JDK 5 or JDK 6</a> (JRE alone is not sufficient)</li>
+ <li><a href="http://ant.apache.org/">Apache Ant</a> 1.6.5 or later for Linux and Mac, 1.7 or later for Windows</li>
+ <li><strong>Not</strong> compatible with Gnu Compiler for Java (gcj)</li>
+ </ul>
+ </li>
+</ul>
+
+<p class="note"><strong>Note:</strong> If JDK is already installed on your development computer, please take a moment to make sure that it meets the version requirements listed above. In
+particular, note that some Linux distributions may include JDK 1.4 or Gnu Compiler for Java, both of which are not supported for Android development. </p> \ No newline at end of file
diff --git a/docs/html/sdk/1.0_r2/upgrading.jd b/docs/html/sdk/1.0_r2/upgrading.jd
new file mode 100644
index 0000000..df9b657
--- /dev/null
+++ b/docs/html/sdk/1.0_r2/upgrading.jd
@@ -0,0 +1,148 @@
+page.title=Upgrading the SDK
+sdk.version=1.0_r2
+@jd:body
+
+<p>For the current SDK release, see the links under <strong>Current SDK Release</strong> in the side navigation.</p>
+
+<p>This guide will help you migrate your development environment and applications
+to <strong>version 1.0, release 2</strong>, of the Android SDK. Use this guide if you've been developing applications
+on a different version of the Android SDK.</p>
+
+<p>To ensure that your applications are compliant with the Android 1.0 system available
+on mobile devices, you need to install the new SDK and port your existing Android
+applications to the updated API. The sections below guide you through the process.</p>
+
+<h2 id="install-new">Install the new SDK</h2>
+
+<p>After unpacking the SDK, you should:</p>
+
+<ul>
+ <li>Wipe your emulator data. <p>Some data formats have changed since the last
+ SDK release, so any previously saved data in your emulator must be removed. Open a console/terminal
+ and navigate to the <code>/tools</code> directory of your SDK. Launch the
+ emulator with the <code>-wipe-data</code> option. </p>
+ <p>Windows: <code>emulator -wipe-data</code><br/>
+ Mac/Linux: <code>./emulator -wipe-data</code></p>
+ </li>
+ <li>Update your PATH variable (Mac/Linux; optional). <p>If you had previously setup your
+ PATH variable to point to the SDK tools directory, then you'll need to update it to
+ point to the new SDK. E.g., for a <code>.bashrc</code> or <code>.bash_profile</code> file:
+ <code>export PATH=$PATH:<em>&lt;your_new_sdk_dir></em>/tools</code></p>
+ </li>
+</ul>
+
+<h2 id="update-plugin">Update your ADT Eclipse Plugin</h2>
+
+<p>If you develop on Eclipse and are using the ADT plugin, follow these steps to install the
+plugin that's required for this version of the SDK.</p>
+
+<table style="font-size:100%">
+<tr><th>Eclipse 3.3 (Europa)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
+<tr>
+<td width="45%">
+<ol>
+ <li><a href="http://dl-ssl.google.com/android/ADT-0.8.0.zip">Download the ADT v0.8.0 zip
+ file</a> (do not unpack it).</li>
+ <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Software Updates</strong> &gt; <strong>Find
+ and Install...</strong>. </li>
+ <li>In the dialog that appears, select <strong>Search for new features to install</strong> and click
+ <strong>Next</strong>. </li>
+ <li>Click <strong>New Archive Site...</strong></li>
+ <li>Browse and select the downloaded the zip file.</li>
+ <li>You should now see the new site added to the search list (and checked).
+ Click <strong>Finish</strong>. </li>
+ <li>In the subsequent Search Results dialog box, select the checkbox for
+ <strong>Android Plugin</strong> &gt; <strong>Developer Tools</strong>.
+ This will check both features: "Android Developer Tools", and "Android
+ Editors". The Android Editors feature is optional, but recommended. If
+ you choose to install it, you need the WST plugin mentioned earlier in this
+ page. Click <strong>Next</strong>. </li>
+ <li>Read the license agreement and then select <strong>Accept terms of the license agreement</strong>.
+ Click <strong>Next</strong>. </li>
+ <li>Click <strong>Finish</strong>. </li>
+ <li>The ADT plugin is not signed; you can accept the installation anyway
+ by clicking <strong>Install All</strong>. </li>
+ <li>Restart Eclipse. </li>
+</ol>
+
+</td>
+<td>
+
+<ol>
+ <li><a href="http://dl-ssl.google.com/android/ADT-0.8.0.zip">Download the ADT v0.8.0 zip
+ file</a> (do not unpack it).</li>
+ <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Software Updates...</strong>.</li>
+ <li>In the dialog that appears, click the <strong>Available Software</strong> tab.</li>
+ <li>Click <strong>Add Site...</strong>, then <strong>Archive...</strong>.</li>
+ <li>Browse and select the downloaded the zip file.</li>
+ <li>Back in the Available Software view, you should see the plugin. Select the checkbox next to
+ <em>Developer Tools</em> and click <strong>Install...</strong></li>
+ <li>On the subsequent Install window, "Android Developer Tools", and "Android Editors" should both be checked.
+ The Android Editors feature is optional, but recommended. If
+ you choose to install it, you need the WST plugin mentioned earlier in this
+ page. Click <strong>Next</strong>.</li>
+ <li>Accept the license agreement and click <strong>Finish</strong>.</li>
+ <li>Restart Eclipse. </li>
+</ol>
+
+</td>
+</tr>
+</table>
+
+<p>After restart, update your Eclipse preferences to point to the SDK directory:</p>
+ <ol>
+ <li>Select <strong>Window</strong> > <strong>Preferences...</strong> to open the Preferences panel. (Mac OSX: <strong>Eclipse</strong> > <strong>Preferences</strong>)</li>
+ <li>Select <strong>Android</strong> from the left panel.</li>
+ <li>For the SDK Location in the main panel, click <strong>Browse...</strong> and locate the SDK directory.</li>
+ <li>Click <strong>Apply</strong>, then <strong>OK</strong>.</li>
+ </ol>
+
+<h2 id="sign">Set Up Application Signing</h2>
+
+<p>All applications must now be signed before you can install them on the emulator. Both
+the ADT plugin and the Ant-based build tools support this requirement by signing compiled
+.apk files with a debug key. To do so, the build tools use the Keytool utility included
+in the JDK to to create a keystore and a key with a known alias and password. For more
+information, see "Signing and Publishing Your App" in the documentation included with the SDK.
+
+<p>To support signing, you should first make sure that Keytool is available to the SDK build
+tools. In most cases, you can tell the SDK build tools how to find Keytool by making sure that
+your JAVA_HOME environment variable is set and that it references a suitable JDK. Alternatively,
+you can add the JDK version of Keytool to your PATH variable.</p>
+
+<p>If you are developing on a version of Linux that originally came with Gnu Compiler for Java,
+make sure that the system is using the JDK version of Keytool, rather than the gcj version.
+If keytool is already in your PATH, it might be pointing to a symlink at /usr/bin/keytool.
+In this case, check the symlink target to make sure that it points to the keytool in the JDK.</p>
+
+<p>If you use Ant to build your .apk files (rather than ADT for Eclipse), you must regenerate
+your build.xml file. To do that, follow these steps:</p>
+<ol>
+ <li>In your Android application project directory, locate and delete the current build.xml file.</li>
+ <li>Run activitycreator, directing output to the folder containing your application project.
+
+<pre>- exec activitycreator --out &lt;project folder&gt; your.activity.YourActivity</pre>
+
+ </li>
+</ol>
+
+<p>Run in this way, activitycreator will not erase or create new Java files (or manifest files),
+provided the activity and package already exists. It is important that the package and the activity
+are real. The tool creates a new build.xml file, as well as a new directory called "libs" in which
+to place 3rd jar files, which are now automatically handled by the Ant script.</p>
+
+<h2 id="migrate">Migrate your applications</h2>
+
+<p>After updating your SDK, you will likely encounter breakages in your code, due to
+framework and API changes. You'll need to update your code to match changes in the Android APIs.</p>
+
+<p>One way to start is to open your project in Eclipse and see where the ADT
+identifies errors in your application.</p>
+
+<p>If you have additional trouble updating your code, visit the
+<a href="http://groups.google.com/group/android-developers">Android Developers Group</a>
+to seek help from other Android developers.</p>
+
+<p>If you have modified one of the ApiDemos applications and would like to migrate it
+to the new SDK, note that you will need to uninstall the version of ApiDemos that comes
+preinstalled in the emulator.</p>
diff --git a/docs/html/sdk/1.1_r1/index.jd b/docs/html/sdk/1.1_r1/index.jd
new file mode 100644
index 0000000..c4a9bf0
--- /dev/null
+++ b/docs/html/sdk/1.1_r1/index.jd
@@ -0,0 +1,62 @@
+page.title=Android 1.1 SDK, Release 1
+
+sdk.version=1.1_r1
+sdk.date=February 2009
+
+sdk.win_download=android-sdk-windows-1.1_r1.zip
+sdk.win_bytes=86038515
+sdk.win_checksum=8c4b9080b430025370689e03d20842f3
+
+sdk.mac_download=android-sdk-mac_x86-1.1_r1.zip
+sdk.mac_bytes=79046151
+sdk.mac_checksum=becf0f1763d61eedce15d2a903d6c1dd
+
+sdk.linux_download=android-sdk-linux_x86-1.1_r1.zip
+sdk.linux_bytes=79345522
+sdk.linux_checksum=ebcb16b0cd4aef198b4dd9a1418efbf1
+
+
+@jd:body
+
+<h2>SDK Contents</h2>
+
+<h4>Development tools</h4>
+
+<p>The SDK includes a variety of tools for developing and debugging application code and designing an application UI. You can read about the tools in the
+<a href="{@docRoot}guide/developing/tools/index.html">Dev Guide</a> and access them in the <code>&lt;sdk&gt;/tools/</code> directory.
+
+<p>The tools package included in this SDK is the same as that included in the Android 1.0, Release 2 SDK. </p>
+
+<h4 id="system_images">System Images</h4>
+
+<p>The Android system images listed below are included in this SDK. For more information about a system image &mdash; features, applications included, localizations, API changes, and so on &mdash; see its Version Notes. </p>
+
+<table style="margin-right:1em;" width="80%">
+<tr>
+<th><nobr>System Image</nobr></th><th><nobr>API Level</nobr></th><th>Notes</th><th>Description</th>
+</tr>
+
+<tr>
+<td width="5%"><nobr>Android 1.1</nobr></td>
+<td width="5%">2</td>
+<td width="5%"><nobr><a href="{@docRoot}sdk/android-1.1.html">Version Notes</a></nobr></td>
+<td>Includes com.google.android.maps external library and a set of standard development applications. </td>
+
+</tr>
+
+</table>
+
+<h4>Sample Code and Applications</h4>
+
+<p>You can look at a variety of tutorials and samples in the <a href="{@docRoot}guide/samples/index.html">Dev Guide</a> and access the sample code itself
+in the <code>&lt;sdk&gt;/samples/</code> directory of the SDK package.</p>
+
+<h4>Documentation</h4>
+
+<p>The SDK package includes a full set of local documentation. To view it, open the <code>&lt;sdk&gt;/documentation.html</code> file in a web browser. If you are developing in an IDE such as Eclipse, you can also view the reference documentation directly in the IDE. </p>
+
+<p>The most current documentation is always available on the Android Developers site:</p>
+
+<p style="margin-left:2em;"><a href="http://developer.android.com/index.html">http://developer.android.com/</a></p>
+
+
diff --git a/docs/html/sdk/1.1_r1/installing.jd b/docs/html/sdk/1.1_r1/installing.jd
new file mode 100644
index 0000000..d5a7106
--- /dev/null
+++ b/docs/html/sdk/1.1_r1/installing.jd
@@ -0,0 +1,312 @@
+page.title=Installing the Android SDK
+sdk.version=1.1_r1
+
+@jd:body
+
+
+<p>This page describes how to install the Android SDK and set up your
+development environment. If you haven't downloaded the SDK, you can
+do so from the
+<a href="{@docRoot}sdk/1.1_r1/index.html">Download</a> page.</p>
+
+<p>If you encounter any problems during installation, see the
+<a href="#installnotes">Installation Notes</a> at the bottom of
+this page.</p>
+
+<h4 style="margin-top">Upgrading?</h4>
+<p>If you have already developed applications using an earlier version
+of the SDK, please skip this page and read the
+<a href="{@docRoot}sdk/1.1_r1/upgrading.html"><strong>Upgrading the
+SDK</strong></a></b> document instead.
+</p>
+
+
+<h2 id="setup">Preparing for Installation</h2>
+
+<p>Before you get started with the Android SDK, take a moment to confirm
+that your development machine meets the <a
+href="{@docRoot}sdk/1.1_r1/requirements.html">system requirements</a>.
+</p>
+
+<p>If you will be developing on Eclipse with the Android Development
+Tools (ADT) Plugin &mdash; the recommended path if you are new to
+Android &mdash; make sure that you have a suitable version of Eclipse
+installed on your computer. If you need to install Eclipse, you can
+download it from this location: </p>
+
+<p style="margin-left:2em;"><a href=
+"http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a
+></p>
+
+<p>A Java or RCP version of Eclipse is recommended. </p>
+
+<h2 id="installingsdk">Installing the SDK</h2>
+
+ <p>After downloading the SDK, unpack the .zip archive to a suitable location on your machine. By default, the SDK files are unpacked into a directory named <code>android_sdk_<em>&lt;platform</em>&gt;_<em>&lt;release&gt;</em>_<em>&lt;build&gt;</em></code>. The directory contains a link to a local copy of the documentation and the subdirectories <code>tools/</code>, <code>samples/</code>, and others. </p>
+
+ <p>Make a note of the name and location of the unpacked SDK directory on your system &mdash; you will need to refer to the SDK directory later, when setting up the Android plugin or using SDK tools. </p>
+
+ <p>Optionally, you can add the path to the SDK <code>tools</code> directory to your path. As mentioned above, the <code>tools/</code> directory is located in the SDK directory. </p>
+ <ul>
+ <li>On Linux, edit your ~/.bash_profile or ~/.bashrc file. Look
+ for a line that sets the PATH environment variable and add the
+ full path to the <code>tools/</code> directory to it. If you don't
+ see a line setting the path, you can add one:</li>
+
+ <ul><code>export PATH=${PATH}:<em>&lt;your_sdk_dir&gt;</em>/tools</code></ul>
+
+ <li>On a Mac, look in your home directory for .bash_profile and
+ proceed as for Linux. You can create the .bash_profile, if
+ you haven't already set one up on your machine. </li>
+
+ <li>On Windows, right click on My Computer, and select Properties.
+ Under the Advanced tab, hit the Environment Variables button, and in the
+ dialog that comes up, double-click on Path under System Variables. Add the full path to the <code>tools/</code> directory to the path. </li>
+ </ul>
+
+ <p>Adding <code>tools</code> to your path lets you run Android Debug Bridge (adb) and the other command line <a href="{@docRoot}guide/developing/tools/index.html">tools</a> without needing to supply the full path to the tools directory. Note that, if you update your SDK, you should remember to update your PATH settings to point to the new location, if different.</p>
+
+
+<p>If you will be using the Eclipse IDE as your environment for developing Android applications, continue reading the next
+section in order to install the Android Development Tools plugin and set up Eclipse. If you choose not to use Eclipse, you can
+develop Android applications using other tools &mdash; read the guide to developing
+<a href="{@docRoot}guide/developing/other-ide.html">in other IDEs</a>.</p>
+
+
+<h2 id="installingplugin">Installing the ADT Plugin for Eclipse</h2>
+
+<p>Android offers a custom plugin for the Eclipse IDE, called Android
+Development Tools (ADT), that is designed to give you a powerful,
+integrated environment in which to build Android applications. It
+extends the capabilites of Eclipse to let you quickly set up new Android
+projects, create an application UI, add components based on the Android
+Framework API, and debug using the Android SDK tools.</p>
+
+<p>If you are new to Android or want to develop using the Eclipse IDE,
+the ADT plugin will be an essential part of your development
+environment. In general, using Eclipse with ADT is a highly recommended
+approach and is the fastest way to get started. This section describes
+how to install ADT into your Eclipse environment.
+
+<p>If you prefer to work in a development environment other than Eclipse,
+you do not need to install Eclipse or the ADT Plugin. Instead, you can
+access the SDK tools directly to build and debug your application. </p>
+
+<p>Once you have Eclipse installed, as described in <a href="#setup">
+Preparing for Installation</a>, follow the steps below to
+download the ADT plugin and install it in your respective Eclipse
+environment. </p>
+
+<table style="font-size:100%">
+<tr><th>Eclipse 3.3 (Europa)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
+<tr>
+<td width="45%">
+<ol>
+ <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Software Updates</strong> &gt; <strong>Find
+ and Install...</strong>. </li>
+
+ <li>In the dialog that appears, select <strong>Search for new features to install</strong> and click <strong>Next</strong>. </li>
+ <li>Click <strong>New Remote Site</strong>. </li>
+ <li>In the resulting dialog box, enter a name for the remote site (e.g. Android Plugin) and enter this as its URL:
+ <pre>https://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Alternatively, you can use http in the Location URL, if you are having
+ trouble with https (https is preferred for security reasons).</p>
+ <pre>http://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Click <strong>OK</strong>.</p> </li>
+ <li>You should now see the new site added to the search list (and checked).
+ Click <strong>Finish</strong>. </li>
+ <li>In the subsequent Search Results dialog box, select the checkbox for
+ <strong>Android Plugin</strong> &gt; <strong>Developer Tools</strong>.
+ This will check both features: "Android Developer Tools", and "Android
+ Editors". The Android Editors feature is optional, but recommended. If
+ you choose to install it, you need the WST plugin mentioned earlier in this
+ page. Click <strong>Next</strong>. </li>
+ <li>Read the license agreement and then select <strong>Accept terms of the license agreement</strong>.
+ Click <strong>Next</strong>. </li>
+ <li>Click <strong>Finish</strong>. </li>
+
+ <li>The ADT plugin is not signed; you can accept the installation anyway
+ by clicking <strong>Install All</strong>. </li>
+ <li>Restart Eclipse. </li>
+</ol>
+
+</td>
+<td>
+
+<ol>
+ <li>Start Eclipse, then select <strong>Help</strong> &gt; <strong>Software Updates...</strong>.
+ </li>
+ <li>In the dialog that appears, click the <strong>Available Software</strong> tab.
+ </li>
+ <li>Click <strong>Add Site...</strong>
+ </li>
+ <li>Enter this as the Location:
+ <pre>https://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Alternatively, you can use http in the Location URL, if you are having
+ trouble with https (https is preferred for security reasons).</p>
+ <pre>http://dl-ssl.google.com/android/eclipse/</pre>
+ <p>Click <strong>OK</strong>.</p></li>
+ <li>Back in the Available Software view, you should see the plugin. Select the checkbox next to
+ <em>Developer Tools</em> and click <strong>Install...</strong>
+ </li>
+ <li>On the subsequent Install window, "Android Developer Tools", and "Android Editors" should both be checked.
+ The Android Editors feature is optional, but recommended. If
+ you choose to install it, you need the WST plugin mentioned earlier in this
+ page. Click <strong>Next</strong>.
+ </li>
+ <li>Accept the license agreement and click <strong>Finish</strong>.</li>
+ <li>Restart Eclipse. </li>
+</ol>
+
+</td>
+</tr>
+</table>
+
+<p>Now, you just need to modify your Eclipse preferences to point to the Android SDK directory:</p>
+<ol>
+ <li>Select <strong>Window</strong> &gt; <strong>Preferences...</strong> to open the Preferences
+ panel. (Mac OS X: <strong>Eclipse</strong> &gt; <strong>Preferences</strong>) </li>
+ <li>Select <strong>Android</strong> from the left panel. </li>
+ <li>For the SDK Location in the main panel, click <strong>Browse...</strong> and locate the SDK directory. </li>
+ <li>Click <strong>Apply</strong>, then <strong>OK</strong>.</li>
+</ol>
+
+<p>Done! If you haven't encountered any problems, then you're ready to
+begin developing Android applications. See the <a href="#next">After
+Installation: Next Steps</a> section for suggestions on how to start. </p>
+
+
+<h3 id="troubleshooting">Troubleshooting ADT Installation</h3>
+<p>
+If you are having trouble downloading the ADT plugin after following the steps above, here are some suggestions: </p>
+
+<ul>
+ <li>If Eclipse can not find the remote update site containing the ADT plugin, try changing the remote site URL to use http, rather than https. That is, set the Location for the remote site to:
+ <pre>http://dl-ssl.google.com/android/eclipse/</pre></li>
+ <li>If you are behind a firewall (such as a corporate firewall), make
+ sure that you have properly configured your proxy settings in Eclipse.
+ In Eclipse 3.3/3.4, you can configure proxy information from the main
+ Eclipse menu in <strong>Window</strong> (on Mac, <strong>Eclipse</strong>) &gt; <strong>Preferences</strong> &gt; <strong>General</strong> &gt; <strong>Network Connections</strong>.</li>
+</ul>
+<p>
+If you are still unable to use Eclipse to download the ADT plugin as a remote update site, you can download the ADT files to your local machine using a browser and the install the files in Eclipse from there:
+</p>
+<ol>
+<li><a href="{@docRoot}sdk/adt_download.html">Download the ADT zip file</a> (do not unpack it).
+<li>Follow steps 1 and 2 in the default install instructions (above).
+<li>In Eclipse 3.3, click <strong>New Archive Site...</strong>. <br/>
+ In Eclipse 3.4, click <strong>Add Site...</strong>, then <strong>Archive...</strong>
+<li>Browse and select the downloaded the zip file.
+<li>Follow the remaining procedures, above, starting from steps 5.
+</ol>
+<p>
+Note that to update your plugin, you will have to follow these steps again instead of the default update instructions.</p>
+
+<p>Note that the "Android Editors" feature of ADT requires several optional
+Eclipse components (for example, WST). If you encounter an error when
+installing ADT, your Eclipse installion might not include those components.
+For information about how to quickly add the necessary components to your
+Eclipse installation, see the troubleshooting topic
+<a href="{@docRoot}guide/appendix/faq/troubleshooting.html#installeclipsecomponents">ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui"</a>.</p>
+
+<h4>For Linux users</h4>
+<p>If you encounter this error when installing the ADT Plugin for Eclipse:
+<pre>
+An error occurred during provisioning.
+Cannot connect to keystore.
+JKS</pre>
+<p>
+...then your development machine lacks a suitable Java VM. Installing Sun
+Java 6 will resolve this issue and you can then reinstall the ADT
+Plugin.</p>
+
+
+<h2 id="next">After Installation: Next Steps</h2>
+<p>Once you have installed the SDK and the ADT Plugin, you are ready to
+begin developing applications. Here are a few ways you can get started: </p>
+
+<p><strong>Learn about Android</strong></p>
+<ul>
+<li>Take a look at the <a href="{@docRoot}guide/index.html">Dev
+Guide</a> and the types of information it provides</li>
+<li>Read an introduction to Android as a platform in <a
+href="{@docRoot}guide/basics/what-is-android.html">What is
+Android?</a></li>
+<li>Learn about the Android framework and how applications run on it in
+<a href="{@docRoot}guide/topics/fundamentals.html">Application
+Fundamentals</a></li>
+<li>Take a look at the Android framework API specification in the <a
+href="{@docRoot}reference/index.html">Reference</a> tab</li>
+</ul>
+
+<p><strong>Explore the SDK</strong></p>
+<ul>
+<li>Get an overview of the <a
+href="{@docRoot}guide/development/tools/index.html">development
+tools</a> that are available to you</li>
+<li>Read the overviews of how to develop <a
+href="{@docRoot}guide/developing/eclipse-adt.html">in Eclipse/ADT</a> or
+<a href="{@docRoot}guide/developing/other-ide.html">in other IDEs</a>
+</li>
+</ul>
+
+<p><strong>Explore some code</strong></p>
+<ul>
+<li>Set up a <a href="{@docRoot}guide/tutorials/hello-world.html">Hello
+World application</a></li>
+<li>Follow the <a href="{@docRoot}guide/tutorials/notepad/index.html">
+Notepad Tutorial</a> to build a full Android application </li>
+<li>Create a new project for one of the other sample applications
+included in <code>&lt;sdk&gt;/samples</code>, then compile and run it in
+your development environment</li>
+</ul>
+
+<p><strong>Visit the Android developer groups</strong></p>
+<ul>
+<li>Take a look at the <a
+href="{@docRoot}community/index.html">Community</a> tab to see a list of
+Android developers groups. In particular, you might want to look at the
+<a href="http://groups.google.com/group/android-developers">Android
+Developers</a> group to get a sense for what the Android developer
+community is like.</li>
+</ul>
+
+
+<h2 id="installnotes">Installation Notes</h2>
+<h4>Ubuntu Linux Notes</h4>
+<ul>
+ <li>If you need help installing and configuring Java on your
+development machine, you might find these resources helpful:
+ <ul>
+ <li><a href="https://help.ubuntu.com/community/Java">https://help.ubuntu.com/community/Java </a></li>
+ <li><a href="https://help.ubuntu.com/community/Java">https://help.ubuntu.com/community/JavaInstallation </a></li>
+ </ul>
+ </li>
+<li>Here are the steps to install Java and Eclipse, prior to installing
+the Android SDK and ADT Plugin.
+<ol>
+ <li>If you are running a 64-bit distribution on your development
+machine, you need to install the <code>ia32-libs</code> package using
+<code>apt-get:</code>:
+ <pre>apt-get install ia32-libs</pre></li>
+ <li>Next, install Java:
+ <pre>apt-get install sun-java6-bin</pre></li>
+ <li>The Ubuntu package manager does not currently offer an Eclipse 3.3
+ version for download, so we recommend that you download Eclipse from
+eclipse.org (<a
+href="http://www.eclipse.org/downloads/">http://www.eclipse.org/
+downloads/</a>). A Java or RCP version of Eclipse is recommended.</li>
+<li>Follow the steps given in previous sections to install the SDK
+and the ADT plugin. </li>
+</ol>
+</ul>
+<h4>Other Linux Notes</h4>
+<ul>
+ <li>If JDK is already installed on your development computer, please
+take a moment to make sure that it meets the version requirements listed
+in the <a href="{@docRoot}sdk/1.1_r1/requirements.html">System Requirements</a>.
+In particular, note that some Linux distributions may include JDK 1.4 or Gnu
+Compiler for Java, both of which are not supported for Android development.</li>
+</ul>
+
+
diff --git a/docs/html/sdk/1.0_r1/requirements.jd b/docs/html/sdk/1.1_r1/requirements.jd
index 6af3900..95b658b 100644
--- a/docs/html/sdk/1.0_r1/requirements.jd
+++ b/docs/html/sdk/1.1_r1/requirements.jd
@@ -1,18 +1,20 @@
-page.title=System and Software Requirements
-@jd:body
+page.title=System Requirements
+
+sdk.version=1.1_r1
+sdk.date=February 2009
+@jd:body
-<p>To develop Android applications using the code and tools in the Android SDK,
-you need a suitable development computer and development environment, as described below.</p>
+<p>The sections below describe the system and software requirements for developing Android applications using the Android SDK tools included in Android 1.1 SDK, Release 1. </p>
-<p><strong>Supported Operating Systems:</strong></p>
+<h3>Supported Operating Systems</h3>
<ul>
- <li>Windows XP or Vista</li>
+ <li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
<li>Mac OS X 10.4.8 or later (x86 only)</li>
<li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
</ul>
-<p><strong>Supported Development Environments:</strong></p>
+<h3>Supported Development Environments</h3>
<ul>
<li>Eclipse IDE
<ul>
diff --git a/docs/html/sdk/1.1_r1/upgrading.jd b/docs/html/sdk/1.1_r1/upgrading.jd
new file mode 100644
index 0000000..2ad6757
--- /dev/null
+++ b/docs/html/sdk/1.1_r1/upgrading.jd
@@ -0,0 +1,150 @@
+page.title=Upgrading the SDK
+sdk.version=1.1_r1
+@jd:body
+
+<!--
+<div class="sidebox-wrapper">
+ <div class="sidebox-inner">
+
+ <h2>Useful Links</h2>
+
+ <ul class="noindent">
+ <li><a href="migrating/0.9-1.0/changes-overview.html">Overview of Changes</a>
+ <p>A high-level look at what's changed in Android, with
+ discussion of how the changes may affect your apps.</p></li>
+
+ <li><a href="migrating/0.9-1.0/changes.html">API Diff Report</a>
+ <p>A detailed report that lists all the specific changes in the latest SDK.</p></li>
+
+ <li><a href="RELEASENOTES.html">Release Notes</a>
+ <p>Version details, known issues, and resolved issues. </p></li>
+
+ <li><a href="http://groups.google.com/group/android-developers">Android Developers Group</a>
+ <p>A forum where you can discuss migration issues and learn from other Android developers. </p></li>
+
+ <li><a href="http://code.google.com/p/android/issues/list">Android Issue Tracker</a>
+ <p>If you think you may have found a bug, use the issue tracker to report it.</p></li>
+ </ul>
+
+ </div>
+</div>
+-->
+
+<p>This document describes how to move your development environment and existing
+Android applications from an Android 1.0 SDK to the Android 1.1, Release 1 SDK.
+If you are migrating applications from an earlier SDK, please read the upgrading
+document available in the Android 1.0 SDK package.
+</p>
+
+<p>To ensure that your applications are compliant with the Android 1.1 system available
+on mobile devices, you need to install the Android 1.1 SDK and port your existing Android
+applications to it. The sections below will guide you through the process.</p>
+
+<h2 id="install-new">Installing the Latest SDK</h2>
+
+<p><a href="{@docRoot}sdk/1.1_r1/index.html">Download the SDK</a> and unpack it into a safe location.</p>
+
+<p>After unpacking the new SDK and saving it an appropriate location, you should:</p>
+
+<ul>
+ <li>Wipe your emulator data. <p>Some data formats have changed since the last
+ SDK release, so any previously saved data in your emulator must be removed. Open a console/terminal
+ and navigate to the <code>/tools</code> directory of your new SDK. Launch the
+ emulator with the <code>-wipe-data</code> option.
+ <p>Windows: <code>emulator -wipe-data</code><br/>
+ Mac/Linux: <code>./emulator -wipe-data</code></p>
+ </li>
+ <li>Update your PATH variable (Mac/Linux; optional). <p>If you had previously setup your
+ PATH variable to point to the SDK tools directory, then you'll need to update it to
+ point to the new SDK. For example, for a <code>.bashrc</code> or <code>.bash_profile</code> file:
+ <code>export PATH=$PATH:<em>&lt;your_new_sdk_dir></em>/tools</code></p>
+ </li>
+ <li>If (and only if) you are developing using Ant, you will also need to modify
+ your build.xml properties to point to the new SDK.
+ <p>Open the <code>default.properties</code> file associated with your build.xml
+ file (typically located in the same directory). In the default.properties
+ file, update the <code>sdk-folder</code> property with the full path to
+ the new SDK directory.</p></li>
+</ul>
+
+<a name="Updating_the_ADT_plugin" id="Updating_the_ADT_plugin"></a>
+<h2 id="update-plugin">Update your ADT Eclipse Plugin</h2>
+
+<p>If you develop on Eclipse and are migrating from an Android 1.0
+SDK, no update of the ADT plugin is needed &mdash; skip to <a href="#updateEclipsePrefs">Update your Eclipse SDK Preferences</a>. </p>
+
+<p>If you are migrating from an earlier version of the SDK, you will
+need to update the ADT plugin. <p>You may also want to upgrade your
+ADT plugin when a new version becomes available for your existing version
+of the SDK.</p>
+
+<p>The steps below describe how to update the ADT plugin to the latest
+version available. </p>
+
+<table style="font-size:100%">
+<tr><th>Eclipse 3.3 (Europa)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
+<tr>
+<td width="50%">
+<ol>
+ <li> Select <strong>Help</strong> &gt; <strong>Software Updates</strong> &gt; <strong>Find and Install...</strong>. </li>
+ <li> Select <strong>Search for updates of the currently installed features</strong> and click <strong>Finish</strong>. </li>
+ <li> If any update for ADT is available, select and install. </li>
+ <li> Restart Eclipse.</li>
+</ol>
+<p> Alternatively, </p>
+<ol>
+ <li> Select <strong>Help</strong> &gt; <strong>Software Updates</strong> &gt; <strong>Manage Configuration</strong>. </li>
+
+ <li> Navigate down the tree and select <strong>Android Development Tools &lt;version&gt;</strong> </li>
+ <li> Select <strong>Scan for Updates</strong> under <strong>Available Tasks</strong>.</li>
+</ol>
+</td>
+<td>
+<ol>
+ <li>Select <strong>Help</strong> &gt; <strong>Software Updates...</strong></li>
+ <li>Select the <strong>Installed Software</strong> tab.</li>
+ <li>Click <strong>Update...</strong></li>
+ <li>If an update for ADT is available, select it and click <strong>Finish</strong>.</li>
+ <li>Restart Eclipse.</li>
+</ol>
+</td>
+</tr>
+</table>
+
+<h2 id="updateEclipsePrefs">Update your Eclipse SDK Preferences</h2>
+
+<p>The last step is to update your Eclipse preferences to point to the new SDK directory:</p>
+ <ol>
+ <li>Select <strong>Window</strong> > <strong>Preferences...</strong> to open the Preferences panel. (Mac OSX: <strong>Eclipse</strong> > <strong>Preferences</strong>)</li>
+ <li>Select <strong>Android</strong> from the left panel.</li>
+ <li>For the SDK Location in the main panel, click <strong>Browse...</strong> and locate the SDK directory.</li>
+ <li>Click <strong>Apply</strong>, then <strong>OK</strong>.</li>
+ </ol>
+
+<h2 id="migrate">Migrate Your Applications, if Necessary</h2>
+
+<p>If (and only if) you have written apps in an SDK released previous to
+the Android 1.0 SDK, you will need to migrate your applications. After
+installing the new SDK and updating the ADT Plugin (if applicable), you
+may encounter breakages in your application code, due to
+framework and API changes. You'll need to update your code to match the
+latest APIs.</p>
+
+<p>One way to start is to open your project in Eclipse and see where the ADT
+identifies errors in your application. From there, you can lookup
+specific API changes in the Android 1.0 APIs in the
+<a href="http://code.google.com/android/migrating/changes-overview.html">
+Overview of Changes</a> and <a href="http://code.google.com/android/migrating/changes.html">
+API Diffs Report</a>.</p>
+
+<p>If you have additional trouble updating your code, visit the
+<a href="http://groups.google.com/group/android-developers">Android Developers Group</a>
+to seek help from other Android developers.</p>
+
+<p>If you have modified one of the ApiDemos applications and would like to migrate it
+to the new SDK, note that you will need to uninstall the version of ApiDemos that comes
+preinstalled in the emulator. For more information, or if you encounter an "reinstallation"
+error when running or installing ApiDemos, see the troubleshooting topic
+<a href="{@docRoot}guide/appendix/faq/troubleshooting.html#apidemosreinstall">I can't install ApiDemos
+apps in my IDE because of a signing error</a> for information about how to solve the problem.</p>
+
diff --git a/docs/html/sdk/RELEASENOTES.jd b/docs/html/sdk/RELEASENOTES.jd
new file mode 100644
index 0000000..bad71a2
--- /dev/null
+++ b/docs/html/sdk/RELEASENOTES.jd
@@ -0,0 +1,327 @@
+page.title=SDK Release Notes
+@jd:body
+
+<p>This document provides version-specific information about Android SDK releases. For the latest known issues, please ensure that you're viewing this page at: <a href="http://developer.android.com/sdk/RELEASENOTES.html">http://developer.android.com/sdk/RELEASENOTES.html</a>.</p>
+
+<h2 id="1.1_r1">Android 1.1 SDK, Release 1</h2>
+
+<p>This SDK provides the development tools and Android system image you need to create applications for Android-powered devices. Applications developed on this SDK will be compatible with mobile devices running the Android 1.1 platform. </p>
+
+<p>This release provides an updated system image (Android 1.1), updated documentation, and the same set of development tools provided in the Android 1.0 r2 SDK. The updated system image includes bug fixes and some smaller features, as well as a few minor API changes from the 1.0 version. </p>
+
+<p>For details about the Android 1.1 system image included in the SDK &mdash; including bug fixes, features, and API changes &mdash; please read the <a href="{@docRoot}sdk/android-1.1.html">Android 1.1 Version Notes</a>.</p>
+
+<h3>App Versioning for Android 1.1</h3>
+
+<p>If you are using this SDK to build an application that is compatible <em>only</em> with Android-powered devices running the Android 1.1 platform, please note that you <strong>must</strong> set the the <code>android:minSdkVersion</code> attribute in the application's manifest to the API Level of Android 1.1 &mdash; "2".</p>
+
+<p>Specifically, you specify the <code>android:minSdkVersion</code> attribute in a <code>&lt;uses-sdk&gt;</code> element as a child of <code>&lt;manifest&gt;</code> in the manifest file. When set, the attribute looks like this: </p>
+
+<pre><code>&lt;manifest&gt;
+ ...
+ &lt;uses-sdk minSdkVersion="2" /&gt;
+ ...
+&lt;/manifest&gt;</code>
+</pre>
+
+<p>By setting <code>android:minSdkVersion</code> in this way, you ensure that users will only be able to install your application if their devices are running the Android 1.1 platform. In turn, this ensures that your application will function properly on their devices, especially if it uses APIs introduced in Android 1.1. </p>
+
+<p>If your application uses APIs introduced in Android 1.1 but does not declare <code>&lt;uses-sdk minSdkVersion="2" /&gt;</code>, then it will run properly on Android 1.1 devices but <em>not</em> on Android 1.0 devices. </p>
+
+<p>If your application does not use any new APIs introduced in Android 1.1, you can indicate Android 1.0 compatibility by removing <code>minSdkVersion</code> or setting the attribute to "1". However, before publishing your application, you must make sure to compile your application against the Android 1.0 system image (available in the Android 1.0 SDK), to ensure that it builds and functions properly for Android 1.0 devices. You should test the application against system images corresponding to the API Levels that the application is designed to be compatible with.</p>
+
+<p>If you are sure your application is not using Android 1.1 APIs and has no need to use them, you might find it easier to keep working in the Android 1.0 SDK, rather than migrating to the Android 1.1 SDK and having to do additional testing.</p>
+
+
+<h3>ADT Plugin Compatibility</h3>
+
+<p>For this version of the SDK &mdash; Android 1.1 SDK, Release 1
+&mdash; the compatible version of the Android Development Tools (ADT)
+Plugin for Eclipse is <strong>0.8.0</strong>. If you are using a
+previous version of ADT, you should update to the latest version for use
+with this SDK. For information about how to update your ADT plugin, see
+<a href="{@docRoot}sdk/1.1_r1/upgrading.html#update-plugin">Upgrading
+the SDK</a>.</p>
+
+<h3>Installation and Upgrade Notes</h3>
+
+<p>If you've been developing an application using an Android 1.0 SDK no
+changes to your application are needed. You may want to wipe application
+user data (emulator option <code>-wipe-data</code>) when running your
+application on the Android 1.1 emulator for the first time.</p>
+
+<p>If you're installing the Android SDK for the first time, please see
+the instructions in <a
+href="{@docRoot}sdk/1.1_r1/installing.html">Installing the SDK</a>.
+
+<h3>Other Notes</h3>
+
+<p><strong>MapView API Key</strong></p>
+
+<p>com.google.android.maps.MapView is a class that lets you
+easily integrate Google Maps into your application. Before you can
+access the maps data, you will need to register with the Google Maps
+service and receive a Maps API Key, which you then add to your MapView
+for authentication to the server.</p>
+
+<p>Developers should note that the registration service for MapView is now
+active and Google Maps is actively enforcing the Maps API Key requirement.
+For information about how to register for a Maps API Key, see
+<a href="{@docRoot}guide/topics/location/geo/mapkey.html">
+Obtaining a Maps API Key</a>.</p>
+
+<p><strong>USB Drivers for Windows</strong></p>
+
+<p>If you using Windows and want to develop or test your application on an
+Android-powered device (such as the T-Mobile G1), you need an appropriate USB
+driver. For your convenience, the Windows version of the Android SDK includes
+these USB drivers that you can install, to let you develop on the device:</p>
+
+<ul>
+<li>USB driver for 32-bit XP and Vista</li>
+<li>USB driver for 64-bit Vista only</li>
+</ul>
+
+<p>The USB driver files are located in the
+<code>&lt;SDK&gt;/usb_driver</code> directory. For details and
+installation instructions, see <a
+href="{@docRoot}guide/developing/device.html#setting-up">Setting Up a
+Device for Development</a>.</p>
+</p>
+
+<h3>Resolved Issues, Changes</h3>
+
+<p><strong>Emulator</strong></p>
+<ul>
+<li>Emulator now saves the user image in &lt;android&gt;/SDK1.1/</code></li>
+</ul>
+
+<h3>Known Issues</h3>
+
+<p><strong>JUnit and Eclipse/ADT</strong></p>
+<ul>
+<li>If you are developing in Eclipse/ADT and want to add JUnit test
+classes, you can do so. However, you need to set up a custom JUnit configuration
+before your tests will run properly. For detailed information about how to set
+up the JUnit configuration, see the troubleshooting topic <a
+href="{@docRoot}guide/appendix/faq/troubleshooting.html#addjunit">Running a Junit test class
+in Eclipse</a>.</li>
+</ul>
+
+<p><strong>Other</strong></p>
+
+<ul>
+<li>It is not possible to send MMS messages between emulator instances. </li>
+<li>In some cases, you may encounter problems when using the browser on an
+emulator started with the command-line option <code>-http-proxy</code>. </li>
+<li>On the OSX platform, if you manually remove the ~/.android directory
+using <code>rm -rf ~/.android</code>, then try to run
+the emulator, it crashes. This happens because the emulator fails to create
+a new .android directory before attempting to create the child SDK1.0 directory.
+To work around this issue, manually create a new .android directory using
+<code>mkdir ~/.android</code>, then run the emulator. The emulator
+creates the SDK1.0 directory and starts normally. </li>
+<li>We regret to inform developers that Android 1.1 will not include support
+for ARCNet network interfaces.</li>
+<li>The final set of Intent patterns honored by Android 1.0 has not yet been
+fully documented. Documentation will be provided in future releases.</li>
+<li>In ADT Editor, you can add at most ten new resource values at a time,
+in a given res/values/*.xml, using the form in the Android Resources pane.
+If you add more than ten, the Android Resources pane will not display the
+attributes fields for the additional resource entries. To work around this
+problem, you can close the file in the editor and open it again, or you
+can edit the resource entries in the XML text mode. </li>
+<li>The emulator's battery-control commands (<code>power &lt;option&gt</code>)
+are not working in this release.</li>
+</ul>
+
+
+
+
+
+<h2 id="1.0_r2">Android 1.0 SDK, Release 2</h2>
+
+<p>This SDK release includes the Android 1.0 platform and application API.
+Applications developed on this SDK will be compatible with mobile devices
+running the Android 1.0 platform.</p>
+
+<p>This release includes mainly bug fixes, although some smaller features were
+added.</p>
+
+<h3>ADT Plugin Compatibility</h3>
+
+<p>For this release of the SDK, the compatible version of the Android
+Development Tools (ADT) Plugin for Eclipse is <strong>0.8.0</strong>. If you are
+using a previous version of ADT, you should update to the latest version for use
+with this SDK. For information about how to update your ADT plugin, see <a
+href="/android/intro/upgrading.html">Upgrading the SDK</a>.</p>
+
+<h3>Installation and Upgrade Notes</h3>
+
+<p>If you're installing the Android SDK for the first time, please see the
+instructions in <a href="/android/intro/installing.html">Installing the
+SDK</a>.
+
+<h3>Other Notes</h3>
+
+<p><strong>T-Mobile G1 Compatability</strong></p>
+
+<p>This version of the SDK has been tested for compatability with the first
+Android-powered mobile device, the <a href="http://www.t-mobileg1.com">T-Mobile
+G1</a>. </p>
+
+<p><strong>MapView API Key</strong></p>
+
+<p>MapView is a class that lets you easily integrate Google Maps into your
+application. Before you can access the maps data, you will need to register with
+the Google Maps service and receive a Maps API Key, which you then add to your
+MapView for authentication to the server.</p>
+
+<p>Developers should note that the registration service for MapView is now
+active and Google Maps is actively enforcing the Maps API Key requirement. For
+information about how to register for a Maps API Key, see <a
+href="http://code.google.com/android/toolbox/apis/mapkey.html">http://code.
+google.com/android/toolbox/apis/mapkey.html</a>.</p>
+
+<p><strong>USB Driver for Windows</strong></p>
+<p>If you using Windows and want to develop or test your application on an
+Android-powered device (such as the T-Mobile G1), you need an appropriate USB
+driver. For your convenience, the Windows version of the Android SDK includes a
+USB driver that you can install, to let you develop on the device. The USB
+driver files are located in the <code>&lt;SDK&gt;/usb_driver</code> directory.
+
+</p>
+
+<h3>Resolved Issues, Changes</h3>
+<ul>
+<li>The android.jar in this SDK release now includes several classes that were
+missing from the previous SDK. </li>
+<li>The android.R.styleable class and its fields were removed from the public
+API, to better ensure forward-compatibility for applications. The constants
+declared in android.R.styleable were platform-specific and subject to arbitrary
+change across versions, so were not suitable for use by applications. You can
+still access the platform's styleable attributes from your resources or code. To
+do so, declare a custom resource element using a
+<code>&lt;declare-styleable&gt;</code> in your project's res/values/R.attrs
+file, then declare the attribute inside. For examples, see
+&lt;sdk&gt;/samples/ApiDemos/res/values/attrs.xml. For more information about
+custom resources, see <a
+href="/android/reference/available-resources.html#customresources">Custom
+Layout Resources</a>. Note that the android.R.styleable documentation is still
+provided in the SDK, but only as a reference of the platform's styleable
+attributes for the various elements.</li>
+<li>The VM now properly ensures that private classes are not
+available to applications through reflection. If you were using reflection
+to access private classes in a previous release, you will now get a run-time
+error. </li>
+
+<li>The Settings and Email applications are now included in the SDK and
+available in the emulator.</li>
+<li>We regret to inform developers that SDK 1.0_r2 does not support MFM, RLL,
+or Winchester hard disk drives.</li>
+<li>In the emulator, the control key for enabling/disabling trackball mode
+is changed from Control-T to F6. You can also enter trackball mode temporarily
+using the Delete key. While the key is pressed, you can send trackball events.</li>
+</ul>
+
+<p>Unless otherwise noted, Known Issues from the previous SDK release also apply
+to this release.</p>
+
+
+
+
+
+
+<h2 id="1.0_r1">Android 1.0 SDK, Release 1</h2>
+
+<p>This SDK release is the first to include the Android 1.0 platform and application API. Applications developed on this SDK will be compatible with mobile devices running the Android 1.0 platform, when such devices are available.</p>
+
+<p>This release includes mainly bug fixes, although some smaller features were added. The Android 1.0 also includes several API changes from the 0.9 version. For more information on API changes, see the <a href="/android/migrating/0.9-1.0/changes-overview.html">Overview of Changes</a> and the <a href="/android/migrating/0.9-1.0/changes.html">API Differences Report</a>. For those porting from the M5 release, the SDK also includes the legacy changes overview and API Differences Reports. See the current Overview of Changes for more information. </p>
+
+<h3>ADT Plugin Compatibility</h3>
+
+<p>For this version of the SDK &mdash; Android 1.0 SDK, Release 1 &mdash; the compatible version of the Android Development Tools (ADT) Plugin for Eclipse is <strong>0.8.0</strong>. If you are using a previous version of ADT, you should update to the latest version for use with this SDK. For information about how to update your ADT plugin, see <a href="/android/intro/upgrading.html">Upgrading the SDK</a>.</p>
+
+<h3>Installation and Upgrade Notes</h3>
+
+<p>If you've been developing an application using a previous SDK version and you want the application to run on Android-powered mobile devices, you must port the application to the Android 1.0 SDK. Please see <a href="/android/intro/upgrading.html">Upgrading the SDK</a> for detailed instructions on how to make the transition to this release. Be sure to wipe application user data (emulator option <code>-wipe-data</code>) when running your application on the Android 1.0 SDK emulator.</p>
+
+<p>If you're installing the Android SDK for the first time, please see the instructions in <a href="/android/intro/installing.html">Installing the SDK</a>.
+
+<h3>Other Notes</h3>
+
+<p><strong>MapView API Key</strong></p>
+
+<p><a href="/android/reference/com/google/android/maps/MapView.html">MapView</a> is a class that lets you easily integrate Google Maps into your application. Before you can access the maps data, you will need to register with the Google Maps service and receive a Maps API Key, which you then add to your MapView for authentication to the server.</p>
+
+<p>Currently, the registration service for MapView is not yet active and Google Maps is not yet enforcing the Maps API Key requirement. However, note that the registration service will be activated soon, so that MapViews in any application deployed to a mobile device will require registration and a valid Maps API Key. </p>
+
+<p>As soon as the registration service becomes available, we will update the page at <a href="http://code.google.com/android/toolbox/apis/mapkey.html">http://code.google.com/android/toolbox/apis/mapkey.html</a> with details about how and where to register. Please check that page periodically for registration information, if you are using a MapView.</p>
+
+
+<h3>Resolved Issues, Changes</h3>
+
+<p><strong>Emulator</strong></p>
+<ul>
+<li>Emulator now saves the user image in &lt;android&gt;/SDK1.0/</code></li>
+<li>Fixed EsounD-related freezes on Linux.</li>
+<li>Fixed the documentation in -help-audio. '-audio list' doesn't work, one
+ needs to call -help-audio-out and -help-audio-in to get the list of valid
+ audio backends.</li>
+<li>Fixed scrollwheel Dpad emulation in rotated mode. before that, using the
+ scroll-wheel would always generated Dpad Up/Down events, even when in
+ landscape mode.</li>
+
+<li>Several Obsolete command options were removed.</li>
+<li>Setting the network speed through the console or the -netspeed option will
+ properly modify the connectivity icon on the device.</li>
+<li>Setting the GSM voice registration state to 'roaming' in the console will
+ properly modify the voice icon on the device</li>
+</ul>
+
+<p><strong>SQLite</strong></p>
+<ul>
+<li>SQLite is now included in the SDK package on all platforms. </li>
+</ul>
+
+<h3>Known Issues</h3>
+
+<p><strong>JUnit and Eclipse/ADT</strong></p>
+<ul>
+<li>If you are developing in Eclipse/ADT and want to add JUnit test
+classes, you can do so. However, you need to set up a custom JUnit configuration
+before your tests will run properly. For detailed information about how to set
+up the JUnit configuration, see the troubleshooting topic <a
+href="/android/kb/troubleshooting.html#addjunit">Running a Junit test class
+in Eclipse</a>.</li>
+</ul>
+
+<p><strong>Other</strong></p>
+
+<ul>
+<li>It is not possible to send MMS messages between emulator instances. </li>
+<li>In some cases, you may encounter problems when using the browser on an
+emulator started with the command-line option <code>-http-proxy</code>. </li>
+
+<li>We regret to inform developers that Android 1.0 will not include support for
+dot-matrix printers.</li>
+<li>On the OSX platform, if you manually remove the ~/.android directory
+using <code>rm -rf ~/.android</code>, then try to run
+the emulator, it crashes. This happens because the emulator fails to create
+a new .android directory before attempting to create the child SDK1.0 directory.
+To work around this issue, manually create a new .android directory using
+<code>mkdir ~/.android</code>, then run the emulator. The emulator
+creates the SDK1.0 directory and starts normally. </li>
+<li>The final set of Intent patterns honored by Android 1.0 has not yet been
+fully documented. Documentation will be provided in future releases.</li>
+<li>In ADT Editor, you can add at most ten new resource values at a time,
+in a given res/values/*.xml, using the form in the Android Resources pane.
+If you add more than ten, the Android Resources pane will not display the
+attributes fields for the additional resource entries. To work around this
+problem, you can close the file in the editor and open it again, or you
+can edit the resource entries in the XML text mode. </li>
+<li>The emulator's battery-control commands (<code>power &lt;option&gt</code>)
+are not working in this release.</li>
+
+</ul>
+
diff --git a/docs/html/guide/developing/tools/adt_download.jd b/docs/html/sdk/adt_download.jd
index f03cc46..6e9eec4 100644
--- a/docs/html/guide/developing/tools/adt_download.jd
+++ b/docs/html/sdk/adt_download.jd
@@ -29,8 +29,8 @@ page</a>.
<td style="background-color:#ffcccc;">0.8.0</td>
<td style="background-color:#ffcccc;"><a href="http://dl-ssl.google.com/android/ADT-0.8.0.zip">ADT-0.8.0.zip</a></td>
<td style="background-color:#ffcccc;">23&nbsp;September&nbsp;2008</td>
- <td style="background-color:#ffcccc;">Android&nbsp;1.0&nbsp;SDK,&nbsp;Release&nbsp;1</td>
- <td style="background-color:#ffcccc;">Required for users of Android 1.0 SDK, Release&nbsp;1. </td>
+ <td style="background-color:#ffcccc;">Android&nbsp;1.1&nbsp;SDK,&nbsp;Release&nbsp;1<br />Android&nbsp;1.0&nbsp;SDK,&nbsp;Release&nbsp;1<br /></td>
+ <td style="background-color:#ffcccc;">Required for users of Android 1.1 SDK, Release&nbsp;1 and Android&nbsp;1.0&nbsp;SDK,&nbsp;Release&nbsp;1<br /> </td>
</tr>
<tr>
<td>0.7.1</td>
diff --git a/docs/html/sdk/android-1.1.jd b/docs/html/sdk/android-1.1.jd
new file mode 100644
index 0000000..f70ad26
--- /dev/null
+++ b/docs/html/sdk/android-1.1.jd
@@ -0,0 +1,249 @@
+page.title=Android 1.1 Version Notes
+sdk.version=1.1_r1
+sys.date=February 2009
+@jd:body
+
+<p>
+<em>Date:</em> February 2009<br />
+<em>API Level:</em>&nbsp;<strong>2</strong></p>
+
+
+<p>This document provides version notes for the Android 1.1 system image included in the SDK.
+
+<ul>
+<li><a href="#overview">Overview</a>
+<li><a href="#overview">External Libraries</a>
+<li><a href="#comp">Device Compatibility</a>
+<li><a href="#apps">Built-in Applications</a>
+<li><a href="#locs">UI Localizations</a>
+<li><a href="#resolved-issues">Resolved Issues</a>
+<li><a href="#features">New Features</a>
+<li><a href="#api-changes">API Changes</a>
+</ul></p>
+
+<h2 id="overview">Overview</h2>
+
+<p>The Android 1.1 system image delivered in the SDK is the development
+counterpart to the Android 1.1 production system image, deployable to
+Android-powered handsets starting in February 2009. </p>
+
+<p>The Android 1.1 system image delivers an updated version of the framework
+API. As with the Android 1.0 API, the Android 1.1 API
+is assigned an integer identifier &mdash; <strong>2</strong> &mdash; that is
+stored in the system itself. This identifier, called the "API Level", allows the
+system to correctly determine whether an application is compatible with
+the system, prior to installing the application.</p>
+
+<p>Applications can reference a specific API Level value in their
+manifest files, to indicate the minimum version of the Android system
+required to run the app. To reference a minimum API Level, applications
+can add a <code>minSdkVersion</code> attribute in their manifest files.
+The value of the attribute is an integer corresponding to an API Level
+identifier. Prior to installing an application, the system then checks the value of
+<code>minSdkVersion</code> and allows the install only
+if the referenced integer is less than or equal to the API Level integer stored
+in the system itself. </p>
+
+<p>If you use the Android 1.1 system image to build an application
+compatible with Android-powered devices running the Android 1.1
+platform, please note that you <strong><span
+style="color:red;">must</span></strong> set the the
+<code>android:minSdkVersion</code> attribute in the application's
+manifest to "2", which is the API strictly associated with Android 1.1.
+</p>
+
+<p>Specifically, you specify the <code>android:minSdkVersion</code>
+attribute in a <code>&lt;uses-sdk&gt;</code> element as a child of
+<code>&lt;manifest&gt;</code> in the manifest file. When set, the
+attribute looks like this: </p>
+
+<pre><code>&lt;manifest&gt;
+ ...
+ &lt;uses-sdk minSdkVersion="2" /&gt;
+ ...
+&lt;/manifest&gt;</code>
+</pre>
+
+<p>By setting <code>android:minSdkVersion</code> in this way, you ensure
+that users will only be able to install your application if their
+devices are running the Android 1.1 platform. In turn, this ensures that
+your application will function properly on their devices, especially if
+it uses <a href="#apichange">APIs introduced in Android 1.1</a>. </p>
+
+<p>If your application uses APIs introduced in Android 1.1 but does not
+declare <code>&lt;uses-sdk minSdkVersion="2" /&gt;</code>, then it will
+run properly on Android 1.1 devices but <em>not</em> on Android 1.0
+devices. In the latter case, the application will crash at runtime when
+it tries to use the Android 1.1 APIs.</p>
+
+<p>If your application does not use any new APIs introduced in Android
+1.1, you can indicate Android 1.0 compatibility by removing
+<code>minSdkVersion</code> or setting the attribute to "1". However,
+before publishing your application, you must make sure to compile your
+application against the Android 1.0 system image (available in the
+Android 1.0 SDK), to ensure that it builds and functions properly for
+Android 1.0 devices. You should test the application against system
+images corresponding to the API Levels that the application is designed
+to be compatible with.</p>
+
+<p>If you are sure your application is not using Android 1.1 APIs and
+has no need to use them, you might find it easier to keep working in the
+Android 1.0 SDK, rather than migrating to the Android 1.1 SDK and having
+to do additional testing.</p>
+
+
+<h2 id="extlibs">External Libraries</h2>
+
+<p>The system image includes these external libraries, which you can
+access from your application by adding a <a
+href="{@docRoot}guide/topics/manifest/uses-library-element.html">
+&lt;uses-library&gt;</a>.</p>
+ <ul>
+ <li>com.google.android.maps &mdash; gives your
+application access to Google Maps data. Note that, to use Google Maps
+data, a Maps API Key is required.</li>
+ </ul>
+
+<h2 id="comp">Device Compatibility</h2>
+
+<p>The Android 1.1 system image was tested for compatability with the
+Android-powered devices listed below:</p>
+ <ul>
+ <li><a href="http://www.t-mobileg1.com">T-Mobile G1</a></li>
+ </ul>
+
+<h2 id="apps">Built-in Applications</h2>
+
+<p>The system image includes these built-in applications:</p>
+ <ul>
+ <li>Alarm Clock</li>
+ <li>API Demos</li>
+ <li>Browser</li>
+ <li>Calculator</li>
+ <li>Camera</li>
+ <li>Contacts</li>
+ <li>Dev Tools</li>
+ <li>Dialer</li>
+ <li>Email</li>
+ <li>Maps (and StreetView)</li>
+ <li>Messaging</li>
+ <li>Music</li>
+ <li>Pictures</li>
+ <li>Settings</li>
+ </ul>
+
+<h2 id="locs">UI Localizations</h2>
+
+<p>The system image provides localized UI strings for the languages
+listed below.</p>
+ <ul>
+ <li>English, US (en_US)</li>
+ <li>German (de) </li>
+ </ul>
+
+<p>Localized UI strings match the locales that are displayable in
+the emulator, accessible through the device Settings application.</p>
+
+<h2 id="resolved-issues">Resolved Issues</h2>
+<ul>
+<li>AlarmClock alert now plays audio/vibe directly, rather than through
+AlarmManager. AlarmClock alert starts playing audio/vibe in its
+IntentReceiver, rather than on activity start. These changes should
+prevent alarms from being blocked by modal dialogs.</li>
+<li>Fixes to device sleep. </li>
+<li>Single tap no longer opens the in-call dialpad; users now need to
+touch and drag it. </li>
+<li>Fixes a bug causing approximately 1 in 25 outbound messages to
+freeze up the IMAP connection (to a Gmail based server) when transferred
+to the Sent folder.</li>
+<li>Removes automatic account setup entries that were broken or not
+testable. Adds minor fixes to a few of the remaining entries. Makes
+improvements to warning dialogs used for a few special cases. </li>
+<li>Changes default mail checking interval to every 15 minutes (instead
+of defaulting to "never").</li>
+<li>Fixes password-quoting bugs in IMAP, so that users can include
+special characters in passwords (e.g. spaces).</li>
+<li>Fixes various errors in auto and manual account setup </li>
+<li>Improves reporting for various connection errors, making it easier
+for the user to diagnose failed account setups.</li>
+<li>Fixes new-mail notifications for POP3 accounts.</li>
+<li>Ensures proper auto-checking of accounts marked as "never
+check".</li>
+<li>Now displays date and time using user preference (e.g. 24 hr vs.
+AM/PM).</li>
+<li>Now shows cc: in message view.</li>
+<li>Improves recovery from POP3 connection failures.</li>
+<li>POP3 parser rules loosened, so the application can work with
+non-compliant email servers.</li>
+</ul>
+
+<h2 id="features">New Features</h2>
+
+<ul>
+<li>Maps: Adds details and reviews when a user does a search on Maps and
+clicks on a business to view its details.</li>
+<li>Dialer: In-call screen timeout default is now longer when using the
+speakerphone.</li>
+<li>Dialer: Adds a "Show dialpad" / "Hide dialpad" item to the in-call
+menu, to make it easier to discover the DTMF dialpad. </li>
+<li>Adds support for saving attachments from MMS</li>
+<li>Adds support for marquee in layouts.</li>
+</ul>
+
+<h2 id="api-changes">API Changes</h2>
+
+<h3>Overview</strong></h3>
+
+<ul>
+<li>Adds annotations for test systems, no actual (non-test) API
+changes.</li>
+<li>Adds a method to allow a process to easily determine its UID.
+<li>Adds support for marquee in layouts.</li>
+<li>Adds new methods for determining padding in views. Useful if you are
+writing your own
+subclasses of {@link android.view.View View}.</li>
+<li>Adds new permissions that allow an application to broadcast an SMS
+or WAP Push message. </li>
+<li>API cleanup: removes protected constructor from
+SDK-bound system images. </li>
+</ul>
+
+<h3>API Change Details</h3>
+
+<table>
+<tr>
+<th>Module or Feature</th><th>Change Description</th>
+</tr>
+<tr><td rowspan="4">Annotations for test systems</td></tr>
+ <tr><td>Added {@link android.test.suitebuilder.annotation.LargeTest LargeTest} annotation.</td></tr>
+ <tr><td>Added {@link android.test.suitebuilder.annotation.MediumTest MediumTest} annotation.</td></tr>
+ <tr><td>Added {@link android.test.suitebuilder.annotation.SmallTest SmallTest} annotation.</td></tr>
+
+<tr><td rowspan="2">Allow a process to easily know its UID.</td></tr>
+ <tr><td>Added public method {@link android.os.Process#myUid} to class {@link android.os.Process android.os.Process}</td></tr>
+
+<tr><td rowspan="6">Padding in views</td></tr>
+ <tr><td>Added public method {@link android.view.View#getBottomPaddingOffset} to class {@link android.view.View android.view.View}.</td></tr>
+ <tr><td>Added public method {@link android.view.View#getLeftPaddingOffset} to class {@link android.view.View android.view.View}.</td></tr>
+ <tr><td>Added public method {@link android.view.View#getRightPaddingOffset} to class {@link android.view.View android.view.View}.</td></tr>
+ <tr><td>Added public method {@link android.view.View#getTopPaddingOffset} to class {@link android.view.View android.view.View}.</td></tr>
+ <tr><td>Added public method {@link android.view.View#isPaddingOffsetRequired} to class {@link android.view.View android.view.View}.</td></tr>
+
+<tr><td rowspan="3">Marquee support</td></tr>
+ <tr><td>Added public method {@link android.widget.TextView#setMarqueeRepeatLimit} to class {@link android.widget.TextView}</td></tr>
+ <tr><td>Added public field {@link android.R.attr#marqueeRepeatLimit android.R.attr.marqueeRepeatLimit}</td></tr>
+
+<tr><td rowspan="3">New permissions</td></tr>
+ <tr><td>Added public field {@link android.Manifest.permission#BROADCAST_SMS android.Manifest.permission.BROADCAST_SMS}</td></tr>
+ <tr><td>Added public field {@link android.Manifest.permission#BROADCAST_WAP_PUSH android.Manifest.permission.BROADCAST_WAP_PUSH}</td></tr>
+
+<tr><td rowspan="2">API cleanup</td></tr>
+ <tr><td>Removed protected constructor java.net.ServerSocket.ServerSocket(java.net.SocketImpl).</td></tr>
+
+</table>
+
+
+
+
+
+
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
new file mode 100644
index 0000000..3c4f06b
--- /dev/null
+++ b/docs/html/sdk/download.jd
@@ -0,0 +1,86 @@
+page.title=Download the Android SDK
+hide_license_footer=true
+
+@jd:body
+
+<script language="javascript">
+ function verify() {
+ document.getElementById('download-button').disabled = !document.getElementById('checkbox').checked;
+ }
+ function submit() {
+ var location = window.location.href;
+ if (location.indexOf('?v=') != -1) {
+ var filename = location.substring(location.indexOf('=')+1,location.length);
+ if (document.getElementById('checkbox').checked) {
+ document.location = "http://dl.google.com/android/" + filename;
+ }
+ document.getElementById('click-download').setAttribute("href", "http://dl.google.com/android/" + filename);
+ $("#terms-form").hide(500);
+ $("#next-steps").show(500);
+ document.getElementById('checkbox').disabled=true;
+ document.getElementById('download-button').disabled=true;
+ } else {
+ alert("You have not selected an SDK version. Please return to the Download page");
+ }
+ }
+</script>
+
+<div id="terms-form">
+ <p>Please carefully review the Android SDK License Agreement before downloading the SDK.
+The License Agreement constitutes a contract between you and Google with respect to your use of the SDK.</p>
+
+ <iframe id="terms" style="border:1px solid #888;margin:0 0 1em;height:400px;width:95%;" src="terms_body.html">
+ </iframe>
+
+ <p>
+ <input type="checkbox" id="checkbox" onclick="verify()" />
+ <label for="checkbox">I agree to the terms of the Android SDK License Agreement.</label>
+ </p>
+ <p>
+ <input type="submit" value="Download" id="download-button" disabled="disabled" onclick="submit()" />
+ </p>
+ <p>
+ <script language="javascript">
+ var loc = window.location.href;
+ if (loc.indexOf('?v=') != -1) {
+ var filename = loc.substring(loc.indexOf('=')+1,loc.length);
+ document.write("File: " + filename);
+ }
+ </script>
+ </p>
+</div><!-- end terms-form -->
+
+<noscript>
+ <p><strong>Please enable Javascript in your browser in order to agree to the terms and download the SDK.</strong></p>
+</noscript>
+
+<div class="special" id="next-steps" style="display:none">
+ <h2>Thank you for downloading the Android SDK!</h2>
+ <p>Your download should be underway. If not, <a id="click-download">click here to start the download</a>.</p>
+ <p>If you are upgrading from a previously installed version of the Android SDK, see
+ <a href="upgrading.html" class="addVersionPath">Upgrading the SDK</a>.</p>
+ <p>If you are installing for the first time, read
+ <a href="installing.html" class="addVersionPath">Installing the Android SDK</a> to get your environment set up.
+ Once you have completed your installation, visit the <em>Dev Guide</em> tab and begin with the
+ <a href="/guide/tutorials/hello-world.html">Hello World</a> tutorial to create your first
+ Android application. From there, learn more about Android with the
+ <a href="/guide/topics/fundamentals.html">Application Fundamentals</a> documentation.</p>
+ <p>If you want to re-read the license agreement, it's available to you in the <em>SDK</em> tab.</p>
+</div>
+
+<script language="javascript">
+ var loc = window.location.href;
+ var filename = loc.substring(loc.indexOf('=')+1,loc.length);
+ version = filename.substring(filename.indexOf('.')-1,filename.lastIndexOf('.'));
+ $(".addVersionPath").each(function(i) {
+ var oldHref = $(this).attr("href");
+ $(this).attr({href: "/sdk/" + version + "/" + oldHref});
+ });
+</script>
+
+
+
+
+
+
+
diff --git a/docs/html/sdk/index.html b/docs/html/sdk/index.html
deleted file mode 100644
index c5468dd..0000000
--- a/docs/html/sdk/index.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<html>
-<head>
-<title>Redirecting...</title>
-<meta http-equiv="refresh" content="0;url=1.0_r1/index.html">
-</head>
-</html> \ No newline at end of file
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
new file mode 100644
index 0000000..38db6f8
--- /dev/null
+++ b/docs/html/sdk/index.jd
@@ -0,0 +1,5 @@
+sdk.redirect=1.1_r1
+@jd:body
+
+
+
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 11d3086..76c1c84 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -1,37 +1,42 @@
-<ul>
- <li><h2>Android 1.0</h2>
+<ul>
+ <li><?cs
+ if:android.whichdoc != "online" ?>
+ <h2>Android 1.1 SDK, r1</h2><?cs
+ else ?>
+ <h2>Current SDK Release</h2><?cs
+ /if ?>
+ <ul><?cs
+ if:android.whichdoc == "online" ?>
+ <li><a href="<?cs var:toroot ?>sdk/1.1_r1/index.html">Download</a></li><?cs
+ /if ?>
+ <li><a href="<?cs var:toroot ?>sdk/1.1_r1/installing.html">Installing</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/1.1_r1/upgrading.html">Upgrading</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/1.1_r1/requirements.html">System Requirements</a></li>
+ </ul>
<ul>
- <li><strong><a href="<?cs var:toroot ?>sdk/1.0_r1/index.html">Release 1</a></strong>
- <ul>
- <li><a href="<?cs var:toroot ?>sdk/1.0_r1/RELEASENOTES.html">Release Notes</a></li>
- </ul>
- </li>
-
- <li><strong><a href="<?cs var:toroot ?>sdk/1.0_r2/index.html">Release 2</a></strong>
- <ul>
- <li><a href="<?cs var:toroot ?>sdk/1.0_r2/RELEASENOTES.html">Release Notes</a></li>
- </ul>
- </li>
-
+ <li><a href="<?cs var:toroot ?>sdk/terms.html">SDK Terms and Conditions</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/RELEASENOTES.html">SDK Release Notes</a></li>
+ </ul><?cs
+ if:android.whichdoc == "online" ?>
+ <li>
+ <h2>Android System Images</h2>
+ <ul>
+ <li><a href="<?cs var:toroot ?>sdk/android-1.1.html">Android 1.1 Version Notes</a></li>
</ul>
</li>
-<!-- just a template
- <li><h2>Android 1.1</h2>
+ <li>
+ <h2>Previous SDK Releases</h2>
<ul>
- <li><strong><a href="<?cs var:toroot ?>sdk/1.1_r1/index.html">Release 1</a></strong>
- <ul>
- <li><a href="<?cs var:toroot ?>sdk/1.1_r1/RELEASENOTES.html">Release Notes</a></li>
- </ul>
- </li>
- <li><strong><a href="<?cs var:toroot ?>sdk/1.1_r2/index.html">Release 2</a></strong>
- <ul>
- <li><a href="<?cs var:toroot ?>sdk/1.1_r2/RELEASENOTES.html">Release Notes</a></li>
- </ul>
- </li>
+ <li><a href="<?cs var:toroot ?>sdk/1.0_r2/index.html">Android 1.0 SDK, release 2</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/1.0_r1/index.html">Android 1.0 SDK, release 1</a></li>
</ul>
- </li>
--->
- <li><a href="<?cs var:toroot ?>sdk/terms.html">Terms and Conditions</a></li>
+ </li><?cs
+ /if ?>
</ul>
+<script type="text/javascript">
+<!--
+ buildToggleLists();
+//-->
+</script> \ No newline at end of file
diff --git a/docs/html/sdk/terms.jd b/docs/html/sdk/terms.jd
index 5599fa6..4638850 100644
--- a/docs/html/sdk/terms.jd
+++ b/docs/html/sdk/terms.jd
@@ -1,4 +1,5 @@
page.title=Terms and Conditions
+hide_license_footer=true
@jd:body
<p>This is the Android Software Development Kit License Agreement.</p>
diff --git a/docs/html/sdk/terms_body.html b/docs/html/sdk/terms_body.html
new file mode 100644
index 0000000..e8fdc3c
--- /dev/null
+++ b/docs/html/sdk/terms_body.html
@@ -0,0 +1,216 @@
+
+<p>This is the Android Software Development Kit License Agreement.</p>
+
+<h2>
+ 1. Introduction
+</h2>
+<p>
+ 1.1 The Android Software Development Kit (referred to in this License Agreement as the "SDK" and specifically including the Android system files and packaged APIs) is licensed to you subject to the terms of this License Agreement. This License Agreement forms a legally binding contract between you and Google in relation to your use of the SDK.
+</p>
+<p>
+ 1.2 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.
+</p>
+<h2>
+ 2. Accepting this License Agreement
+</h2>
+<p>
+ 2.1 In order to use the SDK, you must first agree to this License Agreement. You may not use the SDK if you do not accept this License Agreement.
+</p>
+<p>
+ 2.2 You can accept this License Agreement by:
+</p>
+<p>
+ (A) clicking to accept or agree to this License Agreement, where this option is made available to you; or
+</p>
+<p>
+ (B) by actually using the SDK. In this case, you agree that use of the SDK constitutes acceptance of the Licensing Agreement from that point onwards.
+</p>
+<p>
+ 2.3 You may not use the SDK and may not accept the Licensing Agreement if you are a person barred from receiving the SDK under the laws of the United States or other countries including the country in which you are resident or from which you use the SDK.
+</p>
+<p>
+ 2.4 If you are agreeing to be bound by this License Agreement on behalf of your employer or other entity, you represent and warrant that you have full legal authority to bind your employer or such entity to this License Agreement. If you do not have the requisite authority, you may not accept the Licensing Agreement or use the SDK on behalf of your employer or other entity.
+</p>
+<h2>
+ 3. SDK License from Google
+</h2>
+<p>
+ 3.1 Subject to the terms of this License Agreement, Google grants you a limited, worldwide, royalty-free, non- assignable and non-exclusive license to use the SDK solely to develop applications to run on the Android platform.
+</p>
+<p>
+ 3.2 You agree that Google or third parties own all legal right, title and interest in and to the SDK, including any Intellectual Property Rights that subsist in the SDK. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. The Android Open Source Project
+</p>
+<p>
+ 3.3 Except to the extent required by applicable third party licenses, you may not copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the SDK or any part of the SDK. Except to the extent required by applicable third party licenses, you may not load any part of the SDK onto a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other software, or distribute any software or device incorporating a part of the SDK.
+</p>
+<p>
+ 3.4 Use, reproduction and distribution of components of the SDK licensed under an open source software license are governed solely by the terms of that open source software license and not this License Agreement.
+</p>
+<p>
+ 3.5 You agree that the form and nature of the SDK that Google provides may change without prior notice to you and that future versions of the SDK may be incompatible with applications developed on previous versions of the SDK. You agree that Google may stop (permanently or temporarily) providing the SDK (or any features within the SDK) to you or to users generally at Google's sole discretion, without prior notice to you.
+</p>
+<p>
+ 3.6 Nothing in this License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features.
+</p>
+<p>
+ 3.7 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the SDK.
+</p>
+<h2>
+ 4. Use of the SDK by You
+</h2>
+<p>
+ 4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under this License Agreement in or to any software applications that you develop using the SDK, including any intellectual property rights which subsist in those applications.
+</p>
+<p>
+ 4.2 You agree to use the SDK and write applications only for purposes that are permitted by (a) this License Agreement and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries).
+</p>
+<p>
+ 4.3 You agree that if you use the SDK to develop applications for general public users, you will protect the privacy and legal rights of those users. If the users provide you with user names, passwords, or other login information or personal information, your must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If the user provides your application with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, the user has given you permission to do so.
+</p>
+<p>
+ 4.4 You agree that you will not engage in any activity with the SDK, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party including, but not limited to, Google or any mobile communications carrier.
+</p>
+<p>
+ 4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through the Android platform and/or applications for the Android platform, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so.
+</p>
+<p>
+ 4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under this License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach.
+</p>
+<h2>
+ 5. Your Developer Credentials
+</h2>
+<p>
+ 5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials.
+</p>
+<h2>
+ 6. Privacy and Information
+</h2>
+<p>
+ 6.1 In order to continually innovate and improve the SDK, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the SDK are being used and how they are being used. Before any of this information is collected, the SDK will notify you and seek your consent. If you withhold consent, the information will not be collected.
+</p>
+<p>
+ 6.2 The data collected is examined in the aggregate to improve the SDK and is maintained in accordance with Google's Privacy Policy.
+</p>
+<h2>
+ 7. Third Party Applications for the Android Platform
+</h2>
+<p>
+ 7.1 If you use the SDK to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources.
+</p>
+<p>
+ 7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners.
+</p>
+<p>
+ 7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party. In that case, this License Agreement does not affect your legal relationship with these third parties.
+</p>
+<h2>
+ 8. Using Android APIs
+</h2>
+<p>
+ 8.1 Android Maps API
+</p>
+<p>
+ 8.1.1 If you use the Android Maps API (described in the SDK by the Package names "com.google.android.maps" and "com.android.location.Geocoder"), the terms of your binding legal agreement with Google include this License Agreement, the <a href="http://www.google.com/apis/maps/terms.html">Google Maps API Terms of Service</a> and the <a href="http://www.google.com/intl/en_ALL/help/terms_local.html">Google Maps Terms of Service</a>. You must read and agree to those Terms of Service before you use the Android Maps API.
+</p>
+<p>
+ 8.1.2 If you use the Android Maps API to retrieve map or satellite image data from Google, you must include the following copyright notice in your application or service in a manner that is reasonably available to users:
+</p>
+<p>
+ "Copyright Notice: Data: (c)2007 TeleAtlas, AND, Europa Technologies, Kingway, Map Data Sciences Pty Ltd, PSMA, ZENRIN, Geocentre, MapLink/TeleAtlas; Imagery: (c)2007 DigitalGlobe, EarthSat, Sanborn, NYGIS, Scankort, TerraMetrics, MassGIS Commonwealth of Massachusetts, Digital Earth Technology."
+</p>
+<p>
+ 8.2 Google Data APIs
+</p>
+<p>
+ 8.2.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by those who provide that data (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless you have been specifically given permission to do so by the owners of that data.
+</p>
+<p>
+ 8.2.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so.
+</p>
+<h2>
+ 9. Terminating this License Agreement
+</h2>
+<p>
+ 9.1 This License Agreement will continue to apply until terminated by either you or Google as set out below.
+</p>
+<p>
+ 9.2 If you want to terminate this License Agreement, you may do so by ceasing your use of the SDK and any relevant developer credentials.
+</p>
+<p>
+ 9.3 Google may at any time, terminate this License Agreement with you if:
+</p>
+<p>
+ (A) you have breached any provision of this License Agreement; or
+</p>
+<p>
+ (B) Google is required to do so by law; or
+</p>
+<p>
+ (C) the partner with whom Google offered certain parts of SDK (such as APIs) to you has terminated its relationship with Google or ceased to offer certain parts of the SDK to you; or
+</p>
+<p>
+ (D) Google decides to no longer providing the SDK or certain parts of the SDK to users in the country in which you are resident or from which you use the service, or the provision of the SDK or certain SDK services to you by Google is, in Google's sole discretion, no longer commercially viable.
+</p>
+<p>
+ 9.4 When this License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and Google have benefited from, been subject to (or which have accrued over time whilst this License Agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely.
+</p>
+<h2>
+ 10. DISCLAIMER OF WARRANTIES
+</h2>
+<p>
+ 10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND THAT THE SDK IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE.
+</p>
+<p>
+ 10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE SDK IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE.
+</p>
+<p>
+ 10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+</p>
+<h2>
+ 11. LIMITATION OF LIABILITY
+</h2>
+<p>
+ 11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING.
+</p>
+<h2>
+ 12. Indemnification
+</h2>
+<p>
+ 12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or accruing from (a) your use of the SDK, (b) any application you develop on the SDK that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with this License Agreement.
+</p>
+<h2>
+ 13. Changes to the License Agreement
+</h2>
+<p>
+ 13.1 Google may make changes to the License Agreement as it distributes new versions of the SDK. When these changes are made, Google will make a new version of the License Agreement available on the website where the SDK is made available and with the SDK downloadable.
+</p>
+<p>
+ 13.2 You agree that your use of a specific version of the SDK is governed by the License Agreement included with that version of the SDK.
+</p>
+<h2>
+ 14. General Legal Terms
+</h2>
+<p>
+ 14.1 This License Agreement constitute the whole legal agreement between you and Google and govern your use of the SDK (excluding any services which Google may provide to you under a separate written agreement), and completely replace any prior agreements between you and Google in relation to the SDK.
+</p>
+<p>
+ 14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in this License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google.
+</p>
+<p>
+ 14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of this License Agreement is invalid, then that provision will be removed from this License Agreement without affecting the rest of this License Agreement. The remaining provisions of this License Agreement will continue to be valid and enforceable.
+</p>
+<p>
+ 14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to this License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of this License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to this License Agreement.
+</p>
+<p>
+ 14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE.
+</p>
+<p>
+ 14.6 The rights granted in this License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under this License Agreement without the prior written approval of the other party.
+</p>
+<p>
+ 14.7 This License Agreement, and your relationship with Google under this License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from this License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
+</p>
+<p>
+ <em>August 18, 2008</em>
+</p>
diff --git a/docs/html/search.jd b/docs/html/search.jd
index 9269d2c..0a802a6 100755..100644
--- a/docs/html/search.jd
+++ b/docs/html/search.jd
@@ -1,77 +1,101 @@
page.title=Search Results
@jd:body
-
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="/assets/jquery-history.js" type="text/javascript"></script>
<script type="text/javascript">
google.load('search', '1');
-
- // the cse class encapsulates a left and right search control
- // both controls are driven by a shared search form
- function cse() {
- var sFormDiv = document.getElementById("searchForm");
- var leftScDiv = document.getElementById("leftSearchControl");
-
- // create a left, right search control
- // create a custom search form
- this.leftControl = new google.search.SearchControl();
- this.searchForm = new google.search.SearchForm(true, sFormDiv);
-
- // bind clear and submit functions
- this.searchForm.setOnSubmitCallback(this, cse.prototype.onSubmit);
- this.searchForm.setOnClearCallback(this, cse.prototype.onClear);
-
- // set up for small result sets
- this.leftControl.setResultSetSize(google.search.Search.LARGE_RESULTSET);
-
- var searcher;
- var options;
-
- // configure left control
- // Site Restrict to CSE ID for reviews
- searcher = new google.search.WebSearch();
- options = new google.search.SearcherOptions();
- //searcher.setSiteRestriction("000455696194071821846:reviews");
- //searcher.setUserDefinedLabel("Product Reviews");
- options.setExpandMode(GSearchControl.EXPAND_MODE_OPEN);
- this.leftControl.addSearcher(searcher, options);
-
- // draw the left and right controls
- this.leftControl.draw(leftScDiv);
-
- // execute a starter search
- urlquery=location.href.split("?");
- urlterms=urlquery[1].split(",");
- document.getElementById("searchTitle").innerHTML = urlterms[0];
- this.searchForm.execute(urlterms[0]);
- }
+ function OnLoad() {
+ document.getElementById("search_autocomplete").style.color = "#000";
- // when the form fires a submit, grab its
- // value and call the left and right control
- cse.prototype.onSubmit = function(form) {
- var q = form.input.value;
- if (q && q!= "") {
- this.leftControl.execute(q);
-
- document.getElementById("searchTitle").innerHTML = "search results for \"" + q + "\"";
- }
- return false;
- }
+ // create search control
+ searchControl = new google.search.SearchControl();
- // when the form fires a clear, call the left and right control
- cse.prototype.onClear = function(form) {
- //this.leftControl.clearAllResults();
- //form.input.value = "";
- document.getElementById("searchTitle").innerHTML = form.input.value;
- return false;
- }
+ // use our existing search form and use tabs when multiple searchers are used
+ drawOptions = new google.search.DrawOptions();
+ drawOptions.setDrawMode(google.search.SearchControl.DRAW_MODE_TABBED);
+ drawOptions.setInput(document.getElementById("search_autocomplete"));
- function OnLoad() {
- new cse();
+ // configure search result options
+ searchOptions = new google.search.SearcherOptions();
+ searchOptions.setExpandMode(GSearchControl.EXPAND_MODE_OPEN);
+
+ // configure each of the searchers, for each tab
+ devSiteSearcher = new google.search.WebSearch();
+ devSiteSearcher.setUserDefinedLabel("All Developers Site");
+ devSiteSearcher.setSiteRestriction("http://developer.android.com/");
+
+ devGuideSearcher = new google.search.WebSearch();
+ devGuideSearcher.setUserDefinedLabel("Dev Guide");
+ devGuideSearcher.setSiteRestriction("http://developer.android.com/guide/");
+
+ referenceSearcher = new google.search.WebSearch();
+ referenceSearcher.setUserDefinedLabel("Reference");
+ referenceSearcher.setSiteRestriction("http://developer.android.com/reference/");
+
+ blogSearcher = new google.search.WebSearch();
+ blogSearcher.setUserDefinedLabel("Blog");
+ blogSearcher.setSiteRestriction("http://android-developers.blogspot.com");
+
+ groupsSearcher = new google.search.WebSearch();
+ groupsSearcher.setUserDefinedLabel("Developer Groups");
+ groupsSearcher.setSiteRestriction("001283715400630100512:ggqrtvkztwm");
+
+ sourceSiteSearcher = new google.search.WebSearch();
+ sourceSiteSearcher.setUserDefinedLabel("Android Source");
+ sourceSiteSearcher.setSiteRestriction("http://source.android.com");
+
+ homeSiteSearcher = new google.search.WebSearch();
+ homeSiteSearcher.setUserDefinedLabel("Android Home");
+ homeSiteSearcher.setSiteRestriction("http://www.android.com");
+
+ // add each searcher to the search control
+ searchControl.addSearcher(devSiteSearcher, searchOptions);
+ searchControl.addSearcher(devGuideSearcher, searchOptions);
+ searchControl.addSearcher(referenceSearcher, searchOptions);
+ searchControl.addSearcher(groupsSearcher, searchOptions);
+ searchControl.addSearcher(sourceSiteSearcher, searchOptions);
+ searchControl.addSearcher(blogSearcher, searchOptions);
+
+ // configure result options
+ searchControl.setResultSetSize(google.search.Search.LARGE_RESULTSET);
+ searchControl.setLinkTarget(google.search.Search.LINK_TARGET_SELF);
+ searchControl.setTimeoutInterval(google.search.SearchControl.TIMEOUT_LONG);
+ searchControl.setNoResultsString(google.search.SearchControl.NO_RESULTS_DEFAULT_STRING);
+
+ // upon ajax search, refresh the url and search title
+ searchControl.setSearchStartingCallback(this, function(control, searcher, query) {
+ $("#searchTitle").html("search results for <em>" + query + "</em>");
+ $.history.add('q=' + query); // add the current query to the browser history
+ });
+
+ // draw the search results box
+ searchControl.draw(document.getElementById("leftSearchControl"), drawOptions);
+
+ // execute a search upon page load, from url hash query
+ if (location.href.indexOf("#q=") != -1) {
+ url = location.href.split("#q=");
+ searchControl.execute(decodeURI(url[1]));
+ }
+ document.getElementById("search_autocomplete").focus();
}
+
google.setOnLoadCallback(OnLoad, true);
+
+ // when an event on the browser history occurs (back, forward, load) perform a search
+ $(window).history(function(e, hash) {
+ hashParts = hash.split('=');
+ searchControl.execute(decodeURI(hashParts[1]));
+ $("#searchTitle").html("search results for <em>" + decodeURI(hashParts[1]) + "</em>");
+ });
+
+ // forcefully regain key-up event control (previously jacked by search api)
+ $("#search_autocomplete").keyup(function(event) {
+ return search_changed(event, false, '/');
+ });
</script>
+
<div id="mainBodyFixed" style="width:auto; margin:20px">
<h2 id="searchTitle">search results</h2>
<img src="{@docRoot}assets/images/hr_gray_main.jpg" />
diff --git a/docs/html/sitemap.txt b/docs/html/sitemap.txt
new file mode 100644
index 0000000..a8221bf
--- /dev/null
+++ b/docs/html/sitemap.txt
@@ -0,0 +1,5444 @@
+http://developer.android.com/index.html
+http://developer.android.com/sdk/1.1_r1/index.html
+http://developer.android.com/guide/index.html
+http://developer.android.com/reference/packages.html
+http://developer.android.com/community/index.html
+http://developer.android.com/sdk/index.html
+http://developer.android.com/license.html
+http://developer.android.com/sdk/terms.html
+http://developer.android.com/guide/developing/tools/index.html
+http://developer.android.com/reference/com/google/android/maps/package-summary.html
+http://developer.android.com/reference/classes.html
+http://developer.android.com/reference/android/package-summary.html
+http://developer.android.com/reference/android/app/package-summary.html
+http://developer.android.com/reference/android/content/package-summary.html
+http://developer.android.com/reference/android/content/pm/package-summary.html
+http://developer.android.com/reference/android/content/res/package-summary.html
+http://developer.android.com/reference/android/database/package-summary.html
+http://developer.android.com/reference/android/database/sqlite/package-summary.html
+http://developer.android.com/reference/android/graphics/package-summary.html
+http://developer.android.com/reference/android/graphics/drawable/package-summary.html
+http://developer.android.com/reference/android/graphics/drawable/shapes/package-summary.html
+http://developer.android.com/reference/android/hardware/package-summary.html
+http://developer.android.com/reference/android/location/package-summary.html
+http://developer.android.com/reference/android/media/package-summary.html
+http://developer.android.com/reference/android/net/package-summary.html
+
+http://developer.android.com/reference/android/net/http/package-summary.html
+http://developer.android.com/reference/android/net/wifi/package-summary.html
+
+http://developer.android.com/reference/android/opengl/package-summary.html
+http://developer.android.com/reference/android/os/package-summary.html
+
+http://developer.android.com/reference/android/preference/package-summary.html
+http://developer.android.com/reference/android/provider/package-summary.html
+
+http://developer.android.com/reference/android/sax/package-summary.html
+http://developer.android.com/reference/android/telephony/package-summary.html
+
+http://developer.android.com/reference/android/telephony/gsm/package-summary.html
+http://developer.android.com/reference/android/test/package-summary.html
+
+http://developer.android.com/reference/android/test/mock/package-summary.html
+http://developer.android.com/reference/android/test/suitebuilder/package-summary.html
+
+http://developer.android.com/reference/android/text/package-summary.html
+http://developer.android.com/reference/android/text/method/package-summary.html
+
+http://developer.android.com/reference/android/text/style/package-summary.html
+http://developer.android.com/reference/android/text/util/package-summary.html
+
+http://developer.android.com/reference/android/util/package-summary.html
+http://developer.android.com/reference/android/view/package-summary.html
+
+http://developer.android.com/reference/android/view/animation/package-summary.html
+http://developer.android.com/reference/android/webkit/package-summary.html
+
+http://developer.android.com/reference/android/widget/package-summary.html
+http://developer.android.com/reference/dalvik/bytecode/package-summary.html
+
+http://developer.android.com/reference/dalvik/system/package-summary.html
+http://developer.android.com/reference/java/awt/font/package-summary.html
+
+http://developer.android.com/reference/java/io/package-summary.html
+http://developer.android.com/reference/java/lang/package-summary.html
+
+http://developer.android.com/reference/java/lang/annotation/package-summary.html
+http://developer.android.com/reference/java/lang/ref/package-summary.html
+
+http://developer.android.com/reference/java/lang/reflect/package-summary.html
+http://developer.android.com/reference/java/math/package-summary.html
+
+http://developer.android.com/reference/java/net/package-summary.html
+http://developer.android.com/reference/java/nio/package-summary.html
+
+http://developer.android.com/reference/java/nio/channels/package-summary.html
+http://developer.android.com/reference/java/nio/channels/spi/package-summary.html
+
+http://developer.android.com/reference/java/nio/charset/package-summary.html
+http://developer.android.com/reference/java/nio/charset/spi/package-summary.html
+
+http://developer.android.com/reference/java/security/package-summary.html
+http://developer.android.com/reference/java/security/acl/package-summary.html
+
+http://developer.android.com/reference/java/security/cert/package-summary.html
+http://developer.android.com/reference/java/security/interfaces/package-summary.html
+
+http://developer.android.com/reference/java/security/spec/package-summary.html
+http://developer.android.com/reference/java/sql/package-summary.html
+
+http://developer.android.com/reference/java/text/package-summary.html
+http://developer.android.com/reference/java/util/package-summary.html
+
+http://developer.android.com/reference/java/util/concurrent/package-summary.html
+http://developer.android.com/reference/java/util/concurrent/atomic/package-summary.html
+
+http://developer.android.com/reference/java/util/concurrent/locks/package-summary.html
+http://developer.android.com/reference/java/util/jar/package-summary.html
+
+http://developer.android.com/reference/java/util/logging/package-summary.html
+http://developer.android.com/reference/java/util/prefs/package-summary.html
+
+http://developer.android.com/reference/java/util/regex/package-summary.html
+http://developer.android.com/reference/java/util/zip/package-summary.html
+
+http://developer.android.com/reference/javax/crypto/package-summary.html
+http://developer.android.com/reference/javax/crypto/interfaces/package-summary.html
+
+http://developer.android.com/reference/javax/crypto/spec/package-summary.html
+http://developer.android.com/reference/javax/microedition/khronos/egl/package-summary.html
+
+http://developer.android.com/reference/javax/microedition/khronos/opengles/package-summary.html
+
+http://developer.android.com/reference/javax/net/package-summary.html
+http://developer.android.com/reference/javax/net/ssl/package-summary.html
+
+http://developer.android.com/reference/javax/security/auth/package-summary.html
+http://developer.android.com/reference/javax/security/auth/callback/package-summary.html
+
+http://developer.android.com/reference/javax/security/auth/login/package-summary.html
+http://developer.android.com/reference/javax/security/auth/x500/package-summary.html
+
+http://developer.android.com/reference/javax/security/cert/package-summary.html
+http://developer.android.com/reference/javax/sql/package-summary.html
+
+http://developer.android.com/reference/javax/xml/package-summary.html
+http://developer.android.com/reference/javax/xml/parsers/package-summary.html
+
+http://developer.android.com/reference/junit/framework/package-summary.html
+http://developer.android.com/reference/junit/runner/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/package-summary.html
+http://developer.android.com/reference/org/apache/http/auth/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/auth/params/package-summary.html
+http://developer.android.com/reference/org/apache/http/client/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/client/entity/package-summary.html
+http://developer.android.com/reference/org/apache/http/client/methods/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/client/params/package-summary.html
+http://developer.android.com/reference/org/apache/http/client/protocol/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/client/utils/package-summary.html
+http://developer.android.com/reference/org/apache/http/conn/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/conn/params/package-summary.html
+http://developer.android.com/reference/org/apache/http/conn/routing/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/conn/scheme/package-summary.html
+http://developer.android.com/reference/org/apache/http/conn/ssl/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/conn/util/package-summary.html
+http://developer.android.com/reference/org/apache/http/cookie/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/cookie/params/package-summary.html
+http://developer.android.com/reference/org/apache/http/entity/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/impl/package-summary.html
+http://developer.android.com/reference/org/apache/http/impl/auth/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/package-summary.html
+http://developer.android.com/reference/org/apache/http/impl/conn/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/package-summary.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/impl/entity/package-summary.html
+http://developer.android.com/reference/org/apache/http/impl/io/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/io/package-summary.html
+http://developer.android.com/reference/org/apache/http/message/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/params/package-summary.html
+http://developer.android.com/reference/org/apache/http/protocol/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/util/package-summary.html
+http://developer.android.com/reference/org/json/package-summary.html
+
+http://developer.android.com/reference/org/w3c/dom/package-summary.html
+http://developer.android.com/reference/org/xml/sax/package-summary.html
+
+http://developer.android.com/reference/org/xml/sax/ext/package-summary.html
+http://developer.android.com/reference/org/xml/sax/helpers/package-summary.html
+
+http://developer.android.com/reference/org/xmlpull/v1/package-summary.html
+http://developer.android.com/reference/org/xmlpull/v1/sax2/package-summary.html
+
+http://developer.android.com/reference/org/apache/http/message/AbstractHttpMessage.html
+http://developer.android.com/guide/basics/what-is-android.html
+
+http://developer.android.com/guide/topics/fundamentals.html
+http://developer.android.com/guide/topics/ui/index.html
+
+http://developer.android.com/guide/topics/ui/declaring-layout.html
+http://developer.android.com/guide/topics/ui/menus.html
+
+http://developer.android.com/guide/topics/ui/layout-objects.html
+http://developer.android.com/guide/topics/ui/binding.html
+
+http://developer.android.com/guide/topics/ui/ui-events.html
+http://developer.android.com/guide/topics/ui/themes.html
+
+http://developer.android.com/guide/topics/ui/custom-components.html
+http://developer.android.com/guide/topics/ui/how-android-draws.html
+
+http://developer.android.com/guide/topics/resources/index.html
+http://developer.android.com/guide/topics/resources/resources-i18n.html
+
+http://developer.android.com/guide/topics/resources/available-resources.html
+http://developer.android.com/guide/topics/intents/intents-filters.html
+
+http://developer.android.com/guide/topics/data/data-storage.html
+http://developer.android.com/guide/topics/providers/content-providers.html
+
+http://developer.android.com/guide/topics/security/security.html
+http://developer.android.com/guide/topics/manifest/manifest-intro.html
+
+http://developer.android.com/guide/topics/manifest/action-element.html
+http://developer.android.com/guide/topics/manifest/activity-element.html
+
+http://developer.android.com/guide/topics/manifest/activity-alias-element.html
+http://developer.android.com/guide/topics/manifest/application-element.html
+
+http://developer.android.com/guide/topics/manifest/category-element.html
+http://developer.android.com/guide/topics/manifest/data-element.html
+
+http://developer.android.com/guide/topics/manifest/grant-uri-permission-element.html
+http://developer.android.com/guide/topics/manifest/instrumentation-element.html
+
+http://developer.android.com/guide/topics/manifest/intent-filter-element.html
+http://developer.android.com/guide/topics/manifest/manifest-element.html
+
+http://developer.android.com/guide/topics/manifest/meta-data-element.html
+http://developer.android.com/guide/topics/manifest/permission-element.html
+
+http://developer.android.com/guide/topics/manifest/permission-group-element.html
+http://developer.android.com/guide/topics/manifest/permission-tree-element.html
+
+http://developer.android.com/guide/topics/manifest/provider-element.html
+http://developer.android.com/guide/topics/manifest/receiver-element.html
+
+http://developer.android.com/guide/topics/manifest/service-element.html
+http://developer.android.com/guide/topics/manifest/uses-library-element.html
+
+http://developer.android.com/guide/topics/manifest/uses-permission-element.html
+http://developer.android.com/guide/topics/manifest/uses-sdk-element.html
+
+http://developer.android.com/guide/topics/graphics/index.html
+http://developer.android.com/guide/topics/graphics/2d-graphics.html
+
+http://developer.android.com/guide/topics/graphics/opengl.html
+http://developer.android.com/guide/topics/media/index.html
+
+http://developer.android.com/guide/topics/location/index.html
+http://developer.android.com/guide/developing/eclipse-adt.html
+
+http://developer.android.com/guide/developing/other-ide.html
+http://developer.android.com/guide/developing/device.html
+
+http://developer.android.com/guide/developing/debug-tasks.html
+http://developer.android.com/guide/developing/tools/aapt.html
+
+http://developer.android.com/guide/developing/tools/adb.html
+http://developer.android.com/guide/developing/tools/othertools.html
+
+http://developer.android.com/guide/developing/tools/aidl.html
+http://developer.android.com/guide/developing/tools/ddms.html
+
+http://developer.android.com/guide/developing/tools/draw9patch.html
+http://developer.android.com/guide/developing/tools/emulator.html
+
+http://developer.android.com/guide/developing/tools/hierarchy-viewer.html
+http://developer.android.com/guide/developing/tools/monkey.html
+
+http://developer.android.com/guide/developing/tools/traceview.html
+http://developer.android.com/guide/publishing/app-signing.html
+
+http://developer.android.com/guide/publishing/versioning.html
+http://developer.android.com/guide/publishing/preparing.html
+
+http://developer.android.com/guide/publishing/publishing.html
+http://developer.android.com/guide/practices/design/performance.html
+
+http://developer.android.com/guide/practices/design/responsiveness.html
+http://developer.android.com/guide/practices/design/seamlessness.html
+
+http://developer.android.com/guide/tutorials/hello-world.html
+http://developer.android.com/guide/tutorials/views/index.html
+
+http://developer.android.com/guide/tutorials/notepad/index.html
+http://developer.android.com/guide/samples/ApiDemos/index.html
+
+http://developer.android.com/guide/samples/LunarLander/index.html
+http://developer.android.com/guide/samples/NotePad/index.html
+
+http://developer.android.com/guide/appendix/media-formats.html
+http://developer.android.com/guide/appendix/g-app-intents.html
+
+http://developer.android.com/guide/appendix/glossary.html
+http://developer.android.com/guide/appendix/faq/commontasks.html
+
+http://developer.android.com/guide/appendix/faq/framework.html
+http://developer.android.com/guide/appendix/faq/troubleshooting.html
+
+http://developer.android.com/guide/appendix/faq/licensingandoss.html
+http://developer.android.com/guide/appendix/faq/security.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/AbstractAuthenticationHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/AbstractHttpClient.html
+http://developer.android.com/reference/org/apache/http/impl/client/BasicCookieStore.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/BasicCredentialsProvider.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/BasicResponseHandler.html
+http://developer.android.com/reference/org/apache/http/impl/client/ClientParamsStack.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/DefaultConnectionKeepAliveStrategy.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/DefaultHttpClient.html
+http://developer.android.com/reference/org/apache/http/impl/client/DefaultHttpRequestRetryHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/DefaultProxyAuthenticationHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/DefaultRedirectHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/DefaultRequestDirector.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/DefaultTargetAuthenticationHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/DefaultUserTokenHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/EntityEnclosingRequestWrapper.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/RedirectLocations.html
+http://developer.android.com/reference/org/apache/http/impl/client/RequestWrapper.html
+
+http://developer.android.com/reference/org/apache/http/impl/client/RoutedRequest.html
+http://developer.android.com/reference/org/apache/http/impl/client/TunnelRefusedException.html
+
+http://developer.android.com/reference/org/apache/http/client/CookieStore.html
+http://developer.android.com/reference/org/apache/http/client/CredentialsProvider.html
+
+http://developer.android.com/reference/org/apache/http/client/ResponseHandler.html
+http://developer.android.com/reference/org/apache/http/client/HttpRequestRetryHandler.html
+
+http://developer.android.com/reference/org/apache/http/client/RedirectHandler.html
+http://developer.android.com/reference/org/apache/http/client/RequestDirector.html
+
+http://developer.android.com/reference/org/apache/http/HttpEntityEnclosingRequest.html
+http://developer.android.com/reference/org/apache/http/HttpRequest.html
+
+http://developer.android.com/reference/android/Manifest.html
+http://developer.android.com/reference/android/Manifest.permission.html
+
+http://developer.android.com/reference/android/Manifest.permission_group.html
+http://developer.android.com/reference/android/R.html
+
+http://developer.android.com/reference/android/R.anim.html
+http://developer.android.com/reference/android/R.array.html
+
+http://developer.android.com/reference/android/R.attr.html
+http://developer.android.com/reference/android/R.color.html
+
+http://developer.android.com/reference/android/R.dimen.html
+http://developer.android.com/reference/android/R.drawable.html
+
+http://developer.android.com/reference/android/R.id.html
+http://developer.android.com/reference/android/R.layout.html
+
+http://developer.android.com/reference/android/R.plurals.html
+http://developer.android.com/reference/android/R.raw.html
+
+http://developer.android.com/reference/android/R.string.html
+http://developer.android.com/reference/android/R.style.html
+
+http://developer.android.com/reference/android/R.styleable.html
+http://developer.android.com/reference/android/R.xml.html
+
+http://developer.android.com/reference/android/package-descr.html
+http://developer.android.com/reference/android/os/Debug.html
+
+http://developer.android.com/reference/java/security/acl/Acl.html
+http://developer.android.com/reference/java/security/acl/AclEntry.html
+
+http://developer.android.com/reference/java/security/acl/Group.html
+http://developer.android.com/reference/java/security/acl/Owner.html
+
+http://developer.android.com/reference/java/security/acl/Permission.html
+http://developer.android.com/reference/java/security/acl/AclNotFoundException.html
+
+http://developer.android.com/reference/java/security/acl/LastOwnerException.html
+http://developer.android.com/reference/java/security/acl/NotOwnerException.html
+
+http://developer.android.com/reference/java/security/acl/package-descr.html
+http://developer.android.com/reference/java/text/AttributedCharacterIterator.html
+
+http://developer.android.com/reference/java/text/CharacterIterator.html
+http://developer.android.com/reference/java/text/Annotation.html
+
+http://developer.android.com/reference/java/text/AttributedCharacterIterator.Attribute.html
+http://developer.android.com/reference/java/text/AttributedString.html
+
+http://developer.android.com/reference/java/text/Bidi.html
+http://developer.android.com/reference/java/text/BreakIterator.html
+
+http://developer.android.com/reference/java/text/ChoiceFormat.html
+http://developer.android.com/reference/java/text/CollationElementIterator.html
+
+http://developer.android.com/reference/java/text/CollationKey.html
+http://developer.android.com/reference/java/text/Collator.html
+
+http://developer.android.com/reference/java/text/DateFormat.html
+http://developer.android.com/reference/java/text/DateFormat.Field.html
+
+http://developer.android.com/reference/java/text/DateFormatSymbols.html
+http://developer.android.com/reference/java/text/DecimalFormat.html
+
+http://developer.android.com/reference/java/text/DecimalFormatSymbols.html
+http://developer.android.com/reference/java/text/FieldPosition.html
+
+http://developer.android.com/reference/java/text/Format.html
+http://developer.android.com/reference/java/text/Format.Field.html
+
+http://developer.android.com/reference/java/text/MessageFormat.html
+http://developer.android.com/reference/java/text/MessageFormat.Field.html
+
+http://developer.android.com/reference/java/text/NumberFormat.html
+http://developer.android.com/reference/java/text/NumberFormat.Field.html
+
+http://developer.android.com/reference/java/text/ParsePosition.html
+http://developer.android.com/reference/java/text/RuleBasedCollator.html
+
+http://developer.android.com/reference/java/text/SimpleDateFormat.html
+http://developer.android.com/reference/java/text/StringCharacterIterator.html
+
+http://developer.android.com/reference/java/text/ParseException.html
+http://developer.android.com/reference/java/text/package-descr.html
+
+http://developer.android.com/reference/android/view/Menu.html
+http://developer.android.com/reference/android/view/ContextMenu.html
+
+http://developer.android.com/reference/android/view/SubMenu.html
+http://developer.android.com/reference/android/app/Activity.html
+
+http://developer.android.com/reference/android/view/MenuItem.html
+http://developer.android.com/reference/android/widget/ListView.html
+
+http://developer.android.com/reference/android/view/View.html
+http://developer.android.com/reference/android/view/ContextMenu.ContextMenuInfo.html
+
+http://developer.android.com/reference/android/widget/AdapterView.AdapterContextMenuInfo.html
+
+http://developer.android.com/reference/android/app/ListActivity.html
+http://developer.android.com/reference/android/view/MenuInflater.html
+
+http://developer.android.com/reference/android/preference/PreferenceActivity.html
+http://developer.android.com/reference/android/media/MediaPlayer.html
+
+http://developer.android.com/reference/android/media/MediaRecorder.html
+http://developer.android.com/reference/android/content/ContentValues.html
+
+http://developer.android.com/reference/android/content/ContentResolver.html
+http://developer.android.com/reference/android/test/PerformanceTestCase.html
+
+http://developer.android.com/reference/android/test/PerformanceTestCase.Intermediates.html
+http://developer.android.com/reference/android/test/TestSuiteProvider.html
+
+http://developer.android.com/reference/android/test/ActivityInstrumentationTestCase.html
+http://developer.android.com/reference/android/test/ActivityTestCase.html
+
+http://developer.android.com/reference/android/test/ActivityUnitTestCase.html
+http://developer.android.com/reference/android/test/AndroidTestCase.html
+
+http://developer.android.com/reference/android/test/AndroidTestRunner.html
+http://developer.android.com/reference/android/test/ApplicationTestCase.html
+
+http://developer.android.com/reference/android/app/Application.html
+http://developer.android.com/reference/android/test/InstrumentationTestCase.html
+
+http://developer.android.com/reference/android/test/InstrumentationTestRunner.html
+http://developer.android.com/reference/android/test/InstrumentationTestSuite.html
+
+http://developer.android.com/reference/android/test/IsolatedContext.html
+http://developer.android.com/reference/android/test/MoreAsserts.html
+
+http://developer.android.com/reference/android/test/ProviderTestCase.html
+http://developer.android.com/reference/android/content/ContentProvider.html
+
+http://developer.android.com/reference/android/test/RenamingDelegatingContext.html
+http://developer.android.com/reference/android/test/ServiceTestCase.html
+
+http://developer.android.com/reference/android/app/Service.html
+http://developer.android.com/reference/android/test/SingleLaunchActivityTestCase.html
+
+http://developer.android.com/reference/android/test/SyncBaseInstrumentation.html
+http://developer.android.com/reference/android/test/TouchUtils.html
+
+http://developer.android.com/reference/android/test/ViewAsserts.html
+http://developer.android.com/reference/android/test/AssertionFailedError.html
+
+http://developer.android.com/reference/android/test/ComparisonFailure.html
+http://developer.android.com/reference/android/app/Instrumentation.html
+
+http://developer.android.com/reference/junit/framework/TestCase.html
+http://developer.android.com/reference/junit/framework/TestSuite.html
+
+http://developer.android.com/reference/android/content/Intent.html
+http://developer.android.com/reference/android/content/Context.html
+
+http://developer.android.com/reference/android/os/Bundle.html
+http://developer.android.com/reference/android/view/ViewGroup.html
+
+http://developer.android.com/reference/android/widget/Button.html
+http://developer.android.com/reference/android/widget/TextView.html
+
+http://developer.android.com/reference/android/widget/EditText.html
+http://developer.android.com/reference/android/widget/CheckBox.html
+
+http://developer.android.com/reference/android/widget/RadioButton.html
+http://developer.android.com/reference/android/widget/Gallery.html
+
+http://developer.android.com/reference/android/widget/Spinner.html
+http://developer.android.com/reference/android/widget/AutoCompleteTextView.html
+
+http://developer.android.com/reference/android/widget/ImageSwitcher.html
+http://developer.android.com/reference/android/widget/TextSwitcher.html
+
+http://developer.android.com/reference/android/widget/LinearLayout.html
+http://developer.android.com/reference/android/widget/FrameLayout.html
+
+http://developer.android.com/reference/android/widget/AbsoluteLayout.html
+http://developer.android.com/reference/android/graphics/Canvas.html
+
+http://developer.android.com/reference/android/view/SurfaceView.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LabelView.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/custom_view_1.html
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/notepad/NoteEditor.html
+
+http://developer.android.com/reference/java/net/ContentHandlerFactory.html
+http://developer.android.com/reference/java/net/DatagramSocketImplFactory.html
+
+http://developer.android.com/reference/java/net/FileNameMap.html
+http://developer.android.com/reference/java/net/SocketImplFactory.html
+
+http://developer.android.com/reference/java/net/SocketOptions.html
+http://developer.android.com/reference/java/net/URLStreamHandlerFactory.html
+
+http://developer.android.com/reference/java/net/Authenticator.html
+http://developer.android.com/reference/java/net/CacheRequest.html
+
+http://developer.android.com/reference/java/net/CacheResponse.html
+http://developer.android.com/reference/java/net/ContentHandler.html
+
+http://developer.android.com/reference/java/net/CookieHandler.html
+http://developer.android.com/reference/java/net/DatagramPacket.html
+
+http://developer.android.com/reference/java/net/DatagramSocket.html
+http://developer.android.com/reference/java/net/DatagramSocketImpl.html
+
+http://developer.android.com/reference/java/net/HttpURLConnection.html
+http://developer.android.com/reference/java/net/Inet4Address.html
+
+http://developer.android.com/reference/java/net/Inet6Address.html
+http://developer.android.com/reference/java/net/InetAddress.html
+
+http://developer.android.com/reference/java/net/InetSocketAddress.html
+http://developer.android.com/reference/java/net/JarURLConnection.html
+
+http://developer.android.com/reference/java/net/MulticastSocket.html
+http://developer.android.com/reference/java/net/NetPermission.html
+
+http://developer.android.com/reference/java/net/NetworkInterface.html
+http://developer.android.com/reference/java/net/PasswordAuthentication.html
+
+http://developer.android.com/reference/java/net/Proxy.html
+http://developer.android.com/reference/java/net/ProxySelector.html
+
+http://developer.android.com/reference/java/net/ResponseCache.html
+http://developer.android.com/reference/java/net/SecureCacheResponse.html
+
+http://developer.android.com/reference/java/net/ServerSocket.html
+http://developer.android.com/reference/java/net/Socket.html
+
+http://developer.android.com/reference/java/net/SocketAddress.html
+http://developer.android.com/reference/java/net/SocketImpl.html
+
+http://developer.android.com/reference/java/net/SocketPermission.html
+http://developer.android.com/reference/java/net/URI.html
+
+http://developer.android.com/reference/java/net/URL.html
+http://developer.android.com/reference/java/net/URLClassLoader.html
+
+http://developer.android.com/reference/java/net/URLConnection.html
+http://developer.android.com/reference/java/net/URLDecoder.html
+
+http://developer.android.com/reference/java/net/URLEncoder.html
+http://developer.android.com/reference/java/net/URLStreamHandler.html
+
+http://developer.android.com/reference/java/net/Authenticator.RequestorType.html
+http://developer.android.com/reference/java/net/Proxy.Type.html
+
+http://developer.android.com/reference/java/net/BindException.html
+http://developer.android.com/reference/java/net/ConnectException.html
+
+http://developer.android.com/reference/java/net/HttpRetryException.html
+http://developer.android.com/reference/java/net/MalformedURLException.html
+
+http://developer.android.com/reference/java/net/NoRouteToHostException.html
+http://developer.android.com/reference/java/net/PortUnreachableException.html
+
+http://developer.android.com/reference/java/net/ProtocolException.html
+http://developer.android.com/reference/java/net/SocketException.html
+
+http://developer.android.com/reference/java/net/SocketTimeoutException.html
+http://developer.android.com/reference/java/net/UnknownHostException.html
+
+http://developer.android.com/reference/java/net/UnknownServiceException.html
+http://developer.android.com/reference/java/net/URISyntaxException.html
+
+http://developer.android.com/reference/java/net/package-descr.html
+http://developer.android.com/reference/android/graphics/drawable/Drawable.html
+
+http://developer.android.com/reference/android/graphics/drawable/BitmapDrawable.html
+http://developer.android.com/reference/android/graphics/drawable/ShapeDrawable.html
+
+http://developer.android.com/reference/android/graphics/drawable/PictureDrawable.html
+http://developer.android.com/reference/android/graphics/drawable/LayerDrawable.html
+
+http://developer.android.com/reference/android/widget/ImageView.html
+http://developer.android.com/reference/android/content/res/Resources.html
+
+http://developer.android.com/reference/android/graphics/drawable/shapes/OvalShape.html
+http://developer.android.com/reference/android/graphics/drawable/NinePatchDrawable.html
+
+http://developer.android.com/reference/android/view/animation/AnimationSet.html
+http://developer.android.com/reference/android/view/animation/Animation.html
+
+http://developer.android.com/reference/android/view/animation/Interpolator.html
+http://developer.android.com/reference/android/view/animation/AccelerateInterpolator.html
+
+http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html
+http://developer.android.com/reference/java/util/logging/Filter.html
+
+http://developer.android.com/reference/java/util/logging/LoggingMXBean.html
+http://developer.android.com/reference/java/util/logging/ConsoleHandler.html
+
+http://developer.android.com/reference/java/util/logging/ErrorManager.html
+http://developer.android.com/reference/java/util/logging/FileHandler.html
+
+http://developer.android.com/reference/java/util/logging/Formatter.html
+http://developer.android.com/reference/java/util/logging/Handler.html
+
+http://developer.android.com/reference/java/util/logging/Level.html
+http://developer.android.com/reference/java/util/logging/Logger.html
+
+http://developer.android.com/reference/java/util/logging/LoggingPermission.html
+http://developer.android.com/reference/java/util/logging/LogManager.html
+
+http://developer.android.com/reference/java/util/logging/LogRecord.html
+http://developer.android.com/reference/java/util/logging/MemoryHandler.html
+
+http://developer.android.com/reference/java/util/logging/SimpleFormatter.html
+http://developer.android.com/reference/java/util/logging/SocketHandler.html
+
+http://developer.android.com/reference/java/util/logging/StreamHandler.html
+http://developer.android.com/reference/java/util/logging/XMLFormatter.html
+
+http://developer.android.com/reference/java/util/logging/package-descr.html
+http://developer.android.com/reference/android/test/suitebuilder/annotation/LargeTest.html
+http://developer.android.com/reference/android/test/suitebuilder/annotation/MediumTest.html
+
+http://developer.android.com/reference/android/test/suitebuilder/annotation/SmallTest.html
+http://developer.android.com/reference/android/os/Process.html
+
+http://developer.android.com/reference/android/graphics/AvoidXfermode.html
+http://developer.android.com/reference/android/graphics/Bitmap.html
+
+http://developer.android.com/reference/android/graphics/BitmapFactory.html
+http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html
+
+http://developer.android.com/reference/android/graphics/BitmapShader.html
+http://developer.android.com/reference/android/graphics/BlurMaskFilter.html
+
+http://developer.android.com/reference/android/graphics/Camera.html
+http://developer.android.com/reference/android/graphics/Color.html
+
+http://developer.android.com/reference/android/graphics/ColorFilter.html
+http://developer.android.com/reference/android/graphics/ColorMatrix.html
+
+http://developer.android.com/reference/android/graphics/ColorMatrixColorFilter.html
+http://developer.android.com/reference/android/graphics/ComposePathEffect.html
+
+http://developer.android.com/reference/android/graphics/ComposeShader.html
+http://developer.android.com/reference/android/graphics/CornerPathEffect.html
+
+http://developer.android.com/reference/android/graphics/DashPathEffect.html
+http://developer.android.com/reference/android/graphics/DiscretePathEffect.html
+
+http://developer.android.com/reference/android/graphics/DrawFilter.html
+http://developer.android.com/reference/android/graphics/EmbossMaskFilter.html
+
+http://developer.android.com/reference/android/graphics/Interpolator.html
+http://developer.android.com/reference/android/graphics/LayerRasterizer.html
+
+http://developer.android.com/reference/android/graphics/LightingColorFilter.html
+http://developer.android.com/reference/android/graphics/LinearGradient.html
+
+http://developer.android.com/reference/android/graphics/MaskFilter.html
+http://developer.android.com/reference/android/graphics/Matrix.html
+
+http://developer.android.com/reference/android/graphics/Movie.html
+http://developer.android.com/reference/android/graphics/NinePatch.html
+
+http://developer.android.com/reference/android/graphics/Paint.html
+http://developer.android.com/reference/android/graphics/Paint.FontMetrics.html
+
+http://developer.android.com/reference/android/graphics/Paint.FontMetricsInt.html
+http://developer.android.com/reference/android/graphics/PaintFlagsDrawFilter.html
+
+http://developer.android.com/reference/android/graphics/Path.html
+http://developer.android.com/reference/android/graphics/PathDashPathEffect.html
+
+http://developer.android.com/reference/android/graphics/PathEffect.html
+http://developer.android.com/reference/android/graphics/PathMeasure.html
+
+http://developer.android.com/reference/android/graphics/Picture.html
+http://developer.android.com/reference/android/graphics/PixelFormat.html
+
+http://developer.android.com/reference/android/graphics/PixelXorXfermode.html
+http://developer.android.com/reference/android/graphics/Point.html
+
+http://developer.android.com/reference/android/graphics/PointF.html
+http://developer.android.com/reference/android/graphics/PorterDuff.html
+
+http://developer.android.com/reference/android/graphics/PorterDuffColorFilter.html
+http://developer.android.com/reference/android/graphics/PorterDuffXfermode.html
+
+http://developer.android.com/reference/android/graphics/RadialGradient.html
+http://developer.android.com/reference/android/graphics/Rasterizer.html
+
+http://developer.android.com/reference/android/graphics/Rect.html
+http://developer.android.com/reference/android/graphics/RectF.html
+
+http://developer.android.com/reference/android/graphics/Region.html
+http://developer.android.com/reference/android/graphics/RegionIterator.html
+
+http://developer.android.com/reference/android/graphics/Shader.html
+http://developer.android.com/reference/android/graphics/SumPathEffect.html
+
+http://developer.android.com/reference/android/graphics/SweepGradient.html
+http://developer.android.com/reference/android/graphics/Typeface.html
+
+http://developer.android.com/reference/android/graphics/Xfermode.html
+http://developer.android.com/reference/android/graphics/AvoidXfermode.Mode.html
+
+http://developer.android.com/reference/android/graphics/Bitmap.CompressFormat.html
+http://developer.android.com/reference/android/graphics/Bitmap.Config.html
+
+http://developer.android.com/reference/android/graphics/BlurMaskFilter.Blur.html
+http://developer.android.com/reference/android/graphics/Canvas.EdgeType.html
+
+http://developer.android.com/reference/android/graphics/Canvas.VertexMode.html
+http://developer.android.com/reference/android/graphics/Interpolator.Result.html
+
+http://developer.android.com/reference/android/graphics/Matrix.ScaleToFit.html
+http://developer.android.com/reference/android/graphics/Paint.Align.html
+
+http://developer.android.com/reference/android/graphics/Paint.Cap.html
+http://developer.android.com/reference/android/graphics/Paint.Join.html
+
+http://developer.android.com/reference/android/graphics/Paint.Style.html
+http://developer.android.com/reference/android/graphics/Path.Direction.html
+
+http://developer.android.com/reference/android/graphics/Path.FillType.html
+http://developer.android.com/reference/android/graphics/PathDashPathEffect.Style.html
+
+http://developer.android.com/reference/android/graphics/PorterDuff.Mode.html
+http://developer.android.com/reference/android/graphics/Region.Op.html
+
+http://developer.android.com/reference/android/graphics/Shader.TileMode.html
+http://developer.android.com/reference/android/graphics/package-descr.html
+
+http://developer.android.com/reference/android/content/BroadcastReceiver.html
+http://developer.android.com/reference/org/apache/http/cookie/ClientCookie.html
+
+http://developer.android.com/reference/org/apache/http/cookie/Cookie.html
+http://developer.android.com/reference/org/apache/http/cookie/CookieAttributeHandler.html
+
+http://developer.android.com/reference/org/apache/http/cookie/CookieSpec.html
+http://developer.android.com/reference/org/apache/http/cookie/CookieSpecFactory.html
+
+http://developer.android.com/reference/org/apache/http/cookie/SetCookie.html
+http://developer.android.com/reference/org/apache/http/cookie/SetCookie2.html
+
+http://developer.android.com/reference/org/apache/http/cookie/SM.html
+http://developer.android.com/reference/org/apache/http/cookie/CookieIdentityComparator.html
+
+http://developer.android.com/reference/org/apache/http/cookie/CookieOrigin.html
+http://developer.android.com/reference/org/apache/http/cookie/CookiePathComparator.html
+
+http://developer.android.com/reference/org/apache/http/cookie/CookieSpecRegistry.html
+http://developer.android.com/reference/org/apache/http/cookie/MalformedCookieException.html
+
+http://developer.android.com/reference/org/apache/http/cookie/package-descr.html
+http://developer.android.com/reference/java/nio/channels/spi/AbstractInterruptibleChannel.html
+
+http://developer.android.com/reference/java/nio/channels/spi/AbstractSelectableChannel.html
+http://developer.android.com/reference/java/nio/channels/spi/AbstractSelectionKey.html
+
+http://developer.android.com/reference/java/nio/channels/spi/AbstractSelector.html
+http://developer.android.com/reference/java/nio/channels/spi/SelectorProvider.html
+
+http://developer.android.com/reference/java/nio/channels/spi/package-descr.html
+http://developer.android.com/reference/org/apache/http/client/AuthenticationHandler.html
+
+http://developer.android.com/reference/org/apache/http/client/HttpClient.html
+http://developer.android.com/reference/org/apache/http/client/UserTokenHandler.html
+
+http://developer.android.com/reference/org/apache/http/client/CircularRedirectException.html
+http://developer.android.com/reference/org/apache/http/client/ClientProtocolException.html
+
+http://developer.android.com/reference/org/apache/http/client/HttpResponseException.html
+http://developer.android.com/reference/org/apache/http/client/NonRepeatableRequestException.html
+
+http://developer.android.com/reference/org/apache/http/client/RedirectException.html
+http://developer.android.com/reference/org/apache/http/client/package-descr.html
+
+http://developer.android.com/reference/org/apache/http/HttpResponse.html
+http://developer.android.com/reference/java/util/prefs/NodeChangeListener.html
+
+http://developer.android.com/reference/java/util/prefs/PreferenceChangeListener.html
+http://developer.android.com/reference/java/util/prefs/PreferencesFactory.html
+
+http://developer.android.com/reference/java/util/prefs/AbstractPreferences.html
+http://developer.android.com/reference/java/util/prefs/NodeChangeEvent.html
+
+http://developer.android.com/reference/java/util/prefs/PreferenceChangeEvent.html
+http://developer.android.com/reference/java/util/prefs/Preferences.html
+
+http://developer.android.com/reference/java/util/prefs/BackingStoreException.html
+http://developer.android.com/reference/java/util/prefs/InvalidPreferencesFormatException.html
+
+http://developer.android.com/reference/java/util/prefs/package-descr.html
+http://developer.android.com/sdk/adt_download.html
+http://developer.android.com/reference/android/provider/BaseColumns.html
+
+http://developer.android.com/reference/android/provider/Contacts.ContactMethodsColumns.html
+http://developer.android.com/reference/android/provider/Contacts.ExtensionsColumns.html
+
+http://developer.android.com/reference/android/provider/Contacts.GroupsColumns.html
+http://developer.android.com/reference/android/provider/Contacts.OrganizationColumns.html
+
+http://developer.android.com/reference/android/provider/Contacts.PeopleColumns.html
+http://developer.android.com/reference/android/provider/Contacts.PhonesColumns.html
+
+http://developer.android.com/reference/android/provider/Contacts.PhotosColumns.html
+http://developer.android.com/reference/android/provider/Contacts.PresenceColumns.html
+
+http://developer.android.com/reference/android/provider/Contacts.SettingsColumns.html
+http://developer.android.com/reference/android/provider/MediaStore.Audio.AlbumColumns.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Audio.ArtistColumns.html
+http://developer.android.com/reference/android/provider/MediaStore.Audio.AudioColumns.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Audio.GenresColumns.html
+http://developer.android.com/reference/android/provider/MediaStore.Audio.PlaylistsColumns.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Images.ImageColumns.html
+http://developer.android.com/reference/android/provider/MediaStore.MediaColumns.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Video.VideoColumns.html
+http://developer.android.com/reference/android/provider/OpenableColumns.html
+
+http://developer.android.com/reference/android/provider/Browser.html
+http://developer.android.com/reference/android/provider/Browser.BookmarkColumns.html
+
+http://developer.android.com/reference/android/provider/Browser.SearchColumns.html
+http://developer.android.com/reference/android/provider/CallLog.html
+
+http://developer.android.com/reference/android/provider/CallLog.Calls.html
+http://developer.android.com/reference/android/provider/Contacts.html
+
+http://developer.android.com/reference/android/provider/Contacts.ContactMethods.html
+http://developer.android.com/reference/android/provider/Contacts.Extensions.html
+
+http://developer.android.com/reference/android/provider/Contacts.GroupMembership.html
+http://developer.android.com/reference/android/provider/Contacts.Groups.html
+
+http://developer.android.com/reference/android/provider/Contacts.Intents.html
+http://developer.android.com/reference/android/provider/Contacts.Intents.Insert.html
+
+http://developer.android.com/reference/android/provider/Contacts.Intents.UI.html
+http://developer.android.com/reference/android/provider/Contacts.Organizations.html
+
+http://developer.android.com/reference/android/provider/Contacts.People.html
+http://developer.android.com/reference/android/provider/Contacts.People.ContactMethods.html
+
+http://developer.android.com/reference/android/provider/Contacts.People.Extensions.html
+http://developer.android.com/reference/android/provider/Contacts.People.Phones.html
+
+http://developer.android.com/reference/android/provider/Contacts.Phones.html
+http://developer.android.com/reference/android/provider/Contacts.Photos.html
+
+http://developer.android.com/reference/android/provider/Contacts.Settings.html
+http://developer.android.com/reference/android/provider/MediaStore.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Audio.html
+http://developer.android.com/reference/android/provider/MediaStore.Audio.Albums.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Audio.Artists.html
+http://developer.android.com/reference/android/provider/MediaStore.Audio.Artists.Albums.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Audio.Genres.html
+http://developer.android.com/reference/android/provider/MediaStore.Audio.Genres.Members.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Audio.Media.html
+http://developer.android.com/reference/android/provider/MediaStore.Audio.Playlists.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Audio.Playlists.Members.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Images.html
+http://developer.android.com/reference/android/provider/MediaStore.Images.Media.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Images.Thumbnails.html
+http://developer.android.com/reference/android/provider/MediaStore.Video.html
+
+http://developer.android.com/reference/android/provider/MediaStore.Video.Media.html
+http://developer.android.com/reference/android/provider/SearchRecentSuggestions.html
+
+http://developer.android.com/reference/android/provider/Settings.html
+http://developer.android.com/reference/android/provider/Settings.NameValueTable.html
+
+http://developer.android.com/reference/android/provider/Settings.System.html
+http://developer.android.com/reference/android/provider/Settings.SettingNotFoundException.html
+
+http://developer.android.com/reference/android/provider/package-descr.html
+http://developer.android.com/reference/android/content/SearchRecentSuggestionsProvider.html
+
+http://developer.android.com/reference/android/net/UrlQuerySanitizer.ValueSanitizer.html
+http://developer.android.com/reference/android/net/ConnectivityManager.html
+
+http://developer.android.com/reference/android/net/Credentials.html
+http://developer.android.com/reference/android/net/DhcpInfo.html
+
+http://developer.android.com/reference/android/net/LocalServerSocket.html
+http://developer.android.com/reference/android/net/LocalSocket.html
+
+http://developer.android.com/reference/android/net/LocalSocketAddress.html
+http://developer.android.com/reference/android/net/MailTo.html
+
+http://developer.android.com/reference/android/net/NetworkInfo.html
+http://developer.android.com/reference/android/net/Proxy.html
+
+http://developer.android.com/reference/android/net/SSLCertificateSocketFactory.html
+http://developer.android.com/reference/android/net/Uri.html
+
+http://developer.android.com/reference/android/net/Uri.Builder.html
+http://developer.android.com/reference/android/net/UrlQuerySanitizer.html
+
+http://developer.android.com/reference/android/net/UrlQuerySanitizer.IllegalCharacterValueSanitizer.html
+
+http://developer.android.com/reference/android/net/UrlQuerySanitizer.ParameterValuePair.html
+http://developer.android.com/reference/android/net/LocalSocketAddress.Namespace.html
+
+http://developer.android.com/reference/android/net/NetworkInfo.DetailedState.html
+http://developer.android.com/reference/android/net/NetworkInfo.State.html
+
+http://developer.android.com/reference/android/net/package-descr.html
+http://developer.android.com/reference/javax/microedition/khronos/egl/EGL.html
+
+http://developer.android.com/reference/javax/microedition/khronos/egl/EGL10.html
+http://developer.android.com/reference/javax/microedition/khronos/egl/EGL11.html
+
+http://developer.android.com/reference/javax/microedition/khronos/egl/EGLConfig.html
+http://developer.android.com/reference/javax/microedition/khronos/egl/EGLContext.html
+
+http://developer.android.com/reference/javax/microedition/khronos/egl/EGLDisplay.html
+http://developer.android.com/reference/javax/microedition/khronos/egl/EGLSurface.html
+
+http://developer.android.com/reference/android/content/pm/PackageItemInfo.html
+http://developer.android.com/reference/org/apache/http/auth/params/AuthPNames.html
+
+http://developer.android.com/reference/org/apache/http/auth/params/AuthParamBean.html
+http://developer.android.com/reference/org/apache/http/auth/params/AuthParams.html
+
+http://developer.android.com/reference/org/apache/http/auth/params/package-descr.html
+http://developer.android.com/reference/org/apache/http/params/HttpParams.html
+
+http://developer.android.com/reference/java/lang/Object.html
+http://developer.android.com/reference/org/apache/http/conn/ConnectionKeepAliveStrategy.html
+
+http://developer.android.com/reference/org/apache/http/protocol/HttpContext.html
+http://developer.android.com/reference/java/lang/Class.html
+
+http://developer.android.com/reference/java/lang/String.html
+http://developer.android.com/reference/org/apache/http/ConnectionReuseStrategy.html
+
+http://developer.android.com/reference/org/xml/sax/ext/Attributes2.html
+http://developer.android.com/reference/org/xml/sax/ext/DeclHandler.html
+
+http://developer.android.com/reference/org/xml/sax/ext/EntityResolver2.html
+http://developer.android.com/reference/org/xml/sax/ext/LexicalHandler.html
+
+http://developer.android.com/reference/org/xml/sax/ext/Locator2.html
+http://developer.android.com/reference/org/xml/sax/ext/Attributes2Impl.html
+
+http://developer.android.com/reference/org/xml/sax/ext/DefaultHandler2.html
+http://developer.android.com/reference/org/xml/sax/ext/Locator2Impl.html
+
+http://developer.android.com/reference/org/xml/sax/ext/package-descr.html
+http://developer.android.com/reference/org/xml/sax/Attributes.html
+
+http://developer.android.com/reference/org/xml/sax/Locator.html
+http://developer.android.com/reference/android/content/pm/PackageManager.html
+
+http://developer.android.com/reference/org/apache/http/HttpHost.html
+
+http://developer.android.com/reference/org/apache/http/HttpException.html
+http://developer.android.com/reference/java/io/IOException.html
+
+http://developer.android.com/reference/javax/security/auth/x500/X500Principal.html
+http://developer.android.com/reference/javax/security/auth/x500/package-descr.html
+
+http://developer.android.com/reference/java/util/Date.html
+http://developer.android.com/reference/java/util/List.html
+
+http://developer.android.com/reference/android/sax/ElementListener.html
+http://developer.android.com/reference/android/sax/EndElementListener.html
+
+http://developer.android.com/reference/android/sax/EndTextElementListener.html
+http://developer.android.com/reference/android/sax/StartElementListener.html
+
+http://developer.android.com/reference/android/sax/TextElementListener.html
+http://developer.android.com/reference/android/sax/Element.html
+
+http://developer.android.com/reference/android/sax/RootElement.html
+http://developer.android.com/reference/android/sax/package-descr.html
+
+http://developer.android.com/reference/junit/runner/BaseTestRunner.html
+http://developer.android.com/reference/junit/framework/TestListener.html
+
+http://developer.android.com/reference/junit/framework/TestResult.html
+http://developer.android.com/reference/junit/framework/Test.html
+
+http://developer.android.com/reference/java/lang/Throwable.html
+http://developer.android.com/reference/junit/framework/AssertionFailedError.html
+
+http://developer.android.com/reference/junit/runner/TestSuiteLoader.html
+http://developer.android.com/reference/java/util/Properties.html
+
+http://developer.android.com/reference/java/lang/ClassNotFoundException.html
+http://developer.android.com/reference/org/apache/http/impl/io/AbstractMessageParser.html
+
+http://developer.android.com/reference/org/apache/http/impl/io/AbstractMessageWriter.html
+http://developer.android.com/reference/org/apache/http/impl/io/AbstractSessionInputBuffer.html
+
+http://developer.android.com/reference/org/apache/http/impl/io/AbstractSessionOutputBuffer.html
+
+http://developer.android.com/reference/org/apache/http/impl/io/ChunkedInputStream.html
+http://developer.android.com/reference/org/apache/http/impl/io/ChunkedOutputStream.html
+
+http://developer.android.com/reference/org/apache/http/impl/io/ContentLengthInputStream.html
+http://developer.android.com/reference/org/apache/http/impl/io/ContentLengthOutputStream.html
+
+http://developer.android.com/reference/org/apache/http/impl/io/HttpRequestParser.html
+http://developer.android.com/reference/org/apache/http/impl/io/HttpRequestWriter.html
+
+http://developer.android.com/reference/org/apache/http/impl/io/HttpResponseParser.html
+http://developer.android.com/reference/org/apache/http/impl/io/HttpResponseWriter.html
+
+http://developer.android.com/reference/org/apache/http/impl/io/HttpTransportMetricsImpl.html
+http://developer.android.com/reference/org/apache/http/impl/io/IdentityInputStream.html
+
+http://developer.android.com/reference/org/apache/http/impl/io/IdentityOutputStream.html
+http://developer.android.com/reference/org/apache/http/impl/io/SocketInputBuffer.html
+
+http://developer.android.com/reference/org/apache/http/impl/io/SocketOutputBuffer.html
+http://developer.android.com/reference/org/apache/http/impl/io/package-descr.html
+
+http://developer.android.com/reference/java/io/InputStream.html
+http://developer.android.com/reference/java/io/OutputStream.html
+
+http://developer.android.com/reference/org/apache/http/io/HttpTransportMetrics.html
+http://developer.android.com/reference/org/apache/http/io/SessionInputBuffer.html
+
+http://developer.android.com/reference/junit/framework/Assert.html
+http://developer.android.com/reference/java/lang/IllegalAccessException.html
+
+http://developer.android.com/reference/java/lang/Exception.html
+http://developer.android.com/reference/java/util/jar/Pack200.Packer.html
+
+http://developer.android.com/reference/java/util/jar/Pack200.Unpacker.html
+http://developer.android.com/reference/java/util/jar/Attributes.html
+
+http://developer.android.com/reference/java/util/jar/Attributes.Name.html
+http://developer.android.com/reference/java/util/jar/JarEntry.html
+
+http://developer.android.com/reference/java/util/jar/JarFile.html
+http://developer.android.com/reference/java/util/jar/JarInputStream.html
+
+http://developer.android.com/reference/java/util/jar/JarOutputStream.html
+http://developer.android.com/reference/java/util/jar/Manifest.html
+
+http://developer.android.com/reference/java/util/jar/Pack200.html
+http://developer.android.com/reference/java/util/jar/JarException.html
+
+http://developer.android.com/reference/java/util/jar/package-descr.html
+http://developer.android.com/reference/android/view/View.MeasureSpec.html
+
+http://developer.android.com/guide/tutorials/views/hello-formstuff.html
+http://developer.android.com/reference/android/view/View.OnClickListener.html
+
+http://developer.android.com/reference/android/view/View.OnLongClickListener.html
+http://developer.android.com/reference/android/view/View.OnFocusChangeListener.html
+
+http://developer.android.com/reference/android/view/View.OnKeyListener.html
+http://developer.android.com/reference/android/view/View.OnTouchListener.html
+
+http://developer.android.com/reference/android/view/View.OnCreateContextMenuListener.html
+http://developer.android.com/reference/android/view/ViewParent.html
+
+http://developer.android.com/reference/android/database/sqlite/SQLiteCursorDriver.html
+http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.CursorFactory.html
+
+http://developer.android.com/reference/android/database/sqlite/SQLiteClosable.html
+http://developer.android.com/reference/android/database/sqlite/SQLiteCursor.html
+
+http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
+http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html
+
+http://developer.android.com/reference/android/database/sqlite/SQLiteProgram.html
+http://developer.android.com/reference/android/database/sqlite/SQLiteQuery.html
+
+http://developer.android.com/reference/android/database/sqlite/SQLiteQueryBuilder.html
+http://developer.android.com/reference/android/database/sqlite/SQLiteStatement.html
+
+http://developer.android.com/reference/android/database/sqlite/SQLiteAbortException.html
+http://developer.android.com/reference/android/database/sqlite/SQLiteConstraintException.html
+
+http://developer.android.com/reference/android/database/sqlite/SQLiteDatabaseCorruptException.html
+
+http://developer.android.com/reference/android/database/sqlite/SQLiteDiskIOException.html
+http://developer.android.com/reference/android/database/sqlite/SQLiteDoneException.html
+
+http://developer.android.com/reference/android/database/sqlite/SQLiteException.html
+http://developer.android.com/reference/android/database/sqlite/SQLiteFullException.html
+
+http://developer.android.com/reference/android/database/sqlite/SQLiteMisuseException.html
+http://developer.android.com/reference/android/database/sqlite/package-descr.html
+
+http://developer.android.com/reference/android/database/Cursor.html
+http://developer.android.com/reference/java/lang/StackTraceElement.html
+
+http://developer.android.com/reference/java/io/PrintWriter.html
+http://developer.android.com/reference/java/io/PrintStream.html
+
+http://developer.android.com/reference/java/math/BigDecimal.html
+http://developer.android.com/reference/java/math/BigInteger.html
+
+http://developer.android.com/reference/java/math/MathContext.html
+http://developer.android.com/reference/java/math/RoundingMode.html
+
+http://developer.android.com/reference/java/math/package-descr.html
+http://developer.android.com/reference/dalvik/system/DexFile.html
+
+http://developer.android.com/reference/dalvik/system/PathClassLoader.html
+http://developer.android.com/reference/dalvik/system/TemporaryDirectory.html
+
+http://developer.android.com/reference/dalvik/system/TouchDex.html
+http://developer.android.com/reference/dalvik/system/VMDebug.html
+
+http://developer.android.com/reference/dalvik/system/VMRuntime.html
+http://developer.android.com/reference/dalvik/system/VMStack.html
+
+http://developer.android.com/reference/dalvik/system/Zygote.html
+http://developer.android.com/reference/dalvik/system/AllocationLimitError.html
+
+http://developer.android.com/reference/dalvik/system/PotentialDeadlockError.html
+http://developer.android.com/reference/dalvik/system/StaleDexCacheError.html
+
+http://developer.android.com/reference/org/apache/http/client/protocol/ClientContext.html
+http://developer.android.com/reference/org/apache/http/client/protocol/ClientContextConfigurer.html
+
+http://developer.android.com/reference/org/apache/http/client/protocol/RequestAddCookies.html
+
+http://developer.android.com/reference/org/apache/http/client/protocol/RequestDefaultHeaders.html
+
+http://developer.android.com/reference/org/apache/http/client/protocol/RequestProxyAuthentication.html
+
+http://developer.android.com/reference/org/apache/http/client/protocol/RequestTargetAuthentication.html
+
+http://developer.android.com/reference/org/apache/http/client/protocol/ResponseProcessCookies.html
+
+http://developer.android.com/reference/org/apache/http/client/protocol/package-descr.html
+http://developer.android.com/reference/android/graphics/drawable/Drawable.Callback.html
+
+http://developer.android.com/reference/android/graphics/drawable/ClipDrawable.html
+http://developer.android.com/reference/android/graphics/drawable/ColorDrawable.html
+
+http://developer.android.com/reference/android/graphics/drawable/Drawable.ConstantState.html
+http://developer.android.com/reference/android/graphics/drawable/DrawableContainer.html
+
+http://developer.android.com/reference/android/graphics/drawable/DrawableContainer.DrawableContainerState.html
+
+http://developer.android.com/reference/android/graphics/drawable/GradientDrawable.html
+http://developer.android.com/reference/android/graphics/drawable/InsetDrawable.html
+
+http://developer.android.com/reference/android/graphics/drawable/LevelListDrawable.html
+http://developer.android.com/reference/android/graphics/drawable/PaintDrawable.html
+
+http://developer.android.com/reference/android/graphics/drawable/RotateDrawable.html
+http://developer.android.com/reference/android/graphics/drawable/ScaleDrawable.html
+
+http://developer.android.com/reference/android/graphics/drawable/ShapeDrawable.ShaderFactory.html
+
+http://developer.android.com/reference/android/graphics/drawable/StateListDrawable.html
+http://developer.android.com/reference/android/graphics/drawable/TransitionDrawable.html
+
+http://developer.android.com/reference/android/graphics/drawable/GradientDrawable.Orientation.html
+
+http://developer.android.com/reference/java/lang/Runnable.html
+http://developer.android.com/reference/org/xmlpull/v1/XmlPullParser.html
+
+http://developer.android.com/reference/android/util/AttributeSet.html
+http://developer.android.com/reference/org/xmlpull/v1/XmlPullParserException.html
+
+http://developer.android.com/reference/java/util/EventListener.html
+http://developer.android.com/reference/android/app/AliasActivity.html
+
+http://developer.android.com/reference/java/lang/ref/PhantomReference.html
+http://developer.android.com/reference/java/lang/ref/Reference.html
+
+http://developer.android.com/reference/java/lang/ref/ReferenceQueue.html
+http://developer.android.com/reference/java/lang/ref/SoftReference.html
+
+http://developer.android.com/reference/java/lang/ref/WeakReference.html
+http://developer.android.com/reference/javax/xml/parsers/DocumentBuilder.html
+
+http://developer.android.com/reference/javax/xml/parsers/DocumentBuilderFactory.html
+http://developer.android.com/reference/javax/xml/parsers/SAXParser.html
+
+http://developer.android.com/reference/javax/xml/parsers/SAXParserFactory.html
+http://developer.android.com/reference/javax/xml/parsers/ParserConfigurationException.html
+
+http://developer.android.com/reference/javax/xml/parsers/FactoryConfigurationError.html
+http://developer.android.com/reference/javax/xml/parsers/package-descr.html
+
+http://developer.android.com/reference/android/app/DatePickerDialog.OnDateSetListener.html
+http://developer.android.com/reference/android/app/KeyguardManager.OnKeyguardExitResult.html
+
+http://developer.android.com/reference/android/app/PendingIntent.OnFinished.html
+http://developer.android.com/reference/android/app/SearchManager.OnCancelListener.html
+
+http://developer.android.com/reference/android/app/SearchManager.OnDismissListener.html
+http://developer.android.com/reference/android/app/TimePickerDialog.OnTimeSetListener.html
+
+http://developer.android.com/reference/android/app/ActivityGroup.html
+http://developer.android.com/reference/android/app/ActivityManager.html
+
+http://developer.android.com/reference/android/app/ActivityManager.MemoryInfo.html
+http://developer.android.com/reference/android/app/ActivityManager.ProcessErrorStateInfo.html
+
+http://developer.android.com/reference/android/app/ActivityManager.RecentTaskInfo.html
+http://developer.android.com/reference/android/app/ActivityManager.RunningServiceInfo.html
+
+http://developer.android.com/reference/android/app/ActivityManager.RunningTaskInfo.html
+http://developer.android.com/reference/android/app/AlarmManager.html
+
+http://developer.android.com/reference/android/app/AlertDialog.html
+http://developer.android.com/reference/android/app/AlertDialog.Builder.html
+
+http://developer.android.com/reference/android/app/DatePickerDialog.html
+http://developer.android.com/reference/android/app/Dialog.html
+
+http://developer.android.com/reference/android/app/ExpandableListActivity.html
+http://developer.android.com/reference/android/app/Instrumentation.ActivityMonitor.html
+
+http://developer.android.com/reference/android/app/Instrumentation.ActivityResult.html
+http://developer.android.com/reference/android/app/KeyguardManager.html
+
+http://developer.android.com/reference/android/app/KeyguardManager.KeyguardLock.html
+http://developer.android.com/reference/android/app/LauncherActivity.html
+
+http://developer.android.com/reference/android/app/LocalActivityManager.html
+http://developer.android.com/reference/android/app/Notification.html
+
+http://developer.android.com/reference/android/app/NotificationManager.html
+http://developer.android.com/reference/android/app/PendingIntent.html
+
+http://developer.android.com/reference/android/app/ProgressDialog.html
+http://developer.android.com/reference/android/app/SearchManager.html
+
+http://developer.android.com/reference/android/app/TabActivity.html
+http://developer.android.com/reference/android/app/TimePickerDialog.html
+
+http://developer.android.com/reference/android/app/PendingIntent.CanceledException.html
+http://developer.android.com/reference/android/content/ContextWrapper.html
+
+http://developer.android.com/reference/android/view/ContextThemeWrapper.html
+http://developer.android.com/reference/android/widget/ListAdapter.html
+
+http://developer.android.com/reference/android/widget/SimpleAdapter.html
+http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html
+
+http://developer.android.com/reference/android/media/AudioManager.html
+http://developer.android.com/reference/android/text/ClipboardManager.html
+
+http://developer.android.com/reference/android/view/LayoutInflater.html
+http://developer.android.com/reference/android/location/LocationManager.html
+
+http://developer.android.com/reference/android/os/PowerManager.html
+http://developer.android.com/reference/android/hardware/SensorManager.html
+
+http://developer.android.com/reference/android/telephony/TelephonyManager.html
+http://developer.android.com/reference/android/os/Vibrator.html
+
+http://developer.android.com/reference/android/net/wifi/WifiManager.html
+http://developer.android.com/reference/android/view/WindowManager.html
+
+http://developer.android.com/reference/android/view/ViewGroup.LayoutParams.html
+http://developer.android.com/reference/android/view/KeyEvent.html
+
+http://developer.android.com/reference/android/view/MotionEvent.html
+http://developer.android.com/reference/android/content/ComponentName.html
+
+http://developer.android.com/reference/android/view/Window.html
+http://developer.android.com/reference/android/content/SharedPreferences.html
+
+http://developer.android.com/reference/java/lang/CharSequence.html
+http://developer.android.com/reference/android/content/res/Resources.Theme.html
+
+http://developer.android.com/reference/android/content/res/Configuration.html
+http://developer.android.com/reference/android/view/Window.Callback.html
+
+http://developer.android.com/reference/android/view/LayoutInflater.Factory.html
+http://developer.android.com/reference/android/view/KeyEvent.Callback.html
+
+http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html
+http://developer.android.com/reference/android/content/ServiceConnection.html
+
+http://developer.android.com/reference/java/lang/SecurityException.html
+http://developer.android.com/reference/android/content/res/AssetManager.html
+
+http://developer.android.com/reference/java/io/File.html
+http://developer.android.com/reference/java/lang/ClassLoader.html
+
+http://developer.android.com/reference/android/os/Looper.html
+http://developer.android.com/reference/java/io/FileInputStream.html
+
+http://developer.android.com/reference/java/io/FileOutputStream.html
+http://developer.android.com/reference/android/content/IntentFilter.html
+
+http://developer.android.com/reference/android/os/Handler.html
+http://developer.android.com/reference/java/util/Formatter.html
+
+http://developer.android.com/reference/android/content/res/TypedArray.html
+http://developer.android.com/reference/android/content/ComponentCallbacks.html
+
+http://developer.android.com/reference/android/view/animation/Animation.AnimationListener.html
+
+http://developer.android.com/reference/android/view/animation/AccelerateDecelerateInterpolator.html
+
+http://developer.android.com/reference/android/view/animation/AlphaAnimation.html
+http://developer.android.com/reference/android/view/animation/Animation.Description.html
+
+http://developer.android.com/reference/android/view/animation/AnimationUtils.html
+http://developer.android.com/reference/android/view/animation/CycleInterpolator.html
+
+http://developer.android.com/reference/android/view/animation/DecelerateInterpolator.html
+http://developer.android.com/reference/android/view/animation/GridLayoutAnimationController.html
+
+http://developer.android.com/reference/android/view/animation/GridLayoutAnimationController.AnimationParameters.html
+
+http://developer.android.com/reference/android/view/animation/LayoutAnimationController.html
+http://developer.android.com/reference/android/view/animation/LayoutAnimationController.AnimationParameters.html
+
+http://developer.android.com/reference/android/view/animation/LinearInterpolator.html
+http://developer.android.com/reference/android/view/animation/RotateAnimation.html
+
+http://developer.android.com/reference/android/view/animation/ScaleAnimation.html
+http://developer.android.com/reference/android/view/animation/Transformation.html
+
+http://developer.android.com/reference/android/view/animation/TranslateAnimation.html
+http://developer.android.com/reference/android/view/animation/package-descr.html
+
+http://developer.android.com/reference/android/os/IBinder.html
+http://developer.android.com/reference/android/os/IBinder.DeathRecipient.html
+
+http://developer.android.com/reference/android/os/IInterface.html
+http://developer.android.com/reference/android/os/MessageQueue.IdleHandler.html
+
+http://developer.android.com/reference/android/os/Parcelable.html
+http://developer.android.com/reference/android/os/Parcelable.Creator.html
+
+http://developer.android.com/reference/android/os/BatteryManager.html
+http://developer.android.com/reference/android/os/Binder.html
+
+http://developer.android.com/reference/android/os/Build.html
+http://developer.android.com/reference/android/os/Build.VERSION.html
+
+http://developer.android.com/reference/android/os/ConditionVariable.html
+http://developer.android.com/reference/android/os/CountDownTimer.html
+
+http://developer.android.com/reference/android/os/Debug.InstructionCount.html
+http://developer.android.com/reference/android/os/Debug.MemoryInfo.html
+
+http://developer.android.com/reference/android/os/Environment.html
+http://developer.android.com/reference/android/os/FileObserver.html
+
+http://developer.android.com/reference/android/os/HandlerThread.html
+http://developer.android.com/reference/android/os/MemoryFile.html
+
+http://developer.android.com/reference/android/os/Message.html
+http://developer.android.com/reference/android/os/MessageQueue.html
+
+http://developer.android.com/reference/android/os/Messenger.html
+http://developer.android.com/reference/android/os/Parcel.html
+
+http://developer.android.com/reference/android/os/ParcelFileDescriptor.html
+http://developer.android.com/reference/android/os/ParcelFileDescriptor.AutoCloseInputStream.html
+
+http://developer.android.com/reference/android/os/ParcelFileDescriptor.AutoCloseOutputStream.html
+
+http://developer.android.com/reference/android/os/PatternMatcher.html
+http://developer.android.com/reference/android/os/PowerManager.WakeLock.html
+
+http://developer.android.com/reference/android/os/RemoteCallbackList.html
+http://developer.android.com/reference/android/os/StatFs.html
+
+http://developer.android.com/reference/android/os/SystemClock.html
+http://developer.android.com/reference/android/os/TokenWatcher.html
+
+http://developer.android.com/reference/android/os/BadParcelableException.html
+http://developer.android.com/reference/android/os/DeadObjectException.html
+
+http://developer.android.com/reference/android/os/ParcelFormatException.html
+http://developer.android.com/reference/android/os/RemoteException.html
+
+http://developer.android.com/reference/java/lang/Cloneable.html
+http://developer.android.com/reference/java/lang/Byte.html
+
+http://developer.android.com/reference/java/util/ArrayList.html
+http://developer.android.com/reference/java/lang/Integer.html
+
+http://developer.android.com/reference/java/io/Serializable.html
+http://developer.android.com/reference/android/util/SparseArray.html
+
+http://developer.android.com/reference/java/util/Set.html
+http://developer.android.com/reference/java/nio/channels/DatagramChannel.html
+
+http://developer.android.com/reference/java/lang/IllegalArgumentException.html
+http://developer.android.com/reference/android/webkit/WebView.html
+
+http://developer.android.com/reference/android/hardware/Camera.html
+http://developer.android.com/reference/android/text/Spannable.html
+
+http://developer.android.com/reference/android/util/Log.html
+http://developer.android.com/reference/org/xml/sax/helpers/AttributeListImpl.html
+
+http://developer.android.com/reference/org/xml/sax/helpers/AttributesImpl.html
+http://developer.android.com/reference/org/xml/sax/helpers/DefaultHandler.html
+
+http://developer.android.com/reference/org/xml/sax/helpers/LocatorImpl.html
+http://developer.android.com/reference/org/xml/sax/helpers/NamespaceSupport.html
+
+http://developer.android.com/reference/org/xml/sax/helpers/ParserAdapter.html
+http://developer.android.com/reference/org/xml/sax/helpers/ParserFactory.html
+
+http://developer.android.com/reference/org/xml/sax/helpers/XMLFilterImpl.html
+http://developer.android.com/reference/org/xml/sax/helpers/XMLReaderAdapter.html
+
+http://developer.android.com/reference/org/xml/sax/helpers/XMLReaderFactory.html
+http://developer.android.com/reference/org/xml/sax/helpers/package-descr.html
+
+http://developer.android.com/reference/org/xml/sax/AttributeList.html
+http://developer.android.com/reference/org/xml/sax/Parser.html
+
+http://developer.android.com/reference/android/widget/AbsListView.OnScrollListener.html
+http://developer.android.com/reference/android/widget/AbsListView.RecyclerListener.html
+
+http://developer.android.com/reference/android/widget/Adapter.html
+http://developer.android.com/reference/android/widget/AdapterView.OnItemClickListener.html
+
+http://developer.android.com/reference/android/widget/AdapterView.OnItemLongClickListener.html
+
+http://developer.android.com/reference/android/widget/AdapterView.OnItemSelectedListener.html
+
+http://developer.android.com/reference/android/widget/AutoCompleteTextView.Validator.html
+http://developer.android.com/reference/android/widget/Checkable.html
+
+http://developer.android.com/reference/android/widget/CompoundButton.OnCheckedChangeListener.html
+
+http://developer.android.com/reference/android/widget/DatePicker.OnDateChangedListener.html
+http://developer.android.com/reference/android/widget/ExpandableListAdapter.html
+
+http://developer.android.com/reference/android/widget/ExpandableListView.OnChildClickListener.html
+
+http://developer.android.com/reference/android/widget/ExpandableListView.OnGroupClickListener.html
+
+http://developer.android.com/reference/android/widget/ExpandableListView.OnGroupCollapseListener.html
+
+http://developer.android.com/reference/android/widget/ExpandableListView.OnGroupExpandListener.html
+
+http://developer.android.com/reference/android/widget/Filter.FilterListener.html
+http://developer.android.com/reference/android/widget/Filterable.html
+
+http://developer.android.com/reference/android/widget/FilterQueryProvider.html
+http://developer.android.com/reference/android/widget/MediaController.MediaPlayerControl.html
+
+http://developer.android.com/reference/android/widget/MultiAutoCompleteTextView.Tokenizer.html
+
+http://developer.android.com/reference/android/widget/RadioGroup.OnCheckedChangeListener.html
+
+http://developer.android.com/reference/android/widget/RatingBar.OnRatingBarChangeListener.html
+
+http://developer.android.com/reference/android/widget/SeekBar.OnSeekBarChangeListener.html
+http://developer.android.com/reference/android/widget/SimpleAdapter.ViewBinder.html
+
+http://developer.android.com/reference/android/widget/SimpleCursorAdapter.CursorToStringConverter.html
+
+http://developer.android.com/reference/android/widget/SimpleCursorAdapter.ViewBinder.html
+http://developer.android.com/reference/android/widget/SpinnerAdapter.html
+
+http://developer.android.com/reference/android/widget/TabHost.OnTabChangeListener.html
+http://developer.android.com/reference/android/widget/TabHost.TabContentFactory.html
+
+http://developer.android.com/reference/android/widget/TimePicker.OnTimeChangedListener.html
+http://developer.android.com/reference/android/widget/ViewSwitcher.ViewFactory.html
+
+http://developer.android.com/reference/android/widget/WrapperListAdapter.html
+http://developer.android.com/reference/android/widget/AbsListView.html
+
+http://developer.android.com/reference/android/widget/AbsListView.LayoutParams.html
+http://developer.android.com/reference/android/widget/AbsoluteLayout.LayoutParams.html
+
+http://developer.android.com/reference/android/widget/AbsSeekBar.html
+http://developer.android.com/reference/android/widget/AbsSpinner.html
+
+http://developer.android.com/reference/android/widget/AdapterView.html
+http://developer.android.com/reference/android/widget/AnalogClock.html
+
+http://developer.android.com/reference/android/widget/ArrayAdapter.html
+http://developer.android.com/reference/android/widget/BaseAdapter.html
+
+http://developer.android.com/reference/android/widget/BaseExpandableListAdapter.html
+http://developer.android.com/reference/android/widget/CheckedTextView.html
+
+http://developer.android.com/reference/android/widget/Chronometer.html
+http://developer.android.com/reference/android/widget/CompoundButton.html
+
+http://developer.android.com/reference/android/widget/CursorAdapter.html
+http://developer.android.com/reference/android/widget/CursorTreeAdapter.html
+
+http://developer.android.com/reference/android/widget/DatePicker.html
+http://developer.android.com/reference/android/widget/DialerFilter.html
+
+http://developer.android.com/reference/android/widget/DigitalClock.html
+http://developer.android.com/reference/android/widget/ExpandableListView.html
+
+http://developer.android.com/reference/android/widget/ExpandableListView.ExpandableListContextMenuInfo.html
+
+http://developer.android.com/reference/android/widget/Filter.html
+http://developer.android.com/reference/android/widget/Filter.FilterResults.html
+
+http://developer.android.com/reference/android/widget/FrameLayout.LayoutParams.html
+http://developer.android.com/reference/android/widget/Gallery.LayoutParams.html
+
+http://developer.android.com/reference/android/widget/GridView.html
+http://developer.android.com/reference/android/widget/HeaderViewListAdapter.html
+
+http://developer.android.com/reference/android/widget/ImageButton.html
+http://developer.android.com/reference/android/widget/LinearLayout.LayoutParams.html
+
+http://developer.android.com/reference/android/widget/ListView.FixedViewInfo.html
+http://developer.android.com/reference/android/widget/MediaController.html
+
+http://developer.android.com/reference/android/widget/MultiAutoCompleteTextView.html
+http://developer.android.com/reference/android/widget/MultiAutoCompleteTextView.CommaTokenizer.html
+
+http://developer.android.com/reference/android/widget/PopupWindow.html
+http://developer.android.com/reference/android/widget/ProgressBar.html
+
+http://developer.android.com/reference/android/widget/RadioGroup.html
+http://developer.android.com/reference/android/widget/RadioGroup.LayoutParams.html
+
+http://developer.android.com/reference/android/widget/RatingBar.html
+http://developer.android.com/reference/android/widget/RelativeLayout.html
+
+http://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams.html
+http://developer.android.com/reference/android/widget/RemoteViews.html
+
+http://developer.android.com/reference/android/widget/ResourceCursorAdapter.html
+http://developer.android.com/reference/android/widget/ResourceCursorTreeAdapter.html
+
+http://developer.android.com/reference/android/widget/Scroller.html
+http://developer.android.com/reference/android/widget/ScrollView.html
+
+http://developer.android.com/reference/android/widget/SeekBar.html
+http://developer.android.com/reference/android/widget/SimpleCursorTreeAdapter.html
+
+http://developer.android.com/reference/android/widget/SimpleExpandableListAdapter.html
+http://developer.android.com/reference/android/widget/TabHost.html
+
+http://developer.android.com/reference/android/widget/TabHost.TabSpec.html
+http://developer.android.com/reference/android/widget/TableLayout.html
+
+http://developer.android.com/reference/android/widget/TableLayout.LayoutParams.html
+http://developer.android.com/reference/android/widget/TableRow.html
+
+http://developer.android.com/reference/android/widget/TableRow.LayoutParams.html
+http://developer.android.com/reference/android/widget/TabWidget.html
+
+http://developer.android.com/reference/android/widget/TextView.SavedState.html
+http://developer.android.com/reference/android/widget/TimePicker.html
+
+http://developer.android.com/reference/android/widget/Toast.html
+http://developer.android.com/reference/android/widget/ToggleButton.html
+
+http://developer.android.com/reference/android/widget/TwoLineListItem.html
+http://developer.android.com/reference/android/widget/VideoView.html
+
+http://developer.android.com/reference/android/widget/ViewAnimator.html
+http://developer.android.com/reference/android/widget/ViewFlipper.html
+
+http://developer.android.com/reference/android/widget/ViewSwitcher.html
+http://developer.android.com/reference/android/widget/ZoomButton.html
+
+http://developer.android.com/reference/android/widget/ZoomControls.html
+http://developer.android.com/reference/android/widget/ImageView.ScaleType.html
+
+http://developer.android.com/reference/android/widget/TextView.BufferType.html
+http://developer.android.com/reference/android/widget/RemoteViews.ActionException.html
+
+http://developer.android.com/reference/java/lang/RuntimeException.html
+http://developer.android.com/reference/android/view/ViewGroup.OnHierarchyChangeListener.html
+
+http://developer.android.com/reference/android/view/TouchDelegate.html
+http://developer.android.com/reference/android/view/ViewTreeObserver.html
+
+http://developer.android.com/reference/android/view/ViewManager.html
+http://developer.android.com/reference/android/view/Gravity.html
+
+http://developer.android.com/reference/javax/microedition/khronos/opengles/GL.html
+http://developer.android.com/reference/java/awt/font/NumericShaper.html
+
+http://developer.android.com/reference/java/awt/font/TextAttribute.html
+http://developer.android.com/reference/android/text/TextWatcher.html
+
+http://developer.android.com/reference/android/text/method/MovementMethod.html
+http://developer.android.com/reference/android/text/TextUtils.TruncateAt.html
+
+http://developer.android.com/reference/android/text/InputFilter.html
+http://developer.android.com/reference/android/content/res/ColorStateList.html
+
+http://developer.android.com/reference/android/text/method/KeyListener.html
+http://developer.android.com/reference/android/text/Layout.html
+
+http://developer.android.com/reference/android/text/method/LinkMovementMethod.html
+http://developer.android.com/reference/android/text/TextPaint.html
+
+http://developer.android.com/reference/android/text/Selection.html
+http://developer.android.com/reference/android/text/method/TransformationMethod.html
+
+http://developer.android.com/reference/android/text/style/URLSpan.html
+http://developer.android.com/reference/android/text/util/Linkify.html
+
+http://developer.android.com/reference/android/text/Editable.Factory.html
+http://developer.android.com/reference/android/text/Spannable.Factory.html
+
+http://developer.android.com/reference/android/view/ViewTreeObserver.OnPreDrawListener.html
+http://developer.android.com/reference/java/security/BasicPermission.html
+
+http://developer.android.com/reference/java/security/Guard.html
+http://developer.android.com/reference/java/security/Permission.html
+
+http://developer.android.com/reference/java/security/PermissionCollection.html
+http://developer.android.com/reference/java/util/Locale.html
+
+http://developer.android.com/reference/java/lang/NullPointerException.html
+http://developer.android.com/reference/org/apache/http/FormattedHeader.html
+
+http://developer.android.com/reference/org/apache/http/Header.html
+http://developer.android.com/reference/org/apache/http/HeaderElement.html
+
+http://developer.android.com/reference/org/apache/http/HeaderElementIterator.html
+http://developer.android.com/reference/org/apache/http/HeaderIterator.html
+
+http://developer.android.com/reference/org/apache/http/HttpClientConnection.html
+http://developer.android.com/reference/org/apache/http/HttpConnection.html
+
+http://developer.android.com/reference/org/apache/http/HttpConnectionMetrics.html
+http://developer.android.com/reference/org/apache/http/HttpEntity.html
+
+http://developer.android.com/reference/org/apache/http/HttpInetConnection.html
+http://developer.android.com/reference/org/apache/http/HttpMessage.html
+
+http://developer.android.com/reference/org/apache/http/HttpRequestFactory.html
+http://developer.android.com/reference/org/apache/http/HttpRequestInterceptor.html
+
+http://developer.android.com/reference/org/apache/http/HttpResponseFactory.html
+http://developer.android.com/reference/org/apache/http/HttpResponseInterceptor.html
+
+http://developer.android.com/reference/org/apache/http/HttpServerConnection.html
+http://developer.android.com/reference/org/apache/http/HttpStatus.html
+
+http://developer.android.com/reference/org/apache/http/NameValuePair.html
+http://developer.android.com/reference/org/apache/http/ReasonPhraseCatalog.html
+
+http://developer.android.com/reference/org/apache/http/RequestLine.html
+http://developer.android.com/reference/org/apache/http/StatusLine.html
+
+http://developer.android.com/reference/org/apache/http/TokenIterator.html
+http://developer.android.com/reference/org/apache/http/HttpVersion.html
+
+http://developer.android.com/reference/org/apache/http/ProtocolVersion.html
+http://developer.android.com/reference/org/apache/http/ConnectionClosedException.html
+
+http://developer.android.com/reference/org/apache/http/MalformedChunkCodingException.html
+http://developer.android.com/reference/org/apache/http/MethodNotSupportedException.html
+
+http://developer.android.com/reference/org/apache/http/NoHttpResponseException.html
+http://developer.android.com/reference/org/apache/http/ParseException.html
+
+http://developer.android.com/reference/org/apache/http/ProtocolException.html
+http://developer.android.com/reference/org/apache/http/UnsupportedHttpVersionException.html
+
+http://developer.android.com/reference/org/apache/http/impl/DefaultConnectionReuseStrategy.html
+
+http://developer.android.com/reference/org/apache/http/impl/NoConnectionReuseStrategy.html
+http://developer.android.com/reference/java/lang/Enum.html
+
+http://developer.android.com/reference/java/lang/Comparable.html
+http://developer.android.com/reference/javax/crypto/SecretKey.html
+
+http://developer.android.com/reference/javax/crypto/Cipher.html
+http://developer.android.com/reference/javax/crypto/CipherInputStream.html
+
+http://developer.android.com/reference/javax/crypto/CipherOutputStream.html
+http://developer.android.com/reference/javax/crypto/CipherSpi.html
+
+http://developer.android.com/reference/javax/crypto/EncryptedPrivateKeyInfo.html
+http://developer.android.com/reference/javax/crypto/ExemptionMechanism.html
+
+http://developer.android.com/reference/javax/crypto/ExemptionMechanismSpi.html
+http://developer.android.com/reference/javax/crypto/KeyAgreement.html
+
+http://developer.android.com/reference/javax/crypto/KeyAgreementSpi.html
+http://developer.android.com/reference/javax/crypto/KeyGenerator.html
+
+http://developer.android.com/reference/javax/crypto/KeyGeneratorSpi.html
+http://developer.android.com/reference/javax/crypto/Mac.html
+
+http://developer.android.com/reference/javax/crypto/MacSpi.html
+http://developer.android.com/reference/javax/crypto/NullCipher.html
+
+http://developer.android.com/reference/javax/crypto/SealedObject.html
+http://developer.android.com/reference/javax/crypto/SecretKeyFactory.html
+
+http://developer.android.com/reference/javax/crypto/SecretKeyFactorySpi.html
+http://developer.android.com/reference/javax/crypto/BadPaddingException.html
+
+http://developer.android.com/reference/javax/crypto/ExemptionMechanismException.html
+http://developer.android.com/reference/javax/crypto/IllegalBlockSizeException.html
+
+http://developer.android.com/reference/javax/crypto/NoSuchPaddingException.html
+http://developer.android.com/reference/javax/crypto/ShortBufferException.html
+
+http://developer.android.com/reference/javax/crypto/package-descr.html
+http://developer.android.com/reference/android/database/CrossProcessCursor.html
+
+http://developer.android.com/reference/android/database/AbstractCursor.html
+http://developer.android.com/reference/android/database/AbstractCursor.SelfContentObserver.html
+
+http://developer.android.com/reference/android/database/AbstractWindowedCursor.html
+http://developer.android.com/reference/android/database/CharArrayBuffer.html
+
+http://developer.android.com/reference/android/database/ContentObservable.html
+http://developer.android.com/reference/android/database/ContentObserver.html
+
+http://developer.android.com/reference/android/database/CursorJoiner.html
+http://developer.android.com/reference/android/database/CursorWindow.html
+
+http://developer.android.com/reference/android/database/CursorWrapper.html
+http://developer.android.com/reference/android/database/DatabaseUtils.html
+
+http://developer.android.com/reference/android/database/DatabaseUtils.InsertHelper.html
+http://developer.android.com/reference/android/database/DataSetObservable.html
+
+http://developer.android.com/reference/android/database/DataSetObserver.html
+http://developer.android.com/reference/android/database/MatrixCursor.html
+
+http://developer.android.com/reference/android/database/MatrixCursor.RowBuilder.html
+http://developer.android.com/reference/android/database/MergeCursor.html
+
+http://developer.android.com/reference/android/database/Observable.html
+http://developer.android.com/reference/android/database/CursorJoiner.Result.html
+
+http://developer.android.com/reference/android/database/CursorIndexOutOfBoundsException.html
+http://developer.android.com/reference/android/database/SQLException.html
+
+http://developer.android.com/reference/android/database/StaleDataException.html
+http://developer.android.com/reference/android/database/package-descr.html
+
+http://developer.android.com/reference/org/apache/http/conn/ClientConnectionManager.html
+http://developer.android.com/reference/org/apache/http/conn/ClientConnectionManagerFactory.html
+
+http://developer.android.com/reference/org/apache/http/conn/ClientConnectionOperator.html
+http://developer.android.com/reference/org/apache/http/conn/ClientConnectionRequest.html
+
+http://developer.android.com/reference/org/apache/http/conn/ConnectionReleaseTrigger.html
+http://developer.android.com/reference/org/apache/http/conn/EofSensorWatcher.html
+
+http://developer.android.com/reference/org/apache/http/conn/ManagedClientConnection.html
+http://developer.android.com/reference/org/apache/http/conn/OperatedClientConnection.html
+
+http://developer.android.com/reference/org/apache/http/conn/BasicEofSensorWatcher.html
+http://developer.android.com/reference/org/apache/http/conn/BasicManagedEntity.html
+
+http://developer.android.com/reference/org/apache/http/conn/EofSensorInputStream.html
+http://developer.android.com/reference/org/apache/http/conn/MultihomePlainSocketFactory.html
+
+http://developer.android.com/reference/org/apache/http/conn/ConnectionPoolTimeoutException.html
+
+http://developer.android.com/reference/org/apache/http/conn/ConnectTimeoutException.html
+http://developer.android.com/reference/org/apache/http/conn/HttpHostConnectException.html
+
+http://developer.android.com/reference/java/nio/charset/Charset.html
+http://developer.android.com/reference/java/nio/charset/CharsetDecoder.html
+
+http://developer.android.com/reference/java/nio/charset/CharsetEncoder.html
+http://developer.android.com/reference/java/nio/charset/CoderResult.html
+
+http://developer.android.com/reference/java/nio/charset/CodingErrorAction.html
+http://developer.android.com/reference/java/nio/charset/CharacterCodingException.html
+
+http://developer.android.com/reference/java/nio/charset/IllegalCharsetNameException.html
+http://developer.android.com/reference/java/nio/charset/MalformedInputException.html
+
+http://developer.android.com/reference/java/nio/charset/UnmappableCharacterException.html
+http://developer.android.com/reference/java/nio/charset/UnsupportedCharsetException.html
+
+http://developer.android.com/reference/java/nio/charset/CoderMalfunctionError.html
+http://developer.android.com/reference/java/nio/charset/package-descr.html
+
+http://developer.android.com/reference/com/google/android/maps/MapView.html
+http://developer.android.com/reference/com/google/android/maps/MapActivity.html
+
+http://developer.android.com/guide/topics/location/geo/mapkey.html
+http://developer.android.com/reference/com/google/android/maps/MapController.html
+
+http://developer.android.com/reference/com/google/android/maps/ItemizedOverlay.html
+http://developer.android.com/reference/com/google/android/maps/Overlay.html
+
+http://developer.android.com/reference/java/lang/CloneNotSupportedException.html
+http://developer.android.com/reference/java/security/AlgorithmParameters.html
+
+http://developer.android.com/reference/java/security/spec/PKCS8EncodedKeySpec.html
+http://developer.android.com/reference/java/security/Key.html
+
+http://developer.android.com/reference/java/security/Provider.html
+http://developer.android.com/reference/java/security/NoSuchAlgorithmException.html
+
+http://developer.android.com/reference/java/security/NoSuchProviderException.html
+http://developer.android.com/reference/java/security/InvalidKeyException.html
+
+http://developer.android.com/reference/java/security/spec/InvalidKeySpecException.html
+http://developer.android.com/reference/android/webkit/DownloadListener.html
+
+http://developer.android.com/reference/android/webkit/Plugin.PreferencesClickHandler.html
+http://developer.android.com/reference/android/webkit/UrlInterceptHandler.html
+
+http://developer.android.com/reference/android/webkit/WebIconDatabase.IconListener.html
+http://developer.android.com/reference/android/webkit/WebView.PictureListener.html
+
+http://developer.android.com/reference/android/webkit/CacheManager.html
+http://developer.android.com/reference/android/webkit/CacheManager.CacheResult.html
+
+http://developer.android.com/reference/android/webkit/CookieManager.html
+http://developer.android.com/reference/android/webkit/CookieSyncManager.html
+
+http://developer.android.com/reference/android/webkit/DateSorter.html
+http://developer.android.com/reference/android/webkit/HttpAuthHandler.html
+
+http://developer.android.com/reference/android/webkit/JsPromptResult.html
+http://developer.android.com/reference/android/webkit/JsResult.html
+
+http://developer.android.com/reference/android/webkit/MimeTypeMap.html
+http://developer.android.com/reference/android/webkit/Plugin.html
+
+http://developer.android.com/reference/android/webkit/PluginList.html
+http://developer.android.com/reference/android/webkit/SslErrorHandler.html
+
+http://developer.android.com/reference/android/webkit/UrlInterceptRegistry.html
+http://developer.android.com/reference/android/webkit/URLUtil.html
+
+http://developer.android.com/reference/android/webkit/WebBackForwardList.html
+http://developer.android.com/reference/android/webkit/WebChromeClient.html
+
+http://developer.android.com/reference/android/webkit/WebHistoryItem.html
+http://developer.android.com/reference/android/webkit/WebIconDatabase.html
+
+http://developer.android.com/reference/android/webkit/WebSettings.html
+http://developer.android.com/reference/android/webkit/WebView.HitTestResult.html
+
+http://developer.android.com/reference/android/webkit/WebView.WebViewTransport.html
+http://developer.android.com/reference/android/webkit/WebViewClient.html
+
+http://developer.android.com/reference/android/webkit/WebViewDatabase.html
+http://developer.android.com/reference/android/webkit/WebSettings.LayoutAlgorithm.html
+
+http://developer.android.com/reference/android/webkit/WebSettings.RenderPriority.html
+http://developer.android.com/reference/android/webkit/WebSettings.TextSize.html
+
+http://developer.android.com/reference/android/webkit/package-descr.html
+http://developer.android.com/reference/java/util/Map.html
+
+http://developer.android.com/reference/android/graphics/drawable/shapes/ArcShape.html
+http://developer.android.com/reference/android/graphics/drawable/shapes/PathShape.html
+
+http://developer.android.com/reference/android/graphics/drawable/shapes/RectShape.html
+http://developer.android.com/reference/android/graphics/drawable/shapes/RoundRectShape.html
+
+http://developer.android.com/reference/android/graphics/drawable/shapes/Shape.html
+http://developer.android.com/reference/android/graphics/drawable/package-descr.html
+
+http://developer.android.com/reference/java/lang/IndexOutOfBoundsException.html
+http://developer.android.com/reference/android/content/pm/ActivityInfo.html
+
+http://developer.android.com/reference/java/lang/InstantiationException.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/GLSurfaceView.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/GLSurfaceViewActivity.html
+
+http://developer.android.com/reference/java/util/concurrent/BlockingQueue.html
+http://developer.android.com/reference/java/util/concurrent/Callable.html
+
+http://developer.android.com/reference/java/util/concurrent/CompletionService.html
+http://developer.android.com/reference/java/util/concurrent/ConcurrentMap.html
+
+http://developer.android.com/reference/java/util/concurrent/Delayed.html
+http://developer.android.com/reference/java/util/concurrent/Executor.html
+
+http://developer.android.com/reference/java/util/concurrent/ExecutorService.html
+http://developer.android.com/reference/java/util/concurrent/Future.html
+
+http://developer.android.com/reference/java/util/concurrent/RejectedExecutionHandler.html
+http://developer.android.com/reference/java/util/concurrent/ScheduledExecutorService.html
+
+http://developer.android.com/reference/java/util/concurrent/ScheduledFuture.html
+http://developer.android.com/reference/java/util/concurrent/ThreadFactory.html
+
+http://developer.android.com/reference/java/util/concurrent/AbstractExecutorService.html
+http://developer.android.com/reference/java/util/concurrent/ArrayBlockingQueue.html
+
+http://developer.android.com/reference/java/util/concurrent/ConcurrentHashMap.html
+http://developer.android.com/reference/java/util/concurrent/ConcurrentLinkedQueue.html
+
+http://developer.android.com/reference/java/util/concurrent/CopyOnWriteArrayList.html
+http://developer.android.com/reference/java/util/concurrent/CopyOnWriteArraySet.html
+
+http://developer.android.com/reference/java/util/concurrent/CountDownLatch.html
+http://developer.android.com/reference/java/util/concurrent/CyclicBarrier.html
+
+http://developer.android.com/reference/java/util/concurrent/DelayQueue.html
+http://developer.android.com/reference/java/util/concurrent/Exchanger.html
+
+http://developer.android.com/reference/java/util/concurrent/ExecutorCompletionService.html
+http://developer.android.com/reference/java/util/concurrent/Executors.html
+
+http://developer.android.com/reference/java/util/concurrent/FutureTask.html
+http://developer.android.com/reference/java/util/concurrent/LinkedBlockingQueue.html
+
+http://developer.android.com/reference/java/util/concurrent/PriorityBlockingQueue.html
+http://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor.html
+
+http://developer.android.com/reference/java/util/concurrent/Semaphore.html
+http://developer.android.com/reference/java/util/concurrent/SynchronousQueue.html
+
+http://developer.android.com/reference/java/util/concurrent/ThreadPoolExecutor.html
+http://developer.android.com/reference/java/util/concurrent/ThreadPoolExecutor.AbortPolicy.html
+
+http://developer.android.com/reference/java/util/concurrent/ThreadPoolExecutor.CallerRunsPolicy.html
+
+http://developer.android.com/reference/java/util/concurrent/ThreadPoolExecutor.DiscardOldestPolicy.html
+
+http://developer.android.com/reference/java/util/concurrent/ThreadPoolExecutor.DiscardPolicy.html
+
+http://developer.android.com/reference/java/util/concurrent/TimeUnit.html
+http://developer.android.com/reference/java/util/concurrent/BrokenBarrierException.html
+
+http://developer.android.com/reference/java/util/concurrent/CancellationException.html
+http://developer.android.com/reference/java/util/concurrent/ExecutionException.html
+
+http://developer.android.com/reference/java/util/concurrent/RejectedExecutionException.html
+http://developer.android.com/reference/java/util/concurrent/TimeoutException.html
+
+http://developer.android.com/reference/java/util/concurrent/package-descr.html
+http://developer.android.com/reference/java/util/Queue.html
+
+http://developer.android.com/reference/java/util/PriorityQueue.html
+http://developer.android.com/reference/android/telephony/CellLocation.html
+
+http://developer.android.com/reference/android/telephony/PhoneNumberFormattingTextWatcher.html
+
+http://developer.android.com/reference/android/telephony/PhoneNumberUtils.html
+http://developer.android.com/reference/android/telephony/PhoneStateListener.html
+
+http://developer.android.com/reference/android/telephony/ServiceState.html
+http://developer.android.com/reference/java/lang/Appendable.html
+
+http://developer.android.com/reference/java/lang/Iterable.html
+http://developer.android.com/reference/java/lang/Readable.html
+
+http://developer.android.com/reference/java/lang/Thread.UncaughtExceptionHandler.html
+http://developer.android.com/reference/java/lang/Boolean.html
+
+http://developer.android.com/reference/java/lang/Character.html
+http://developer.android.com/reference/java/lang/Character.Subset.html
+
+http://developer.android.com/reference/java/lang/Character.UnicodeBlock.html
+http://developer.android.com/reference/java/lang/Compiler.html
+
+http://developer.android.com/reference/java/lang/Double.html
+http://developer.android.com/reference/java/lang/Float.html
+
+http://developer.android.com/reference/java/lang/InheritableThreadLocal.html
+http://developer.android.com/reference/java/lang/Long.html
+
+http://developer.android.com/reference/java/lang/Math.html
+http://developer.android.com/reference/java/lang/Number.html
+
+http://developer.android.com/reference/java/lang/Package.html
+http://developer.android.com/reference/java/lang/Process.html
+
+http://developer.android.com/reference/java/lang/ProcessBuilder.html
+http://developer.android.com/reference/java/lang/Runtime.html
+
+http://developer.android.com/reference/java/lang/RuntimePermission.html
+http://developer.android.com/reference/java/lang/SecurityManager.html
+
+http://developer.android.com/reference/java/lang/Short.html
+http://developer.android.com/reference/java/lang/StrictMath.html
+
+http://developer.android.com/reference/java/lang/StringBuffer.html
+http://developer.android.com/reference/java/lang/StringBuilder.html
+
+http://developer.android.com/reference/java/lang/System.html
+http://developer.android.com/reference/java/lang/Thread.html
+
+http://developer.android.com/reference/java/lang/ThreadGroup.html
+http://developer.android.com/reference/java/lang/ThreadLocal.html
+
+http://developer.android.com/reference/java/lang/Void.html
+http://developer.android.com/reference/java/lang/Thread.State.html
+
+http://developer.android.com/reference/java/lang/ArithmeticException.html
+http://developer.android.com/reference/java/lang/ArrayIndexOutOfBoundsException.html
+
+http://developer.android.com/reference/java/lang/ArrayStoreException.html
+http://developer.android.com/reference/java/lang/ClassCastException.html
+
+http://developer.android.com/reference/java/lang/EnumConstantNotPresentException.html
+http://developer.android.com/reference/java/lang/IllegalMonitorStateException.html
+
+http://developer.android.com/reference/java/lang/IllegalStateException.html
+http://developer.android.com/reference/java/lang/IllegalThreadStateException.html
+
+http://developer.android.com/reference/java/lang/InterruptedException.html
+http://developer.android.com/reference/java/lang/NegativeArraySizeException.html
+
+http://developer.android.com/reference/java/lang/NoSuchFieldException.html
+http://developer.android.com/reference/java/lang/NoSuchMethodException.html
+
+http://developer.android.com/reference/java/lang/NumberFormatException.html
+http://developer.android.com/reference/java/lang/StringIndexOutOfBoundsException.html
+
+http://developer.android.com/reference/java/lang/TypeNotPresentException.html
+http://developer.android.com/reference/java/lang/UnsupportedOperationException.html
+
+http://developer.android.com/reference/java/lang/AbstractMethodError.html
+http://developer.android.com/reference/java/lang/AssertionError.html
+
+http://developer.android.com/reference/java/lang/ClassCircularityError.html
+http://developer.android.com/reference/java/lang/ClassFormatError.html
+
+http://developer.android.com/reference/java/lang/Error.html
+http://developer.android.com/reference/java/lang/ExceptionInInitializerError.html
+
+http://developer.android.com/reference/java/lang/IllegalAccessError.html
+http://developer.android.com/reference/java/lang/IncompatibleClassChangeError.html
+
+http://developer.android.com/reference/java/lang/InstantiationError.html
+http://developer.android.com/reference/java/lang/InternalError.html
+
+http://developer.android.com/reference/java/lang/LinkageError.html
+http://developer.android.com/reference/java/lang/NoClassDefFoundError.html
+
+http://developer.android.com/reference/java/lang/NoSuchFieldError.html
+http://developer.android.com/reference/java/lang/NoSuchMethodError.html
+
+http://developer.android.com/reference/java/lang/OutOfMemoryError.html
+http://developer.android.com/reference/java/lang/StackOverflowError.html
+
+http://developer.android.com/reference/java/lang/ThreadDeath.html
+http://developer.android.com/reference/java/lang/UnknownError.html
+
+http://developer.android.com/reference/java/lang/UnsatisfiedLinkError.html
+http://developer.android.com/reference/java/lang/UnsupportedClassVersionError.html
+
+http://developer.android.com/reference/java/lang/VerifyError.html
+http://developer.android.com/reference/java/lang/VirtualMachineError.html
+
+http://developer.android.com/reference/java/nio/ByteBuffer.html
+http://developer.android.com/reference/java/util/Calendar.html
+
+http://developer.android.com/reference/java/nio/CharBuffer.html
+http://developer.android.com/reference/android/preference/CheckBoxPreference.html
+
+http://developer.android.com/reference/java/sql/Date.html
+http://developer.android.com/reference/android/preference/DialogPreference.html
+
+http://developer.android.com/reference/java/nio/DoubleBuffer.html
+http://developer.android.com/reference/android/preference/EditTextPreference.html
+
+http://developer.android.com/reference/java/lang/annotation/ElementType.html
+http://developer.android.com/reference/java/nio/FloatBuffer.html
+
+http://developer.android.com/reference/java/util/Formatter.BigDecimalLayoutForm.html
+http://developer.android.com/reference/java/util/GregorianCalendar.html
+
+http://developer.android.com/reference/java/nio/IntBuffer.html
+http://developer.android.com/reference/java/security/KeyRep.Type.html
+
+http://developer.android.com/reference/android/text/Layout.Alignment.html
+http://developer.android.com/reference/android/preference/ListPreference.html
+
+http://developer.android.com/reference/java/nio/LongBuffer.html
+http://developer.android.com/reference/com/google/android/maps/MapView.ReticleDrawMode.html
+
+http://developer.android.com/reference/java/nio/MappedByteBuffer.html
+http://developer.android.com/reference/java/io/ObjectStreamField.html
+
+http://developer.android.com/reference/android/preference/Preference.html
+http://developer.android.com/reference/android/preference/PreferenceCategory.html
+
+http://developer.android.com/reference/android/preference/PreferenceGroup.html
+http://developer.android.com/reference/android/preference/PreferenceScreen.html
+
+http://developer.android.com/reference/java/lang/annotation/RetentionPolicy.html
+http://developer.android.com/reference/android/preference/RingtonePreference.html
+
+http://developer.android.com/reference/org/apache/http/conn/routing/RouteInfo.LayerType.html
+http://developer.android.com/reference/org/apache/http/conn/routing/RouteInfo.TunnelType.html
+
+http://developer.android.com/reference/javax/net/ssl/SSLEngineResult.HandshakeStatus.html
+http://developer.android.com/reference/javax/net/ssl/SSLEngineResult.Status.html
+
+http://developer.android.com/reference/java/nio/ShortBuffer.html
+http://developer.android.com/reference/android/telephony/gsm/SmsMessage.MessageClass.html
+
+http://developer.android.com/reference/android/net/wifi/SupplicantState.html
+http://developer.android.com/reference/android/text/method/TextKeyListener.Capitalize.html
+
+http://developer.android.com/reference/java/sql/Time.html
+http://developer.android.com/reference/java/sql/Timestamp.html
+
+http://developer.android.com/reference/java/util/UUID.html
+http://developer.android.com/reference/android/view/ViewDebug.HierarchyTraceType.html
+
+http://developer.android.com/reference/android/view/ViewDebug.RecyclerTraceType.html
+http://developer.android.com/reference/android/util/Xml.Encoding.html
+
+http://developer.android.com/reference/org/apache/http/impl/auth/NTLMEngine.html
+http://developer.android.com/reference/org/apache/http/impl/auth/AuthSchemeBase.html
+
+http://developer.android.com/reference/org/apache/http/impl/auth/BasicScheme.html
+http://developer.android.com/reference/org/apache/http/impl/auth/BasicSchemeFactory.html
+
+http://developer.android.com/reference/org/apache/http/impl/auth/DigestScheme.html
+http://developer.android.com/reference/org/apache/http/impl/auth/DigestSchemeFactory.html
+
+http://developer.android.com/reference/org/apache/http/impl/auth/NTLMScheme.html
+http://developer.android.com/reference/org/apache/http/impl/auth/RFC2617Scheme.html
+
+http://developer.android.com/reference/org/apache/http/impl/auth/NTLMEngineException.html
+http://developer.android.com/reference/org/apache/http/impl/auth/UnsupportedDigestAlgorithmException.html
+
+http://developer.android.com/reference/android/preference/Preference.OnPreferenceChangeListener.html
+
+http://developer.android.com/reference/android/preference/Preference.OnPreferenceClickListener.html
+
+http://developer.android.com/reference/android/preference/PreferenceManager.OnActivityDestroyListener.html
+
+http://developer.android.com/reference/android/preference/PreferenceManager.OnActivityResultListener.html
+
+http://developer.android.com/reference/android/preference/PreferenceManager.OnActivityStopListener.html
+
+http://developer.android.com/reference/android/preference/Preference.BaseSavedState.html
+http://developer.android.com/reference/android/preference/PreferenceManager.html
+
+http://developer.android.com/reference/android/util/Printer.html
+http://developer.android.com/reference/android/util/Config.html
+
+http://developer.android.com/reference/android/util/DebugUtils.html
+http://developer.android.com/reference/android/util/DisplayMetrics.html
+
+http://developer.android.com/reference/android/util/EventLogTags.html
+http://developer.android.com/reference/android/util/EventLogTags.Description.html
+
+http://developer.android.com/reference/android/util/FloatMath.html
+http://developer.android.com/reference/android/util/LogPrinter.html
+
+http://developer.android.com/reference/android/util/MonthDisplayHelper.html
+http://developer.android.com/reference/android/util/PrintWriterPrinter.html
+
+http://developer.android.com/reference/android/util/SparseBooleanArray.html
+http://developer.android.com/reference/android/util/SparseIntArray.html
+
+http://developer.android.com/reference/android/util/StateSet.html
+http://developer.android.com/reference/android/util/StringBuilderPrinter.html
+
+http://developer.android.com/reference/android/util/TimeUtils.html
+http://developer.android.com/reference/android/util/TimingLogger.html
+
+http://developer.android.com/reference/android/util/TypedValue.html
+http://developer.android.com/reference/android/util/Xml.html
+
+http://developer.android.com/reference/android/util/AndroidException.html
+http://developer.android.com/reference/android/util/AndroidRuntimeException.html
+
+http://developer.android.com/reference/android/util/TimeFormatException.html
+http://developer.android.com/reference/android/content/res/XmlResourceParser.html
+
+http://developer.android.com/reference/javax/net/ssl/SSLSocketFactory.html
+http://developer.android.com/reference/javax/net/SocketFactory.html
+
+http://developer.android.com/reference/java/security/KeyManagementException.html
+http://developer.android.com/reference/org/apache/http/message/BasicHeader.html
+
+http://developer.android.com/reference/org/apache/http/message/BufferedHeader.html
+http://developer.android.com/reference/android/view/GestureDetector.OnGestureListener.html
+
+http://developer.android.com/reference/android/view/LayoutInflater.Filter.html
+http://developer.android.com/reference/android/view/MenuItem.OnMenuItemClickListener.html
+
+http://developer.android.com/reference/android/view/SurfaceHolder.html
+http://developer.android.com/reference/android/view/SurfaceHolder.Callback.html
+
+http://developer.android.com/reference/android/view/ViewStub.OnInflateListener.html
+http://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalFocusChangeListener.html
+
+http://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener.html
+
+http://developer.android.com/reference/android/view/ViewTreeObserver.OnTouchModeChangeListener.html
+
+http://developer.android.com/reference/android/view/AbsSavedState.html
+http://developer.android.com/reference/android/view/Display.html
+
+http://developer.android.com/reference/android/view/FocusFinder.html
+http://developer.android.com/reference/android/view/GestureDetector.html
+
+http://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener.html
+
+http://developer.android.com/reference/android/view/KeyCharacterMap.html
+http://developer.android.com/reference/android/view/KeyCharacterMap.KeyData.html
+
+http://developer.android.com/reference/android/view/OrientationListener.html
+http://developer.android.com/reference/android/view/SoundEffectConstants.html
+
+http://developer.android.com/reference/android/view/Surface.html
+http://developer.android.com/reference/android/view/VelocityTracker.html
+
+http://developer.android.com/reference/android/view/View.BaseSavedState.html
+http://developer.android.com/reference/android/view/ViewConfiguration.html
+
+http://developer.android.com/reference/android/view/ViewDebug.html
+http://developer.android.com/reference/android/view/ViewGroup.MarginLayoutParams.html
+
+http://developer.android.com/reference/android/view/ViewStub.html
+http://developer.android.com/reference/android/view/InflateException.html
+
+http://developer.android.com/reference/android/view/Surface.OutOfResourcesException.html
+http://developer.android.com/reference/android/view/SurfaceHolder.BadSurfaceTypeException.html
+
+http://developer.android.com/reference/android/view/WindowManager.BadTokenException.html
+http://developer.android.com/reference/org/apache/http/entity/AbstractHttpEntity.html
+
+http://developer.android.com/reference/org/apache/http/entity/BasicHttpEntity.html
+http://developer.android.com/reference/org/apache/http/entity/BufferedHttpEntity.html
+
+http://developer.android.com/reference/org/apache/http/entity/ByteArrayEntity.html
+http://developer.android.com/reference/org/apache/http/entity/EntityTemplate.html
+
+http://developer.android.com/reference/org/apache/http/entity/FileEntity.html
+http://developer.android.com/reference/org/apache/http/entity/HttpEntityWrapper.html
+
+http://developer.android.com/reference/org/apache/http/entity/InputStreamEntity.html
+http://developer.android.com/reference/org/apache/http/entity/SerializableEntity.html
+
+http://developer.android.com/reference/org/apache/http/entity/StringEntity.html
+http://developer.android.com/reference/org/apache/http/client/entity/UrlEncodedFormEntity.html
+
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicInteger.html
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicLong.html
+
+http://developer.android.com/reference/java/util/Collection.html
+http://developer.android.com/reference/java/util/Comparator.html
+
+http://developer.android.com/reference/java/util/Enumeration.html
+http://developer.android.com/reference/java/util/Formattable.html
+
+http://developer.android.com/reference/java/util/Iterator.html
+http://developer.android.com/reference/java/util/ListIterator.html
+
+http://developer.android.com/reference/java/util/Map.Entry.html
+http://developer.android.com/reference/java/util/Observer.html
+
+http://developer.android.com/reference/java/util/RandomAccess.html
+http://developer.android.com/reference/java/util/SortedMap.html
+
+http://developer.android.com/reference/java/util/SortedSet.html
+http://developer.android.com/reference/java/util/AbstractCollection.html
+
+http://developer.android.com/reference/java/util/AbstractList.html
+http://developer.android.com/reference/java/util/AbstractMap.html
+
+http://developer.android.com/reference/java/util/AbstractQueue.html
+http://developer.android.com/reference/java/util/AbstractSequentialList.html
+
+http://developer.android.com/reference/java/util/AbstractSet.html
+http://developer.android.com/reference/java/util/Arrays.html
+
+http://developer.android.com/reference/java/util/BitSet.html
+http://developer.android.com/reference/java/util/Collections.html
+
+http://developer.android.com/reference/java/util/Currency.html
+http://developer.android.com/reference/java/util/Dictionary.html
+
+http://developer.android.com/reference/java/util/EnumMap.html
+http://developer.android.com/reference/java/util/EnumSet.html
+
+http://developer.android.com/reference/java/util/EventListenerProxy.html
+http://developer.android.com/reference/java/util/EventObject.html
+
+http://developer.android.com/reference/java/util/FormattableFlags.html
+http://developer.android.com/reference/java/util/HashMap.html
+
+http://developer.android.com/reference/java/util/HashSet.html
+http://developer.android.com/reference/java/util/Hashtable.html
+
+http://developer.android.com/reference/java/util/IdentityHashMap.html
+http://developer.android.com/reference/java/util/LinkedHashMap.html
+
+http://developer.android.com/reference/java/util/LinkedHashSet.html
+http://developer.android.com/reference/java/util/LinkedList.html
+
+http://developer.android.com/reference/java/util/ListResourceBundle.html
+http://developer.android.com/reference/java/util/Observable.html
+
+http://developer.android.com/reference/java/util/PropertyPermission.html
+http://developer.android.com/reference/java/util/PropertyResourceBundle.html
+
+http://developer.android.com/reference/java/util/Random.html
+http://developer.android.com/reference/java/util/ResourceBundle.html
+
+http://developer.android.com/reference/java/util/Scanner.html
+http://developer.android.com/reference/java/util/SimpleTimeZone.html
+
+http://developer.android.com/reference/java/util/Stack.html
+http://developer.android.com/reference/java/util/StringTokenizer.html
+
+http://developer.android.com/reference/java/util/Timer.html
+http://developer.android.com/reference/java/util/TimerTask.html
+
+http://developer.android.com/reference/java/util/TimeZone.html
+http://developer.android.com/reference/java/util/TreeMap.html
+
+http://developer.android.com/reference/java/util/TreeSet.html
+http://developer.android.com/reference/java/util/Vector.html
+
+http://developer.android.com/reference/java/util/WeakHashMap.html
+http://developer.android.com/reference/java/util/ConcurrentModificationException.html
+
+http://developer.android.com/reference/java/util/DuplicateFormatFlagsException.html
+http://developer.android.com/reference/java/util/EmptyStackException.html
+
+http://developer.android.com/reference/java/util/FormatFlagsConversionMismatchException.html
+http://developer.android.com/reference/java/util/FormatterClosedException.html
+
+http://developer.android.com/reference/java/util/IllegalFormatCodePointException.html
+http://developer.android.com/reference/java/util/IllegalFormatConversionException.html
+
+http://developer.android.com/reference/java/util/IllegalFormatException.html
+http://developer.android.com/reference/java/util/IllegalFormatFlagsException.html
+
+http://developer.android.com/reference/java/util/IllegalFormatPrecisionException.html
+http://developer.android.com/reference/java/util/IllegalFormatWidthException.html
+
+http://developer.android.com/reference/java/util/InputMismatchException.html
+http://developer.android.com/reference/java/util/InvalidPropertiesFormatException.html
+
+http://developer.android.com/reference/java/util/MissingFormatArgumentException.html
+http://developer.android.com/reference/java/util/MissingFormatWidthException.html
+
+http://developer.android.com/reference/java/util/MissingResourceException.html
+http://developer.android.com/reference/java/util/NoSuchElementException.html
+
+http://developer.android.com/reference/java/util/TooManyListenersException.html
+http://developer.android.com/reference/java/util/UnknownFormatConversionException.html
+
+http://developer.android.com/reference/java/util/UnknownFormatFlagsException.html
+http://developer.android.com/reference/org/apache/http/impl/EnglishReasonPhraseCatalog.html
+
+http://developer.android.com/reference/org/apache/http/params/CoreConnectionPNames.html
+http://developer.android.com/reference/org/apache/http/params/CoreProtocolPNames.html
+
+http://developer.android.com/reference/org/apache/http/params/AbstractHttpParams.html
+http://developer.android.com/reference/org/apache/http/params/BasicHttpParams.html
+
+http://developer.android.com/reference/org/apache/http/params/DefaultedHttpParams.html
+http://developer.android.com/reference/org/apache/http/params/HttpAbstractParamBean.html
+
+http://developer.android.com/reference/org/apache/http/params/HttpConnectionParamBean.html
+http://developer.android.com/reference/org/apache/http/params/HttpConnectionParams.html
+
+http://developer.android.com/reference/org/apache/http/params/HttpProtocolParamBean.html
+http://developer.android.com/reference/org/apache/http/params/HttpProtocolParams.html
+
+http://developer.android.com/reference/org/apache/http/params/package-descr.html
+http://developer.android.com/reference/org/apache/http/io/SessionOutputBuffer.html
+
+http://developer.android.com/reference/org/apache/http/util/CharArrayBuffer.html
+http://developer.android.com/reference/android/content/res/AssetFileDescriptor.html
+
+http://developer.android.com/reference/android/content/res/AssetManager.AssetInputStream.html
+
+http://developer.android.com/reference/android/content/res/Resources.NotFoundException.html
+http://developer.android.com/reference/java/util/zip/ZipEntry.html
+
+http://developer.android.com/reference/java/security/cert/Certificate.html
+http://developer.android.com/reference/java/security/CodeSigner.html
+
+http://developer.android.com/reference/org/apache/http/auth/AuthSchemeFactory.html
+http://developer.android.com/reference/org/apache/http/auth/AuthScheme.html
+
+http://developer.android.com/reference/android/content/SharedPreferences.Editor.html
+http://developer.android.com/reference/android/media/RingtoneManager.html
+
+http://developer.android.com/reference/android/content/DialogInterface.html
+http://developer.android.com/reference/android/content/DialogInterface.OnClickListener.html
+
+http://developer.android.com/reference/android/content/DialogInterface.OnDismissListener.html
+
+http://developer.android.com/reference/org/apache/http/conn/routing/HttpRouteDirector.html
+http://developer.android.com/reference/org/apache/http/conn/routing/HttpRoutePlanner.html
+
+http://developer.android.com/reference/org/apache/http/conn/routing/RouteInfo.html
+http://developer.android.com/reference/org/apache/http/conn/routing/BasicRouteDirector.html
+
+http://developer.android.com/reference/org/apache/http/conn/routing/HttpRoute.html
+http://developer.android.com/reference/org/apache/http/conn/routing/RouteTracker.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/DefaultClientConnectionOperator.html
+
+http://developer.android.com/reference/org/apache/http/conn/scheme/SocketFactory.html
+http://developer.android.com/reference/java/nio/channels/Channel.html
+
+http://developer.android.com/reference/org/apache/http/message/LineParser.html
+http://developer.android.com/reference/org/apache/http/io/HttpMessageParser.html
+
+http://developer.android.com/reference/java/security/AuthProvider.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/BasicClientCookie.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/BasicClientCookie2.html
+http://developer.android.com/reference/org/apache/http/message/BasicHeaderElement.html
+
+http://developer.android.com/reference/org/apache/http/protocol/BasicHttpProcessor.html
+http://developer.android.com/reference/org/apache/http/message/BasicNameValuePair.html
+
+http://developer.android.com/reference/org/apache/http/message/BasicRequestLine.html
+http://developer.android.com/reference/org/apache/http/message/BasicStatusLine.html
+
+http://developer.android.com/reference/java/security/cert/CRLSelector.html
+http://developer.android.com/reference/java/security/cert/CertPathBuilderResult.html
+
+http://developer.android.com/reference/java/security/cert/CertPathParameters.html
+http://developer.android.com/reference/java/security/cert/CertPathValidatorResult.html
+
+http://developer.android.com/reference/java/security/cert/CertSelector.html
+http://developer.android.com/reference/java/security/cert/CertStoreParameters.html
+
+http://developer.android.com/reference/java/security/cert/CollectionCertStoreParameters.html
+http://developer.android.com/reference/org/apache/http/message/HeaderGroup.html
+
+http://developer.android.com/reference/org/apache/http/client/methods/HttpDelete.html
+http://developer.android.com/reference/org/apache/http/client/methods/HttpEntityEnclosingRequestBase.html
+
+http://developer.android.com/reference/org/apache/http/client/methods/HttpGet.html
+http://developer.android.com/reference/org/apache/http/client/methods/HttpHead.html
+
+http://developer.android.com/reference/org/apache/http/client/methods/HttpOptions.html
+http://developer.android.com/reference/org/apache/http/client/methods/HttpPost.html
+
+http://developer.android.com/reference/org/apache/http/client/methods/HttpPut.html
+http://developer.android.com/reference/org/apache/http/client/methods/HttpRequestBase.html
+
+http://developer.android.com/reference/org/apache/http/client/methods/HttpTrace.html
+http://developer.android.com/reference/java/security/cert/LDAPCertStoreParameters.html
+
+http://developer.android.com/reference/java/security/cert/PKIXBuilderParameters.html
+http://developer.android.com/reference/java/security/cert/PKIXCertPathBuilderResult.html
+
+http://developer.android.com/reference/java/security/cert/PKIXCertPathChecker.html
+http://developer.android.com/reference/java/security/cert/PKIXCertPathValidatorResult.html
+
+http://developer.android.com/reference/java/security/cert/PKIXParameters.html
+http://developer.android.com/reference/java/security/cert/X509CRLSelector.html
+
+http://developer.android.com/reference/java/security/cert/X509CertSelector.html
+http://developer.android.com/reference/android/text/Editable.html
+http://developer.android.com/reference/java/security/spec/AlgorithmParameterSpec.html
+
+http://developer.android.com/reference/java/security/SecureRandom.html
+http://developer.android.com/reference/javax/net/ssl/HandshakeCompletedListener.html
+
+http://developer.android.com/reference/javax/net/ssl/HostnameVerifier.html
+http://developer.android.com/reference/javax/net/ssl/KeyManager.html
+
+http://developer.android.com/reference/javax/net/ssl/ManagerFactoryParameters.html
+http://developer.android.com/reference/javax/net/ssl/SSLSession.html
+
+http://developer.android.com/reference/javax/net/ssl/SSLSessionBindingListener.html
+http://developer.android.com/reference/javax/net/ssl/SSLSessionContext.html
+
+http://developer.android.com/reference/javax/net/ssl/TrustManager.html
+http://developer.android.com/reference/javax/net/ssl/X509KeyManager.html
+
+http://developer.android.com/reference/javax/net/ssl/X509TrustManager.html
+http://developer.android.com/reference/javax/net/ssl/CertPathTrustManagerParameters.html
+
+http://developer.android.com/reference/javax/net/ssl/HandshakeCompletedEvent.html
+http://developer.android.com/reference/javax/net/ssl/HttpsURLConnection.html
+
+http://developer.android.com/reference/javax/net/ssl/KeyManagerFactory.html
+http://developer.android.com/reference/javax/net/ssl/KeyManagerFactorySpi.html
+
+http://developer.android.com/reference/javax/net/ssl/KeyStoreBuilderParameters.html
+http://developer.android.com/reference/javax/net/ssl/SSLContext.html
+
+http://developer.android.com/reference/javax/net/ssl/SSLContextSpi.html
+http://developer.android.com/reference/javax/net/ssl/SSLEngine.html
+
+http://developer.android.com/reference/javax/net/ssl/SSLEngineResult.html
+http://developer.android.com/reference/javax/net/ssl/SSLPermission.html
+
+http://developer.android.com/reference/javax/net/ssl/SSLServerSocket.html
+http://developer.android.com/reference/javax/net/ssl/SSLServerSocketFactory.html
+
+http://developer.android.com/reference/javax/net/ssl/SSLSessionBindingEvent.html
+http://developer.android.com/reference/javax/net/ssl/SSLSocket.html
+
+http://developer.android.com/reference/javax/net/ssl/TrustManagerFactory.html
+http://developer.android.com/reference/javax/net/ssl/TrustManagerFactorySpi.html
+
+http://developer.android.com/reference/javax/net/ssl/X509ExtendedKeyManager.html
+http://developer.android.com/reference/javax/net/ssl/SSLException.html
+
+http://developer.android.com/reference/javax/net/ssl/SSLHandshakeException.html
+http://developer.android.com/reference/javax/net/ssl/SSLKeyException.html
+
+http://developer.android.com/reference/javax/net/ssl/SSLPeerUnverifiedException.html
+http://developer.android.com/reference/javax/net/ssl/SSLProtocolException.html
+
+http://developer.android.com/reference/javax/crypto/spec/DESedeKeySpec.html
+http://developer.android.com/reference/javax/crypto/spec/DESKeySpec.html
+
+http://developer.android.com/reference/javax/crypto/spec/DHGenParameterSpec.html
+http://developer.android.com/reference/javax/crypto/spec/DHParameterSpec.html
+
+http://developer.android.com/reference/javax/crypto/spec/DHPrivateKeySpec.html
+http://developer.android.com/reference/javax/crypto/spec/DHPublicKeySpec.html
+
+http://developer.android.com/reference/javax/crypto/spec/IvParameterSpec.html
+http://developer.android.com/reference/javax/crypto/spec/OAEPParameterSpec.html
+
+http://developer.android.com/reference/javax/crypto/spec/PBEKeySpec.html
+http://developer.android.com/reference/javax/crypto/spec/PBEParameterSpec.html
+
+http://developer.android.com/reference/javax/crypto/spec/PSource.html
+http://developer.android.com/reference/javax/crypto/spec/PSource.PSpecified.html
+
+http://developer.android.com/reference/javax/crypto/spec/RC2ParameterSpec.html
+http://developer.android.com/reference/javax/crypto/spec/RC5ParameterSpec.html
+
+http://developer.android.com/reference/javax/crypto/spec/SecretKeySpec.html
+http://developer.android.com/reference/javax/crypto/spec/package-descr.html
+
+http://developer.android.com/reference/android/text/method/ArrowKeyMovementMethod.html
+http://developer.android.com/reference/android/text/method/BaseKeyListener.html
+
+http://developer.android.com/reference/android/text/method/CharacterPickerDialog.html
+http://developer.android.com/reference/android/text/method/DateKeyListener.html
+
+http://developer.android.com/reference/android/text/method/DateTimeKeyListener.html
+http://developer.android.com/reference/android/text/method/DialerKeyListener.html
+
+http://developer.android.com/reference/android/text/method/DigitsKeyListener.html
+http://developer.android.com/reference/android/text/method/HideReturnsTransformationMethod.html
+
+http://developer.android.com/reference/android/text/method/MetaKeyKeyListener.html
+http://developer.android.com/reference/android/text/method/MultiTapKeyListener.html
+
+http://developer.android.com/reference/android/text/method/NumberKeyListener.html
+http://developer.android.com/reference/android/text/method/PasswordTransformationMethod.html
+
+http://developer.android.com/reference/android/text/method/QwertyKeyListener.html
+http://developer.android.com/reference/android/text/method/ReplacementTransformationMethod.html
+
+http://developer.android.com/reference/android/text/method/ScrollingMovementMethod.html
+http://developer.android.com/reference/android/text/method/SingleLineTransformationMethod.html
+
+http://developer.android.com/reference/android/text/method/TextKeyListener.html
+http://developer.android.com/reference/android/text/method/TimeKeyListener.html
+
+http://developer.android.com/reference/android/text/method/Touch.html
+http://developer.android.com/reference/android/location/Address.html
+
+http://developer.android.com/reference/android/content/pm/ApplicationInfo.html
+http://developer.android.com/reference/android/location/Criteria.html
+
+http://developer.android.com/reference/android/content/pm/InstrumentationInfo.html
+http://developer.android.com/reference/android/content/Intent.ShortcutIconResource.html
+
+http://developer.android.com/reference/android/location/Location.html
+http://developer.android.com/reference/android/content/pm/PackageInfo.html
+
+http://developer.android.com/reference/android/content/pm/PackageStats.html
+http://developer.android.com/reference/android/content/pm/PermissionGroupInfo.html
+
+http://developer.android.com/reference/android/content/pm/PermissionInfo.html
+http://developer.android.com/reference/android/content/pm/ProviderInfo.html
+
+http://developer.android.com/reference/android/content/pm/ResolveInfo.html
+http://developer.android.com/reference/android/net/wifi/ScanResult.html
+
+http://developer.android.com/reference/android/content/pm/ServiceInfo.html
+http://developer.android.com/reference/android/content/pm/Signature.html
+
+http://developer.android.com/reference/android/net/wifi/WifiConfiguration.html
+http://developer.android.com/reference/android/net/wifi/WifiInfo.html
+
+http://developer.android.com/reference/java/io/FileDescriptor.html
+http://developer.android.com/reference/java/security/SecureClassLoader.html
+
+http://developer.android.com/reference/java/security/ProtectionDomain.html
+http://developer.android.com/reference/java/io/Closeable.html
+
+http://developer.android.com/reference/java/io/DataInput.html
+http://developer.android.com/reference/java/io/DataOutput.html
+
+http://developer.android.com/reference/java/io/Externalizable.html
+http://developer.android.com/reference/java/io/FileFilter.html
+
+http://developer.android.com/reference/java/io/FilenameFilter.html
+http://developer.android.com/reference/java/io/Flushable.html
+
+http://developer.android.com/reference/java/io/ObjectInput.html
+http://developer.android.com/reference/java/io/ObjectInputValidation.html
+
+http://developer.android.com/reference/java/io/ObjectOutput.html
+http://developer.android.com/reference/java/io/ObjectStreamConstants.html
+
+http://developer.android.com/reference/java/io/BufferedInputStream.html
+http://developer.android.com/reference/java/io/BufferedOutputStream.html
+
+http://developer.android.com/reference/java/io/BufferedReader.html
+http://developer.android.com/reference/java/io/BufferedWriter.html
+
+http://developer.android.com/reference/java/io/ByteArrayInputStream.html
+http://developer.android.com/reference/java/io/ByteArrayOutputStream.html
+
+http://developer.android.com/reference/java/io/CharArrayReader.html
+http://developer.android.com/reference/java/io/CharArrayWriter.html
+
+http://developer.android.com/reference/java/io/DataInputStream.html
+http://developer.android.com/reference/java/io/DataOutputStream.html
+
+http://developer.android.com/reference/java/io/FilePermission.html
+http://developer.android.com/reference/java/io/FileReader.html
+
+http://developer.android.com/reference/java/io/FileWriter.html
+http://developer.android.com/reference/java/io/FilterInputStream.html
+
+http://developer.android.com/reference/java/io/FilterOutputStream.html
+http://developer.android.com/reference/java/io/FilterReader.html
+
+http://developer.android.com/reference/java/io/FilterWriter.html
+http://developer.android.com/reference/java/io/InputStreamReader.html
+
+http://developer.android.com/reference/java/io/LineNumberInputStream.html
+http://developer.android.com/reference/java/io/LineNumberReader.html
+
+http://developer.android.com/reference/java/io/ObjectInputStream.html
+http://developer.android.com/reference/java/io/ObjectInputStream.GetField.html
+
+http://developer.android.com/reference/java/io/ObjectOutputStream.html
+http://developer.android.com/reference/java/io/ObjectOutputStream.PutField.html
+
+http://developer.android.com/reference/java/io/ObjectStreamClass.html
+http://developer.android.com/reference/java/io/OutputStreamWriter.html
+
+http://developer.android.com/reference/java/io/PipedInputStream.html
+http://developer.android.com/reference/java/io/PipedOutputStream.html
+
+http://developer.android.com/reference/java/io/PipedReader.html
+http://developer.android.com/reference/java/io/PipedWriter.html
+
+http://developer.android.com/reference/java/io/PushbackInputStream.html
+http://developer.android.com/reference/java/io/PushbackReader.html
+
+http://developer.android.com/reference/java/io/RandomAccessFile.html
+http://developer.android.com/reference/java/io/Reader.html
+
+http://developer.android.com/reference/java/io/SequenceInputStream.html
+http://developer.android.com/reference/java/io/SerializablePermission.html
+
+http://developer.android.com/reference/java/io/StreamTokenizer.html
+http://developer.android.com/reference/java/io/StringBufferInputStream.html
+
+http://developer.android.com/reference/java/io/StringReader.html
+http://developer.android.com/reference/java/io/StringWriter.html
+
+http://developer.android.com/reference/java/io/Writer.html
+http://developer.android.com/reference/java/io/CharConversionException.html
+
+http://developer.android.com/reference/java/io/EOFException.html
+http://developer.android.com/reference/java/io/FileNotFoundException.html
+
+http://developer.android.com/reference/java/io/InterruptedIOException.html
+http://developer.android.com/reference/java/io/InvalidClassException.html
+
+http://developer.android.com/reference/java/io/InvalidObjectException.html
+http://developer.android.com/reference/java/io/NotActiveException.html
+
+http://developer.android.com/reference/java/io/NotSerializableException.html
+http://developer.android.com/reference/java/io/ObjectStreamException.html
+
+http://developer.android.com/reference/java/io/OptionalDataException.html
+http://developer.android.com/reference/java/io/StreamCorruptedException.html
+
+http://developer.android.com/reference/java/io/SyncFailedException.html
+http://developer.android.com/reference/java/io/UnsupportedEncodingException.html
+
+http://developer.android.com/reference/java/io/UTFDataFormatException.html
+http://developer.android.com/reference/java/io/WriteAbortedException.html
+
+http://developer.android.com/reference/org/apache/http/entity/ContentLengthStrategy.html
+http://developer.android.com/reference/org/apache/http/entity/ContentProducer.html
+
+http://developer.android.com/reference/java/security/Certificate.html
+http://developer.android.com/reference/java/security/DomainCombiner.html
+
+http://developer.android.com/reference/java/security/KeyStore.Entry.html
+http://developer.android.com/reference/java/security/KeyStore.LoadStoreParameter.html
+
+http://developer.android.com/reference/java/security/KeyStore.ProtectionParameter.html
+http://developer.android.com/reference/java/security/Principal.html
+
+http://developer.android.com/reference/java/security/PrivateKey.html
+http://developer.android.com/reference/java/security/PrivilegedAction.html
+
+http://developer.android.com/reference/java/security/PrivilegedExceptionAction.html
+http://developer.android.com/reference/java/security/PublicKey.html
+
+http://developer.android.com/reference/java/security/AccessControlContext.html
+http://developer.android.com/reference/java/security/AccessController.html
+
+http://developer.android.com/reference/java/security/AlgorithmParameterGenerator.html
+http://developer.android.com/reference/java/security/AlgorithmParameterGeneratorSpi.html
+
+http://developer.android.com/reference/java/security/AlgorithmParametersSpi.html
+http://developer.android.com/reference/java/security/AllPermission.html
+
+http://developer.android.com/reference/java/security/CodeSource.html
+http://developer.android.com/reference/java/security/DigestInputStream.html
+
+http://developer.android.com/reference/java/security/DigestOutputStream.html
+http://developer.android.com/reference/java/security/GuardedObject.html
+
+http://developer.android.com/reference/java/security/Identity.html
+http://developer.android.com/reference/java/security/IdentityScope.html
+
+http://developer.android.com/reference/java/security/KeyFactory.html
+http://developer.android.com/reference/java/security/KeyFactorySpi.html
+
+http://developer.android.com/reference/java/security/KeyPair.html
+http://developer.android.com/reference/java/security/KeyPairGenerator.html
+
+http://developer.android.com/reference/java/security/KeyPairGeneratorSpi.html
+http://developer.android.com/reference/java/security/KeyRep.html
+
+http://developer.android.com/reference/java/security/KeyStore.html
+http://developer.android.com/reference/java/security/KeyStore.Builder.html
+
+http://developer.android.com/reference/java/security/KeyStore.CallbackHandlerProtection.html
+http://developer.android.com/reference/java/security/KeyStore.PasswordProtection.html
+
+http://developer.android.com/reference/java/security/KeyStore.PrivateKeyEntry.html
+http://developer.android.com/reference/java/security/KeyStore.SecretKeyEntry.html
+
+http://developer.android.com/reference/java/security/KeyStore.TrustedCertificateEntry.html
+http://developer.android.com/reference/java/security/KeyStoreSpi.html
+
+http://developer.android.com/reference/java/security/MessageDigest.html
+http://developer.android.com/reference/java/security/MessageDigestSpi.html
+
+http://developer.android.com/reference/java/security/Permissions.html
+http://developer.android.com/reference/java/security/Policy.html
+
+http://developer.android.com/reference/java/security/Provider.Service.html
+http://developer.android.com/reference/java/security/SecureRandomSpi.html
+
+http://developer.android.com/reference/java/security/Security.html
+http://developer.android.com/reference/java/security/SecurityPermission.html
+
+http://developer.android.com/reference/java/security/Signature.html
+http://developer.android.com/reference/java/security/SignatureSpi.html
+
+http://developer.android.com/reference/java/security/SignedObject.html
+http://developer.android.com/reference/java/security/Signer.html
+
+http://developer.android.com/reference/java/security/Timestamp.html
+http://developer.android.com/reference/java/security/UnresolvedPermission.html
+
+http://developer.android.com/reference/java/security/AccessControlException.html
+http://developer.android.com/reference/java/security/DigestException.html
+
+http://developer.android.com/reference/java/security/GeneralSecurityException.html
+http://developer.android.com/reference/java/security/InvalidAlgorithmParameterException.html
+
+http://developer.android.com/reference/java/security/InvalidParameterException.html
+http://developer.android.com/reference/java/security/KeyException.html
+
+http://developer.android.com/reference/java/security/KeyStoreException.html
+http://developer.android.com/reference/java/security/PrivilegedActionException.html
+
+http://developer.android.com/reference/java/security/ProviderException.html
+http://developer.android.com/reference/java/security/SignatureException.html
+
+http://developer.android.com/reference/java/security/UnrecoverableEntryException.html
+http://developer.android.com/reference/java/security/UnrecoverableKeyException.html
+
+http://developer.android.com/reference/java/nio/Buffer.html
+http://developer.android.com/reference/java/nio/ByteOrder.html
+
+http://developer.android.com/reference/java/nio/BufferOverflowException.html
+http://developer.android.com/reference/java/nio/BufferUnderflowException.html
+
+http://developer.android.com/reference/java/nio/InvalidMarkException.html
+http://developer.android.com/reference/java/nio/ReadOnlyBufferException.html
+
+http://developer.android.com/reference/org/apache/http/client/methods/AbortableHttpRequest.html
+
+http://developer.android.com/reference/org/apache/http/client/methods/HttpUriRequest.html
+http://developer.android.com/reference/org/apache/http/conn/package-descr.html
+
+http://developer.android.com/reference/java/security/cert/PolicyNode.html
+http://developer.android.com/reference/java/security/cert/X509Extension.html
+
+http://developer.android.com/reference/java/security/cert/Certificate.CertificateRep.html
+http://developer.android.com/reference/java/security/cert/CertificateFactory.html
+
+http://developer.android.com/reference/java/security/cert/CertificateFactorySpi.html
+http://developer.android.com/reference/java/security/cert/CertPath.html
+
+http://developer.android.com/reference/java/security/cert/CertPath.CertPathRep.html
+http://developer.android.com/reference/java/security/cert/CertPathBuilder.html
+
+http://developer.android.com/reference/java/security/cert/CertPathBuilderSpi.html
+http://developer.android.com/reference/java/security/cert/CertPathValidator.html
+
+http://developer.android.com/reference/java/security/cert/CertPathValidatorSpi.html
+http://developer.android.com/reference/java/security/cert/CertStore.html
+
+http://developer.android.com/reference/java/security/cert/CertStoreSpi.html
+http://developer.android.com/reference/java/security/cert/CRL.html
+
+http://developer.android.com/reference/java/security/cert/PolicyQualifierInfo.html
+http://developer.android.com/reference/java/security/cert/TrustAnchor.html
+
+http://developer.android.com/reference/java/security/cert/X509Certificate.html
+http://developer.android.com/reference/java/security/cert/X509CRL.html
+
+http://developer.android.com/reference/java/security/cert/X509CRLEntry.html
+http://developer.android.com/reference/java/security/cert/CertificateEncodingException.html
+
+http://developer.android.com/reference/java/security/cert/CertificateException.html
+http://developer.android.com/reference/java/security/cert/CertificateExpiredException.html
+
+http://developer.android.com/reference/java/security/cert/CertificateNotYetValidException.html
+
+http://developer.android.com/reference/java/security/cert/CertificateParsingException.html
+http://developer.android.com/reference/java/security/cert/CertPathBuilderException.html
+
+http://developer.android.com/reference/java/security/cert/CertPathValidatorException.html
+http://developer.android.com/reference/java/security/cert/CertStoreException.html
+
+http://developer.android.com/reference/java/security/cert/CRLException.html
+http://developer.android.com/reference/com/google/android/maps/ItemizedOverlay.OnFocusChangeListener.html
+
+http://developer.android.com/reference/com/google/android/maps/Projection.html
+http://developer.android.com/reference/com/google/android/maps/GeoPoint.html
+
+http://developer.android.com/reference/com/google/android/maps/OverlayItem.html
+http://developer.android.com/reference/com/google/android/maps/MapView.LayoutParams.html
+
+http://developer.android.com/reference/com/google/android/maps/MyLocationOverlay.html
+http://developer.android.com/reference/com/google/android/maps/TrackballGestureDetector.html
+
+http://developer.android.com/reference/java/sql/Array.html
+http://developer.android.com/reference/java/sql/Blob.html
+
+http://developer.android.com/reference/java/sql/CallableStatement.html
+http://developer.android.com/reference/java/sql/Clob.html
+
+http://developer.android.com/reference/java/sql/Connection.html
+http://developer.android.com/reference/java/sql/DatabaseMetaData.html
+
+http://developer.android.com/reference/java/sql/Driver.html
+http://developer.android.com/reference/java/sql/ParameterMetaData.html
+
+http://developer.android.com/reference/java/sql/PreparedStatement.html
+http://developer.android.com/reference/java/sql/Ref.html
+
+http://developer.android.com/reference/java/sql/ResultSet.html
+http://developer.android.com/reference/java/sql/ResultSetMetaData.html
+
+http://developer.android.com/reference/java/sql/Savepoint.html
+http://developer.android.com/reference/java/sql/SQLData.html
+
+http://developer.android.com/reference/java/sql/SQLInput.html
+http://developer.android.com/reference/java/sql/SQLOutput.html
+
+http://developer.android.com/reference/java/sql/Statement.html
+http://developer.android.com/reference/java/sql/Struct.html
+
+http://developer.android.com/reference/java/sql/DriverManager.html
+http://developer.android.com/reference/java/sql/DriverPropertyInfo.html
+
+http://developer.android.com/reference/java/sql/SQLPermission.html
+http://developer.android.com/reference/java/sql/Types.html
+
+http://developer.android.com/reference/java/sql/BatchUpdateException.html
+http://developer.android.com/reference/java/sql/DataTruncation.html
+
+http://developer.android.com/reference/java/sql/SQLException.html
+http://developer.android.com/reference/java/sql/SQLWarning.html
+
+http://developer.android.com/reference/org/apache/http/message/BasicTokenIterator.html
+http://developer.android.com/reference/java/security/package-descr.html
+
+http://developer.android.com/reference/java/security/spec/KeySpec.html
+http://developer.android.com/reference/android/text/GetChars.html
+
+http://developer.android.com/reference/android/text/Html.ImageGetter.html
+http://developer.android.com/reference/android/text/Html.TagHandler.html
+
+http://developer.android.com/reference/android/text/Spanned.html
+http://developer.android.com/reference/android/text/SpanWatcher.html
+
+http://developer.android.com/reference/android/text/TextUtils.EllipsizeCallback.html
+http://developer.android.com/reference/android/text/TextUtils.StringSplitter.html
+
+http://developer.android.com/reference/android/text/AlteredCharSequence.html
+http://developer.android.com/reference/android/text/AndroidCharacter.html
+
+http://developer.android.com/reference/android/text/Annotation.html
+http://developer.android.com/reference/android/text/AutoText.html
+
+http://developer.android.com/reference/android/text/BoringLayout.html
+http://developer.android.com/reference/android/text/BoringLayout.Metrics.html
+
+http://developer.android.com/reference/android/text/DynamicLayout.html
+http://developer.android.com/reference/android/text/Html.html
+
+http://developer.android.com/reference/android/text/InputFilter.AllCaps.html
+http://developer.android.com/reference/android/text/InputFilter.LengthFilter.html
+
+http://developer.android.com/reference/android/text/Layout.Directions.html
+http://developer.android.com/reference/android/text/LoginFilter.html
+
+http://developer.android.com/reference/android/text/LoginFilter.PasswordFilterGMail.html
+http://developer.android.com/reference/android/text/LoginFilter.UsernameFilterGeneric.html
+
+http://developer.android.com/reference/android/text/LoginFilter.UsernameFilterGMail.html
+http://developer.android.com/reference/android/text/SpannableString.html
+
+http://developer.android.com/reference/android/text/SpannableStringBuilder.html
+http://developer.android.com/reference/android/text/SpannedString.html
+
+http://developer.android.com/reference/android/text/StaticLayout.html
+http://developer.android.com/reference/android/text/TextUtils.html
+
+http://developer.android.com/reference/android/text/TextUtils.SimpleStringSplitter.html
+http://developer.android.com/reference/javax/security/auth/Subject.html
+
+http://developer.android.com/reference/javax/security/auth/callback/CallbackHandler.html
+http://developer.android.com/reference/javax/security/auth/login/LoginException.html
+
+http://developer.android.com/reference/java/nio/package-descr.html
+
+http://developer.android.com/reference/java/util/zip/ZipFile.html
+http://developer.android.com/reference/android/widget/RemoteViews.RemoteView.html
+
+http://developer.android.com/reference/javax/security/auth/Destroyable.html
+http://developer.android.com/reference/javax/security/auth/AuthPermission.html
+
+http://developer.android.com/reference/javax/security/auth/PrivateCredentialPermission.html
+http://developer.android.com/reference/javax/security/auth/SubjectDomainCombiner.html
+
+http://developer.android.com/reference/javax/security/auth/DestroyFailedException.html
+http://developer.android.com/reference/javax/security/auth/package-descr.html
+
+http://developer.android.com/guide/tutorials/views/hello-linearlayout.html
+http://developer.android.com/guide/tutorials/views/hello-tablelayout.html
+
+http://developer.android.com/guide/tutorials/views/hello-relativelayout.html
+http://developer.android.com/reference/android/view/ViewDebug.ExportedProperty.html
+
+http://developer.android.com/reference/android/view/ViewDebug.IntToString.html
+http://developer.android.com/reference/android/content/DialogInterface.OnCancelListener.html
+
+http://developer.android.com/reference/android/content/DialogInterface.OnKeyListener.html
+http://developer.android.com/reference/android/content/DialogInterface.OnMultiChoiceClickListener.html
+
+http://developer.android.com/reference/android/content/SharedPreferences.OnSharedPreferenceChangeListener.html
+
+http://developer.android.com/reference/android/content/AsyncQueryHandler.html
+http://developer.android.com/reference/android/content/AsyncQueryHandler.WorkerArgs.html
+
+http://developer.android.com/reference/android/content/AsyncQueryHandler.WorkerHandler.html
+http://developer.android.com/reference/android/content/ContentQueryMap.html
+
+http://developer.android.com/reference/android/content/ContentUris.html
+http://developer.android.com/reference/android/content/Intent.FilterComparison.html
+
+http://developer.android.com/reference/android/content/IntentFilter.AuthorityEntry.html
+http://developer.android.com/reference/android/content/MutableContextWrapper.html
+
+http://developer.android.com/reference/android/content/UriMatcher.html
+http://developer.android.com/reference/android/content/ActivityNotFoundException.html
+
+http://developer.android.com/reference/android/content/IntentFilter.MalformedMimeTypeException.html
+
+http://developer.android.com/reference/android/content/ReceiverCallNotAllowedException.html
+http://developer.android.com/reference/android/test/mock/MockContext.html
+
+http://developer.android.com/reference/android/test/mock/MockApplication.html
+http://developer.android.com/reference/android/content/pm/PackageManager.NameNotFoundException.html
+
+http://developer.android.com/reference/org/xml/sax/ContentHandler.html
+http://developer.android.com/reference/org/xml/sax/DocumentHandler.html
+
+http://developer.android.com/reference/org/xml/sax/DTDHandler.html
+http://developer.android.com/reference/org/xml/sax/EntityResolver.html
+
+http://developer.android.com/reference/org/xml/sax/ErrorHandler.html
+http://developer.android.com/reference/org/xml/sax/XMLFilter.html
+
+http://developer.android.com/reference/org/xml/sax/XMLReader.html
+http://developer.android.com/reference/org/xml/sax/HandlerBase.html
+
+http://developer.android.com/reference/org/xml/sax/InputSource.html
+http://developer.android.com/reference/org/xml/sax/SAXException.html
+
+http://developer.android.com/reference/org/xml/sax/SAXNotRecognizedException.html
+http://developer.android.com/reference/org/xml/sax/SAXNotSupportedException.html
+
+http://developer.android.com/reference/org/xml/sax/SAXParseException.html
+http://developer.android.com/reference/org/xml/sax/package-descr.html
+
+http://developer.android.com/reference/javax/sql/RowSet.html
+http://developer.android.com/reference/android/content/pm/IPackageInstallObserver.html
+
+http://developer.android.com/reference/android/content/pm/ApplicationInfo.DisplayNameComparator.html
+
+http://developer.android.com/reference/android/content/pm/ComponentInfo.html
+http://developer.android.com/reference/android/content/pm/IPackageInstallObserver.Stub.html
+
+http://developer.android.com/reference/android/content/pm/PackageItemInfo.DisplayNameComparator.html
+
+http://developer.android.com/reference/android/content/pm/ResolveInfo.DisplayNameComparator.html
+
+http://developer.android.com/guide/samples/NotePad/res/index.html
+http://developer.android.com/guide/samples/NotePad/src/index.html
+
+http://developer.android.com/guide/samples/NotePad/tests/index.html
+http://developer.android.com/guide/samples/NotePad/AndroidManifest.html
+
+http://developer.android.com/guide/samples/NotePad/sample_note.html
+http://developer.android.com/guide/samples/NotePad/sample_notepad.html
+
+http://developer.android.com/reference/android/telephony/gsm/GsmCellLocation.html
+
+http://developer.android.com/reference/java/nio/channels/ServerSocketChannel.html
+http://developer.android.com/reference/javax/xml/XMLConstants.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/DefaultResponseParser.html
+http://developer.android.com/reference/java/nio/channels/ByteChannel.html
+
+http://developer.android.com/reference/java/nio/channels/GatheringByteChannel.html
+http://developer.android.com/reference/java/nio/channels/InterruptibleChannel.html
+
+http://developer.android.com/reference/java/nio/channels/ReadableByteChannel.html
+http://developer.android.com/reference/java/nio/channels/ScatteringByteChannel.html
+
+http://developer.android.com/reference/java/nio/channels/WritableByteChannel.html
+http://developer.android.com/reference/java/nio/channels/Channels.html
+
+http://developer.android.com/reference/java/nio/channels/FileChannel.html
+http://developer.android.com/reference/java/nio/channels/FileChannel.MapMode.html
+
+http://developer.android.com/reference/java/nio/channels/FileLock.html
+http://developer.android.com/reference/java/nio/channels/Pipe.html
+
+http://developer.android.com/reference/java/nio/channels/Pipe.SinkChannel.html
+http://developer.android.com/reference/java/nio/channels/Pipe.SourceChannel.html
+
+http://developer.android.com/reference/java/nio/channels/SelectableChannel.html
+http://developer.android.com/reference/java/nio/channels/SelectionKey.html
+
+http://developer.android.com/reference/java/nio/channels/Selector.html
+http://developer.android.com/reference/java/nio/channels/SocketChannel.html
+
+http://developer.android.com/reference/java/nio/channels/AlreadyConnectedException.html
+http://developer.android.com/reference/java/nio/channels/AsynchronousCloseException.html
+
+http://developer.android.com/reference/java/nio/channels/CancelledKeyException.html
+http://developer.android.com/reference/java/nio/channels/ClosedByInterruptException.html
+
+http://developer.android.com/reference/java/nio/channels/ClosedChannelException.html
+http://developer.android.com/reference/java/nio/channels/ClosedSelectorException.html
+
+http://developer.android.com/reference/java/nio/channels/ConnectionPendingException.html
+http://developer.android.com/reference/java/nio/channels/FileLockInterruptionException.html
+
+http://developer.android.com/reference/java/nio/channels/IllegalBlockingModeException.html
+http://developer.android.com/reference/java/nio/channels/IllegalSelectorException.html
+
+http://developer.android.com/reference/java/nio/channels/NoConnectionPendingException.html
+http://developer.android.com/reference/java/nio/channels/NonReadableChannelException.html
+
+http://developer.android.com/reference/java/nio/channels/NonWritableChannelException.html
+http://developer.android.com/reference/java/nio/channels/NotYetBoundException.html
+
+http://developer.android.com/reference/java/nio/channels/NotYetConnectedException.html
+http://developer.android.com/reference/java/nio/channels/OverlappingFileLockException.html
+
+http://developer.android.com/reference/java/nio/channels/UnresolvedAddressException.html
+http://developer.android.com/reference/java/nio/channels/UnsupportedAddressTypeException.html
+
+http://developer.android.com/reference/org/apache/http/message/BasicHeaderIterator.html
+http://developer.android.com/reference/org/apache/http/message/BasicListHeaderIterator.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/AbstractClientConnAdapter.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/AbstractPooledConnAdapter.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/AbstractPoolEntry.html
+http://developer.android.com/reference/org/apache/http/impl/conn/DefaultClientConnection.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/DefaultHttpRoutePlanner.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/IdleConnectionHandler.html
+http://developer.android.com/reference/org/apache/http/impl/conn/LoggingSessionInputBuffer.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/LoggingSessionOutputBuffer.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/ProxySelectorRoutePlanner.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/SingleClientConnManager.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/SingleClientConnManager.ConnAdapter.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/SingleClientConnManager.PoolEntry.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/Wire.html
+http://developer.android.com/reference/java/security/spec/ECField.html
+
+http://developer.android.com/reference/java/security/spec/DSAParameterSpec.html
+http://developer.android.com/reference/java/security/spec/DSAPrivateKeySpec.html
+
+http://developer.android.com/reference/java/security/spec/DSAPublicKeySpec.html
+http://developer.android.com/reference/java/security/spec/ECFieldF2m.html
+
+http://developer.android.com/reference/java/security/spec/ECFieldFp.html
+http://developer.android.com/reference/java/security/spec/ECGenParameterSpec.html
+
+http://developer.android.com/reference/java/security/spec/ECParameterSpec.html
+http://developer.android.com/reference/java/security/spec/ECPoint.html
+
+http://developer.android.com/reference/java/security/spec/ECPrivateKeySpec.html
+http://developer.android.com/reference/java/security/spec/ECPublicKeySpec.html
+
+http://developer.android.com/reference/java/security/spec/EllipticCurve.html
+http://developer.android.com/reference/java/security/spec/EncodedKeySpec.html
+
+http://developer.android.com/reference/java/security/spec/MGF1ParameterSpec.html
+http://developer.android.com/reference/java/security/spec/PSSParameterSpec.html
+
+http://developer.android.com/reference/java/security/spec/RSAKeyGenParameterSpec.html
+http://developer.android.com/reference/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.html
+
+http://developer.android.com/reference/java/security/spec/RSAOtherPrimeInfo.html
+http://developer.android.com/reference/java/security/spec/RSAPrivateCrtKeySpec.html
+
+http://developer.android.com/reference/java/security/spec/RSAPrivateKeySpec.html
+http://developer.android.com/reference/java/security/spec/RSAPublicKeySpec.html
+
+http://developer.android.com/reference/java/security/spec/X509EncodedKeySpec.html
+http://developer.android.com/reference/java/security/spec/InvalidParameterSpecException.html
+
+http://developer.android.com/reference/org/apache/http/auth/Credentials.html
+http://developer.android.com/reference/org/apache/http/auth/AUTH.html
+
+http://developer.android.com/reference/org/apache/http/auth/AuthSchemeRegistry.html
+http://developer.android.com/reference/org/apache/http/auth/AuthScope.html
+
+http://developer.android.com/reference/org/apache/http/auth/AuthState.html
+http://developer.android.com/reference/org/apache/http/auth/BasicUserPrincipal.html
+
+http://developer.android.com/reference/org/apache/http/auth/NTCredentials.html
+http://developer.android.com/reference/org/apache/http/auth/NTUserPrincipal.html
+
+http://developer.android.com/reference/org/apache/http/auth/UsernamePasswordCredentials.html
+http://developer.android.com/reference/org/apache/http/auth/AuthenticationException.html
+
+http://developer.android.com/reference/org/apache/http/auth/InvalidCredentialsException.html
+http://developer.android.com/reference/org/apache/http/auth/MalformedChallengeException.html
+
+http://developer.android.com/reference/org/apache/http/auth/package-descr.html
+http://developer.android.com/reference/android/net/wifi/WifiConfiguration.AuthAlgorithm.html
+
+http://developer.android.com/reference/android/net/wifi/WifiConfiguration.GroupCipher.html
+http://developer.android.com/reference/android/net/wifi/WifiConfiguration.KeyMgmt.html
+
+http://developer.android.com/reference/android/net/wifi/WifiConfiguration.PairwiseCipher.html
+
+http://developer.android.com/reference/android/net/wifi/WifiConfiguration.Protocol.html
+http://developer.android.com/reference/android/net/wifi/WifiConfiguration.Status.html
+
+http://developer.android.com/reference/android/net/wifi/WifiManager.WifiLock.html
+http://developer.android.com/reference/org/apache/http/protocol/HTTP.html
+
+http://developer.android.com/reference/java/util/zip/ZipInputStream.html
+http://developer.android.com/reference/java/util/zip/InflaterInputStream.html
+
+http://developer.android.com/reference/java/util/zip/Inflater.html
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/PoolEntryRequest.html
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/RefQueueHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/AbstractConnPool.html
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/BasicPooledConnAdapter.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/BasicPoolEntry.html
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/BasicPoolEntryRef.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/ConnPoolByRoute.html
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/RefQueueWorker.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/RouteSpecificPool.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/ThreadSafeClientConnManager.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/WaitingThread.html
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/WaitingThreadAborter.html
+
+http://developer.android.com/reference/org/apache/http/impl/conn/tsccm/package-descr.html
+http://developer.android.com/reference/java/util/regex/PatternSyntaxException.html
+
+http://developer.android.com/reference/org/xmlpull/v1/sax2/Driver.html
+http://developer.android.com/guide/tutorials/views/hello-spinner.html
+
+http://developer.android.com/guide/tutorials/views/hello-listview.html
+http://developer.android.com/guide/tutorials/views/hello-gridview.html
+
+http://developer.android.com/reference/android/test/mock/MockPackageManager.html
+
+http://developer.android.com/reference/android/text/util/Linkify.MatchFilter.html
+
+http://developer.android.com/reference/android/text/util/Linkify.TransformFilter.html
+http://developer.android.com/reference/android/text/util/Rfc822Token.html
+
+http://developer.android.com/reference/android/text/util/Rfc822Tokenizer.html
+http://developer.android.com/reference/java/util/regex/Pattern.html
+
+http://developer.android.com/reference/java/lang/reflect/ReflectPermission.html
+
+http://developer.android.com/reference/javax/security/auth/callback/Callback.html
+http://developer.android.com/reference/javax/security/auth/callback/PasswordCallback.html
+
+http://developer.android.com/reference/javax/security/auth/callback/UnsupportedCallbackException.html
+
+http://developer.android.com/reference/javax/security/cert/Certificate.html
+http://developer.android.com/reference/javax/security/cert/X509Certificate.html
+
+http://developer.android.com/reference/javax/security/cert/CertificateEncodingException.html
+http://developer.android.com/reference/javax/security/cert/CertificateException.html
+
+http://developer.android.com/reference/javax/security/cert/CertificateExpiredException.html
+http://developer.android.com/reference/javax/security/cert/CertificateNotYetValidException.html
+
+http://developer.android.com/reference/javax/security/cert/CertificateParsingException.html
+http://developer.android.com/reference/javax/security/cert/package-descr.html
+
+http://developer.android.com/reference/org/apache/http/protocol/HttpRequestExecutor.html
+http://developer.android.com/reference/org/apache/http/protocol/HttpProcessor.html
+
+http://developer.android.com/reference/org/apache/http/impl/DefaultHttpRequestFactory.html
+http://developer.android.com/reference/javax/crypto/interfaces/PBEKey.html
+
+http://developer.android.com/reference/java/lang/annotation/Annotation.html
+http://developer.android.com/reference/java/lang/annotation/AnnotationTypeMismatchException.html
+
+http://developer.android.com/reference/java/lang/annotation/IncompleteAnnotationException.html
+
+http://developer.android.com/reference/java/lang/annotation/AnnotationFormatError.html
+http://developer.android.com/reference/java/lang/annotation/package-descr.html
+
+http://developer.android.com/reference/android/app/package-descr.html
+http://developer.android.com/reference/java/lang/reflect/Method.html
+
+http://developer.android.com/reference/org/apache/http/message/BasicHttpEntityEnclosingRequest.html
+
+http://developer.android.com/reference/org/apache/http/message/BasicHttpRequest.html
+http://developer.android.com/reference/org/apache/http/message/BasicHttpResponse.html
+
+http://developer.android.com/guide/samples/NotePad/src/com/index.html
+http://developer.android.com/reference/org/apache/http/io/HttpMessageWriter.html
+
+http://developer.android.com/reference/org/apache/http/io/package-descr.html
+http://developer.android.com/reference/android/location/LocationListener.html
+
+http://developer.android.com/reference/android/location/Geocoder.html
+http://developer.android.com/reference/android/location/LocationProvider.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/AbstractCookieAttributeHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/AbstractCookieSpec.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/BasicCommentHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/BasicDomainHandler.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/BasicExpiresHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/BasicMaxAgeHandler.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/BasicPathHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/BasicSecureHandler.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/BestMatchSpec.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/BestMatchSpecFactory.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/BrowserCompatSpec.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/BrowserCompatSpecFactory.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/CookieSpecBase.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/DateUtils.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/NetscapeDomainHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/NetscapeDraftHeaderParser.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/NetscapeDraftSpec.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/NetscapeDraftSpecFactory.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/RFC2109DomainHandler.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/RFC2109Spec.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/RFC2109SpecFactory.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/RFC2109VersionHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/RFC2965CommentUrlAttributeHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/RFC2965DiscardAttributeHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/RFC2965DomainAttributeHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/RFC2965Spec.html
+http://developer.android.com/reference/org/apache/http/impl/cookie/RFC2965SpecFactory.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.html
+
+http://developer.android.com/reference/org/apache/http/impl/cookie/DateParseException.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LabelView.java
+
+http://developer.android.com/reference/android/net/http/SslCertificate.html
+http://developer.android.com/reference/android/net/http/SslCertificate.DName.html
+
+http://developer.android.com/reference/android/test/mock/MockContentResolver.html
+http://developer.android.com/reference/android/test/mock/MockDialogInterface.html
+
+http://developer.android.com/reference/android/test/mock/MockResources.html
+http://developer.android.com/reference/android/test/mock/package-descr.html
+
+http://developer.android.com/reference/junit/framework/Protectable.html
+http://developer.android.com/reference/junit/framework/TestFailure.html
+
+http://developer.android.com/reference/junit/framework/ComparisonFailure.html
+http://developer.android.com/reference/android/test/suitebuilder/TestSuiteBuilder.FailedToCreateTests.html
+
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicBoolean.html
+
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicIntegerArray.html
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.html
+
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicLongArray.html
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicLongFieldUpdater.html
+
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicMarkableReference.html
+
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicReference.html
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicReferenceArray.html
+
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.html
+
+http://developer.android.com/reference/java/util/concurrent/atomic/AtomicStampedReference.html
+
+http://developer.android.com/reference/java/util/concurrent/atomic/package-descr.html
+http://developer.android.com/reference/org/apache/http/impl/AbstractHttpClientConnection.html
+
+http://developer.android.com/reference/org/apache/http/impl/AbstractHttpServerConnection.html
+
+http://developer.android.com/reference/java/util/concurrent/locks/AbstractQueuedSynchronizer.html
+
+http://developer.android.com/reference/java/util/concurrent/locks/AbstractQueuedSynchronizer.ConditionObject.html
+
+http://developer.android.com/reference/org/apache/http/conn/ssl/AbstractVerifier.html
+http://developer.android.com/reference/java/lang/reflect/AccessibleObject.html
+
+http://developer.android.com/reference/java/util/zip/Adler32.html
+http://developer.android.com/reference/android/text/style/AlignmentSpan.Standard.html
+
+http://developer.android.com/reference/java/lang/reflect/Array.html
+http://developer.android.com/reference/android/media/AsyncPlayer.html
+
+http://developer.android.com/reference/org/apache/http/client/params/AuthPolicy.html
+http://developer.android.com/reference/org/apache/http/message/BasicHeaderElementIterator.html
+
+http://developer.android.com/reference/org/apache/http/message/BasicHeaderValueFormatter.html
+
+http://developer.android.com/reference/org/apache/http/message/BasicHeaderValueParser.html
+http://developer.android.com/reference/org/apache/http/protocol/BasicHttpContext.html
+
+http://developer.android.com/reference/org/apache/http/message/BasicLineFormatter.html
+http://developer.android.com/reference/org/apache/http/message/BasicLineParser.html
+
+http://developer.android.com/reference/android/text/style/BulletSpan.html
+http://developer.android.com/reference/org/apache/http/util/ByteArrayBuffer.html
+
+http://developer.android.com/reference/java/util/zip/CRC32.html
+http://developer.android.com/reference/android/hardware/Camera.Parameters.html
+
+http://developer.android.com/reference/android/hardware/Camera.Size.html
+http://developer.android.com/reference/android/text/style/CharacterStyle.html
+
+http://developer.android.com/reference/java/nio/charset/spi/CharsetProvider.html
+http://developer.android.com/reference/org/apache/http/client/utils/CloneUtils.html
+
+http://developer.android.com/reference/org/apache/http/conn/params/ConnManagerParams.html
+http://developer.android.com/reference/org/apache/http/conn/params/ConnPerRouteBean.html
+
+http://developer.android.com/reference/org/apache/http/conn/params/ConnRouteParams.html
+http://developer.android.com/reference/org/apache/http/client/params/CookiePolicy.html
+
+http://developer.android.com/reference/org/apache/http/impl/DefaultHttpResponseFactory.html
+http://developer.android.com/reference/org/apache/http/protocol/DefaultedHttpContext.html
+
+http://developer.android.com/reference/java/util/zip/Deflater.html
+http://developer.android.com/reference/android/text/style/DrawableMarginSpan.html
+
+http://developer.android.com/reference/org/apache/http/util/EncodingUtils.html
+http://developer.android.com/reference/org/apache/http/impl/entity/EntityDeserializer.html
+
+http://developer.android.com/reference/org/apache/http/impl/entity/EntitySerializer.html
+http://developer.android.com/reference/org/apache/http/util/EntityUtils.html
+
+http://developer.android.com/reference/org/apache/http/util/ExceptionUtils.html
+http://developer.android.com/reference/android/media/FaceDetector.html
+
+http://developer.android.com/reference/android/media/FaceDetector.Face.html
+http://developer.android.com/reference/android/opengl/GLDebugHelper.html
+
+http://developer.android.com/reference/android/opengl/GLU.html
+http://developer.android.com/reference/android/opengl/GLUtils.html
+
+http://developer.android.com/reference/org/apache/http/client/params/HttpClientParams.html
+http://developer.android.com/reference/org/apache/http/impl/HttpConnectionMetricsImpl.html
+
+http://developer.android.com/reference/org/apache/http/protocol/HttpDateGenerator.html
+http://developer.android.com/reference/org/apache/http/protocol/HttpRequestHandlerRegistry.html
+
+http://developer.android.com/reference/org/apache/http/protocol/HttpService.html
+http://developer.android.com/reference/android/text/style/IconMarginSpan.html
+
+http://developer.android.com/reference/org/apache/http/conn/util/InetAddressUtils.html
+http://developer.android.com/reference/org/json/JSONArray.html
+
+http://developer.android.com/reference/org/json/JSONObject.html
+http://developer.android.com/reference/org/json/JSONStringer.html
+
+http://developer.android.com/reference/org/json/JSONTokener.html
+http://developer.android.com/reference/org/apache/http/util/LangUtils.html
+
+http://developer.android.com/reference/org/apache/http/impl/entity/LaxContentLengthStrategy.html
+
+http://developer.android.com/reference/android/text/style/LeadingMarginSpan.Standard.html
+http://developer.android.com/reference/java/util/concurrent/locks/LockSupport.html
+
+http://developer.android.com/reference/java/util/regex/Matcher.html
+http://developer.android.com/reference/android/opengl/Matrix.html
+
+http://developer.android.com/reference/android/media/MediaRecorder.AudioEncoder.html
+http://developer.android.com/reference/android/media/MediaRecorder.AudioSource.html
+
+http://developer.android.com/reference/android/media/MediaRecorder.OutputFormat.html
+http://developer.android.com/reference/android/media/MediaScannerConnection.html
+
+http://developer.android.com/reference/java/lang/reflect/Modifier.html
+http://developer.android.com/reference/org/apache/http/message/ParserCursor.html
+
+http://developer.android.com/reference/org/apache/http/conn/scheme/PlainSocketFactory.html
+http://developer.android.com/reference/android/text/style/QuoteSpan.html
+
+http://developer.android.com/reference/java/util/concurrent/locks/ReentrantLock.html
+http://developer.android.com/reference/java/util/concurrent/locks/ReentrantReadWriteLock.html
+
+http://developer.android.com/reference/java/util/concurrent/locks/ReentrantReadWriteLock.ReadLock.html
+
+http://developer.android.com/reference/java/util/concurrent/locks/ReentrantReadWriteLock.WriteLock.html
+
+http://developer.android.com/reference/org/apache/http/protocol/RequestConnControl.html
+http://developer.android.com/reference/org/apache/http/protocol/RequestContent.html
+
+http://developer.android.com/reference/org/apache/http/protocol/RequestDate.html
+http://developer.android.com/reference/org/apache/http/protocol/RequestExpectContinue.html
+
+http://developer.android.com/reference/org/apache/http/protocol/RequestTargetHost.html
+http://developer.android.com/reference/org/apache/http/protocol/RequestUserAgent.html
+
+http://developer.android.com/reference/org/apache/http/protocol/ResponseConnControl.html
+http://developer.android.com/reference/org/apache/http/protocol/ResponseContent.html
+
+http://developer.android.com/reference/org/apache/http/protocol/ResponseDate.html
+http://developer.android.com/reference/org/apache/http/protocol/ResponseServer.html
+
+http://developer.android.com/reference/android/media/Ringtone.html
+http://developer.android.com/reference/org/apache/http/conn/ssl/SSLSocketFactory.html
+
+http://developer.android.com/reference/org/apache/http/conn/scheme/Scheme.html
+http://developer.android.com/reference/org/apache/http/conn/scheme/SchemeRegistry.html
+
+http://developer.android.com/reference/javax/net/ServerSocketFactory.html
+http://developer.android.com/reference/android/telephony/gsm/SmsManager.html
+
+http://developer.android.com/reference/android/telephony/gsm/SmsMessage.html
+http://developer.android.com/reference/android/telephony/gsm/SmsMessage.SubmitPdu.html
+
+http://developer.android.com/reference/android/media/SoundPool.html
+http://developer.android.com/reference/org/apache/http/impl/entity/StrictContentLengthStrategy.html
+
+http://developer.android.com/reference/android/text/style/TabStopSpan.Standard.html
+http://developer.android.com/reference/android/test/suitebuilder/TestMethod.html
+
+http://developer.android.com/reference/android/test/suitebuilder/TestSuiteBuilder.html
+http://developer.android.com/reference/android/media/ToneGenerator.html
+
+http://developer.android.com/reference/org/apache/http/client/utils/URIUtils.html
+http://developer.android.com/reference/org/apache/http/client/utils/URLEncodedUtils.html
+
+http://developer.android.com/reference/org/apache/http/protocol/UriPatternMatcher.html
+http://developer.android.com/reference/junit/runner/Version.html
+
+http://developer.android.com/reference/org/apache/http/util/VersionInfo.html
+http://developer.android.com/reference/org/xmlpull/v1/XmlPullParserFactory.html
+
+http://developer.android.com/reference/java/util/concurrent/locks/Lock.html
+http://developer.android.com/reference/org/apache/http/conn/ssl/X509HostnameVerifier.html
+
+http://developer.android.com/reference/java/util/concurrent/locks/ReadWriteLock.html
+http://developer.android.com/reference/android/text/style/AbsoluteSizeSpan.html
+
+http://developer.android.com/reference/org/apache/http/conn/ssl/AllowAllHostnameVerifier.html
+
+http://developer.android.com/reference/android/text/style/BackgroundColorSpan.html
+http://developer.android.com/reference/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.html
+
+http://developer.android.com/reference/java/util/zip/CheckedInputStream.html
+http://developer.android.com/reference/java/util/zip/CheckedOutputStream.html
+
+http://developer.android.com/reference/android/text/style/ClickableSpan.html
+http://developer.android.com/reference/org/apache/http/client/params/ClientParamBean.html
+
+http://developer.android.com/reference/org/apache/http/conn/params/ConnConnectionParamBean.html
+
+http://developer.android.com/reference/org/apache/http/conn/params/ConnManagerParamBean.html
+http://developer.android.com/reference/org/apache/http/conn/params/ConnRouteParamBean.html
+
+http://developer.android.com/reference/javax/sql/ConnectionEvent.html
+http://developer.android.com/reference/java/lang/reflect/Constructor.html
+
+http://developer.android.com/reference/org/apache/http/cookie/params/CookieSpecParamBean.html
+
+http://developer.android.com/reference/org/w3c/dom/DOMException.html
+http://developer.android.com/reference/java/util/zip/DataFormatException.html
+
+http://developer.android.com/reference/org/apache/http/impl/DefaultHttpClientConnection.html
+http://developer.android.com/reference/org/apache/http/impl/DefaultHttpServerConnection.html
+
+http://developer.android.com/reference/java/util/zip/DeflaterOutputStream.html
+http://developer.android.com/reference/android/text/style/DynamicDrawableSpan.html
+
+http://developer.android.com/reference/java/lang/reflect/Field.html
+http://developer.android.com/reference/android/text/style/ForegroundColorSpan.html
+
+http://developer.android.com/reference/android/opengl/GLException.html
+http://developer.android.com/reference/java/util/zip/GZIPInputStream.html
+
+http://developer.android.com/reference/java/util/zip/GZIPOutputStream.html
+http://developer.android.com/reference/java/lang/reflect/GenericSignatureFormatError.html
+
+http://developer.android.com/reference/android/text/style/ImageSpan.html
+http://developer.android.com/reference/java/lang/reflect/InvocationTargetException.html
+
+http://developer.android.com/reference/org/json/JSONException.html
+http://developer.android.com/reference/java/lang/reflect/MalformedParameterizedTypeException.html
+
+http://developer.android.com/reference/android/text/style/MaskFilterSpan.html
+http://developer.android.com/reference/android/text/style/MetricAffectingSpan.html
+
+http://developer.android.com/reference/android/text/style/RasterizerSpan.html
+http://developer.android.com/reference/android/text/style/RelativeSizeSpan.html
+
+http://developer.android.com/reference/android/text/style/ReplacementSpan.html
+http://developer.android.com/reference/javax/sql/RowSetEvent.html
+
+http://developer.android.com/reference/android/text/style/ScaleXSpan.html
+http://developer.android.com/reference/org/apache/http/impl/SocketHttpClientConnection.html
+
+http://developer.android.com/reference/org/apache/http/impl/SocketHttpServerConnection.html
+http://developer.android.com/reference/org/apache/http/conn/ssl/StrictHostnameVerifier.html
+
+http://developer.android.com/reference/android/text/style/StrikethroughSpan.html
+http://developer.android.com/reference/android/text/style/StyleSpan.html
+
+http://developer.android.com/reference/android/text/style/SubscriptSpan.html
+http://developer.android.com/reference/android/text/style/SuperscriptSpan.html
+
+http://developer.android.com/reference/org/apache/http/protocol/SyncBasicHttpContext.html
+http://developer.android.com/reference/android/text/style/TextAppearanceSpan.html
+
+http://developer.android.com/reference/android/text/style/TypefaceSpan.html
+http://developer.android.com/reference/java/lang/reflect/UndeclaredThrowableException.html
+
+http://developer.android.com/reference/android/text/style/UnderlineSpan.html
+http://developer.android.com/reference/java/util/zip/ZipException.html
+
+http://developer.android.com/reference/java/util/zip/ZipOutputStream.html
+http://developer.android.com/reference/android/media/MediaPlayer.OnBufferingUpdateListener.html
+
+http://developer.android.com/reference/android/media/MediaPlayer.OnCompletionListener.html
+http://developer.android.com/reference/android/media/MediaPlayer.OnErrorListener.html
+
+http://developer.android.com/reference/android/media/MediaPlayer.OnPreparedListener.html
+http://developer.android.com/reference/android/media/MediaPlayer.OnSeekCompleteListener.html
+
+http://developer.android.com/reference/android/media/MediaScannerConnection.MediaScannerConnectionClient.html
+
+http://developer.android.com/reference/java/util/zip/Checksum.html
+http://developer.android.com/guide/developing/tools/adt.html
+
+http://developer.android.com/reference/org/apache/http/client/params/AllClientPNames.html
+http://developer.android.com/reference/org/apache/http/message/HeaderValueFormatter.html
+
+http://developer.android.com/reference/org/apache/http/message/HeaderValueParser.html
+http://developer.android.com/reference/org/apache/http/message/LineFormatter.html
+
+http://developer.android.com/reference/java/lang/package-descr.html
+http://developer.android.com/reference/org/apache/http/conn/params/ConnConnectionPNames.html
+
+http://developer.android.com/reference/org/apache/http/conn/params/ConnManagerPNames.html
+http://developer.android.com/reference/org/apache/http/conn/params/ConnPerRoute.html
+
+http://developer.android.com/reference/org/apache/http/conn/params/ConnRoutePNames.html
+http://developer.android.com/reference/org/apache/http/conn/scheme/HostNameResolver.html
+
+http://developer.android.com/reference/org/apache/http/conn/scheme/LayeredSocketFactory.html
+http://developer.android.com/reference/android/text/style/AlignmentSpan.html
+
+http://developer.android.com/reference/java/lang/reflect/AnnotatedElement.html
+http://developer.android.com/reference/org/w3c/dom/Attr.html
+
+http://developer.android.com/reference/android/hardware/Camera.AutoFocusCallback.html
+http://developer.android.com/reference/android/hardware/Camera.ErrorCallback.html
+
+http://developer.android.com/reference/android/hardware/Camera.PictureCallback.html
+http://developer.android.com/reference/android/hardware/Camera.PreviewCallback.html
+
+http://developer.android.com/reference/android/hardware/Camera.ShutterCallback.html
+http://developer.android.com/reference/org/w3c/dom/CDATASection.html
+
+http://developer.android.com/reference/org/w3c/dom/CharacterData.html
+http://developer.android.com/reference/org/apache/http/client/params/ClientPNames.html
+
+http://developer.android.com/reference/org/w3c/dom/Comment.html
+http://developer.android.com/reference/java/util/concurrent/locks/Condition.html
+
+http://developer.android.com/reference/javax/sql/ConnectionEventListener.html
+http://developer.android.com/reference/javax/sql/ConnectionPoolDataSource.html
+
+http://developer.android.com/reference/org/apache/http/cookie/params/CookieSpecPNames.html
+http://developer.android.com/reference/javax/sql/DataSource.html
+
+http://developer.android.com/reference/java/lang/Deprecated.html
+http://developer.android.com/reference/javax/crypto/interfaces/DHKey.html
+
+http://developer.android.com/reference/javax/crypto/interfaces/DHPrivateKey.html
+http://developer.android.com/reference/javax/crypto/interfaces/DHPublicKey.html
+
+http://developer.android.com/reference/org/w3c/dom/Document.html
+http://developer.android.com/reference/java/lang/annotation/Documented.html
+
+http://developer.android.com/reference/org/w3c/dom/DocumentFragment.html
+http://developer.android.com/reference/org/w3c/dom/DocumentType.html
+
+http://developer.android.com/reference/org/w3c/dom/DOMImplementation.html
+http://developer.android.com/reference/java/security/interfaces/DSAKey.html
+
+http://developer.android.com/reference/java/security/interfaces/DSAKeyPairGenerator.html
+http://developer.android.com/reference/java/security/interfaces/DSAParams.html
+
+http://developer.android.com/reference/java/security/interfaces/DSAPrivateKey.html
+http://developer.android.com/reference/java/security/interfaces/DSAPublicKey.html
+
+http://developer.android.com/reference/java/security/interfaces/ECKey.html
+http://developer.android.com/reference/java/security/interfaces/ECPrivateKey.html
+
+http://developer.android.com/reference/java/security/interfaces/ECPublicKey.html
+http://developer.android.com/reference/org/w3c/dom/Element.html
+
+http://developer.android.com/reference/org/w3c/dom/Entity.html
+http://developer.android.com/reference/org/w3c/dom/EntityReference.html
+
+http://developer.android.com/reference/org/apache/http/protocol/ExecutionContext.html
+http://developer.android.com/reference/android/test/FlakyTest.html
+
+http://developer.android.com/reference/java/lang/reflect/GenericArrayType.html
+http://developer.android.com/reference/java/lang/reflect/GenericDeclaration.html
+
+http://developer.android.com/reference/javax/microedition/khronos/opengles/GL10.html
+http://developer.android.com/reference/javax/microedition/khronos/opengles/GL10Ext.html
+
+http://developer.android.com/reference/javax/microedition/khronos/opengles/GL11.html
+http://developer.android.com/reference/javax/microedition/khronos/opengles/GL11Ext.html
+
+http://developer.android.com/reference/javax/microedition/khronos/opengles/GL11ExtensionPack.html
+
+http://developer.android.com/reference/org/apache/http/protocol/HttpExpectationVerifier.html
+http://developer.android.com/reference/org/apache/http/protocol/HttpRequestHandler.html
+
+http://developer.android.com/reference/org/apache/http/protocol/HttpRequestHandlerResolver.html
+
+http://developer.android.com/reference/org/apache/http/protocol/HttpRequestInterceptorList.html
+
+http://developer.android.com/reference/org/apache/http/protocol/HttpResponseInterceptorList.html
+
+http://developer.android.com/reference/java/lang/annotation/Inherited.html
+http://developer.android.com/reference/java/lang/reflect/InvocationHandler.html
+
+http://developer.android.com/reference/android/text/style/LeadingMarginSpan.html
+http://developer.android.com/reference/android/text/style/LineBackgroundSpan.html
+
+http://developer.android.com/reference/android/text/style/LineHeightSpan.html
+http://developer.android.com/reference/java/util/regex/MatchResult.html
+
+http://developer.android.com/reference/java/lang/reflect/Member.html
+http://developer.android.com/reference/org/w3c/dom/NamedNodeMap.html
+
+http://developer.android.com/reference/org/w3c/dom/Node.html
+http://developer.android.com/reference/org/w3c/dom/NodeList.html
+
+http://developer.android.com/reference/org/w3c/dom/Notation.html
+http://developer.android.com/reference/dalvik/bytecode/Opcodes.html
+
+http://developer.android.com/reference/java/lang/Override.html
+http://developer.android.com/reference/android/text/style/ParagraphStyle.html
+
+http://developer.android.com/reference/java/lang/reflect/ParameterizedType.html
+http://developer.android.com/reference/javax/sql/PooledConnection.html
+
+http://developer.android.com/reference/org/w3c/dom/ProcessingInstruction.html
+http://developer.android.com/reference/java/lang/reflect/Proxy.html
+
+http://developer.android.com/reference/java/lang/annotation/Retention.html
+http://developer.android.com/reference/javax/sql/RowSetInternal.html
+
+http://developer.android.com/reference/javax/sql/RowSetListener.html
+http://developer.android.com/reference/javax/sql/RowSetMetaData.html
+
+http://developer.android.com/reference/javax/sql/RowSetReader.html
+http://developer.android.com/reference/javax/sql/RowSetWriter.html
+
+http://developer.android.com/reference/java/security/interfaces/RSAKey.html
+http://developer.android.com/reference/java/security/interfaces/RSAMultiPrimePrivateCrtKey.html
+
+http://developer.android.com/reference/java/security/interfaces/RSAPrivateCrtKey.html
+http://developer.android.com/reference/java/security/interfaces/RSAPrivateKey.html
+
+http://developer.android.com/reference/java/security/interfaces/RSAPublicKey.html
+http://developer.android.com/reference/android/hardware/SensorListener.html
+
+http://developer.android.com/reference/android/test/suitebuilder/annotation/Smoke.html
+http://developer.android.com/reference/android/test/suitebuilder/annotation/Suppress.html
+
+http://developer.android.com/reference/java/lang/SuppressWarnings.html
+http://developer.android.com/reference/android/text/style/TabStopSpan.html
+
+http://developer.android.com/reference/java/lang/annotation/Target.html
+http://developer.android.com/reference/dalvik/annotation/TestTarget.html
+
+http://developer.android.com/reference/dalvik/annotation/TestTargetClass.html
+http://developer.android.com/reference/org/w3c/dom/Text.html
+
+http://developer.android.com/reference/java/lang/reflect/Type.html
+http://developer.android.com/reference/java/lang/reflect/TypeVariable.html
+
+http://developer.android.com/reference/android/test/UiThreadTest.html
+http://developer.android.com/reference/android/text/style/UpdateLayout.html
+
+http://developer.android.com/reference/java/lang/reflect/WildcardType.html
+http://developer.android.com/reference/android/text/style/WrapTogetherSpan.html
+
+http://developer.android.com/reference/org/xmlpull/v1/XmlSerializer.html
+
+http://developer.android.com/reference/java/util/zip/package-descr.html
+http://developer.android.com/reference/javax/security/auth/login/package-descr.html
+
+http://developer.android.com/reference/android/text/style/package-descr.html
+
+http://developer.android.com/reference/java/nio/channels/package-descr.html
+http://developer.android.com/reference/android/opengl/package-descr.html
+
+http://developer.android.com/guide/tutorials/notepad/notepad-ex1.html
+
+http://developer.android.com/guide/tutorials/notepad/notepad-ex2.html
+http://developer.android.com/guide/tutorials/notepad/notepad-ex3.html
+
+http://developer.android.com/guide/tutorials/notepad/notepad-extra-credit.html
+http://developer.android.com/reference/java/util/package-descr.html
+
+http://developer.android.com/reference/org/apache/http/client/methods/package-descr.html
+http://developer.android.com/reference/android/os/package-descr.html
+
+http://developer.android.com/reference/org/apache/http/client/utils/package-descr.html
+
+http://developer.android.com/reference/org/apache/http/impl/package-descr.html
+
+http://developer.android.com/reference/java/io/package-descr.html
+http://developer.android.com/guide/samples/NotePad/src/com/example/index.html
+
+http://developer.android.com/reference/java/nio/charset/spi/package-descr.html
+
+http://developer.android.com/reference/org/apache/http/impl/entity/package-descr.html
+
+http://developer.android.com/guide/samples/LunarLander/res/index.html
+
+http://developer.android.com/guide/samples/LunarLander/src/index.html
+http://developer.android.com/guide/samples/LunarLander/tests/index.html
+
+http://developer.android.com/guide/samples/LunarLander/AndroidManifest.html
+http://developer.android.com/guide/samples/LunarLander/sample_lunarlander.html
+
+http://developer.android.com/reference/javax/crypto/interfaces/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/content/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/text/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/assets/index.html
+http://developer.android.com/guide/samples/ApiDemos/res/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/index.html
+http://developer.android.com/guide/samples/ApiDemos/tests/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/AndroidManifest.html
+http://developer.android.com/reference/android/widget/package-descr.html
+http://developer.android.com/reference/org/apache/http/conn/params/package-descr.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/index.html
+http://developer.android.com/guide/samples/ApiDemos/tests/AndroidManifest.html
+
+http://developer.android.com/reference/android/test/suitebuilder/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/content/StyledText.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/content/ResourcesSample.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/content/ReadAsset.html
+
+http://developer.android.com/reference/android/view/package-descr.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/HelloWorld.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/SaveRestoreState.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/PersistentState.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ReceiveResult.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/Forwarding.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RedirectEnter.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/TranslucentActivity.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceController.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceBinding.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RemoteServiceController.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RemoteServiceBinding.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArgumentsController.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/AlarmController.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/OneShotAlarm.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RepeatingAlarm.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/AlarmService.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/AlarmService_Service.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/NotifyWithText.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessage.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/SearchInvoke.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/SearchQueryResults.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/SearchSuggestionSampleProvider.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/AdvancedPreferences.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/AlertDialogSamples.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ContactsFilter.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ContactsFilterInstrumentation.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ContactsSelectInstrumentation.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/CustomDialogActivity.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/CustomTitle.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/DefaultValues.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/DialogActivity.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ForwardTarget.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessageView.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LauncherShortcuts.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LaunchingPreferences.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LocalSample.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LocalSampleInstrumentation.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/MenuInflateFromXml.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/MyPreference.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/NotifyingController.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/NotifyingService.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/PreferenceDependencies.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/PreferencesFromCode.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/PreferencesFromXml.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RedirectGetter.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RedirectMain.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/SendResult.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/StatusBarNotifications.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/TranslucentBlurActivity.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/CustomDialogActivity.java
+
+http://developer.android.com/reference/org/w3c/dom/package-descr.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceBinding.java
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/index.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/index.html
+http://developer.android.com/guide/samples/ApiDemos/res/menu/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/raw/index.html
+http://developer.android.com/guide/samples/ApiDemos/res/values/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/xml/index.html
+http://developer.android.com/reference/java/sql/package-descr.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RepeatingAlarm.java
+
+http://developer.android.com/guide/samples/LunarLander/res/drawable/index.html
+http://developer.android.com/guide/samples/LunarLander/res/drawable-land/index.html
+
+http://developer.android.com/guide/samples/LunarLander/res/drawable-port/index.html
+http://developer.android.com/guide/samples/LunarLander/res/layout/index.html
+
+http://developer.android.com/guide/samples/LunarLander/res/values/index.html
+http://developer.android.com/reference/android/util/package-descr.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LocalSampleInstrumentation.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RedirectMain.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/Forwarding.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ContactsFilterInstrumentation.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/SearchSuggestionSampleProvider.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LaunchingPreferences.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/SearchInvoke.java
+
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/index.html
+
+http://developer.android.com/reference/android/content/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/ShapeDrawable1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/PolyToPoly.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/DrawPoints.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/PathEffects.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/SurfaceViewOverlay.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/AlphaBitmap.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/AnimateDrawable.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/AnimateDrawables.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Arcs.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/BitmapDecode.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/BitmapMesh.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Clipping.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/ColorMatrixSample.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/ColorPickerDialog.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Compass.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/CreateBitmap.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Cube.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/CubeRenderer.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/FingerPaint.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/GradientDrawable1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/GraphicsActivity.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Layers.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/MeasureText.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/PathFillTypes.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Patterns.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/PictureLayout.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Pictures.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/ProxyDrawable.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Regions.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/RoundRects.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/ScaleToFit.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/SensorTest.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Sweep.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/TextAlign.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/TranslucentGLSurfaceViewActivity.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/TriangleActivity.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/TriangleRenderer.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Typefaces.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/UnicodeChart.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Vertices.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Xfermodes.html
+
+http://developer.android.com/guide/samples/NotePad/tests/src/index.html
+http://developer.android.com/guide/samples/NotePad/tests/AndroidManifest.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/ShapeDrawable1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/AnimateDrawable.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Typefaces.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArgumentsController.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessage.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/RoundRects.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/SaveRestoreState.java
+
+http://developer.android.com/reference/org/apache/http/client/params/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ForwardTarget.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/AlertDialogSamples.java
+
+http://developer.android.com/reference/java/security/spec/package-descr.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/FingerPaint.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/SearchQueryResults.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/NotifyingController.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/ScaleToFit.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/NotifyingService.java
+
+http://developer.android.com/guide/samples/LunarLander/res/drawable-land/earthrise.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RedirectEnter.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ContactsFilter.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/AnimateDrawables.java
+
+http://developer.android.com/reference/org/apache/http/conn/ssl/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Arcs.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/CubeRenderer.java
+
+http://developer.android.com/reference/org/apache/http/message/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/TriangleRenderer.java
+
+http://developer.android.com/guide/samples/ApiDemos/assets/fonts/index.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/TranslucentBlurActivity.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/Grid.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/LabelMaker.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/MatrixGrabber.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/MatrixStack.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/MatrixTrackingGL.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/NumericSprite.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/Projector.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/SpriteTextActivity.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/SpriteTextRenderer.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/GradientDrawable1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/DialogActivity.java
+
+http://developer.android.com/reference/android/text/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/BitmapDecode.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/content/ResourcesSample.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/TranslucentGLSurfaceViewActivity.java
+
+http://developer.android.com/reference/org/apache/http/conn/routing/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Vertices.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/PersistentState.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ReceiveResult.java
+
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/notepad/index.html
+
+http://developer.android.com/reference/com/google/android/maps/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LauncherShortcuts.java
+
+http://developer.android.com/guide/samples/NotePad/tests/src/com/index.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/BitmapMesh.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/SurfaceViewOverlay.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/CreateBitmap.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/CustomTitle.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/AdvancedPreferences.java
+
+http://developer.android.com/
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/GraphicsActivity.java
+
+http://developer.android.com/guide/samples/ApiDemos/res/xml/advanced_preferences.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/xml/default_values.html
+http://developer.android.com/guide/samples/ApiDemos/res/xml/preference_dependencies.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/xml/preferences.html
+http://developer.android.com/guide/samples/ApiDemos/res/xml/searchable.html
+
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/notepad/NotePad.html
+
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/notepad/NotePadProvider.html
+
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/notepad/NotesList.html
+
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/notepad/TitleEditor.html
+
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/notepad/TitleEditor.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Layers.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RemoteServiceBinding.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Compass.java
+
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/notepad/NotesList.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/DefaultValues.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/AlarmService.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/OneShotAlarm.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/AlarmController.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/MatrixTrackingGL.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/ProxyDrawable.java
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/alarm_controller.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/alarm_service.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/alert_dialog.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/alert_dialog_text_entry.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/animation_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/animation_2.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/animations_main_screen.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/autocomplete_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/autocomplete_2.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/autocomplete_3.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/autocomplete_4.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/autocomplete_5.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/autocomplete_6.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/baseline_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/baseline_2.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/baseline_3.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/baseline_4.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/baseline_6.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/baseline_7.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/baseline_nested_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/baseline_nested_2.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/baseline_nested_3.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/buttons_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/chronometer.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/contacts_filter.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/controls_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/custom_dialog_activity.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/custom_title.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/custom_title_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/date_widgets_example_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/date_widgets_example_2.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/dialog_activity.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/focus_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/focus_2.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/focus_3.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/forward_target.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/forwarding.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/gallery_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/gallery_2.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/google_login.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/grid_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/grid_2.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/hello_world.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/image_button_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/image_switcher_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/image_view_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/incoming_message.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/incoming_message_info.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/incoming_message_panel.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/incoming_message_view.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/launcher_shortcuts.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/layout_animation_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/layout_animation_3.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/layout_animation_4.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/layout_animation_5.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/layout_animation_6.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/layout_animation_7.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/linear_layout_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/linear_layout_10.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/linear_layout_2.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/linear_layout_3.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/linear_layout_4.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/linear_layout_5.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/linear_layout_6.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/linear_layout_7.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/linear_layout_8.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/linear_layout_9.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/link.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/list_12.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/list_13.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/list_7.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/list_8.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/list_item_checkbox.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/list_item_icon_text.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/list_position.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/local_sample.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/local_service_binding.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/local_service_controller.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/log_text_box_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/mapview.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/marquee.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/mediaplayer_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/mediaplayer_2.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/morse_code.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/notify_with_text.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/notifying_controller.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/preference_widget_mypreference.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/progressbar_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/progressbar_2.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/progressbar_3.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/progressbar_4.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/radio_group_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/ratingbar_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/read_asset.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/receive_result.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/redirect_enter.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/redirect_getter.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/redirect_main.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/relative_layout_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/relative_layout_2.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/remote_service_binding.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/remote_service_controller.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/resources.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/save_restore_state.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/scroll_view_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/scroll_view_2.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/scrollbar1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/scrollbar2.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/scrollbar3.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/search_invoke.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/search_query_results.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/seekbar_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/select_dialog.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/send_result.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/service_start_arguments_controller.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/shape_drawable_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/spinner_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/status_bar_balloon.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/status_bar_notifications.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/styled_text.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/surface_view_overlay.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_10.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_11.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_12.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_2.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_3.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_4.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_5.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_6.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_7.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_8.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/table_layout_9.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/tabs1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/text_switcher_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/translucent_background.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/videoview.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/layout/visibility_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/layout/webview_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/NumericSprite.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/TranslucentActivity.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceController.java
+
+http://developer.android.com/guide/samples/ApiDemos/res/menu/category_order.html
+http://developer.android.com/guide/samples/ApiDemos/res/menu/checkable.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/menu/disabled.html
+http://developer.android.com/guide/samples/ApiDemos/res/menu/groups.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/menu/order.html
+http://developer.android.com/guide/samples/ApiDemos/res/menu/shortcuts.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/menu/submenu.html
+http://developer.android.com/guide/samples/ApiDemos/res/menu/title_icon.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/menu/title_only.html
+http://developer.android.com/guide/samples/ApiDemos/res/menu/visible.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Clipping.java
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/alert_dialog_icon.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/animated_gif.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/app_sample_code.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/arrow_down_float.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/arrow_up_float.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/balloons.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/beach.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/black_box.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/black_opaque_box.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/box.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/button.9.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/circular_progress.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/filled_box.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/frog.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/gallery_background_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/gallery_photo_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/gallery_photo_2.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/gallery_photo_3.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/gallery_photo_4.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/gallery_photo_5.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/gallery_photo_6.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/gallery_photo_7.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/gallery_photo_8.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/ic_popup_reminder.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/icon48x48_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/icon48x48_2.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/line.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/photo1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/photo2.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/photo3.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/photo4.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/photo5.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/photo6.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/picture_frame.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/progress_circular_background.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/progress_particle.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/robot.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_0.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_2.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_3.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_4.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_5.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_6.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_7.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_thumb_0.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_thumb_1.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_thumb_2.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_thumb_3.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_thumb_4.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_thumb_5.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_thumb_6.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/sample_thumb_7.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/scrollbar_state2.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/scrollbar_vertical_thumb.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/scrollbar_vertical_track.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/shape_1.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/shape_2.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/shape_3.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/shape_4.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/shape_5.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/star_big_on.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/stat_happy.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/stat_neutral.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/stat_sad.html
+http://developer.android.com/guide/samples/ApiDemos/res/drawable/stat_sample.html
+
+http://developer.android.com/guide/samples/LunarLander/res/layout/lunar_layout.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Cube.java
+
+http://developer.android.com/reference/android/hardware/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/GLSurfaceViewActivity.java
+
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/notepad/NotePadProvider.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RemoteServiceController.java
+
+http://developer.android.com/reference/junit/runner/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/TextAlign.java
+
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/notepad/NotePad.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/Projector.java
+
+http://developer.android.com/guide/samples/LunarLander/tests/src/index.html
+http://developer.android.com/guide/samples/LunarLander/tests/AndroidManifest.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/ColorMatrixSample.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/PreferencesFromXml.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/MeasureText.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/ColorPickerDialog.java
+
+http://developer.android.com/guide/samples/LunarLander/res/drawable/app_lunar_lander.html
+http://developer.android.com/guide/samples/LunarLander/res/drawable/lander_crashed.html
+
+http://developer.android.com/guide/samples/LunarLander/res/drawable/lander_firing.html
+http://developer.android.com/guide/samples/LunarLander/res/drawable/lander_plain.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/content/StyledText.java
+
+http://developer.android.com/reference/org/apache/http/package-descr.html
+http://developer.android.com/reference/javax/net/ssl/package-descr.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/RedirectGetter.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/DrawPoints.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/MyPreference.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/PathEffects.java
+
+http://developer.android.com/guide/samples/LunarLander/res/values/strings.html
+http://developer.android.com/guide/samples/ApiDemos/res/anim/cycle_7.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/fade.html
+http://developer.android.com/guide/samples/ApiDemos/res/anim/hyperspace_in.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/hyperspace_out.html
+http://developer.android.com/guide/samples/ApiDemos/res/anim/layout_animation_row_left_slide.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/layout_animation_row_right_slide.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/layout_animation_table.html
+http://developer.android.com/guide/samples/ApiDemos/res/anim/layout_bottom_to_top_slide.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/layout_grid_fade.html
+http://developer.android.com/guide/samples/ApiDemos/res/anim/layout_grid_inverse_fade.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/layout_random_fade.html
+http://developer.android.com/guide/samples/ApiDemos/res/anim/layout_wave_scale.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/push_left_in.html
+http://developer.android.com/guide/samples/ApiDemos/res/anim/push_left_out.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/push_up_in.html
+http://developer.android.com/guide/samples/ApiDemos/res/anim/push_up_out.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/shake.html
+http://developer.android.com/guide/samples/ApiDemos/res/anim/slide_left.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/slide_right.html
+http://developer.android.com/guide/samples/ApiDemos/res/anim/slide_top_to_bottom.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/anim/wave_scale.html
+
+http://developer.android.com/guide/tutorials/views/hello-datepicker.html
+
+http://developer.android.com/guide/tutorials/views/hello-timepicker.html
+http://developer.android.com/guide/tutorials/views/hello-autocomplete.html
+
+http://developer.android.com/guide/tutorials/views/hello-gallery.html
+http://developer.android.com/guide/tutorials/views/hello-tabwidget.html
+
+http://developer.android.com/guide/tutorials/views/hello-mapview.html
+http://developer.android.com/guide/tutorials/views/hello-webview.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/SpriteTextActivity.java
+
+http://developer.android.com/guide/samples/NotePad/src/com/example/android/notepad/NoteEditor.java
+
+http://developer.android.com/reference/java/util/concurrent/locks/package-descr.html
+http://developer.android.com/guide/samples/NotePad/tests/src/com/example/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/PictureLayout.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/MatrixGrabber.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/RelativeLayout1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/RelativeLayout2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout4.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout5.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout6.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout7.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout8.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout9.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ScrollView1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ScrollView2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout4.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout5.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout6.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout7.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout8.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout9.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout10.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout11.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout12.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline4.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline6.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline7.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/RadioGroup1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ScrollBar1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ScrollBar2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Visibility1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List4.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List5.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List6.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List7.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List8.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/CustomView1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ImageButton1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/DateWidgets1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/DateWidgets2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Gallery1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Gallery2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Spinner1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Grid1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Grid2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ImageSwitcher1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TextSwitcher1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Animation1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Animation2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Controls1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Controls2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete4.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete5.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar4.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Focus1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Focus2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Focus3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete6.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Buttons1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ChronometerDemo.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ExpandableList1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ExpandableList2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ExpandableList3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ImageView1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/InternalSelectionFocus.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/InternalSelectionScroll.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/InternalSelectionView.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation4.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation5.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation6.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation7.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout10.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List10.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List11.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List12.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List13.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List14.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List9.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/MapViewCompassDemo.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/MapViewDemo.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/RatingBar1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ScrollBar3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/SeekBar1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Tabs1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Tabs2.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Tabs3.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/WebView1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/LabelMaker.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/RelativeLayout1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/CustomView1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation7.java
+
+http://developer.android.com/reference/android/text/method/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/NotifyWithText.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/InternalSelectionScroll.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/RadioGroup1.java
+
+http://developer.android.com/reference/org/apache/http/entity/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/TriangleActivity.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Tabs3.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/WebView1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List14.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout9.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline7.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout6.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout3.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/HelloWorld.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/AlphaBitmap.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Buttons1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout10.java
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/index.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout11.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/index.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ExpandableList2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Focus2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout7.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout3.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ScrollView2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/MatrixStack.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ScrollBar2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout5.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ScrollBar3.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/AlarmService_Service.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete6.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List6.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/Grid.java
+
+http://developer.android.com/reference/org/apache/http/protocol/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Regions.java
+
+http://developer.android.com/guide/samples/LunarLander/src/com/index.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline4.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/PreferencesFromCode.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/PreferenceDependencies.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/GLSurfaceView.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LocalSample.java
+
+http://developer.android.com/guide/samples/NotePad/tests/src/com/example/android/index.html
+http://developer.android.com/reference/javax/security/auth/callback/package-descr.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List5.java
+
+http://developer.android.com/reference/javax/sql/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List9.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List8.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/text/Link.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/text/LogTextBox.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/text/LogTextBox1.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/text/Marquee.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List7.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout10.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline3.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline6.java
+
+http://developer.android.com/reference/android/location/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ImageSwitcher1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.java
+
+http://developer.android.com/reference/java/util/regex/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/Cube.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLColor.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLFace.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLShape.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLVertex.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLWorld.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/Kube.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/KubeRenderer.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/Layer.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/M4.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar4.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Gallery2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Focus3.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Sweep.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List12.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Tabs2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Xfermodes.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/DateWidgets1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Animation2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation4.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLWorld.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/content/ReadAsset.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Tabs1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/PolyToPoly.java
+
+http://developer.android.com/reference/org/apache/http/cookie/params/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout4.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/StatusBarNotifications.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/text/LogTextBox.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Pictures.java
+
+http://developer.android.com/reference/java/security/cert/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List13.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ChronometerDemo.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/KubeRenderer.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/SensorTest.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete5.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation3.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/SendResult.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout9.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Controls2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TextSwitcher1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/ContactsSelectInstrumentation.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ImageButton1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout8.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/Kube.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Controls1.java
+
+http://developer.android.com/reference/org/apache/http/util/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/Layer.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List10.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/BaselineNested3.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List4.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ScrollBar1.java
+
+http://developer.android.com/reference/java/security/interfaces/package-descr.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation5.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout5.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessageView.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Gallery1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLColor.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Visibility1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/DateWidgets2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/PathFillTypes.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout12.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/Patterns.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List3.java
+
+http://developer.android.com/guide/samples/LunarLander/res/drawable-port/earthrise.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Baseline2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout7.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/TableLayout1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Grid1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/RelativeLayout2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Spinner1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/index.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLVertex.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Focus1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout6.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/InternalSelectionFocus.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout4.java
+
+http://developer.android.com/guide/samples/LunarLander/src/com/example/index.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/M4.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/InternalSelectionView.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/text/LogTextBox1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ExpandableList3.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ScrollView1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ExpandableList1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/RatingBar1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Grid2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/index.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/MenuInflateFromXml.java
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/index.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/UnicodeChart.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete3.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/Cube.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout8.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List2.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/text/Marquee.java
+
+http://developer.android.com/guide/samples/ApiDemos/res/values/arrays.html
+http://developer.android.com/guide/samples/ApiDemos/res/values/attrs.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/values/colors.html
+http://developer.android.com/guide/samples/ApiDemos/res/values/ids.html
+
+http://developer.android.com/guide/samples/ApiDemos/res/values/strings.html
+http://developer.android.com/guide/samples/ApiDemos/res/values/styles.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/app/LocalService.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/Animation1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLShape.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LayoutAnimation6.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/MapViewCompassDemo.java
+
+http://developer.android.com/guide/samples/LunarLander/tests/src/com/index.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List11.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ImageView1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/kube/GLFace.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar3.java
+
+http://developer.android.com/guide/samples/LunarLander/src/com/example/android/index.html
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/LinearLayout1.java
+
+http://developer.android.com/guide/samples/NotePad/tests/src/com/example/android/notepad/index.html
+
+http://developer.android.com/guide/samples/NotePad/tests/src/com/example/android/notepad/NotePadTest.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/SeekBar1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/List1.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/SpriteTextRenderer.java
+
+http://developer.android.com/guide/samples/NotePad/res/drawable/index.html
+http://developer.android.com/guide/samples/NotePad/res/layout/index.html
+
+http://developer.android.com/guide/samples/NotePad/res/values/index.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete4.java
+
+http://developer.android.com/guide/samples/NotePad/res/drawable/app_notes.html
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/app/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/os/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/view/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/AllTests.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/ApiDemosApplicationTests.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/ApiDemosTest.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/MapViewDemo.java
+
+http://developer.android.com/guide/samples/NotePad/tests/src/com/example/android/notepad/NotePadTest.java
+
+http://developer.android.com/guide/samples/NotePad/res/values/strings.html
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/view/AutoComplete2.java
+
+http://developer.android.com/guide/samples/LunarLander/tests/src/com/example/index.html
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/view/Focus2ActivityTest.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/view/Focus2AndroidTest.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/ApiDemosTest.java
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/ApiDemosApplicationTests.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/index.html
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/AllTests.java
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/os/MorseCodeConverterTest.html
+
+http://developer.android.com/guide/samples/LunarLander/tests/src/com/example/android/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/app/ForwardingTest.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/app/LocalServiceTest.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/view/Focus2AndroidTest.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/text/Link.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/animation/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/media/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/os/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/ApiDemos.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/ApiDemosApplication.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/app/ForwardingTest.java
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/view/Focus2ActivityTest.java
+
+http://developer.android.com/guide/samples/LunarLander/src/com/example/android/lunarlander/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/os/MorseCodeConverterTest.java
+
+http://developer.android.com/guide/samples/NotePad/res/layout/note_editor.html
+http://developer.android.com/guide/samples/NotePad/res/layout/noteslist_item.html
+
+http://developer.android.com/guide/samples/NotePad/res/layout/title_editor.html
+http://developer.android.com/guide/samples/LunarLander/tests/src/com/example/android/lunarlander/index.html
+
+http://developer.android.com/guide/samples/ApiDemos/tests/src/com/example/android/apis/app/LocalServiceTest.java
+
+http://developer.android.com/guide/samples/LunarLander/src/com/example/android/lunarlander/LunarLander.html
+
+http://developer.android.com/guide/samples/LunarLander/src/com/example/android/lunarlander/LunarView.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/os/MorseCode.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/os/MorseCodeConverter.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/os/Sensors.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/ApiDemosApplication.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Audio.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Video.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/media/VideoViewDemo.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/animation/Rotate3dAnimation.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/animation/Transition3d.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/ApiDemos.java
+
+http://developer.android.com/guide/samples/LunarLander/tests/src/com/example/android/lunarlander/LunarLanderTest.html
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/os/MorseCode.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Audio.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/os/MorseCodeConverter.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/media/VideoViewDemo.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/animation/Rotate3dAnimation.java
+
+http://developer.android.com/guide/samples/LunarLander/src/com/example/android/lunarlander/LunarView.java
+
+http://developer.android.com/guide/samples/LunarLander/src/com/example/android/lunarlander/LunarLander.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/os/Sensors.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/media/MediaPlayerDemo_Video.java
+
+http://developer.android.com/guide/samples/LunarLander/tests/src/com/example/android/lunarlander/LunarLanderTest.java
+
+http://developer.android.com/guide/samples/ApiDemos/src/com/example/android/apis/animation/Transition3d.java \ No newline at end of file
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index dc16c39..0b398bc 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -16,18 +16,25 @@
package android.graphics;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.io.OutputStream;
+import android.os.Parcelable;
+import android.os.Parcel;
+
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.nio.IntBuffer;
-
-import android.os.Parcel;
-import android.os.Parcelable;
+import java.io.OutputStream;
public final class Bitmap implements Parcelable {
+ /**
+ * Indicates that the bitmap was created for an unknown pixel density.
+ *
+ * @see Bitmap#getDensityScale()
+ * @see Bitmap#setDensityScale(float)
+ *
+ * @hide pending API council approval
+ */
+ public static final float DENSITY_SCALE_UNKNOWN = -1.0f;
// Note: mNativeBitmap is used by FaceDetector_jni.cpp
// Don't change/rename without updating FaceDetector_jni.cpp
@@ -41,6 +48,9 @@ public final class Bitmap implements Parcelable {
private static volatile Matrix sScaleMatrix;
+ private float mDensityScale = DENSITY_SCALE_UNKNOWN;
+ private boolean mAutoScaling;
+
/**
* @noinspection UnusedDeclaration
*/
@@ -59,6 +69,104 @@ public final class Bitmap implements Parcelable {
mIsMutable = isMutable;
mNinePatchChunk = ninePatchChunk;
}
+
+ /**
+ * <p>Returns the density scale for this bitmap, expressed as a factor of
+ * the default density (160.) For instance, a bitmap designed for
+ * displays with a density of 240 will have a density scale of 1.5 whereas a bitmap
+ * designed for a density of 160 will have a density scale of 1.0.</p>
+ *
+ * <p>The default density scale is {@link #DENSITY_SCALE_UNKNOWN}.</p>
+ *
+ * @return A scaling factor of the default density (160) or {@link #DENSITY_SCALE_UNKNOWN}
+ * if the scaling factor is unknown.
+ *
+ * @see #setDensityScale(float)
+ * @see #isAutoScalingEnabled()
+ * @see #setAutoScalingEnabled(boolean)
+ * @see android.util.DisplayMetrics#DEFAULT_DENSITY
+ * @see android.util.DisplayMetrics#density
+ * @see #DENSITY_SCALE_UNKNOWN
+ *
+ * @hide pending API council approval
+ */
+ public float getDensityScale() {
+ return mDensityScale;
+ }
+
+ /**
+ * <p>Specifies the density scale for this bitmap, expressed as a factor of
+ * the default density (160.) For instance, a bitmap designed for
+ * displays with a density of 240 will have a density scale of 1.5 whereas a bitmap
+ * designed for a density of 160 will have a density scale of 1.0.</p>
+ *
+ * @param densityScale The density scaling factor to use with this bitmap or
+ * {@link #DENSITY_SCALE_UNKNOWN} if the factor is unknown.
+ *
+ * @see #getDensityScale()
+ * @see #isAutoScalingEnabled()
+ * @see #setAutoScalingEnabled(boolean)
+ * @see android.util.DisplayMetrics#DEFAULT_DENSITY
+ * @see android.util.DisplayMetrics#density
+ * @see #DENSITY_SCALE_UNKNOWN
+ *
+ * @hide pending API council approval
+ */
+ public void setDensityScale(float densityScale) {
+ mDensityScale = densityScale;
+ }
+
+ /**
+ * </p>Indicates whether this bitmap will be automatically be scaled at the
+ * target's density at drawing time. If auto scaling is enabled, this bitmap
+ * will be drawn with the following scale factor:</p>
+ *
+ * <pre>scale = (bitmap density scale factor) / (target density scale factor)</pre>
+ *
+ * <p>Auto scaling is turned off by default. If auto scaling is enabled but the
+ * bitmap has an unknown density scale, then the bitmap will never be automatically
+ * scaled at drawing time.</p>
+ *
+ * @return True if the bitmap must be scaled at drawing time, false otherwise.
+ *
+ * @see #setAutoScalingEnabled(boolean)
+ * @see #getDensityScale()
+ * @see #setDensityScale(float)
+ *
+ * @hide pending API council approval
+ */
+ public boolean isAutoScalingEnabled() {
+ return mAutoScaling;
+ }
+
+ /**
+ * <p>Enables or disables auto scaling for this bitmap. When auto scaling is enabled,
+ * the bitmap will be scaled at drawing time to accomodate the drawing target's pixel
+ * density. The final scale factor for this bitmap is thus defined:</p>
+ *
+ * <pre>scale = (bitmap density scale factor) / (target density scale factor)</pre>
+ *
+ * <p>If auto scaling is enabled but the bitmap has an unknown density scale, then
+ * the bitmap will never be automatically scaled at drawing time.</p>
+ *
+ * @param autoScalingEnabled True to scale the bitmap at drawing time, false otherwise.
+ *
+ * @hide pending API council approval
+ */
+ public void setAutoScalingEnabled(boolean autoScalingEnabled) {
+ mAutoScaling = autoScalingEnabled;
+ }
+
+ /**
+ * Sets the nine patch chunk.
+ *
+ * @param chunk The definition of the nine patch
+ *
+ * @hide
+ */
+ public void setNinePatchChunk(byte[] chunk) {
+ mNinePatchChunk = chunk;
+ }
/**
* Free up the memory associated with this bitmap's pixels, and mark the
@@ -126,7 +234,7 @@ public final class Bitmap implements Parcelable {
throw new IllegalArgumentException("height must be > 0");
}
}
-
+
public enum Config {
// these native values must match up with the enum in SkBitmap.h
ALPHA_8 (2),
@@ -232,7 +340,7 @@ public final class Bitmap implements Parcelable {
public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
int dstHeight, boolean filter) {
- Matrix m = null;
+ Matrix m;
synchronized (Bitmap.class) {
// small pool of just 1 matrix
m = sScaleMatrix;
@@ -279,8 +387,7 @@ public final class Bitmap implements Parcelable {
* @param width The number of pixels in each row
* @param height The number of rows
*/
- public static Bitmap createBitmap(Bitmap source, int x, int y,
- int width, int height) {
+ public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) {
return createBitmap(source, x, y, width, height, null, false);
}
@@ -301,23 +408,21 @@ public final class Bitmap implements Parcelable {
* @throws IllegalArgumentException if the x, y, width, height values are
* outside of the dimensions of the source bitmap.
*/
- public static Bitmap createBitmap(Bitmap source, int x, int y, int width,
- int height, Matrix m, boolean filter) {
+ public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
+ Matrix m, boolean filter) {
+
checkXYSign(x, y);
checkWidthHeight(width, height);
if (x + width > source.getWidth()) {
- throw new IllegalArgumentException(
- "x + width must be <= bitmap.width()");
+ throw new IllegalArgumentException("x + width must be <= bitmap.width()");
}
if (y + height > source.getHeight()) {
- throw new IllegalArgumentException(
- "y + height must be <= bitmap.height()");
+ throw new IllegalArgumentException("y + height must be <= bitmap.height()");
}
// check if we can just return our argument unchanged
- if (!source.isMutable() && x == 0 && y == 0
- && width == source.getWidth() && height == source.getHeight()
- && (m == null || m.isIdentity())) {
+ if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
+ height == source.getHeight() && (m == null || m.isIdentity())) {
return source;
}
@@ -331,8 +436,8 @@ public final class Bitmap implements Parcelable {
RectF dstR = new RectF(0, 0, width, height);
if (m == null || m.isIdentity()) {
- bitmap = createBitmap(neww, newh, source.hasAlpha() ?
- Config.ARGB_8888 : Config.RGB_565);
+ bitmap = createBitmap(neww, newh,
+ source.hasAlpha() ? Config.ARGB_8888 : Config.RGB_565);
paint = null; // not needed
} else {
/* the dst should have alpha if the src does, or if our matrix
@@ -343,8 +448,7 @@ public final class Bitmap implements Parcelable {
m.mapRect(deviceR, dstR);
neww = Math.round(deviceR.width());
newh = Math.round(deviceR.height());
- bitmap = createBitmap(neww, newh, hasAlpha ?
- Config.ARGB_8888 : Config.RGB_565);
+ bitmap = createBitmap(neww, newh, hasAlpha ? Config.ARGB_8888 : Config.RGB_565);
if (hasAlpha) {
bitmap.eraseColor(0);
}
@@ -358,7 +462,12 @@ public final class Bitmap implements Parcelable {
}
canvas.setBitmap(bitmap);
canvas.drawBitmap(source, srcR, dstR, paint);
-
+
+ // The new bitmap was created from a known bitmap source so assume that
+ // they use the same density scale
+ bitmap.setDensityScale(source.getDensityScale());
+ bitmap.setAutoScalingEnabled(source.isAutoScalingEnabled());
+
return bitmap;
}
@@ -371,8 +480,7 @@ public final class Bitmap implements Parcelable {
* @throws IllegalArgumentException if the width or height are <= 0
*/
public static Bitmap createBitmap(int width, int height, Config config) {
- Bitmap bm = nativeCreate(null, 0, width, width, height,
- config.nativeInt, true);
+ Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true);
bm.eraseColor(0); // start with black/transparent pixels
return bm;
}
@@ -395,16 +503,16 @@ public final class Bitmap implements Parcelable {
* the color array's length is less than the number of pixels.
*/
public static Bitmap createBitmap(int colors[], int offset, int stride,
- int width, int height, Config config) {
+ int width, int height, Config config) {
+
checkWidthHeight(width, height);
if (Math.abs(stride) < width) {
throw new IllegalArgumentException("abs(stride) must be >= width");
}
int lastScanline = offset + (height - 1) * stride;
int length = colors.length;
- if (offset < 0 || (offset + width > length)
- || lastScanline < 0
- || (lastScanline + width > length)) {
+ if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
+ (lastScanline + width > length)) {
throw new ArrayIndexOutOfBoundsException();
}
return nativeCreate(colors, offset, stride, width, height,
@@ -425,8 +533,7 @@ public final class Bitmap implements Parcelable {
* @throws IllegalArgumentException if the width or height are <= 0, or if
* the color array's length is less than the number of pixels.
*/
- public static Bitmap createBitmap(int colors[], int width, int height,
- Config config) {
+ public static Bitmap createBitmap(int colors[], int width, int height, Config config) {
return createBitmap(colors, 0, width, width, height, config);
}
@@ -474,8 +581,7 @@ public final class Bitmap implements Parcelable {
* @param stream The outputstream to write the compressed data.
* @return true if successfully compressed to the specified stream.
*/
- public boolean compress(CompressFormat format, int quality,
- OutputStream stream) {
+ public boolean compress(CompressFormat format, int quality, OutputStream stream) {
checkRecycled("Can't compress a recycled bitmap");
// do explicit check before calling the native method
if (stream == null) {
@@ -506,6 +612,32 @@ public final class Bitmap implements Parcelable {
}
/**
+ * Convenience method that returns the width of this bitmap divided
+ * by the density scale factor.
+ *
+ * @return The scaled width of this bitmap, according to the density scale factor.
+ *
+ * @hide pending API council approval
+ */
+ public int getScaledWidth() {
+ final float scale = getDensityScale();
+ return scale == DENSITY_SCALE_UNKNOWN ? getWidth() : (int) (getWidth() / scale);
+ }
+
+ /**
+ * Convenience method that returns the height of this bitmap divided
+ * by the density scale factor.
+ *
+ * @return The scaled height of this bitmap, according to the density scale factor.
+ *
+ * @hide pending API council approval
+ */
+ public int getScaledHeight() {
+ final float scale = getDensityScale();
+ return scale == DENSITY_SCALE_UNKNOWN ? getWidth() : (int) (getHeight() / scale);
+ }
+
+ /**
* Return the number of bytes between rows in the bitmap's pixels. Note that
* this refers to the pixels as stored natively by the bitmap. If you call
* getPixels() or setPixels(), then the pixels are uniformly treated as
@@ -836,7 +968,7 @@ public final class Bitmap implements Parcelable {
private static native Bitmap nativeExtractAlpha(int nativeBitmap,
int nativePaint,
int[] offsetXY);
-
+
/* package */ final int ni() {
return mNativeBitmap;
}
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 2c3f543..3813d8f 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -18,26 +18,20 @@ package android.graphics;
import android.content.res.AssetManager;
import android.content.res.Resources;
-import android.util.Log;
+import android.util.TypedValue;
+import android.util.DisplayMetrics;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.FileDescriptor;
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-import java.nio.ShortBuffer;
-
/**
* Creates Bitmap objects from various sources, including files, streams,
* and byte-arrays.
*/
public class BitmapFactory {
- private static final String TAG = "BitmapFactory";
- private static final boolean DEBUG_LOAD = false;
-
public static class Options {
/**
* Create a default Options object, which if left unchanged will give
@@ -45,6 +39,8 @@ public class BitmapFactory {
*/
public Options() {
inDither = true;
+ inDensity = 0;
+ inScaled = true;
}
/**
@@ -53,6 +49,7 @@ public class BitmapFactory {
* the bitmap without having to allocate the memory for its pixels.
*/
public boolean inJustDecodeBounds;
+
/**
* If set to a value > 1, requests the decoder to subsample the original
* image, returning a smaller image to save memory. The sample size is
@@ -80,20 +77,45 @@ public class BitmapFactory {
* image.
*/
public boolean inDither;
-
+
+ /**
+ * The desired pixel density of the bitmap.
+ *
+ * @see android.util.DisplayMetrics#DEFAULT_DENSITY
+ * @see android.util.DisplayMetrics#density
+ *
+ * @hide pending API council approval
+ */
+ public int inDensity;
+
+ /**
+ * </p>If the bitmap is loaded from {@link android.content.res.Resources} and
+ * this flag is turned on, the bitmap will be scaled to match the default
+ * display's pixel density.</p>
+ *
+ * </p>This flag is turned on by default and should be turned off if you need
+ * a non-scaled version of the bitmap. In this case,
+ * {@link android.graphics.Bitmap#setAutoScalingEnabled(boolean)} can be used
+ * to properly scale the bitmap at drawing time.</p>
+ *
+ * @hide pending API council approval
+ */
+ public boolean inScaled;
+
/**
* The resulting width of the bitmap, set independent of the state of
* inJustDecodeBounds. However, if there is an error trying to decode,
* outWidth will be set to -1.
*/
public int outWidth;
+
/**
* The resulting height of the bitmap, set independent of the state of
* inJustDecodeBounds. However, if there is an error trying to decode,
* outHeight will be set to -1.
*/
public int outHeight;
-
+
/**
* If known, this string is set to the mimetype of the decoded image.
* If not know, or there is an error, it is set to null.
@@ -103,7 +125,7 @@ public class BitmapFactory {
/**
* Temp storage to use for decoding. Suggest 16K or so.
*/
- public byte [] inTempStorage;
+ public byte[] inTempStorage;
private native void requestCancel();
@@ -175,6 +197,58 @@ public class BitmapFactory {
}
/**
+ * Decode a new Bitmap from an InputStream. This InputStream was obtained from
+ * resources, which we pass to be able to scale the bitmap accordingly.
+ *
+ * @hide
+ */
+ public static Bitmap decodeStream(Resources res, TypedValue value, InputStream is,
+ Rect pad, Options opts) {
+
+ if (opts == null) {
+ opts = new Options();
+ }
+
+ Bitmap bm = decodeStream(is, pad, opts);
+
+ if (bm != null && res != null && value != null) {
+ byte[] np = bm.getNinePatchChunk();
+ final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
+
+ final int density = value.density;
+ if (opts.inDensity == 0) {
+ opts.inDensity = density == TypedValue.DENSITY_DEFAULT ?
+ DisplayMetrics.DEFAULT_DENSITY : density;
+ }
+ float scale = opts.inDensity / (float) DisplayMetrics.DEFAULT_DENSITY;
+
+ if (opts.inScaled || isNinePatch) {
+ bm.setDensityScale(1.0f);
+ bm.setAutoScalingEnabled(false);
+ // Assume we are going to prescale for the screen
+ scale = res.getDisplayMetrics().density / scale;
+ if (scale != 1.0f) {
+ // TODO: This is very inefficient and should be done in native by Skia
+ final Bitmap oldBitmap = bm;
+ bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
+ (int) (bm.getHeight() * scale + 0.5f), true);
+ oldBitmap.recycle();
+
+ if (isNinePatch) {
+ np = nativeScaleNinePatch(np, scale, pad);
+ bm.setNinePatchChunk(np);
+ }
+ }
+ } else {
+ bm.setDensityScale(scale);
+ bm.setAutoScalingEnabled(true);
+ }
+ }
+
+ return bm;
+ }
+
+ /**
* Decode an image referenced by a resource ID.
*
* @param res The resources object containing the image data
@@ -189,11 +263,12 @@ public class BitmapFactory {
Bitmap bm = null;
try {
- InputStream is = res.openRawResource(id);
- bm = decodeStream(is, null, opts);
+ final TypedValue value = new TypedValue();
+ final InputStream is = res.openRawResource(id, value);
+
+ bm = decodeStream(res, value, is, null, opts);
is.close();
- }
- catch (java.io.IOException e) {
+ } catch (java.io.IOException e) {
/* do nothing.
If the exception happened on open, bm will be null.
If it happened on close, bm is still valid.
@@ -226,8 +301,7 @@ public class BitmapFactory {
* decoded, or, if opts is non-null, if opts requested only the
* size be returned (in opts.outWidth and opts.outHeight)
*/
- public static Bitmap decodeByteArray(byte[] data, int offset, int length,
- Options opts) {
+ public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
if ((offset | length) < 0 || data.length < offset + length) {
throw new ArrayIndexOutOfBoundsException();
}
@@ -265,8 +339,7 @@ public class BitmapFactory {
* decoded, or, if opts is non-null, if opts requested only the
* size be returned (in opts.outWidth and opts.outHeight)
*/
- public static Bitmap decodeStream(InputStream is, Rect outPadding,
- Options opts) {
+ public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
// we don't throw in this case, thus allowing the caller to only check
// the cache, and not force the image to be decoded.
if (is == null) {
@@ -287,11 +360,9 @@ public class BitmapFactory {
Bitmap bm;
if (is instanceof AssetManager.AssetInputStream) {
- bm = nativeDecodeAsset(
- ((AssetManager.AssetInputStream)is).getAssetInt(), outPadding,
- opts);
- }
- else {
+ bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),
+ outPadding, opts);
+ } else {
// pass some temp storage down to the native code. 1024 is made up,
// but should be large enough to avoid too many small calls back
// into is.read(...) This number is not related to the value passed
@@ -337,8 +408,7 @@ public class BitmapFactory {
* image should be completely decoded, or just is size returned.
* @return the decoded bitmap, or null
*/
- public static Bitmap decodeFileDescriptor(FileDescriptor fd,
- Rect outPadding, Options opts) {
+ public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
return nativeDecodeFileDescriptor(fd, outPadding, opts);
}
@@ -354,13 +424,13 @@ public class BitmapFactory {
return nativeDecodeFileDescriptor(fd, null, null);
}
- private static native Bitmap nativeDecodeStream(InputStream is,
- byte[] storage, Rect padding, Options opts);
+ private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
+ Rect padding, Options opts);
private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
- Rect padding, Options opts);
- private static native Bitmap nativeDecodeAsset(int asset, Rect padding,
- Options opts);
+ Rect padding, Options opts);
+ private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts);
private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
- int length, Options opts);
+ int length, Options opts);
+ private static native byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad);
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index b57f428..32ecd9f 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -50,6 +50,8 @@ public class Canvas {
// Used by native code
@SuppressWarnings({"UnusedDeclaration"})
private int mSurfaceFormat;
+ @SuppressWarnings({"UnusedDeclaration"})
+ private float mDensityScale = 1.0f;
/**
* Construct an empty raster canvas. Use setBitmap() to specify a bitmap to
@@ -74,6 +76,8 @@ public class Canvas {
throwIfRecycled(bitmap);
mNativeCanvas = initRaster(bitmap.ni());
mBitmap = bitmap;
+ mDensityScale = bitmap.getDensityScale();
+ if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f;
}
/*package*/ Canvas(int nativeCanvas) {
@@ -126,6 +130,8 @@ public class Canvas {
native_setBitmap(mNativeCanvas, bitmap.ni());
mBitmap = bitmap;
+ mDensityScale = bitmap.getDensityScale();
+ if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f;
}
/**
@@ -163,6 +169,51 @@ public class Canvas {
*/
public native int getHeight();
+ /**
+ * <p>Returns the density scale for this Canvas' backing bitmap, expressed as a
+ * factor of the default density (160dpi.) For instance, a bitmap designed for
+ * 240dpi displays will have a density scale of 1.5 whereas a bitmap
+ * designed for 160dpi will have a density scale of 1.0.</p>
+ *
+ * <p>The default density scale is {@link Bitmap#DENSITY_SCALE_UNKNOWN}.</p>
+ *
+ * @return A scaling factor of the default density (160dpi) or
+ * {@link Bitmap#DENSITY_SCALE_UNKNOWN} if the scaling factor is unknown.
+ *
+ * @see #setDensityScale(float)
+ * @see Bitmap#getDensityScale()
+ *
+ * @hide pending API council approval
+ */
+ public float getDensityScale() {
+ if (mBitmap != null) {
+ return mBitmap.getDensityScale();
+ }
+ return mDensityScale;
+ }
+
+ /**
+ * <p>Specifies the density scale for this Canvas' backing bitmap, expressed as a
+ * factor of the default density (160dpi.) For instance, a bitmap designed for
+ * 240dpi displays will have a density scale of 1.5 whereas a bitmap
+ * designed for 160dpi will have a density scale of 1.0.</p>
+ *
+ * @param densityScale The density scaling factor to use with this bitmap or
+ * {@link Bitmap#DENSITY_SCALE_UNKNOWN} if the factor is unknown.
+ *
+ * @see #getDensityScale()
+ * @see Bitmap#setDensityScale(float)
+ *
+ * @hide pending API council approval
+ */
+ public void setDensityScale(float densityScale) {
+ if (mBitmap != null) {
+ mBitmap.setDensityScale(densityScale);
+ }
+ mDensityScale = densityScale;
+ if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f;
+ }
+
// the SAVE_FLAG constants must match their native equivalents
/** restore the current matrix when restore() is called */
@@ -910,7 +961,8 @@ public class Canvas {
public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
throwIfRecycled(bitmap);
native_drawBitmap(mNativeCanvas, bitmap.ni(), left, top,
- paint != null ? paint.mNativePaint : 0);
+ paint != null ? paint.mNativePaint : 0, bitmap.isAutoScalingEnabled(),
+ bitmap.getDensityScale());
}
/**
@@ -982,8 +1034,8 @@ public class Canvas {
* be 0xFF for every pixel).
* @param paint May be null. The paint used to draw the bitmap
*/
- public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
- int width, int height, boolean hasAlpha,
+ public void drawBitmap(int[] colors, int offset, int stride, float x,
+ float y, int width, int height, boolean hasAlpha,
Paint paint) {
// check for valid input
if (width < 0) {
@@ -1006,11 +1058,20 @@ public class Canvas {
return;
}
// punch down to native for the actual draw
- native_drawBitmap(mNativeCanvas, colors, offset, stride, x, y,
- width, height, hasAlpha,
- paint != null ? paint.mNativePaint : 0);
+ native_drawBitmap(mNativeCanvas, colors, offset, stride, x, y, width, height, hasAlpha,
+ paint != null ? paint.mNativePaint : 0);
}
+ /** Legacy version of drawBitmap(int[] colors, ...) that took ints for x,y
+ */
+ public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
+ int width, int height, boolean hasAlpha,
+ Paint paint) {
+ // call through to the common float version
+ drawBitmap(colors, offset, stride, (float)x, (float)y, width, height,
+ hasAlpha, paint);
+ }
+
/**
* Draw the bitmap using the specified matrix.
*
@@ -1020,7 +1081,7 @@ public class Canvas {
*/
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
nativeDrawBitmapMatrix(mNativeCanvas, bitmap.ni(), matrix.ni(),
- paint != null ? paint.mNativePaint : 0);
+ paint != null ? paint.mNativePaint : 0);
}
private static void checkRange(int length, int offset, int count) {
@@ -1416,25 +1477,27 @@ public class Canvas {
float ry, int paint);
private static native void native_drawPath(int nativeCanvas, int path,
int paint);
- private static native void native_drawBitmap(int nativeCanvas, int bitmap,
+ private native void native_drawBitmap(int nativeCanvas, int bitmap,
float left, float top,
- int nativePaintOrZero);
- private static native void native_drawBitmap(int nativeCanvas, int bitmap,
+ int nativePaintOrZero, boolean autoScale,
+ float densityScale);
+ private native void native_drawBitmap(int nativeCanvas, int bitmap,
Rect src, RectF dst,
int nativePaintOrZero);
private static native void native_drawBitmap(int nativeCanvas, int bitmap,
Rect src, Rect dst,
int nativePaintOrZero);
private static native void native_drawBitmap(int nativeCanvas, int[] colors,
- int offset, int stride, int x,
- int y, int width, int height,
+ int offset, int stride, float x,
+ float y, int width, int height,
boolean hasAlpha,
int nativePaintOrZero);
private static native void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
int nMatrix, int nPaint);
private static native void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
- int meshWidth, int meshHeight, float[] verts, int vertOffset,
- int[] colors, int colorOffset, int nPaint);
+ int meshWidth, int meshHeight,
+ float[] verts, int vertOffset,
+ int[] colors, int colorOffset, int nPaint);
private static native void nativeDrawVertices(int nCanvas, int mode, int n,
float[] verts, int vertOffset, float[] texs, int texOffset,
int[] colors, int colorOffset, short[] indices,
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index cabd848..2b24ef2 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -26,10 +26,10 @@ package android.graphics;
* way that you define, when content added within the image exceeds the normal
* bounds of the graphic. For a thorough explanation of a NinePatch image,
* read the discussion in the
- * <a href="{@docRoot}reference/available-resources.html#ninepatch">Available
- * Resource Types</a> document.
+ * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D
+ * Graphics</a> document.
* <p>
- * The <a href="{@docRoot}reference/draw9patch.html">Draw 9-patch</a>
+ * The <a href="{@docRoot}guide/developing/tools/draw9patch.html">Draw 9-Patch</a>
* tool offers an extremely handy way to create your NinePatch images,
* using a WYSIWYG graphics editor.
* </p>
@@ -50,6 +50,17 @@ public class NinePatch {
validateNinePatchChunk(mBitmap.ni(), chunk);
}
+ /**
+ * @hide
+ */
+ public NinePatch(NinePatch patch) {
+ mBitmap = patch.mBitmap;
+ mChunk = patch.mChunk;
+ mSrcName = patch.mSrcName;
+ mPaint = new Paint(patch.mPaint);
+ validateNinePatchChunk(mBitmap.ni(), mChunk);
+ }
+
public void setPaint(Paint p) {
mPaint = p;
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 6fac969..81980d9 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -109,13 +109,13 @@ public class Paint {
*/
BUTT (0),
/**
- * The stroke projects out as a square, with the center at the end
- * of the path.
+ * The stroke projects out as a semicircle, with the center at the
+ * end of the path.
*/
ROUND (1),
/**
- * The stroke projects out as a semicircle, with the center at the
- * end of the path.
+ * The stroke projects out as a square, with the center at the end
+ * of the path.
*/
SQUARE (2);
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index c6b772e..bab1703 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -74,6 +74,7 @@ import android.util.AttributeSet;
public class AnimationDrawable extends DrawableContainer implements Runnable {
private final AnimationState mAnimationState;
private int mCurFrame = -1;
+ private boolean mMutated;
public AnimationDrawable() {
this(null);
@@ -283,6 +284,15 @@ public class AnimationDrawable extends DrawableContainer implements Runnable {
setFrame(0, true, false);
}
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mAnimationState.mDurations = mAnimationState.mDurations.clone();
+ mMutated = true;
+ }
+ return this;
+ }
+
private final static class AnimationState extends DrawableContainerState {
private int[] mDurations;
private boolean mOneShot;
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 7f3df9a..5b32246 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -28,6 +28,7 @@ import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.BitmapShader;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.view.Gravity;
import org.xmlpull.v1.XmlPullParser;
@@ -62,9 +63,12 @@ public class BitmapDrawable extends Drawable {
private boolean mApplyGravity;
private boolean mRebuildShader;
+ private int mBitmapWidth;
+ private int mBitmapHeight;
+ private boolean mMutated;
public BitmapDrawable() {
- mBitmapState = new BitmapState(null);
+ mBitmapState = new BitmapState((Bitmap) null);
}
public BitmapDrawable(Bitmap bitmap) {
@@ -92,7 +96,62 @@ public class BitmapDrawable extends Drawable {
public final Bitmap getBitmap() {
return mBitmap;
}
-
+
+ private void setBitmap(Bitmap bitmap) {
+ mBitmap = bitmap;
+ if (bitmap != null) {
+ mBitmapWidth = bitmap.getWidth();
+ mBitmapHeight = bitmap.getHeight();
+ } else {
+ mBitmapWidth = mBitmapHeight = -1;
+ }
+ }
+
+ /**
+ * Set the density scale at which this drawable will be rendered. This
+ * method assumes the drawable will be rendered at the same density as the
+ * specified canvas.
+ *
+ * @param canvas The Canvas from which the density scale must be obtained.
+ *
+ * @see android.graphics.Bitmap#setDensityScale(float)
+ * @see android.graphics.Bitmap#getDensityScale()
+ *
+ * @hide pending API council approval
+ */
+ public void setDensityScale(Canvas canvas) {
+ setDensityScale(canvas.getDensityScale());
+ }
+
+ /**
+ * Set the density scale at which this drawable will be rendered.
+ *
+ * @param metrics The DisplayMetrics indicating the density scale for this drawable.
+ *
+ * @see android.graphics.Bitmap#setDensityScale(float)
+ * @see android.graphics.Bitmap#getDensityScale()
+ *
+ * @hide pending API council approval
+ */
+ public void setDensityScale(DisplayMetrics metrics) {
+ setDensityScale(metrics.density);
+ }
+
+ /**
+ * Set the density scale at which this drawable will be rendered.
+ *
+ * @param density The density scale for this drawable.
+ *
+ * @see android.graphics.Bitmap#setDensityScale(float)
+ * @see android.graphics.Bitmap#getDensityScale()
+ *
+ * @hide pending API council approval
+ */
+ public void setDensityScale(float density) {
+ density = (density == Bitmap.DENSITY_SCALE_UNKNOWN ? 1.0f : density);
+ mBitmapState.mTargetDensityScale = density;
+ }
+
/** Get the gravity used to position/stretch the bitmap within its bounds.
See android.view.Gravity
* @return the gravity applied to the bitmap
@@ -184,7 +243,7 @@ public class BitmapDrawable extends Drawable {
Shader shader = state.mPaint.getShader();
if (shader == null) {
if (mApplyGravity) {
- Gravity.apply(state.mGravity, bitmap.getWidth(), bitmap.getHeight(),
+ Gravity.apply(state.mGravity, mBitmapWidth, mBitmapHeight,
getBounds(), mDstRect);
mApplyGravity = false;
}
@@ -209,6 +268,21 @@ public class BitmapDrawable extends Drawable {
mBitmapState.mPaint.setColorFilter(cf);
}
+ /**
+ * A mutable BitmapDrawable still shares its Bitmap with any other Drawable
+ * that comes from the same resource.
+ *
+ * @return This drawable.
+ */
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mBitmapState = new BitmapState(mBitmapState);
+ mMutated = true;
+ }
+ return this;
+ }
+
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
throws XmlPullParserException, IOException {
@@ -226,7 +300,9 @@ public class BitmapDrawable extends Drawable {
throw new XmlPullParserException(parser.getPositionDescription() +
": <bitmap> requires a valid src attribute");
}
- mBitmapState.mBitmap = mBitmap = bitmap;
+ mBitmapState.mBitmap = bitmap;
+ setBitmap(bitmap);
+ setDensityScale(r.getDisplayMetrics());
final Paint paint = mBitmapState.mPaint;
paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias,
@@ -256,14 +332,29 @@ public class BitmapDrawable extends Drawable {
@Override
public int getIntrinsicWidth() {
- Bitmap bitmap = mBitmap;
- return bitmap != null ? bitmap.getWidth() : -1;
+ final Bitmap bitmap = mBitmap;
+ final BitmapState state = mBitmapState;
+
+ if (!state.mAutoScale || state.mBitmapScale == Bitmap.DENSITY_SCALE_UNKNOWN) {
+ return mBitmapWidth;
+ } else {
+ return bitmap != null ? (int) (mBitmapWidth /
+ (state.mBitmapScale / state.mTargetDensityScale) + 0.5f) : -1;
+
+ }
}
@Override
public int getIntrinsicHeight() {
- Bitmap bitmap = mBitmap;
- return bitmap != null ? bitmap.getHeight() : -1;
+ final Bitmap bitmap = mBitmap;
+ final BitmapState state = mBitmapState;
+
+ if (!state.mAutoScale || state.mBitmapScale == Bitmap.DENSITY_SCALE_UNKNOWN) {
+ return mBitmapHeight;
+ } else {
+ return bitmap != null ? (int) (mBitmapHeight /
+ (state.mBitmapScale / state.mTargetDensityScale) + 0.5f) : -1;
+ }
}
@Override
@@ -289,9 +380,29 @@ public class BitmapDrawable extends Drawable {
Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
Shader.TileMode mTileModeX;
Shader.TileMode mTileModeY;
+ boolean mAutoScale;
+ float mBitmapScale;
+ float mTargetDensityScale = 1.0f;
BitmapState(Bitmap bitmap) {
mBitmap = bitmap;
+ if (bitmap != null) {
+ mBitmapScale = bitmap.getDensityScale();
+ mAutoScale = bitmap.isAutoScalingEnabled();
+ } else {
+ mBitmapScale = 1.0f;
+ mAutoScale = false;
+ }
+ }
+
+ BitmapState(BitmapState bitmapState) {
+ this(bitmapState.mBitmap);
+ mChangingConfigurations = bitmapState.mChangingConfigurations;
+ mGravity = bitmapState.mGravity;
+ mTileModeX = bitmapState.mTileModeX;
+ mTileModeY = bitmapState.mTileModeY;
+ mTargetDensityScale = bitmapState.mTargetDensityScale;
+ mPaint = new Paint(bitmapState.mPaint);
}
@Override
@@ -307,6 +418,6 @@ public class BitmapDrawable extends Drawable {
private BitmapDrawable(BitmapState state) {
mBitmapState = state;
- mBitmap = state.mBitmap;
+ setBitmap(state.mBitmap);
}
}
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 6029388..95d4dd0 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -24,7 +24,6 @@ import android.content.res.TypedArray;
import android.graphics.*;
import android.view.Gravity;
import android.util.AttributeSet;
-import android.util.Log;
import java.io.IOException;
@@ -100,9 +99,8 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
mClipState.mDrawable = dr;
mClipState.mOrientation = orientation;
mClipState.mGravity = g;
- if (dr != null) {
- dr.setCallback(this);
- }
+
+ dr.setCallback(this);
}
// overrides from Drawable.Callback
@@ -168,8 +166,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
@Override
protected boolean onStateChange(int[] state) {
- boolean changed = mClipState.mDrawable.setState(state);
- return changed;
+ return mClipState.mDrawable.setState(state);
}
@Override
@@ -233,7 +230,17 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
return null;
}
+
+
final static class ClipState extends ConstantState {
+ Drawable mDrawable;
+ int mChangingConfigurations;
+ int mOrientation;
+ int mGravity;
+
+ private boolean mCheckedConstantState;
+ private boolean mCanConstantState;
+
ClipState(ClipState orig, ClipDrawable owner) {
if (orig != null) {
mDrawable = orig.mDrawable.getConstantState().newDrawable();
@@ -262,14 +269,6 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
return mCanConstantState;
}
-
- Drawable mDrawable;
- int mChangingConfigurations;
- int mOrientation;
- int mGravity;
-
- private boolean mCheckedConstantState;
- private boolean mCanConstantState;
}
private ClipDrawable(ClipState state) {
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 0021241..42e28e8 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -29,6 +29,7 @@ import android.graphics.*;
import android.util.AttributeSet;
import android.util.StateSet;
import android.util.Xml;
+import android.util.TypedValue;
/**
* A Drawable is a general abstraction for "something that can be drawn." Most
@@ -91,7 +92,7 @@ import android.util.Xml;
* whose overall size is modified based on the current level.
* </ul>
* <p>For information and examples of creating drawable resources (XML or bitmap files that
- * can be loaded in code), see <a href="{@docRoot}devel/resources-i18n.html">Resources
+ * can be loaded in code), see <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources
* and Internationalization</a>.
*/
public abstract class Drawable {
@@ -102,7 +103,7 @@ public abstract class Drawable {
private Rect mBounds = new Rect();
/*package*/ Callback mCallback = null;
private boolean mVisible = true;
-
+
/**
* Draw in its bounds (set via setBounds) respecting optional effects such
* as alpha (set via setAlpha) and color filter (set via setColorFilter).
@@ -618,9 +619,36 @@ public abstract class Drawable {
}
/**
+ * Make this drawable mutable. This operation cannot be reversed. A mutable
+ * drawable is guaranteed to not share its state with any other drawable.
+ * This is especially useful when you need to modify properties of drawables
+ * loaded from resources. By default, all drawables instances loaded from
+ * the same resource share a common state; if you modify the state of one
+ * instance, all the other instances will receive the same modification.
+ *
+ * Calling this method on a mutable Drawable will have no effect.
+ *
+ * @return This drawable.
+ */
+ public Drawable mutate() {
+ return this;
+ }
+
+ /**
* Create a drawable from an inputstream
*/
public static Drawable createFromStream(InputStream is, String srcName) {
+ return createFromResourceStream(null, null, is, srcName);
+ }
+
+ /**
+ * Create a drawable from an inputstream
+ *
+ * @hide pending API council approval
+ */
+ public static Drawable createFromResourceStream(Resources res, TypedValue value,
+ InputStream is, String srcName) {
+
if (is == null) {
return null;
}
@@ -632,14 +660,14 @@ public abstract class Drawable {
Rects only to drop them on the floor.
*/
Rect pad = new Rect();
- Bitmap bm = BitmapFactory.decodeStream(is, pad, null);
+ Bitmap bm = BitmapFactory.decodeStream(res, value, is, pad, null);
if (bm != null) {
byte[] np = bm.getNinePatchChunk();
if (np == null || !NinePatch.isNinePatchChunk(np)) {
np = null;
pad = null;
}
- return drawableFromBitmap(bm, np, pad, srcName);
+ return drawableFromBitmap(res, bm, np, pad, srcName);
}
return null;
}
@@ -647,7 +675,7 @@ public abstract class Drawable {
/**
* Create a drawable from an XML document. For more information on how to
* create resources in XML, see
- * <a href="{@docRoot}devel/resources-i18n.html">Resources and
+ * <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources and
* Internationalization</a>.
*/
public static Drawable createFromXml(Resources r, XmlPullParser parser)
@@ -708,6 +736,11 @@ public abstract class Drawable {
drawable = new InsetDrawable();
} else if (name.equals("bitmap")) {
drawable = new BitmapDrawable();
+ if (r != null) {
+ ((BitmapDrawable) drawable).setDensityScale(r.getDisplayMetrics());
+ }
+ } else if (name.equals("nine-patch")) {
+ drawable = new NinePatchDrawable();
} else {
throw new XmlPullParserException(parser.getPositionDescription() +
": invalid drawable tag " + name);
@@ -728,7 +761,7 @@ public abstract class Drawable {
Bitmap bm = BitmapFactory.decodeFile(pathName);
if (bm != null) {
- return drawableFromBitmap(bm, null, null, pathName);
+ return drawableFromBitmap(null, bm, null, null, pathName);
}
return null;
@@ -758,11 +791,19 @@ public abstract class Drawable {
return null;
}
- private static Drawable drawableFromBitmap(Bitmap bm, byte[] np, Rect pad, String srcName) {
+ private static Drawable drawableFromBitmap(Resources res, Bitmap bm, byte[] np,
+ Rect pad, String srcName) {
+
if (np != null) {
return new NinePatchDrawable(bm, np, pad, srcName);
}
- return new BitmapDrawable(bm);
+
+ final BitmapDrawable drawable = new BitmapDrawable(bm);
+ if (res != null) {
+ drawable.setDensityScale(res.getDisplayMetrics());
+ }
+
+ return drawable;
}
}
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index e6c48be..29f2a00 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -21,12 +21,13 @@ import android.graphics.*;
public class DrawableContainer extends Drawable implements Drawable.Callback {
private DrawableContainerState mDrawableContainerState;
- private Drawable mCurrDrawable;
- private int mAlpha = 0xFF;
- private ColorFilter mColorFilter;
- private boolean mDither;
+ private Drawable mCurrDrawable;
+ private int mAlpha = 0xFF;
+ private ColorFilter mColorFilter;
+ private boolean mDither;
- private int mCurIndex = -1;
+ private int mCurIndex = -1;
+ private boolean mMutated;
// overrides from Drawable
@@ -229,6 +230,17 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
return null;
}
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ for (Drawable child : mDrawableContainerState.mDrawables) {
+ child.mutate();
+ }
+ mMutated = true;
+ }
+ return this;
+ }
+
public abstract static class DrawableContainerState extends ConstantState {
final DrawableContainer mOwner;
@@ -277,7 +289,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
mCheckedConstantState = mCanConstantState = true;
mVariablePadding = orig.mVariablePadding;
- mConstantPadding = orig.mConstantPadding;
+ if (orig.mConstantPadding != null) {
+ mConstantPadding = new Rect(orig.mConstantPadding);
+ }
mConstantSize = orig.mConstantSize;
mComputedConstantSize = orig.mComputedConstantSize;
mConstantWidth = orig.mConstantWidth;
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index cdfca1b..3db45f0 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -47,7 +47,9 @@ import java.io.IOException;
* @attr ref android.R.styleable#GradientDrawable_visible
* @attr ref android.R.styleable#GradientDrawable_shape
* @attr ref android.R.styleable#GradientDrawable_innerRadiusRatio
+ * @attr ref android.R.styleable#GradientDrawable_innerRadius
* @attr ref android.R.styleable#GradientDrawable_thicknessRatio
+ * @attr ref android.R.styleable#GradientDrawable_thickness
* @attr ref android.R.styleable#GradientDrawable_useLevel
* @attr ref android.R.styleable#GradientDrawableSize_width
* @attr ref android.R.styleable#GradientDrawableSize_height
@@ -106,20 +108,23 @@ public class GradientDrawable extends Drawable {
*/
public static final int SWEEP_GRADIENT = 2;
- private final GradientState mGradientState;
+ private GradientState mGradientState;
private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- private Rect mPadding;
- private Paint mStrokePaint; // optional, set by the caller
+ private Rect mPadding;
+ private Paint mStrokePaint; // optional, set by the caller
private ColorFilter mColorFilter; // optional, set by the caller
- private int mAlpha = 0xFF; // modified by the caller
- private boolean mDither;
+ private int mAlpha = 0xFF; // modified by the caller
+ private boolean mDither;
- private final Path mPath = new Path();
+ private final Path mPath = new Path();
private final RectF mRect = new RectF();
- private Paint mLayerPaint; // internal, used if we use saveLayer()
- private boolean mRectIsDirty; // internal state
+ private Paint mLayerPaint; // internal, used if we use saveLayer()
+ private boolean mRectIsDirty; // internal state
+ private boolean mMutated;
+ private Path mRingPath;
+ private boolean mPathIsDirty;
/**
* Controls how the gradient is oriented relative to the drawable's bounds
@@ -212,6 +217,7 @@ public class GradientDrawable extends Drawable {
}
public void setShape(int shape) {
+ mRingPath = null;
mGradientState.setShape(shape);
}
@@ -247,14 +253,12 @@ public class GradientDrawable extends Drawable {
// remember the alpha values, in case we temporarily overwrite them
// when we modulate them with mAlpha
final int prevFillAlpha = mFillPaint.getAlpha();
- final int prevStrokeAlpha = mStrokePaint != null ?
- mStrokePaint.getAlpha() : 0;
+ final int prevStrokeAlpha = mStrokePaint != null ? mStrokePaint.getAlpha() : 0;
// compute the modulate alpha values
final int currFillAlpha = modulateAlpha(prevFillAlpha);
final int currStrokeAlpha = modulateAlpha(prevStrokeAlpha);
- final boolean haveStroke = currStrokeAlpha > 0 &&
- mStrokePaint.getStrokeWidth() > 0;
+ final boolean haveStroke = currStrokeAlpha > 0 && mStrokePaint.getStrokeWidth() > 0;
final boolean haveFill = currFillAlpha > 0;
final GradientState st = mGradientState;
/* we need a layer iff we're drawing both a fill and stroke, and the
@@ -263,7 +267,7 @@ public class GradientDrawable extends Drawable {
of the fill (if any) without worrying about blending artifacts.
*/
final boolean useLayer = haveStroke && haveFill && st.mShape != LINE &&
- currStrokeAlpha < 255;
+ currStrokeAlpha < 255;
/* Drawing with a layer is slower than direct drawing, but it
allows us to apply paint effects like alpha and colorfilter to
@@ -335,10 +339,10 @@ public class GradientDrawable extends Drawable {
break;
}
case RING:
- Path ring = buildRing(st);
- canvas.drawPath(ring, mFillPaint);
+ Path path = buildRing(st);
+ canvas.drawPath(path, mFillPaint);
if (haveStroke) {
- canvas.drawPath(ring, mStrokePaint);
+ canvas.drawPath(path, mStrokePaint);
}
break;
}
@@ -354,6 +358,9 @@ public class GradientDrawable extends Drawable {
}
private Path buildRing(GradientState st) {
+ if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
+ mPathIsDirty = false;
+
float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;
RectF bounds = new RectF(mRect);
@@ -361,9 +368,11 @@ public class GradientDrawable extends Drawable {
float x = bounds.width() / 2.0f;
float y = bounds.height() / 2.0f;
- float thickness = bounds.width() / st.mThickness;
+ float thickness = st.mThickness != -1 ?
+ st.mThickness : bounds.width() / st.mThicknessRatio;
// inner radius
- float radius = bounds.width() / st.mInnerRadius;
+ float radius = st.mInnerRadius != -1 ?
+ st.mInnerRadius : bounds.width() / st.mInnerRadiusRatio;
RectF innerBounds = new RectF(bounds);
innerBounds.inset(x - radius, y - radius);
@@ -371,27 +380,33 @@ public class GradientDrawable extends Drawable {
bounds = new RectF(innerBounds);
bounds.inset(-thickness, -thickness);
- Path path = new Path();
+ if (mRingPath == null) {
+ mRingPath = new Path();
+ } else {
+ mRingPath.reset();
+ }
+
+ final Path ringPath = mRingPath;
// arcTo treats the sweep angle mod 360, so check for that, since we
// think 360 means draw the entire oval
if (sweep < 360 && sweep > -360) {
- path.setFillType(Path.FillType.EVEN_ODD);
+ ringPath.setFillType(Path.FillType.EVEN_ODD);
// inner top
- path.moveTo(x + radius, y);
+ ringPath.moveTo(x + radius, y);
// outer top
- path.lineTo(x + radius + thickness, y);
+ ringPath.lineTo(x + radius + thickness, y);
// outer arc
- path.arcTo(bounds, 0.0f, sweep, false);
+ ringPath.arcTo(bounds, 0.0f, sweep, false);
// inner arc
- path.arcTo(innerBounds, sweep, -sweep, false);
- path.close();
+ ringPath.arcTo(innerBounds, sweep, -sweep, false);
+ ringPath.close();
} else {
// add the entire ovals
- path.addOval(bounds, Path.Direction.CW);
- path.addOval(innerBounds, Path.Direction.CCW);
+ ringPath.addOval(bounds, Path.Direction.CW);
+ ringPath.addOval(innerBounds, Path.Direction.CCW);
}
- return path;
+ return ringPath;
}
public void setColor(int argb) {
@@ -429,6 +444,8 @@ public class GradientDrawable extends Drawable {
@Override
protected void onBoundsChange(Rect r) {
super.onBoundsChange(r);
+ mRingPath = null;
+ mPathIsDirty = true;
mRectIsDirty = true;
}
@@ -436,6 +453,7 @@ public class GradientDrawable extends Drawable {
protected boolean onLevelChange(int level) {
super.onLevelChange(level);
mRectIsDirty = true;
+ mPathIsDirty = true;
invalidateSelf();
return true;
}
@@ -461,8 +479,9 @@ public class GradientDrawable extends Drawable {
mRect.set(bounds.left + inset, bounds.top + inset,
bounds.right - inset, bounds.bottom - inset);
-
- if (st.mColors != null) {
+
+ final int[] colors = st.mColors;
+ if (colors != null) {
RectF r = mRect;
float x0, x1, y0, y1;
@@ -504,8 +523,7 @@ public class GradientDrawable extends Drawable {
}
mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1,
- st.mColors, st.mPositions,
- Shader.TileMode.CLAMP));
+ colors, st.mPositions, Shader.TileMode.CLAMP));
} else if (st.mGradient == RADIAL_GRADIENT) {
x0 = r.left + (r.right - r.left) * st.mCenterX;
y0 = r.top + (r.bottom - r.top) * st.mCenterY;
@@ -513,30 +531,38 @@ public class GradientDrawable extends Drawable {
final float level = st.mUseLevel ? (float) getLevel() / 10000.0f : 1.0f;
mFillPaint.setShader(new RadialGradient(x0, y0,
- level * st.mGradientRadius, st.mColors, null,
+ level * st.mGradientRadius, colors, null,
Shader.TileMode.CLAMP));
} else if (st.mGradient == SWEEP_GRADIENT) {
x0 = r.left + (r.right - r.left) * st.mCenterX;
y0 = r.top + (r.bottom - r.top) * st.mCenterY;
- float[] positions = null;
- int[] colors = st.mColors;
+ int[] tempColors = colors;
+ float[] tempPositions = null;
if (st.mUseLevel) {
- final int length = st.mColors.length;
- colors = new int[length + 1];
- System.arraycopy(st.mColors, 0, colors, 0, length);
- colors[length] = st.mColors[length - 1];
+ tempColors = st.mTempColors;
+ final int length = colors.length;
+ if (tempColors == null || tempColors.length != length + 1) {
+ tempColors = st.mTempColors = new int[length + 1];
+ }
+ System.arraycopy(colors, 0, tempColors, 0, length);
+ tempColors[length] = colors[length - 1];
+ tempPositions = st.mTempPositions;
final float fraction = 1.0f / (float) (length - 1);
- positions = new float[length + 1];
+ if (tempPositions == null || tempPositions.length != length + 1) {
+ tempPositions = st.mTempPositions = new float[length + 1];
+ }
+
final float level = (float) getLevel() / 10000.0f;
for (int i = 0; i < length; i++) {
- positions[i] = i * fraction * level;
+ tempPositions[i] = i * fraction * level;
}
- positions[length] = 1.0f;
+ tempPositions[length] = 1.0f;
+
}
- mFillPaint.setShader(new SweepGradient(x0, y0, colors, positions));
+ mFillPaint.setShader(new SweepGradient(x0, y0, tempColors, tempPositions));
}
}
}
@@ -560,10 +586,18 @@ public class GradientDrawable extends Drawable {
com.android.internal.R.styleable.GradientDrawable_shape, RECTANGLE);
if (shapeType == RING) {
- st.mInnerRadius = a.getFloat(
- com.android.internal.R.styleable.GradientDrawable_innerRadiusRatio, 3.0f);
- st.mThickness = a.getFloat(
- com.android.internal.R.styleable.GradientDrawable_thicknessRatio, 9.0f);
+ st.mInnerRadius = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.GradientDrawable_innerRadius, -1);
+ if (st.mInnerRadius == -1) {
+ st.mInnerRadiusRatio = a.getFloat(
+ com.android.internal.R.styleable.GradientDrawable_innerRadiusRatio, 3.0f);
+ }
+ st.mThickness = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.GradientDrawable_thickness, -1);
+ if (st.mThickness == -1) {
+ st.mThicknessRatio = a.getFloat(
+ com.android.internal.R.styleable.GradientDrawable_thicknessRatio, 9.0f);
+ }
st.mUseLevelForShape = a.getBoolean(
com.android.internal.R.styleable.GradientDrawable_useLevel, true);
}
@@ -791,31 +825,45 @@ public class GradientDrawable extends Drawable {
return mGradientState;
}
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mGradientState = new GradientState(mGradientState);
+ initializeWithState(mGradientState);
+ mMutated = true;
+ }
+ return this;
+ }
+
final static class GradientState extends ConstantState {
- public int mChangingConfigurations;
- public int mShape = RECTANGLE;
- public int mGradient = LINEAR_GRADIENT;
- public Orientation mOrientation;
- public int[] mColors;
- public float[] mPositions;
- public boolean mHasSolidColor;
- public int mSolidColor;
- public int mStrokeWidth = -1; // if >= 0 use stroking.
- public int mStrokeColor;
- public float mStrokeDashWidth;
- public float mStrokeDashGap;
- public float mRadius; // use this if mRadiusArray is null
- public float[] mRadiusArray;
- public Rect mPadding;
- public int mWidth = -1;
- public int mHeight = -1;
- public float mInnerRadius;
- public float mThickness;
- private float mCenterX = 0.5f;
- private float mCenterY = 0.5f;
- private float mGradientRadius = 0.5f;
- private boolean mUseLevel;
- private boolean mUseLevelForShape;
+ public int mChangingConfigurations;
+ public int mShape = RECTANGLE;
+ public int mGradient = LINEAR_GRADIENT;
+ public Orientation mOrientation;
+ public int[] mColors;
+ public int[] mTempColors; // no need to copy
+ public float[] mTempPositions; // no need to copy
+ public float[] mPositions;
+ public boolean mHasSolidColor;
+ public int mSolidColor;
+ public int mStrokeWidth = -1; // if >= 0 use stroking.
+ public int mStrokeColor;
+ public float mStrokeDashWidth;
+ public float mStrokeDashGap;
+ public float mRadius; // use this if mRadiusArray is null
+ public float[] mRadiusArray;
+ public Rect mPadding;
+ public int mWidth = -1;
+ public int mHeight = -1;
+ public float mInnerRadiusRatio;
+ public float mThicknessRatio;
+ public int mInnerRadius;
+ public int mThickness;
+ private float mCenterX = 0.5f;
+ private float mCenterY = 0.5f;
+ private float mGradientRadius = 0.5f;
+ private boolean mUseLevel;
+ private boolean mUseLevelForShape;
GradientState() {
@@ -827,6 +875,40 @@ public class GradientDrawable extends Drawable {
mColors = colors;
}
+ public GradientState(GradientState state) {
+ mChangingConfigurations = state.mChangingConfigurations;
+ mShape = state.mShape;
+ mGradient = state.mGradient;
+ mOrientation = state.mOrientation;
+ mColors = state.mColors.clone();
+ if (state.mPositions != null) {
+ mPositions = state.mPositions.clone();
+ }
+ mHasSolidColor = state.mHasSolidColor;
+ mStrokeWidth = state.mStrokeWidth;
+ mStrokeColor = state.mStrokeColor;
+ mStrokeDashWidth = state.mStrokeDashWidth;
+ mStrokeDashGap = state.mStrokeDashGap;
+ mRadius = state.mRadius;
+ if (state.mRadiusArray != null) {
+ mRadiusArray = state.mRadiusArray.clone();
+ }
+ if (state.mPadding != null) {
+ mPadding = new Rect(state.mPadding);
+ }
+ mWidth = state.mWidth;
+ mHeight = state.mHeight;
+ mInnerRadiusRatio = state.mInnerRadiusRatio;
+ mThicknessRatio = state.mThicknessRatio;
+ mInnerRadius = state.mInnerRadius;
+ mThickness = state.mThickness;
+ mCenterX = state.mCenterX;
+ mCenterY = state.mCenterY;
+ mGradientRadius = state.mGradientRadius;
+ mUseLevel = state.mUseLevel;
+ mUseLevelForShape = state.mUseLevelForShape;
+ }
+
@Override
public Drawable newDrawable() {
return new GradientDrawable(this);
@@ -895,6 +977,11 @@ public class GradientDrawable extends Drawable {
private GradientDrawable(GradientState state) {
mGradientState = state;
+ initializeWithState(state);
+ mRectIsDirty = true;
+ }
+
+ private void initializeWithState(GradientState state) {
if (state.mHasSolidColor) {
mFillPaint.setColor(state.mSolidColor);
}
@@ -906,12 +993,11 @@ public class GradientDrawable extends Drawable {
mStrokePaint.setColor(state.mStrokeColor);
if (state.mStrokeDashWidth != 0.0f) {
- DashPathEffect e = new DashPathEffect(new float[] {
- state.mStrokeDashWidth, state.mStrokeDashGap}, 0);
+ DashPathEffect e = new DashPathEffect(
+ new float[] { state.mStrokeDashWidth, state.mStrokeDashGap }, 0);
mStrokePaint.setPathEffect(e);
}
}
- mRectIsDirty = true;
}
}
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 80b8e96..6047726 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -44,6 +44,9 @@ import java.io.IOException;
public class InsetDrawable extends Drawable implements Drawable.Callback
{
// Most of this is copied from ScaleDrawable.
+ private InsetState mInsetState;
+ private final Rect mTmpRect = new Rect();
+ private boolean mMutated;
/*package*/ InsetDrawable() {
this(null);
@@ -239,7 +242,27 @@ public class InsetDrawable extends Drawable implements Drawable.Callback
return null;
}
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mInsetState.mDrawable.mutate();
+ mMutated = true;
+ }
+ return this;
+ }
+
final static class InsetState extends ConstantState {
+ Drawable mDrawable;
+ int mChangingConfigurations;
+
+ int mInsetLeft;
+ int mInsetTop;
+ int mInsetRight;
+ int mInsetBottom;
+
+ boolean mCheckedConstantState;
+ boolean mCanConstantState;
+
InsetState(InsetState orig, InsetDrawable owner) {
if (orig != null) {
mDrawable = orig.mDrawable.getConstantState().newDrawable();
@@ -270,25 +293,10 @@ public class InsetDrawable extends Drawable implements Drawable.Callback
return mCanConstantState;
}
-
- Drawable mDrawable;
- int mChangingConfigurations;
-
- int mInsetLeft;
- int mInsetTop;
- int mInsetRight;
- int mInsetBottom;
-
- boolean mCheckedConstantState;
- boolean mCanConstantState;
}
private InsetDrawable(InsetState state) {
- InsetState as = new InsetState(state, this);
- mInsetState = as;
+ mInsetState = new InsetState(state, this);
}
-
- private InsetState mInsetState;
- private final Rect mTmpRect = new Rect();
}
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 59dfbd4..c777205 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -51,6 +51,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
private int[] mPaddingB;
private final Rect mTmpRect = new Rect();
+ private boolean mMutated;
/**
* Create a new layer drawable with the list of specified layers.
@@ -71,16 +72,16 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
LayerDrawable(Drawable[] layers, LayerState state) {
this(state);
int length = layers.length;
- Rec[] r = new Rec[length];
+ ChildDrawable[] r = new ChildDrawable[length];
for (int i = 0; i < length; i++) {
- r[i] = new Rec();
+ r[i] = new ChildDrawable();
r[i].mDrawable = layers[i];
layers[i].setCallback(this);
mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations();
}
mLayerState.mNum = length;
- mLayerState.mArray = r;
+ mLayerState.mChildren = r;
ensurePadding();
}
@@ -171,26 +172,26 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
*/
private void addLayer(Drawable layer, int id, int left, int top, int right, int bottom) {
final LayerState st = mLayerState;
- int N = st.mArray != null ? st.mArray.length : 0;
+ int N = st.mChildren != null ? st.mChildren.length : 0;
int i = st.mNum;
if (i >= N) {
- Rec[] nu = new Rec[N + 10];
+ ChildDrawable[] nu = new ChildDrawable[N + 10];
if (i > 0) {
- System.arraycopy(st.mArray, 0, nu, 0, i);
+ System.arraycopy(st.mChildren, 0, nu, 0, i);
}
- st.mArray = nu;
+ st.mChildren = nu;
}
mLayerState.mChildrenChangingConfigurations |= layer.getChangingConfigurations();
- Rec rec = new Rec();
- st.mArray[i] = rec;
- rec.mId = id;
- rec.mDrawable = layer;
- rec.mInsetL = left;
- rec.mInsetT = top;
- rec.mInsetR = right;
- rec.mInsetB = bottom;
+ ChildDrawable childDrawable = new ChildDrawable();
+ st.mChildren[i] = childDrawable;
+ childDrawable.mId = id;
+ childDrawable.mDrawable = layer;
+ childDrawable.mInsetL = left;
+ childDrawable.mInsetT = top;
+ childDrawable.mInsetR = right;
+ childDrawable.mInsetB = bottom;
st.mNum++;
layer.setCallback(this);
@@ -203,7 +204,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
* @return The {@link Drawable} of the layer that has the given id in the hierarchy or null.
*/
public Drawable findDrawableByLayerId(int id) {
- final Rec[] layers = mLayerState.mArray;
+ final ChildDrawable[] layers = mLayerState.mChildren;
for (int i = mLayerState.mNum - 1; i >= 0; i--) {
if (layers[i].mId == id) {
@@ -221,7 +222,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
* @param id The ID to assign to the layer.
*/
public void setId(int index, int id) {
- mLayerState.mArray[index].mId = id;
+ mLayerState.mChildren[index].mId = id;
}
/**
@@ -240,7 +241,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
* @return The {@link android.graphics.drawable.Drawable} at the specified layer index.
*/
public Drawable getDrawable(int index) {
- return mLayerState.mArray[index].mDrawable;
+ return mLayerState.mChildren[index].mDrawable;
}
/**
@@ -251,7 +252,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
* @return The id of the layer or {@link android.view.View#NO_ID} if the layer has no id.
*/
public int getId(int index) {
- return mLayerState.mArray[index].mId;
+ return mLayerState.mChildren[index].mId;
}
/**
@@ -263,7 +264,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
* the id was not found).
*/
public boolean setDrawableByLayerId(int id, Drawable drawable) {
- final Rec[] layers = mLayerState.mArray;
+ final ChildDrawable[] layers = mLayerState.mChildren;
for (int i = mLayerState.mNum - 1; i >= 0; i--) {
if (layers[i].mId == id) {
@@ -282,11 +283,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
bottom -= b;
*/
public void setLayerInset(int index, int l, int t, int r, int b) {
- Rec rec = mLayerState.mArray[index];
- rec.mInsetL = l;
- rec.mInsetT = t;
- rec.mInsetR = r;
- rec.mInsetB = b;
+ ChildDrawable childDrawable = mLayerState.mChildren[index];
+ childDrawable.mInsetL = l;
+ childDrawable.mInsetT = t;
+ childDrawable.mInsetR = r;
+ childDrawable.mInsetB = b;
}
// overrides from Drawable.Callback
@@ -313,7 +314,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
public void draw(Canvas canvas) {
- final Rec[] array = mLayerState.mArray;
+ final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
for (int i=0; i<N; i++) {
array[i].mDrawable.draw(canvas);
@@ -336,7 +337,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
padding.top = 0;
padding.right = 0;
padding.bottom = 0;
- final Rec[] array = mLayerState.mArray;
+ final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
for (int i=0; i<N; i++) {
reapplyPadding(i, array[i]);
@@ -351,7 +352,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
public boolean setVisible(boolean visible, boolean restart) {
boolean changed = super.setVisible(visible, restart);
- final Rec[] array = mLayerState.mArray;
+ final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
for (int i=0; i<N; i++) {
array[i].mDrawable.setVisible(visible, restart);
@@ -361,7 +362,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
public void setDither(boolean dither) {
- final Rec[] array = mLayerState.mArray;
+ final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
for (int i=0; i<N; i++) {
array[i].mDrawable.setDither(dither);
@@ -370,7 +371,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
public void setAlpha(int alpha) {
- final Rec[] array = mLayerState.mArray;
+ final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
for (int i=0; i<N; i++) {
array[i].mDrawable.setAlpha(alpha);
@@ -379,7 +380,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
public void setColorFilter(ColorFilter cf) {
- final Rec[] array = mLayerState.mArray;
+ final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
for (int i=0; i<N; i++) {
array[i].mDrawable.setColorFilter(cf);
@@ -398,12 +399,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
protected boolean onStateChange(int[] state) {
- final Rec[] array = mLayerState.mArray;
+ final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
boolean paddingChanged = false;
boolean changed = false;
for (int i=0; i<N; i++) {
- final Rec r = array[i];
+ final ChildDrawable r = array[i];
if (r.mDrawable.setState(state)) {
changed = true;
}
@@ -419,12 +420,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
protected boolean onLevelChange(int level) {
- final Rec[] array = mLayerState.mArray;
+ final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
boolean paddingChanged = false;
boolean changed = false;
for (int i=0; i<N; i++) {
- final Rec r = array[i];
+ final ChildDrawable r = array[i];
if (r.mDrawable.setLevel(level)) {
changed = true;
}
@@ -440,11 +441,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
protected void onBoundsChange(Rect bounds) {
- final Rec[] array = mLayerState.mArray;
+ final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
int padL=0, padT=0, padR=0, padB=0;
for (int i=0; i<N; i++) {
- final Rec r = array[i];
+ final ChildDrawable r = array[i];
r.mDrawable.setBounds(bounds.left + r.mInsetL + padL,
bounds.top + r.mInsetT + padT,
bounds.right - r.mInsetR - padR,
@@ -459,11 +460,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
public int getIntrinsicWidth() {
int width = -1;
- final Rec[] array = mLayerState.mArray;
+ final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
int padL=0, padR=0;
for (int i=0; i<N; i++) {
- final Rec r = array[i];
+ final ChildDrawable r = array[i];
int w = r.mDrawable.getIntrinsicWidth()
+ r.mInsetL + r.mInsetR + padL + padR;
if (w > width) {
@@ -478,11 +479,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
@Override
public int getIntrinsicHeight() {
int height = -1;
- final Rec[] array = mLayerState.mArray;
+ final ChildDrawable[] array = mLayerState.mChildren;
final int N = mLayerState.mNum;
int padT=0, padB=0;
for (int i=0; i<N; i++) {
- final Rec r = array[i];
+ final ChildDrawable r = array[i];
int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + + padT + padB;
if (h > height) {
height = h;
@@ -493,7 +494,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
return height;
}
- private boolean reapplyPadding(int i, Rec r) {
+ private boolean reapplyPadding(int i, ChildDrawable r) {
final Rect rect = mTmpRect;
r.mDrawable.getPadding(rect);
if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] ||
@@ -527,7 +528,20 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
return null;
}
- static class Rec {
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ final int N = mLayerState.mNum;
+ for (int i = 0; i < N; i++) {
+ array[i].mDrawable.mutate();
+ }
+ mMutated = true;
+ }
+ return this;
+ }
+
+ static class ChildDrawable {
public Drawable mDrawable;
public int mInsetL, mInsetT, mInsetR, mInsetB;
public int mId;
@@ -535,7 +549,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
static class LayerState extends ConstantState {
int mNum;
- Rec[] mArray;
+ ChildDrawable[] mChildren;
int mChangingConfigurations;
int mChildrenChangingConfigurations;
@@ -551,18 +565,18 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
LayerState(LayerState orig, LayerDrawable owner) {
if (orig != null) {
- final Rec[] origRec = orig.mArray;
+ final ChildDrawable[] origChildDrawable = orig.mChildren;
final int N = orig.mNum;
mNum = N;
- mArray = new Rec[N];
+ mChildren = new ChildDrawable[N];
mChangingConfigurations = orig.mChangingConfigurations;
mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations;
for (int i = 0; i < N; i++) {
- final Rec r = mArray[i] = new Rec();
- final Rec or = origRec[i];
+ final ChildDrawable r = mChildren[i] = new ChildDrawable();
+ final ChildDrawable or = origChildDrawable[i];
r.mDrawable = or.mDrawable.getConstantState().newDrawable();
r.mDrawable.setCallback(owner);
r.mInsetL = or.mInsetL;
@@ -579,7 +593,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
mCheckedConstantState = mCanConstantState = true;
} else {
mNum = 0;
- mArray = null;
+ mChildren = null;
}
}
@@ -599,11 +613,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
}
final int N = mNum;
- int op = N > 0 ? mArray[0].mDrawable.getOpacity()
- : PixelFormat.TRANSPARENT;
+ int op = N > 0 ? mChildren[0].mDrawable.getOpacity() : PixelFormat.TRANSPARENT;
for (int i = 1; i < N; i++) {
- op = Drawable.resolveOpacity(op, mArray[i].mDrawable
- .getOpacity());
+ op = Drawable.resolveOpacity(op, mChildren[i].mDrawable.getOpacity());
}
mOpacity = op;
mHaveOpacity = true;
@@ -618,7 +630,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
boolean stateful = false;
final int N = mNum;
for (int i = 0; i < N; i++) {
- if (mArray[i].mDrawable.isStateful()) {
+ if (mChildren[i].mDrawable.isStateful()) {
stateful = true;
break;
}
@@ -630,11 +642,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
}
public synchronized boolean canConstantState() {
- if (!mCheckedConstantState && mArray != null) {
+ if (!mCheckedConstantState && mChildren != null) {
mCanConstantState = true;
final int N = mNum;
for (int i=0; i<N; i++) {
- if (mArray[i].mDrawable.getConstantState() == null) {
+ if (mChildren[i].mDrawable.getConstantState() == null) {
mCanConstantState = false;
break;
}
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index 93dc32c..7ae649f 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -26,24 +26,37 @@ import android.content.res.TypedArray;
import android.util.AttributeSet;
/**
- *
- * A resource that manages a number of alternate Drawables, each assigned a maximum numerical value.
- * Setting the level value of the object with {@link #setLevel(int)} will load the image with the next
- * greater or equal value assigned to its max attribute.
- * A good example use of
+ * A resource that manages a number of alternate Drawables, each assigned a maximum numerical value.
+ * Setting the level value of the object with {@link #setLevel(int)} will load the image with the next
+ * greater or equal value assigned to its max attribute.
+ * A good example use of
* a LevelListDrawable would be a battery level indicator icon, with different images to indicate the current
* battery level.
* <p>
* It can be defined in an XML file with the <code>&lt;level-list></code> element.
- * Each Drawable level is defined in a nested <code>&lt;item></code>
+ * Each Drawable level is defined in a nested <code>&lt;item></code>. For example:
* </p>
+ * <pre>
+ * &lt;level-list xmlns:android="http://schemas.android.com/apk/res/android">
+ * &lt;item android:maxLevel="0" android:drawable="@drawable/ic_wifi_signal_1" />
+ * &lt;item android:maxLevel="1" android:drawable="@drawable/ic_wifi_signal_2" />
+ * &lt;item android:maxLevel="2" android:drawable="@drawable/ic_wifi_signal_3" />
+ * &lt;item android:maxLevel="3" android:drawable="@drawable/ic_wifi_signal_4" />
+ * &lt;/level-list>
+ *</pre>
+ * <p>With this XML saved into the res/drawable/ folder of the project, it can be referenced as
+ * the drawable for an {@link android.widget.ImageView}. The default image is the first in the list.
+ * It can then be changed to one of the other levels with
+ * {@link android.widget.ImageView#setImageLevel(int)}.</p>
* @attr ref android.R.styleable#LevelListDrawableItem_minLevel
* @attr ref android.R.styleable#LevelListDrawableItem_maxLevel
* @attr ref android.R.styleable#LevelListDrawableItem_drawable
*/
public class LevelListDrawable extends DrawableContainer {
- public LevelListDrawable()
- {
+ private final LevelListState mLevelListState;
+ private boolean mMutated;
+
+ public LevelListDrawable() {
this(null);
}
@@ -54,7 +67,7 @@ public class LevelListDrawable extends DrawableContainer {
onLevelChange(getLevel());
}
}
-
+
// overrides from Drawable
@Override
@@ -65,21 +78,22 @@ public class LevelListDrawable extends DrawableContainer {
}
return super.onLevelChange(level);
}
-
- @Override public void inflate(Resources r, XmlPullParser parser,
- AttributeSet attrs)
- throws XmlPullParserException, IOException {
+
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+
super.inflate(r, parser, attrs);
-
+
int type;
int low = 0;
- final int innerDepth = parser.getDepth()+1;
+ final int innerDepth = parser.getDepth() + 1;
int depth;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth=parser.getDepth()) >= innerDepth
- || type != XmlPullParser.END_TAG)) {
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth = parser.getDepth()) >= innerDepth
+ || type != XmlPullParser.END_TAG)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
@@ -87,50 +101,60 @@ public class LevelListDrawable extends DrawableContainer {
if (depth > innerDepth || !parser.getName().equals("item")) {
continue;
}
-
+
TypedArray a = r.obtainAttributes(attrs,
com.android.internal.R.styleable.LevelListDrawableItem);
-
+
low = a.getInt(
com.android.internal.R.styleable.LevelListDrawableItem_minLevel, 0);
int high = a.getInt(
com.android.internal.R.styleable.LevelListDrawableItem_maxLevel, 0);
int drawableRes = a.getResourceId(
com.android.internal.R.styleable.LevelListDrawableItem_drawable, 0);
-
+
a.recycle();
-
+
if (high < 0) {
throw new XmlPullParserException(parser.getPositionDescription()
- + ": <item> tag requires a 'maxLevel' attribute");
+ + ": <item> tag requires a 'maxLevel' attribute");
}
-
+
Drawable dr;
if (drawableRes != 0) {
dr = r.getDrawable(drawableRes);
} else {
- while ((type=parser.next()) == XmlPullParser.TEXT) {
+ while ((type = parser.next()) == XmlPullParser.TEXT) {
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException(
parser.getPositionDescription()
- + ": <item> tag requires a 'drawable' attribute or "
- + "child tag defining a drawable");
+ + ": <item> tag requires a 'drawable' attribute or "
+ + "child tag defining a drawable");
}
dr = Drawable.createFromXmlInner(r, parser, attrs);
}
mLevelListState.addLevel(low, high, dr);
- low = high+1;
}
onLevelChange(getLevel());
}
- private final static class LevelListState extends DrawableContainerState
- {
- LevelListState(LevelListState orig, LevelListDrawable owner)
- {
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mLevelListState.mLows = mLevelListState.mLows.clone();
+ mLevelListState.mHighs = mLevelListState.mHighs.clone();
+ mMutated = true;
+ }
+ return this;
+ }
+
+ private final static class LevelListState extends DrawableContainerState {
+ private int[] mLows;
+ private int[] mHighs;
+
+ LevelListState(LevelListState orig, LevelListDrawable owner) {
super(orig, owner);
if (orig != null) {
@@ -142,19 +166,17 @@ public class LevelListDrawable extends DrawableContainer {
}
}
- public void addLevel(int low, int high, Drawable drawable)
- {
+ public void addLevel(int low, int high, Drawable drawable) {
int pos = addChild(drawable);
mLows[pos] = low;
mHighs[pos] = high;
}
- public int indexOfLevel(int level)
- {
+ public int indexOfLevel(int level) {
final int[] lows = mLows;
final int[] highs = mHighs;
final int N = getChildCount();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
if (level >= lows[i] && level <= highs[i]) {
return i;
}
@@ -163,14 +185,12 @@ public class LevelListDrawable extends DrawableContainer {
}
@Override
- public Drawable newDrawable()
- {
+ public Drawable newDrawable() {
return new LevelListDrawable(this);
}
@Override
- public void growArray(int oldSize, int newSize)
- {
+ public void growArray(int oldSize, int newSize) {
super.growArray(oldSize, newSize);
int[] newInts = new int[newSize];
System.arraycopy(mLows, 0, newInts, 0, oldSize);
@@ -179,19 +199,13 @@ public class LevelListDrawable extends DrawableContainer {
System.arraycopy(mHighs, 0, newInts, 0, oldSize);
mHighs = newInts;
}
-
- private int[] mLows;
- private int[] mHighs;
}
- private LevelListDrawable(LevelListState state)
- {
+ private LevelListDrawable(LevelListState state) {
LevelListState as = new LevelListState(state, this);
mLevelListState = as;
setConstantState(as);
onLevelChange(getLevel());
}
-
- private final LevelListState mLevelListState;
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index c98ef5b..dace96c 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -17,6 +17,15 @@
package android.graphics.drawable;
import android.graphics.*;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
/**
*
@@ -26,9 +35,16 @@ import android.graphics.*;
*
*/
public class NinePatchDrawable extends Drawable {
+ private NinePatchState mNinePatchState;
+ private NinePatch mNinePatch;
+ private Rect mPadding;
+ private Paint mPaint;
+ private boolean mMutated;
+
+ NinePatchDrawable() {
+ }
- public NinePatchDrawable(Bitmap bitmap, byte[] chunk,
- Rect padding, String srcName) {
+ public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding));
}
@@ -36,6 +52,13 @@ public class NinePatchDrawable extends Drawable {
this(new NinePatchState(patch, null));
}
+ private void setNinePatchState(NinePatchState state) {
+ mNinePatchState = state;
+ mNinePatch = state.mNinePatch;
+ mPadding = state.mPadding;
+ if (state.mDither) setDither(state.mDither);
+ }
+
// overrides
@Override
@@ -45,8 +68,7 @@ public class NinePatchDrawable extends Drawable {
@Override
public int getChangingConfigurations() {
- return super.getChangingConfigurations()
- | mNinePatchState.mChangingConfigurations;
+ return super.getChangingConfigurations() | mNinePatchState.mChangingConfigurations;
}
@Override
@@ -70,6 +92,55 @@ public class NinePatchDrawable extends Drawable {
getPaint().setDither(dither);
}
+ @Override
+ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ super.inflate(r, parser, attrs);
+
+ TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.NinePatchDrawable);
+
+ final int id = a.getResourceId(com.android.internal.R.styleable.NinePatchDrawable_src, 0);
+ if (id == 0) {
+ throw new XmlPullParserException(parser.getPositionDescription() +
+ ": <nine-patch> requires a valid src attribute");
+ }
+
+ final boolean dither = a.getBoolean(
+ com.android.internal.R.styleable.NinePatchDrawable_dither, false);
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ if (dither) {
+ options.inDither = false;
+ }
+
+ final Rect padding = new Rect();
+ Bitmap bitmap = null;
+
+ try {
+ final TypedValue value = new TypedValue();
+ final InputStream is = r.openRawResource(id, value);
+
+ bitmap = BitmapFactory.decodeStream(r, value, is, padding, options);
+
+ is.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+
+ if (bitmap == null) {
+ throw new XmlPullParserException(parser.getPositionDescription() +
+ ": <nine-patch> requires a valid src attribute");
+ } else if (bitmap.getNinePatchChunk() == null) {
+ throw new XmlPullParserException(parser.getPositionDescription() +
+ ": <nine-patch> requires a valid 9-patch source image");
+ }
+
+ setNinePatchState(new NinePatchState(
+ new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"), padding, dither));
+
+ a.recycle();
+ }
+
+
public Paint getPaint() {
if (mPaint == null) {
mPaint = new Paint();
@@ -104,12 +175,13 @@ public class NinePatchDrawable extends Drawable {
}
/**
- * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat} value of OPAQUE or TRANSLUCENT.
+ * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat}
+ * value of OPAQUE or TRANSLUCENT.
*/
@Override
public int getOpacity() {
- return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255)
- ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
+ return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255) ?
+ PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
}
@Override
@@ -123,16 +195,42 @@ public class NinePatchDrawable extends Drawable {
return mNinePatchState;
}
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mNinePatchState = new NinePatchState(mNinePatchState);
+ mNinePatch = mNinePatchState.mNinePatch;
+ mPadding = mNinePatchState.mPadding;
+ mMutated = true;
+ }
+ return this;
+ }
+
final static class NinePatchState extends ConstantState {
- NinePatchState(NinePatch ninePatch, Rect padding)
- {
+ final NinePatch mNinePatch;
+ final Rect mPadding;
+ final boolean mDither;
+ int mChangingConfigurations;
+
+ NinePatchState(NinePatch ninePatch, Rect padding) {
+ this(ninePatch, padding, false);
+ }
+
+ NinePatchState(NinePatch ninePatch, Rect rect, boolean dither) {
mNinePatch = ninePatch;
- mPadding = padding;
+ mPadding = rect;
+ mDither = dither;
+ }
+
+ NinePatchState(NinePatchState state) {
+ mNinePatch = new NinePatch(state.mNinePatch);
+ mPadding = new Rect(state.mPadding);
+ mChangingConfigurations = state.mChangingConfigurations;
+ mDither = state.mDither;
}
@Override
- public Drawable newDrawable()
- {
+ public Drawable newDrawable() {
return new NinePatchDrawable(this);
}
@@ -140,21 +238,10 @@ public class NinePatchDrawable extends Drawable {
public int getChangingConfigurations() {
return mChangingConfigurations;
}
-
- final NinePatch mNinePatch;
- final Rect mPadding;
- int mChangingConfigurations;
}
private NinePatchDrawable(NinePatchState state) {
- mNinePatchState = state;
- mNinePatch = state.mNinePatch;
- mPadding = state.mPadding;
+ setNinePatchState(state);
}
-
- private final NinePatchState mNinePatchState;
- private final NinePatch mNinePatch;
- private final Rect mPadding;
- private Paint mPaint;
}
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 3e03ed4..cb16cb7 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -45,6 +45,10 @@ import java.io.IOException;
* @attr ref android.R.styleable#RotateDrawable_drawable
*/
public class RotateDrawable extends Drawable implements Drawable.Callback {
+ private static final float MAX_LEVEL = 10000.0f;
+
+ private RotateState mState;
+ private boolean mMutated;
/**
* <p>Create a new rotating drawable with an empty state.</p>
@@ -84,6 +88,13 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
canvas.restoreToCount(saveCount);
}
+ /**
+ * Returns the drawable rotated by this RotateDrawable.
+ */
+ public Drawable getDrawable() {
+ return mState.mDrawable;
+ }
+
@Override
public int getChangingConfigurations() {
return super.getChangingConfigurations()
@@ -248,6 +259,15 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
}
}
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mState.mDrawable.mutate();
+ mMutated = true;
+ }
+ return this;
+ }
+
/**
* <p>Represents the state of a rotation for a given drawable. The same
* rotate drawable can be invoked with different states to drive several
@@ -268,6 +288,9 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
float mCurrentDegrees;
+ private boolean mCanConstantState;
+ private boolean mCheckedConstantState;
+
public RotateState(RotateState source, RotateDrawable owner) {
if (source != null) {
mDrawable = source.mDrawable.getConstantState().newDrawable();
@@ -300,12 +323,5 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
return mCanConstantState;
}
-
- private boolean mCanConstantState;
- private boolean mCheckedConstantState;
}
-
- private static final float MAX_LEVEL = 10000.0f;
-
- private RotateState mState;
}
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index c40c8c0..7125ab1 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -24,7 +24,6 @@ import android.content.res.TypedArray;
import android.graphics.*;
import android.view.Gravity;
import android.util.AttributeSet;
-import android.util.Log;
import java.io.IOException;
@@ -44,6 +43,7 @@ import java.io.IOException;
*/
public class ScaleDrawable extends Drawable implements Drawable.Callback {
private ScaleState mScaleState;
+ private boolean mMutated;
private final Rect mTmpRect = new Rect();
ScaleDrawable() {
@@ -63,6 +63,13 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
}
}
+ /**
+ * Returns the drawable scaled by this ScaleDrawable.
+ */
+ public Drawable getDrawable() {
+ return mScaleState.mDrawable;
+ }
+
private static float getPercent(TypedArray a, int name) {
String s = a.getString(name);
if (s != null) {
@@ -234,7 +241,25 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
return null;
}
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mScaleState.mDrawable.mutate();
+ mMutated = true;
+ }
+ return this;
+ }
+
final static class ScaleState extends ConstantState {
+ Drawable mDrawable;
+ int mChangingConfigurations;
+ float mScaleWidth;
+ float mScaleHeight;
+ int mGravity;
+
+ private boolean mCheckedConstantState;
+ private boolean mCanConstantState;
+
ScaleState(ScaleState orig, ScaleDrawable owner) {
if (orig != null) {
mDrawable = orig.mDrawable.getConstantState().newDrawable();
@@ -264,15 +289,6 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
return mCanConstantState;
}
-
- Drawable mDrawable;
- int mChangingConfigurations;
- float mScaleWidth;
- float mScaleHeight;
- int mGravity;
-
- private boolean mCheckedConstantState;
- private boolean mCanConstantState;
}
private ScaleDrawable(ScaleState state) {
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 7e1284f..d24194f 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -28,15 +28,24 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
/**
- * An object that draws primitive shapes.
+ * A Drawable object that draws primitive shapes.
* A ShapeDrawable takes a {@link android.graphics.drawable.shapes.Shape}
* object and manages its presence on the screen. If no Shape is given, then
* the ShapeDrawable will default to a
* {@link android.graphics.drawable.shapes.RectShape}.
+ *
+ * @attr ref android.R.styleable#ShapeDrawablePadding_left
+ * @attr ref android.R.styleable#ShapeDrawablePadding_top
+ * @attr ref android.R.styleable#ShapeDrawablePadding_right
+ * @attr ref android.R.styleable#ShapeDrawablePadding_bottom
+ * @attr ref android.R.styleable#ShapeDrawable_color
+ * @attr ref android.R.styleable#ShapeDrawable_width
+ * @attr ref android.R.styleable#ShapeDrawable_height
*/
public class ShapeDrawable extends Drawable {
private ShapeState mShapeState;
-
+ private boolean mMutated;
+
/**
* ShapeDrawable constructor.
*/
@@ -334,6 +343,21 @@ public class ShapeDrawable extends Drawable {
return mShapeState;
}
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mShapeState.mPaint = new Paint(mShapeState.mPaint);
+ mShapeState.mPadding = new Rect(mShapeState.mPadding);
+ try {
+ mShapeState.mShape = mShapeState.mShape.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ mMutated = true;
+ }
+ return this;
+ }
+
/**
* Defines the intrinsic properties of this ShapeDrawable's Shape.
*/
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 1dc1627..d22a4ba 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -27,10 +27,9 @@ import android.util.AttributeSet;
import android.util.StateSet;
/**
- *
* Lets you assign a number of graphic images to a single Drawable and swap out the visible item by a string
* ID value.
- *
+ * <p/>
* <p>It can be defined in an XML file with the <code>&lt;selector></code> element.
* Each state Drawable is defined in a nested <code>&lt;item></code> element.</p>
*
@@ -51,15 +50,18 @@ import android.util.StateSet;
* @attr ref android.R.styleable#DrawableStates_state_pressed
*/
public class StateListDrawable extends DrawableContainer {
- public StateListDrawable()
- {
+ private final StateListState mStateListState;
+ private boolean mMutated;
+
+ public StateListDrawable() {
this(null);
}
/**
* Add a new image/string ID to the set of images.
+ *
* @param stateSet - An array of resource Ids to associate with the image.
- * Switch to this image by calling setState().
+ * Switch to this image by calling setState().
* @param drawable -The image to show.
*/
public void addState(int[] stateSet, Drawable drawable) {
@@ -74,7 +76,7 @@ public class StateListDrawable extends DrawableContainer {
public boolean isStateful() {
return true;
}
-
+
@Override
protected boolean onStateChange(int[] stateSet) {
int idx = mStateListState.indexOfStateSet(stateSet);
@@ -87,30 +89,31 @@ public class StateListDrawable extends DrawableContainer {
return super.onStateChange(stateSet);
}
- @Override public void inflate(Resources r, XmlPullParser parser,
+ @Override
+ public void inflate(Resources r, XmlPullParser parser,
AttributeSet attrs)
- throws XmlPullParserException, IOException {
-
+ throws XmlPullParserException, IOException {
+
TypedArray a = r.obtainAttributes(attrs,
com.android.internal.R.styleable.StateListDrawable);
super.inflateWithAttributes(r, parser, a,
com.android.internal.R.styleable.StateListDrawable_visible);
-
+
mStateListState.setVariablePadding(a.getBoolean(
com.android.internal.R.styleable.StateListDrawable_variablePadding, false));
mStateListState.setConstantSize(a.getBoolean(
com.android.internal.R.styleable.StateListDrawable_constantSize, false));
-
+
a.recycle();
-
+
int type;
- final int innerDepth = parser.getDepth()+1;
+ final int innerDepth = parser.getDepth() + 1;
int depth;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && ((depth=parser.getDepth()) >= innerDepth
- || type != XmlPullParser.END_TAG)) {
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && ((depth = parser.getDepth()) >= innerDepth
+ || type != XmlPullParser.END_TAG)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
@@ -118,9 +121,9 @@ public class StateListDrawable extends DrawableContainer {
if (depth > innerDepth || !parser.getName().equals("item")) {
continue;
}
-
+
int drawableRes = 0;
-
+
int i;
int j = 0;
final int numAttrs = attrs.getAttributeCount();
@@ -132,27 +135,27 @@ public class StateListDrawable extends DrawableContainer {
drawableRes = attrs.getAttributeResourceValue(i, 0);
} else {
states[j++] = attrs.getAttributeBooleanValue(i, false)
- ? stateResId
- : -stateResId;
+ ? stateResId
+ : -stateResId;
}
}
states = StateSet.trimStateSet(states, j);
-
+
Drawable dr;
if (drawableRes != 0) {
dr = r.getDrawable(drawableRes);
} else {
- while ((type=parser.next()) == XmlPullParser.TEXT) {
+ while ((type = parser.next()) == XmlPullParser.TEXT) {
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException(
parser.getPositionDescription()
- + ": <item> tag requires a 'drawable' attribute or "
- + "child tag defining a drawable");
+ + ": <item> tag requires a 'drawable' attribute or "
+ + "child tag defining a drawable");
}
dr = Drawable.createFromXmlInner(r, parser, attrs);
}
-
+
mStateListState.addStateSet(states, dr);
}
@@ -162,49 +165,76 @@ public class StateListDrawable extends DrawableContainer {
StateListState getStateListState() {
return mStateListState;
}
-
+
/**
* Gets the number of states contained in this drawable.
- *
+ *
* @return The number of states contained in this drawable.
+ * @hide pending API council
* @see #getStateSet(int)
* @see #getStateDrawable(int)
- * @hide pending API council
*/
public int getStateCount() {
- return mStateListState.getChildCount();
+ return mStateListState.getChildCount();
}
/**
* Gets the state set at an index.
- *
+ *
* @param index The index of the state set.
* @return The state set at the index.
+ * @hide pending API council
* @see #getStateCount()
* @see #getStateDrawable(int)
- * @hide pending API council
*/
public int[] getStateSet(int index) {
return mStateListState.mStateSets[index];
}
-
+
/**
* Gets the drawable at an index.
- *
+ *
* @param index The index of the drawable.
* @return The drawable at the index.
+ * @hide pending API council
* @see #getStateCount()
* @see #getStateSet(int)
- * @hide pending API council
*/
public Drawable getStateDrawable(int index) {
return mStateListState.getChildren()[index];
}
- static final class StateListState extends DrawableContainerState
- {
- StateListState(StateListState orig, StateListDrawable owner)
- {
+ /**
+ * Gets the index of the drawable with the provided state set.
+ *
+ * @param stateSet the state set to look up
+ * @return the index of the provided state set, or -1 if not found
+ * @hide pending API council
+ * @see #getStateDrawable(int)
+ * @see #getStateSet(int)
+ */
+ public int getStateDrawableIndex(int[] stateSet) {
+ return mStateListState.indexOfStateSet(stateSet);
+ }
+
+ @Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ final int[][] sets = mStateListState.mStateSets;
+ final int count = sets.length;
+ mStateListState.mStateSets = new int[count][];
+ for (int i = 0; i < count; i++) {
+ mStateListState.mStateSets[i] = sets[i].clone();
+ }
+ mMutated = true;
+ }
+ return this;
+ }
+
+ static final class StateListState extends DrawableContainerState {
+ private int[][] mStateSets;
+
+ StateListState(StateListState orig, StateListDrawable owner) {
super(orig, owner);
if (orig != null) {
@@ -220,11 +250,10 @@ public class StateListDrawable extends DrawableContainer {
return pos;
}
- private int indexOfStateSet(int[] stateSet)
- {
+ private int indexOfStateSet(int[] stateSet) {
final int[][] stateSets = mStateSets;
final int N = getChildCount();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
if (StateSet.stateSetMatches(stateSets[i], stateSet)) {
return i;
}
@@ -233,31 +262,24 @@ public class StateListDrawable extends DrawableContainer {
}
@Override
- public Drawable newDrawable()
- {
+ public Drawable newDrawable() {
return new StateListDrawable(this);
}
@Override
- public void growArray(int oldSize, int newSize)
- {
+ public void growArray(int oldSize, int newSize) {
super.growArray(oldSize, newSize);
final int[][] newStateSets = new int[newSize][];
System.arraycopy(mStateSets, 0, newStateSets, 0, oldSize);
mStateSets = newStateSets;
}
-
- private int[][] mStateSets;
}
- private StateListDrawable(StateListState state)
- {
+ private StateListDrawable(StateListState state) {
StateListState as = new StateListState(state, this);
mStateListState = as;
setConstantState(as);
onStateChange(getState());
}
-
- private final StateListState mStateListState;
}
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index a99d4e5..358f889 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -63,7 +63,9 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
private int mFrom;
private int mTo;
private int mDuration;
- private TransitionState mState;
+ private int mOriginalDuration;
+ private int mAlpha = 0;
+ private boolean mCrossFade;
/**
* Create a new transition drawable with the specified list of layers. At least
@@ -85,12 +87,10 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
private TransitionDrawable(TransitionState state) {
super(state);
- mState = state;
}
private TransitionDrawable(TransitionState state, Drawable[] layers) {
super(layers, state);
- mState = state;
}
@Override
@@ -106,8 +106,8 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
public void startTransition(int durationMillis) {
mFrom = 0;
mTo = 255;
- mState.mAlpha = 0;
- mState.mDuration = mDuration = durationMillis;
+ mAlpha = 0;
+ mDuration = mOriginalDuration = durationMillis;
mReverse = false;
mTransitionState = TRANSITION_STARTING;
invalidateSelf();
@@ -117,7 +117,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
* Show only the first layer.
*/
public void resetTransition() {
- mState.mAlpha = 0;
+ mAlpha = 0;
mTransitionState = TRANSITION_NONE;
invalidateSelf();
}
@@ -133,36 +133,35 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
public void reverseTransition(int duration) {
final long time = SystemClock.uptimeMillis();
// Animation is over
- if (time - mStartTimeMillis > mState.mDuration) {
- if (mState.mAlpha == 0) {
+ if (time - mStartTimeMillis > mDuration) {
+ if (mAlpha == 0) {
mFrom = 0;
mTo = 255;
- mState.mAlpha = 0;
+ mAlpha = 0;
mReverse = false;
} else {
mFrom = 255;
mTo = 0;
- mState.mAlpha = 255;
+ mAlpha = 255;
mReverse = true;
}
- mDuration = mState.mDuration = duration;
+ mDuration = mOriginalDuration = duration;
mTransitionState = TRANSITION_STARTING;
invalidateSelf();
return;
}
mReverse = !mReverse;
- mFrom = mState.mAlpha;
+ mFrom = mAlpha;
mTo = mReverse ? 0 : 255;
mDuration = (int) (mReverse ? time - mStartTimeMillis :
- mState.mDuration - (time - mStartTimeMillis));
+ mOriginalDuration - (time - mStartTimeMillis));
mTransitionState = TRANSITION_STARTING;
}
@Override
public void draw(Canvas canvas) {
boolean done = true;
- final TransitionState state = mState;
switch (mTransitionState) {
case TRANSITION_STARTING:
@@ -177,14 +176,14 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
(SystemClock.uptimeMillis() - mStartTimeMillis) / mDuration;
done = normalized >= 1.0f;
normalized = Math.min(normalized, 1.0f);
- state.mAlpha = (int) (mFrom + (mTo - mFrom) * normalized);
+ mAlpha = (int) (mFrom + (mTo - mFrom) * normalized);
}
break;
}
- final int alpha = state.mAlpha;
- final boolean crossFade = state.mCrossFade;
- final Rec[] array = mLayerState.mArray;
+ final int alpha = mAlpha;
+ final boolean crossFade = mCrossFade;
+ final ChildDrawable[] array = mLayerState.mChildren;
Drawable d;
d = array[0].mDrawable;
@@ -217,7 +216,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
* @param enabled True to enable cross fading, false otherwise.
*/
public void setCrossFadeEnabled(boolean enabled) {
- mState.mCrossFade = enabled;
+ mCrossFade = enabled;
}
/**
@@ -226,14 +225,10 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
* @return True if cross fading is enabled, false otherwise.
*/
public boolean isCrossFadeEnabled() {
- return mState.mCrossFade;
+ return mCrossFade;
}
static class TransitionState extends LayerState {
- int mAlpha = 0;
- int mDuration;
- boolean mCrossFade;
-
TransitionState(TransitionState orig, TransitionDrawable owner) {
super(orig, owner);
}
diff --git a/graphics/java/android/graphics/drawable/package.html b/graphics/java/android/graphics/drawable/package.html
index 17ee865..da49df7 100644
--- a/graphics/java/android/graphics/drawable/package.html
+++ b/graphics/java/android/graphics/drawable/package.html
@@ -4,6 +4,6 @@ Provides classes to manage a variety of visual elements that are intended for
display only, such as bitmaps and gradients. These elements are often used
by widgets as background images or simply as indicators (for example, a volume
level indicator). You can create most of these in XML as described in <a
-href="{@docRoot}reference/available-resources.html">Resources</a>.
+href="{@docRoot}guide/topics/resources/available-resources.html">Availeble Resource Types</a>.
</BODY>
</HTML>
diff --git a/graphics/java/android/graphics/drawable/shapes/PathShape.java b/graphics/java/android/graphics/drawable/shapes/PathShape.java
index 3656a0b..30b7347 100644
--- a/graphics/java/android/graphics/drawable/shapes/PathShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/PathShape.java
@@ -64,5 +64,12 @@ public class PathShape extends Shape {
mScaleX = width / mStdWidth;
mScaleY = height / mStdHeight;
}
+
+ @Override
+ public PathShape clone() throws CloneNotSupportedException {
+ PathShape shape = (PathShape) super.clone();
+ shape.mPath = new Path(mPath);
+ return shape;
+ }
}
diff --git a/graphics/java/android/graphics/drawable/shapes/RectShape.java b/graphics/java/android/graphics/drawable/shapes/RectShape.java
index 4f038ae..a3d2654 100644
--- a/graphics/java/android/graphics/drawable/shapes/RectShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/RectShape.java
@@ -50,4 +50,11 @@ public class RectShape extends Shape {
protected final RectF rect() {
return mRect;
}
+
+ @Override
+ public RectShape clone() throws CloneNotSupportedException {
+ final RectShape shape = (RectShape) super.clone();
+ shape.mRect = new RectF(mRect);
+ return shape;
+ }
}
diff --git a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
index 54ef3f7..f4cf15c 100644
--- a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
@@ -105,4 +105,15 @@ public class RoundRectShape extends RectShape {
}
}
}
+
+ @Override
+ public RoundRectShape clone() throws CloneNotSupportedException {
+ RoundRectShape shape = (RoundRectShape) super.clone();
+ shape.mOuterRadii = mOuterRadii.clone();
+ shape.mInnerRadii = mInnerRadii.clone();
+ shape.mInset = new RectF(mInset);
+ shape.mInnerRect = new RectF(mInnerRect);
+ shape.mPath = new Path(mPath);
+ return shape;
+ }
}
diff --git a/graphics/java/android/graphics/drawable/shapes/Shape.java b/graphics/java/android/graphics/drawable/shapes/Shape.java
index fc54bc1..4e192f9 100644
--- a/graphics/java/android/graphics/drawable/shapes/Shape.java
+++ b/graphics/java/android/graphics/drawable/shapes/Shape.java
@@ -25,7 +25,7 @@ import android.graphics.Paint;
* but more graphical control is available if you instead pass
* it to a {@link android.graphics.drawable.ShapeDrawable}.
*/
-public abstract class Shape {
+public abstract class Shape implements Cloneable {
private float mWidth;
private float mHeight;
@@ -92,4 +92,9 @@ public abstract class Shape {
* @param height the new height of the Shape
*/
protected void onResize(float width, float height) {}
+
+ @Override
+ public Shape clone() throws CloneNotSupportedException {
+ return (Shape) super.clone();
+ }
}
diff --git a/include/GLES/egl.h b/include/GLES/egl.h
deleted file mode 100644
index 08834ab..0000000
--- a/include/GLES/egl.h
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#ifndef ANDROID_EGL_H
-#define ANDROID_EGL_H
-
-#include <GLES/gl.h>
-#include <GLES/egltypes.h>
-#include <GLES/eglnatives.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define EGL_VERSION_1_0 1
-#define EGL_VERSION_1_1 1
-#define EGL_VERSION_1_2 1
-
-#define EGL_FALSE 0
-#define EGL_TRUE 1
-
-/* Errors */
-#define EGL_SUCCESS 0x3000
-#define EGL_NOT_INITIALIZED 0x3001
-#define EGL_BAD_ACCESS 0x3002
-#define EGL_BAD_ALLOC 0x3003
-#define EGL_BAD_ATTRIBUTE 0x3004
-#define EGL_BAD_CONFIG 0x3005
-#define EGL_BAD_CONTEXT 0x3006
-#define EGL_BAD_CURRENT_SURFACE 0x3007
-#define EGL_BAD_DISPLAY 0x3008
-#define EGL_BAD_MATCH 0x3009
-#define EGL_BAD_NATIVE_PIXMAP 0x300A
-#define EGL_BAD_NATIVE_WINDOW 0x300B
-#define EGL_BAD_PARAMETER 0x300C
-#define EGL_BAD_SURFACE 0x300D
-#define EGL_CONTEXT_LOST 0x300E
-
-/* Config attributes */
-#define EGL_BUFFER_SIZE 0x3020
-#define EGL_ALPHA_SIZE 0x3021
-#define EGL_BLUE_SIZE 0x3022
-#define EGL_GREEN_SIZE 0x3023
-#define EGL_RED_SIZE 0x3024
-#define EGL_DEPTH_SIZE 0x3025
-#define EGL_STENCIL_SIZE 0x3026
-#define EGL_CONFIG_CAVEAT 0x3027
-#define EGL_CONFIG_ID 0x3028
-#define EGL_LEVEL 0x3029
-#define EGL_MAX_PBUFFER_HEIGHT 0x302A
-#define EGL_MAX_PBUFFER_PIXELS 0x302B
-#define EGL_MAX_PBUFFER_WIDTH 0x302C
-#define EGL_NATIVE_RENDERABLE 0x302D
-#define EGL_NATIVE_VISUAL_ID 0x302E
-#define EGL_NATIVE_VISUAL_TYPE 0x302F
-#define EGL_SAMPLES 0x3031
-#define EGL_SAMPLE_BUFFERS 0x3032
-#define EGL_SURFACE_TYPE 0x3033
-#define EGL_TRANSPARENT_TYPE 0x3034
-#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
-#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
-#define EGL_TRANSPARENT_RED_VALUE 0x3037
-#define EGL_NONE 0x3038
-#define EGL_BIND_TO_TEXTURE_RGB 0x3039
-#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
-#define EGL_MIN_SWAP_INTERVAL 0x303B
-#define EGL_MAX_SWAP_INTERVAL 0x303C
-#define EGL_LUMINANCE_SIZE 0x303D
-#define EGL_ALPHA_MASK_SIZE 0x303E
-#define EGL_COLOR_BUFFER_TYPE 0x303F
-#define EGL_RENDERABLE_TYPE 0x3040
-
-/* Config values */
-#define EGL_DONT_CARE ((EGLint)-1)
-
-#define EGL_SLOW_CONFIG 0x3050
-#define EGL_NON_CONFORMANT_CONFIG 0x3051
-#define EGL_TRANSPARENT_RGB 0x3052
-#define EGL_NO_TEXTURE 0x305C
-#define EGL_TEXTURE_RGB 0x305D
-#define EGL_TEXTURE_RGBA 0x305E
-#define EGL_TEXTURE_2D 0x305F
-#define EGL_RGB_BUFFER 0x308E
-#define EGL_LUMINANCE_BUFFER 0x308F
-
-/* Config attribute mask bits */
-#define EGL_PBUFFER_BIT 0x01
-#define EGL_PIXMAP_BIT 0x02
-#define EGL_WINDOW_BIT 0x04
-#define EGL_OPENGL_ES_BIT 0x01
-#define EGL_OPENVG_BIT 0x02
-
-/* String names */
-#define EGL_VENDOR 0x3053
-#define EGL_VERSION 0x3054
-#define EGL_EXTENSIONS 0x3055
-#define EGL_CLIENT_APIS 0x308D
-
-/* Surface attributes */
-#define EGL_HEIGHT 0x3056
-#define EGL_WIDTH 0x3057
-#define EGL_LARGEST_PBUFFER 0x3058
-#define EGL_TEXTURE_FORMAT 0x3080
-#define EGL_TEXTURE_TARGET 0x3081
-#define EGL_MIPMAP_TEXTURE 0x3082
-#define EGL_MIPMAP_LEVEL 0x3083
-#define EGL_RENDER_BUFFER 0x3086
-#define EGL_COLORSPACE 0x3087
-#define EGL_ALPHA_FORMAT 0x3088
-#define EGL_HORIZONTAL_RESOLUTION 0x3090
-#define EGL_VERTICAL_RESOLUTION 0x3091
-#define EGL_PIXEL_ASPECT_RATIO 0x3092
-#define EGL_SWAP_BEHAVIOR 0x3093
-
-#define EGL_BACK_BUFFER 0x3084
-#define EGL_SINGLE_BUFFER 0x3085
-
-#define EGL_DISPLAY_SCALING 10000
-
-#define EGL_UNKNOWN ((EGLint)-1)
-
-/* Back buffer swap behaviors */
-#define EGL_BUFFER_PRESERVED 0x3094
-#define EGL_BUFFER_DESTROYED 0x3095
-
-/* CreatePbufferFromClientBuffer buffer types */
-#define EGL_OPENVG_IMAGE 0x3096
-
-/* QueryContext targets */
-#define EGL_CONTEXT_CLIENT_TYPE 0x3097
-
-/* BindAPI/QueryAPI targets */
-#define EGL_OPENGL_ES_API 0x30A0
-#define EGL_OPENVG_API 0x30A1
-
-/* WaitNative engines */
-#define EGL_CORE_NATIVE_ENGINE 0x305B
-
-/* Current surfaces */
-#define EGL_DRAW 0x3059
-#define EGL_READ 0x305A
-
-
-EGLDisplay eglGetDisplay(NativeDisplayType display);
-EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
-EGLBoolean eglTerminate(EGLDisplay dpy);
-
-EGLBoolean eglGetConfigs( EGLDisplay dpy,
- EGLConfig *configs,
- EGLint config_size, EGLint *num_config);
-
-EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
- EGLConfig *configs, EGLint config_size,
- EGLint *num_config);
-
-EGLBoolean eglGetConfigAttrib( EGLDisplay dpy, EGLConfig config,
- EGLint attribute, EGLint *value);
-
-EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
- NativeWindowType window,
- const EGLint *attrib_list);
-
-EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
- NativePixmapType pixmap,
- const EGLint *attrib_list);
-
-EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list);
-
-EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
-
-EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
- EGLint attribute, EGLint *value);
-
-EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
- EGLContext share_list, const EGLint *attrib_list);
-
-EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
-
-EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
- EGLSurface read, EGLContext ctx);
-
-EGLContext eglGetCurrentContext(void);
-EGLSurface eglGetCurrentSurface(EGLint readdraw);
-EGLDisplay eglGetCurrentDisplay(void);
-EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
- EGLint attribute, EGLint *value);
-
-EGLBoolean eglWaitGL(void);
-EGLBoolean eglWaitNative(EGLint engine);
-EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
-EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
- NativePixmapType target);
-
-EGLint eglGetError(void);
-const char* eglQueryString(EGLDisplay dpy, EGLint name);
-void (*eglGetProcAddress (const char *procname))();
-
-/* ----------------------------------------------------------------------------
- * EGL 1.1
- * ----------------------------------------------------------------------------
- */
-
-EGLBoolean eglSurfaceAttrib(
- EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
-EGLBoolean eglBindTexImage(
- EGLDisplay dpy, EGLSurface surface, EGLint buffer);
-EGLBoolean eglReleaseTexImage(
- EGLDisplay dpy, EGLSurface surface, EGLint buffer);
-
-EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval);
-
-/* ----------------------------------------------------------------------------
- * EGL 1.2
- * ----------------------------------------------------------------------------
- */
-
-EGLBoolean eglBindAPI(EGLenum api);
-EGLenum eglQueryAPI(void);
-EGLBoolean eglWaitClient(void);
-EGLBoolean eglReleaseThread(void);
-EGLSurface eglCreatePbufferFromClientBuffer(
- EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
- EGLConfig config, const EGLint *attrib_list);
-
-/* ----------------------------------------------------------------------------
- * Android extentions
- * ----------------------------------------------------------------------------
- */
-
-EGLBoolean eglSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
- EGLint l, EGLint t, EGLint w, EGLint h);
-
-EGLBoolean eglCopyFrontToBackANDROID(EGLDisplay dpy,
- EGLSurface surface,
- EGLint l, EGLint t, EGLint w, EGLint h);
-
-const char* eglQueryStringConfigANDROID(
- EGLDisplay dpy, EGLConfig config, EGLint name);
-
-void* eglGetRenderBufferAddressANDROID(EGLDisplay dpy, EGLSurface surface);
-
-EGLBoolean eglCopyBitsANDROID(EGLDisplay dpy,
- NativeWindowType draw, EGLint x, EGLint y,
- NativeWindowType read,
- EGLint crop_x, EGLint crop_y, EGLint crop_w, EGLint crop_h,
- EGLint flags);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /*ANDROID_EGL_H*/
diff --git a/include/GLES/gl.h b/include/GLES/gl.h
deleted file mode 100644
index 50b6ac4..0000000
--- a/include/GLES/gl.h
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-#ifndef __gl_h_
-#define __gl_h_
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*****************************************************************************/
-
-typedef int8_t GLbyte; // b
-typedef int16_t GLshort; // s
-typedef int32_t GLint; // i
-typedef ssize_t GLsizei; // i
-typedef int32_t GLfixed; // x
-typedef int32_t GLclampx; // x
-typedef float GLfloat; // f
-typedef float GLclampf; // f
-typedef uint8_t GLubyte; // ub
-typedef uint8_t GLboolean; // ub
-typedef uint16_t GLushort; // us
-typedef uint32_t GLuint; // ui
-typedef unsigned int GLenum; // ui
-typedef unsigned int GLbitfield; // ui
-typedef void GLvoid;
-typedef intptr_t GLintptr;
-typedef int GLsizeiptr;
-typedef GLintptr GLintptrARB;
-typedef GLsizeiptr GLsizeiptrARB;
-
-/*****************************************************************************/
-
-#define GL_VERSION_ES_CM_1_0 1
-#define GL_VERSION_ES_CL_1_0 1
-#define GL_VERSION_ES_CM_1_1 1
-#define GL_VERSION_ES_CL_1_1 1
-
-#define GL_OES_byte_coordinates 1
-#define GL_OES_fixed_point 1
-#define GL_OES_single_precision 1
-#define GL_OES_read_format 1
-#define GL_OES_compressed_paletted_texture 1
-#define GL_OES_draw_texture 1
-#define GL_OES_matrix_get 1
-#define GL_OES_query_matrix 1
-#define GL_OES_vertex_buffer_object 1
-#define GL_OES_point_size_array 1
-#define GL_OES_point_sprite 1
-#define GL_ARB_texture_non_power_of_two 1
-
-/*****************************************************************************/
-/* OpenGL ES 1.0 names */
-
-#define GL_FALSE 0
-#define GL_TRUE 1
-
-/* begin mode */
-#define GL_POINTS 0x0000
-#define GL_LINES 0x0001
-#define GL_LINE_LOOP 0x0002
-#define GL_LINE_STRIP 0x0003
-#define GL_TRIANGLES 0x0004
-#define GL_TRIANGLE_STRIP 0x0005
-#define GL_TRIANGLE_FAN 0x0006
-
-/* clear mask */
-#define GL_DEPTH_BUFFER_BIT 0x00000100
-#define GL_STENCIL_BUFFER_BIT 0x00000400
-#define GL_COLOR_BUFFER_BIT 0x00004000
-
-/* enable/disable */
-#define GL_FOG 0x0B60
-#define GL_LIGHTING 0x0B50
-#define GL_TEXTURE_2D 0x0DE1
-#define GL_CULL_FACE 0x0B44
-#define GL_ALPHA_TEST 0x0BC0
-#define GL_BLEND 0x0BE2
-#define GL_COLOR_LOGIC_OP 0x0BF2
-#define GL_DITHER 0x0BD0
-#define GL_STENCIL_TEST 0x0B90
-#define GL_DEPTH_TEST 0x0B71
-#define GL_POINT_SMOOTH 0x0B10
-#define GL_LINE_SMOOTH 0x0B20
-#define GL_SCISSOR_TEST 0x0C11
-#define GL_COLOR_MATERIAL 0x0B57
-#define GL_NORMALIZE 0x0BA1
-#define GL_RESCALE_NORMAL 0x803A
-#define GL_POLYGON_OFFSET_FILL 0x8037
-#define GL_VERTEX_ARRAY 0x8074
-#define GL_NORMAL_ARRAY 0x8075
-#define GL_COLOR_ARRAY 0x8076
-#define GL_TEXTURE_COORD_ARRAY 0x8078
-#define GL_MULTISAMPLE 0x809D
-#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
-#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
-#define GL_SAMPLE_COVERAGE 0x80A0
-
-/* gets */
-#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
-#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
-#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
-#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
-#define GL_MAX_LIGHTS 0x0D31
-#define GL_MAX_CLIP_PLANES 0x0D32
-#define GL_MAX_TEXTURE_SIZE 0x0D33
-#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36
-#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38
-#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39
-#define GL_MAX_VIEWPORT_DIMS 0x0D3A
-#define GL_MAX_ELEMENTS_VERTICES 0x80E8
-#define GL_MAX_ELEMENTS_INDICES 0x80E9
-#define GL_MAX_TEXTURE_UNITS 0x84E2
-#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
-#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
-#define GL_SUBPIXEL_BITS 0x0D50
-#define GL_RED_BITS 0x0D52
-#define GL_GREEN_BITS 0x0D53
-#define GL_BLUE_BITS 0x0D54
-#define GL_ALPHA_BITS 0x0D55
-#define GL_DEPTH_BITS 0x0D56
-#define GL_STENCIL_BITS 0x0D57
-
-/* clip planes */
-#define GL_CLIP_PLANE0 0x3000
-#define GL_CLIP_PLANE1 0x3001
-#define GL_CLIP_PLANE2 0x3002
-#define GL_CLIP_PLANE3 0x3003
-#define GL_CLIP_PLANE4 0x3004
-#define GL_CLIP_PLANE5 0x3005
-
-/* errors */
-#define GL_NO_ERROR 0
-#define GL_INVALID_ENUM 0x0500
-#define GL_INVALID_VALUE 0x0501
-#define GL_INVALID_OPERATION 0x0502
-#define GL_STACK_OVERFLOW 0x0503
-#define GL_STACK_UNDERFLOW 0x0504
-#define GL_OUT_OF_MEMORY 0x0505
-
-/* fog */
-#define GL_EXP 0x0800
-#define GL_EXP2 0x0801
-#define GL_FOG_DENSITY 0x0B62
-#define GL_FOG_START 0x0B63
-#define GL_FOG_END 0x0B64
-#define GL_FOG_MODE 0x0B65
-#define GL_FOG_COLOR 0x0B66
-
-/* culling */
-#define GL_CW 0x0900
-#define GL_CCW 0x0901
-
-#define GL_FRONT 0x0404
-#define GL_BACK 0x0405
-#define GL_FRONT_AND_BACK 0x0408
-
-/* hints */
-#define GL_DONT_CARE 0x1100
-#define GL_FASTEST 0x1101
-#define GL_NICEST 0x1102
-
-#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50
-#define GL_POINT_SMOOTH_HINT 0x0C51
-#define GL_LINE_SMOOTH_HINT 0x0C52
-#define GL_POLYGON_SMOOTH_HINT 0x0C53
-#define GL_FOG_HINT 0x0C54
-#define GL_GENERATE_MIPMAP_HINT 0x8192
-
-/* lights */
-#define GL_LIGHT_MODEL_AMBIENT 0x0B53
-#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52
-
-#define GL_AMBIENT 0x1200
-#define GL_DIFFUSE 0x1201
-#define GL_SPECULAR 0x1202
-#define GL_POSITION 0x1203
-#define GL_SPOT_DIRECTION 0x1204
-#define GL_SPOT_EXPONENT 0x1205
-#define GL_SPOT_CUTOFF 0x1206
-#define GL_CONSTANT_ATTENUATION 0x1207
-#define GL_LINEAR_ATTENUATION 0x1208
-#define GL_QUADRATIC_ATTENUATION 0x1209
-
-#define GL_LIGHT0 0x4000
-#define GL_LIGHT1 0x4001
-#define GL_LIGHT2 0x4002
-#define GL_LIGHT3 0x4003
-#define GL_LIGHT4 0x4004
-#define GL_LIGHT5 0x4005
-#define GL_LIGHT6 0x4006
-#define GL_LIGHT7 0x4007
-
-/* material */
-#define GL_EMISSION 0x1600
-#define GL_SHININESS 0x1601
-#define GL_AMBIENT_AND_DIFFUSE 0x1602
-
-/* matrix */
-#define GL_MODELVIEW 0x1700
-#define GL_PROJECTION 0x1701
-#define GL_TEXTURE 0x1702
-
-/* types */
-#define GL_BYTE 0x1400
-#define GL_UNSIGNED_BYTE 0x1401
-#define GL_SHORT 0x1402
-#define GL_UNSIGNED_SHORT 0x1403
-#define GL_FLOAT 0x1406
-#define GL_FIXED 0x140C
-
-/* pixel formats */
-#define GL_ALPHA 0x1906
-#define GL_RGB 0x1907
-#define GL_RGBA 0x1908
-#define GL_LUMINANCE 0x1909
-#define GL_LUMINANCE_ALPHA 0x190A
-
-/* pixel store */
-#define GL_UNPACK_ALIGNMENT 0x0CF5
-#define GL_PACK_ALIGNMENT 0x0D05
-
-/* pixel types */
-#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
-#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
-#define GL_UNSIGNED_SHORT_5_6_5 0x8363
-
-/* logic op */
-#define GL_CLEAR 0x1500 // 0
-#define GL_AND 0x1501 // s & d
-#define GL_AND_REVERSE 0x1502 // s & ~d
-#define GL_COPY 0x1503 // s
-#define GL_AND_INVERTED 0x1504 // ~s & d
-#define GL_NOOP 0x1505 // d
-#define GL_XOR 0x1506 // s ^ d
-#define GL_OR 0x1507 // s | d
-#define GL_NOR 0x1508 // ~(s | d)
-#define GL_EQUIV 0x1509 // ~(s ^ d)
-#define GL_INVERT 0x150A // ~d
-#define GL_OR_REVERSE 0x150B // s | ~d
-#define GL_COPY_INVERTED 0x150C // ~s
-#define GL_OR_INVERTED 0x150D // ~s | d
-#define GL_NAND 0x150E // ~(s & d)
-#define GL_SET 0x150F // 1
-
-/* shade model */
-#define GL_FLAT 0x1D00
-#define GL_SMOOTH 0x1D01
-
-/* strings */
-#define GL_VENDOR 0x1F00
-#define GL_RENDERER 0x1F01
-#define GL_VERSION 0x1F02
-#define GL_EXTENSIONS 0x1F03
-
-/* stencil */
-#define GL_KEEP 0x1E00
-#define GL_REPLACE 0x1E01
-#define GL_INCR 0x1E02
-#define GL_DECR 0x1E03
-
-/* alpha & stencil */
-#define GL_NEVER 0x0200
-#define GL_LESS 0x0201
-#define GL_EQUAL 0x0202
-#define GL_LEQUAL 0x0203
-#define GL_GREATER 0x0204
-#define GL_NOTEQUAL 0x0205
-#define GL_GEQUAL 0x0206
-#define GL_ALWAYS 0x0207
-
-/* blending equation & function */
-#define GL_ZERO 0 // SD
-#define GL_ONE 1 // SD
-#define GL_SRC_COLOR 0x0300 // D
-#define GL_ONE_MINUS_SRC_COLOR 0x0301 // D
-#define GL_SRC_ALPHA 0x0302 // SD
-#define GL_ONE_MINUS_SRC_ALPHA 0x0303 // SD
-#define GL_DST_ALPHA 0x0304 // SD
-#define GL_ONE_MINUS_DST_ALPHA 0x0305 // SD
-#define GL_DST_COLOR 0x0306 // S
-#define GL_ONE_MINUS_DST_COLOR 0x0307 // S
-#define GL_SRC_ALPHA_SATURATE 0x0308 // S
-
-/* Texture parameter name */
-#define GL_TEXTURE_MIN_FILTER 0x2801
-#define GL_TEXTURE_MAG_FILTER 0x2800
-#define GL_TEXTURE_WRAP_S 0x2802
-#define GL_TEXTURE_WRAP_T 0x2803
-#define GL_GENERATE_MIPMAP 0x8191
-#define GL_TEXTURE_CROP_RECT_OES 0x8B9D
-
-/* Texture Filter */
-#define GL_NEAREST 0x2600
-#define GL_LINEAR 0x2601
-#define GL_NEAREST_MIPMAP_NEAREST 0x2700
-#define GL_LINEAR_MIPMAP_NEAREST 0x2701
-#define GL_NEAREST_MIPMAP_LINEAR 0x2702
-#define GL_LINEAR_MIPMAP_LINEAR 0x2703
-
-/* Texture Wrap Mode */
-#define GL_CLAMP 0x2900
-#define GL_REPEAT 0x2901
-#define GL_CLAMP_TO_EDGE 0x812F
-
-/* Texture Env Mode */
-#define GL_REPLACE 0x1E01
-#define GL_MODULATE 0x2100
-#define GL_DECAL 0x2101
-#define GL_ADD 0x0104
-
-/* Texture Env Parameter */
-#define GL_TEXTURE_ENV_MODE 0x2200
-#define GL_TEXTURE_ENV_COLOR 0x2201
-
-/* Texture Env Target */
-#define GL_TEXTURE_ENV 0x2300
-
-/* TMUs */
-#define GL_TEXTURE0 0x84C0
-#define GL_TEXTURE1 0x84C1
-#define GL_TEXTURE2 0x84C2
-#define GL_TEXTURE3 0x84C3
-#define GL_TEXTURE4 0x84C4
-#define GL_TEXTURE5 0x84C5
-#define GL_TEXTURE6 0x84C6
-#define GL_TEXTURE7 0x84C7
-#define GL_TEXTURE8 0x84C8
-#define GL_TEXTURE9 0x84C9
-#define GL_TEXTURE10 0x84CA
-#define GL_TEXTURE11 0x84CB
-#define GL_TEXTURE12 0x84CC
-#define GL_TEXTURE13 0x84CD
-#define GL_TEXTURE14 0x84CE
-#define GL_TEXTURE15 0x84CF
-#define GL_TEXTURE16 0x84D0
-#define GL_TEXTURE17 0x84D1
-#define GL_TEXTURE18 0x84D2
-#define GL_TEXTURE19 0x84D3
-#define GL_TEXTURE20 0x84D4
-#define GL_TEXTURE21 0x84D5
-#define GL_TEXTURE22 0x84D6
-#define GL_TEXTURE23 0x84D7
-#define GL_TEXTURE24 0x84D8
-#define GL_TEXTURE25 0x84D9
-#define GL_TEXTURE26 0x84DA
-#define GL_TEXTURE27 0x84DB
-#define GL_TEXTURE28 0x84DC
-#define GL_TEXTURE29 0x84DD
-#define GL_TEXTURE30 0x84DE
-#define GL_TEXTURE31 0x84DF
-
-/*****************************************************************************/
-/* OpenGL ES 1.1 additions */
-
-#define GL_ARRAY_BUFFER 0x8892
-#define GL_ELEMENT_ARRAY_BUFFER 0x8893
-
-#define GL_STATIC_DRAW 0x88E4
-#define GL_DYNAMIC_DRAW 0x88E8
-
-#define GL_BUFFER_SIZE 0x8764
-#define GL_BUFFER_USAGE 0x8765
-
-#define GL_ARRAY_BUFFER_BINDING 0x8894
-#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
-#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896
-#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897
-#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898
-#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
-
-/*****************************************************************************/
-/* Required extensions */
-
-#define GL_PALETTE4_RGB8_OES 0x8B90
-#define GL_PALETTE4_RGBA8_OES 0x8B91
-#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
-#define GL_PALETTE4_RGBA4_OES 0x8B93
-#define GL_PALETTE4_RGB5_A1_OES 0x8B94
-#define GL_PALETTE8_RGB8_OES 0x8B95
-#define GL_PALETTE8_RGBA8_OES 0x8B96
-#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
-#define GL_PALETTE8_RGBA4_OES 0x8B98
-#define GL_PALETTE8_RGB5_A1_OES 0x8B99
-
-#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
-#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
-
-#define GL_POINT_SPRITE_OES 0x8861
-#define GL_COORD_REPLACE_OES 0x8862
-
-#define GL_POINT_SIZE_ARRAY_OES 0x8B9C
-#define GL_POINT_SIZE_ARRAY_TYPE_OES 0x898A
-#define GL_POINT_SIZE_ARRAY_STRIDE_OES 0x898B
-#define GL_POINT_SIZE_ARRAY_POINTER_OES 0x898C
-#define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES 0x8B9F
-
-/*****************************************************************************/
-/* Extensions */
-
-#define GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES 0x898D
-#define GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES 0x898E
-#define GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES 0x898F
-
-#define GL_DIRECT_TEXTURE_2D_QUALCOMM 0x7E80
-
-
-
-
-/*****************************************************************************/
-/* OpenGL ES 1.0 functions */
-
-void glActiveTexture(GLenum texture);
-void glAlphaFunc(GLenum func, GLclampf ref);
-void glAlphaFuncx(GLenum func, GLclampx ref);
-void glBindTexture(GLenum target, GLuint texture);
-void glBlendFunc(GLenum sfactor, GLenum dfactor);
-void glClear(GLbitfield mask);
-void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
-void glClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
-void glClearDepthf(GLclampf depth);
-void glClearDepthx(GLclampx depth);
-void glClearStencil(GLint s);
-void glClientActiveTexture(GLenum texture);
-void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-void glColor4x(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
-void glColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a);
-void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
-void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
- GLsizei width, GLsizei height, GLint border,
- GLsizei imageSize, const GLvoid *data);
-void glCompressedTexSubImage2D( GLenum target, GLint level, GLint xoffset,
- GLint yoffset, GLsizei width, GLsizei height,
- GLenum format, GLsizei imageSize,
- const GLvoid *data);
-void glCopyTexImage2D( GLenum target, GLint level, GLenum internalformat,
- GLint x, GLint y, GLsizei width, GLsizei height,
- GLint border);
-void glCopyTexSubImage2D( GLenum target, GLint level, GLint xoffset,
- GLint yoffset, GLint x, GLint y, GLsizei width,
- GLsizei height);
-void glCullFace(GLenum mode);
-void glDeleteTextures(GLsizei n, const GLuint *textures);
-void glDepthFunc(GLenum func);
-void glDepthMask(GLboolean flag);
-void glDepthRangef(GLclampf zNear, GLclampf zFar);
-void glDepthRangex(GLclampx zNear, GLclampx zFar);
-void glDisable(GLenum cap);
-void glDisableClientState(GLenum array);
-void glDrawArrays(GLenum mode, GLint first, GLsizei count);
-void glDrawElements(GLenum mode, GLsizei count,
- GLenum type, const GLvoid *indices);
-void glEnable(GLenum cap);
-void glEnableClientState(GLenum array);
-void glFinish(void);
-void glFlush(void);
-void glFogf(GLenum pname, GLfloat param);
-void glFogfv(GLenum pname, const GLfloat *params);
-void glFogx(GLenum pname, GLfixed param);
-void glFogxv(GLenum pname, const GLfixed *params);
-void glFrontFace(GLenum mode);
-void glFrustumf(GLfloat left, GLfloat right,
- GLfloat bottom, GLfloat top,
- GLfloat zNear, GLfloat zFar);
-void glFrustumx(GLfixed left, GLfixed right,
- GLfixed bottom, GLfixed top,
- GLfixed zNear, GLfixed zFar);
-void glGenTextures(GLsizei n, GLuint *textures);
-GLenum glGetError(void);
-void glGetIntegerv(GLenum pname, GLint *params);
-const GLubyte * glGetString(GLenum name);
-void glHint(GLenum target, GLenum mode);
-void glLightModelf(GLenum pname, GLfloat param);
-void glLightModelfv(GLenum pname, const GLfloat *params);
-void glLightModelx(GLenum pname, GLfixed param);
-void glLightModelxv(GLenum pname, const GLfixed *params);
-void glLightf(GLenum light, GLenum pname, GLfloat param);
-void glLightfv(GLenum light, GLenum pname, const GLfloat *params);
-void glLightx(GLenum light, GLenum pname, GLfixed param);
-void glLightxv(GLenum light, GLenum pname, const GLfixed *params);
-void glLineWidth(GLfloat width);
-void glLineWidthx(GLfixed width);
-void glLoadIdentity(void);
-void glLoadMatrixf(const GLfloat *m);
-void glLoadMatrixx(const GLfixed *m);
-void glLogicOp(GLenum opcode);
-void glMaterialf(GLenum face, GLenum pname, GLfloat param);
-void glMaterialfv(GLenum face, GLenum pname, const GLfloat *params);
-void glMaterialx(GLenum face, GLenum pname, GLfixed param);
-void glMaterialxv(GLenum face, GLenum pname, const GLfixed *params);
-void glMatrixMode(GLenum mode);
-void glMultMatrixf(const GLfloat *m);
-void glMultMatrixx(const GLfixed *m);
-void glMultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
-void glMultiTexCoord4x(GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
-void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz);
-void glNormal3x(GLfixed nx, GLfixed ny, GLfixed nz);
-void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer);
-void glOrthof( GLfloat left, GLfloat right,
- GLfloat bottom, GLfloat top,
- GLfloat zNear, GLfloat zFar);
-void glOrthox( GLfixed left, GLfixed right,
- GLfixed bottom, GLfixed top,
- GLfixed zNear, GLfixed zFar);
-void glPixelStorei(GLenum pname, GLint param);
-void glPointSize(GLfloat size);
-void glPointSizex(GLfixed size);
-void glPolygonOffset(GLfloat factor, GLfloat units);
-void glPolygonOffsetx(GLfixed factor, GLfixed units);
-void glPopMatrix(void);
-void glPushMatrix(void);
-void glReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum format, GLenum type, GLvoid *pixels);
-void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
-void glRotatex(GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
-void glSampleCoverage(GLclampf value, GLboolean invert);
-void glSampleCoveragex(GLclampx value, GLboolean invert);
-void glScalef(GLfloat x, GLfloat y, GLfloat z);
-void glScalex(GLfixed x, GLfixed y, GLfixed z);
-void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
-void glShadeModel(GLenum mode);
-void glStencilFunc(GLenum func, GLint ref, GLuint mask);
-void glStencilMask(GLuint mask);
-void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass);
-void glTexCoordPointer( GLint size, GLenum type,
- GLsizei stride, const GLvoid *pointer);
-void glTexEnvf(GLenum target, GLenum pname, GLfloat param);
-void glTexEnvfv(GLenum target, GLenum pname, const GLfloat *params);
-void glTexEnvx(GLenum target, GLenum pname, GLfixed param);
-void glTexEnvxv(GLenum target, GLenum pname, const GLfixed *params);
-void glTexImage2D( GLenum target, GLint level, GLenum internalformat,
- GLsizei width, GLsizei height, GLint border, GLenum format,
- GLenum type, const GLvoid *pixels);
-void glTexParameterf(GLenum target, GLenum pname, GLfloat param);
-void glTexParameterx(GLenum target, GLenum pname, GLfixed param);
-void glTexSubImage2D( GLenum target, GLint level, GLint xoffset,
- GLint yoffset, GLsizei width, GLsizei height,
- GLenum format, GLenum type, const GLvoid *pixels);
-void glTranslatef(GLfloat x, GLfloat y, GLfloat z);
-void glTranslatex(GLfixed x, GLfixed y, GLfixed z);
-void glVertexPointer( GLint size, GLenum type,
- GLsizei stride, const GLvoid *pointer);
-void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
-
-/*****************************************************************************/
-/* OpenGL ES 1.1 functions */
-
-void glClipPlanef(GLenum plane, const GLfloat* equation);
-void glClipPlanex(GLenum plane, const GLfixed* equation);
-
-void glBindBuffer(GLenum target, GLuint buffer);
-void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
-void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
-void glDeleteBuffers(GLsizei n, const GLuint* buffers);
-void glGenBuffers(GLsizei n, GLuint* buffers);
-
-void glGetBooleanv(GLenum pname, GLboolean *params);
-void glGetFixedv(GLenum pname, GLfixed *params);
-void glGetFloatv(GLenum pname, GLfloat *params);
-void glGetPointerv(GLenum pname, void **params);
-void glGetBufferParameteriv(GLenum target, GLenum pname, GLint *params);
-void glGetClipPlanef(GLenum pname, GLfloat eqn[4]);
-void glGetClipPlanex(GLenum pname, GLfixed eqn[4]);
-void glGetLightxv(GLenum light, GLenum pname, GLfixed *params);
-void glGetLightfv(GLenum light, GLenum pname, GLfloat *params);
-void glGetMaterialxv(GLenum face, GLenum pname, GLfixed *params);
-void glGetMaterialfv(GLenum face, GLenum pname, GLfloat *params);
-void glGetTexEnvfv(GLenum env, GLenum pname, GLfloat *params);
-void glGetTexEnviv(GLenum env, GLenum pname, GLint *params);
-void glGetTexEnvxv(GLenum env, GLenum pname, GLfixed *params);
-void glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params);
-void glGetTexParameteriv(GLenum target, GLenum pname, GLint *params);
-void glGetTexParameterxv(GLenum target, GLenum pname, GLfixed *params);
-GLboolean glIsBuffer(GLuint buffer);
-GLboolean glIsEnabled(GLenum cap);
-GLboolean glIsTexture(GLuint texture);
-void glPointParameterf(GLenum pname, GLfloat param);
-void glPointParameterfv(GLenum pname, const GLfloat *params);
-void glPointParameterx(GLenum pname, GLfixed param);
-void glPointParameterxv(GLenum pname, const GLfixed *params);
-void glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
-void glTexEnvi(GLenum target, GLenum pname, GLint param);
-void glTexEnviv(GLenum target, GLenum pname, const GLint *params);
-void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params);
-void glTexParameteriv(GLenum target, GLenum pname, const GLint *params);
-void glTexParameteri(GLenum target, GLenum pname, GLint param);
-void glTexParameterxv(GLenum target, GLenum pname, const GLfixed *params);
-
-/*****************************************************************************/
-/* Required extensions functions */
-
-void glPointSizePointerOES(GLenum type, GLsizei stride, const GLvoid *pointer);
-
-
-/*****************************************************************************/
-/* Extensions functions */
-
-void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h);
-void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h);
-void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h);
-void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h);
-void glDrawTexsvOES(const GLshort* coords);
-void glDrawTexivOES(const GLint* coords);
-void glDrawTexfvOES(const GLfloat* coords);
-void glDrawTexxvOES(const GLfixed* coords);
-GLbitfield glQueryMatrixxOES(GLfixed* mantissa, GLint* exponent);
-
-/* called by dalvik */
-void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
- const GLvoid *ptr, GLsizei count);
-void glNormalPointerBounds(GLenum type, GLsizei stride,
- const GLvoid *pointer, GLsizei count);
-void glTexCoordPointerBounds(GLint size, GLenum type,
- GLsizei stride, const GLvoid *pointer, GLsizei count);
-void glVertexPointerBounds(GLint size, GLenum type,
- GLsizei stride, const GLvoid *pointer, GLsizei count);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __gl_h_ */
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index dd585c9..ff64855 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -125,7 +125,8 @@ public:
* channelCount: Number of PCM channels (e.g 2 for stereo).
* frameCount: Total size of track PCM buffer in frames. This defines the
* latency of the track.
- * flags: Reserved for future use.
+ * flags: A bitmask of acoustic values from enum record_flags. It enables
+ * AGC, NS, and IIR.
* cbf: Callback function. If not null, this function is called periodically
* to provide new PCM data.
* notificationFrames: The callback function is called each time notificationFrames PCM
@@ -133,6 +134,12 @@ public:
* user Context for use by the callback receiver.
*/
+ enum record_flags {
+ RECORD_AGC_ENABLE = AudioSystem::AGC_ENABLE,
+ RECORD_NS_ENABLE = AudioSystem::NS_ENABLE,
+ RECORD_IIR_ENABLE = AudioSystem::TX_IIR_ENABLE
+ };
+
AudioRecord(int streamType,
uint32_t sampleRate = 0,
int format = 0,
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 77676bf..77c90ba 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -29,8 +29,27 @@ class AudioSystem
{
public:
+ enum stream_type {
+ DEFAULT =-1,
+ VOICE_CALL = 0,
+ SYSTEM = 1,
+ RING = 2,
+ MUSIC = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ BLUETOOTH_SCO = 6,
+ NUM_STREAM_TYPES
+ };
+
+ enum audio_output_type {
+ AUDIO_OUTPUT_DEFAULT =-1,
+ AUDIO_OUTPUT_HARDWARE = 0,
+ AUDIO_OUTPUT_A2DP = 1,
+ NUM_AUDIO_OUTPUT_TYPES
+ };
+
enum audio_format {
- DEFAULT = 0,
+ FORMAT_DEFAULT = 0,
PCM_16_BIT,
PCM_8_BIT,
INVALID_FORMAT
@@ -51,7 +70,16 @@ public:
ROUTE_BLUETOOTH_SCO = (1 << 2),
ROUTE_HEADSET = (1 << 3),
ROUTE_BLUETOOTH_A2DP = (1 << 4),
- ROUTE_ALL = 0xFFFFFFFF
+ ROUTE_ALL = -1UL,
+ };
+
+ enum audio_in_acoustics {
+ AGC_ENABLE = 0x0001,
+ AGC_DISABLE = 0,
+ NS_ENABLE = 0x0002,
+ NS_DISABLE = 0,
+ TX_IIR_ENABLE = 0x0004,
+ TX_DISABLE = 0
};
/* These are static methods to control the system-wide AudioFlinger
@@ -96,33 +124,52 @@ public:
static float linearToLog(int volume);
static int logToLinear(float volume);
- static status_t getOutputSamplingRate(int* samplingRate);
- static status_t getOutputFrameCount(int* frameCount);
- static status_t getOutputLatency(uint32_t* latency);
+ static status_t getOutputSamplingRate(int* samplingRate, int stream = DEFAULT);
+ static status_t getOutputFrameCount(int* frameCount, int stream = DEFAULT);
+ static status_t getOutputLatency(uint32_t* latency, int stream = DEFAULT);
+
+ static bool routedToA2dpOutput(int streamType);
+
+ static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
+ size_t* buffSize);
// ----------------------------------------------------------------------------
private:
- class DeathNotifier: public IBinder::DeathRecipient
+ class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient
{
public:
- DeathNotifier() {
+ AudioFlingerClient() {
}
+ // DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
+
+ // IAudioFlingerClient
+ virtual void a2dpEnabledChanged(bool enabled);
+
};
+ static int getOutput(int streamType);
- static sp<DeathNotifier> gDeathNotifier;
+ static sp<AudioFlingerClient> gAudioFlingerClient;
- friend class DeathNotifier;
+ friend class AudioFlingerClient;
static Mutex gLock;
static sp<IAudioFlinger> gAudioFlinger;
static audio_error_callback gAudioErrorCallback;
- static int gOutSamplingRate;
- static int gOutFrameCount;
- static uint32_t gOutLatency;
+ static int gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
+ static int gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
+ static uint32_t gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
+ static bool gA2dpEnabled;
+
+ static size_t gInBuffSize;
+ // previous parameters for recording buffer size queries
+ static uint32_t gPrevInSamplingRate;
+ static int gPrevInFormat;
+ static int gPrevInChannelCount;
+
};
}; // namespace android
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index fd62daa..659f5f8 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -42,18 +42,6 @@ class audio_track_cblk_t;
class AudioTrack
{
public:
-
- enum stream_type {
- DEFAULT =-1,
- VOICE_CALL = 0,
- SYSTEM = 1,
- RING = 2,
- MUSIC = 3,
- ALARM = 4,
- NOTIFICATION = 5,
- NUM_STREAM_TYPES
- };
-
enum channel_index {
MONO = 0,
LEFT = 0,
@@ -127,7 +115,7 @@ public:
* Parameters:
*
* streamType: Select the type of audio stream this track is attached to
- * (e.g. AudioTrack::MUSIC).
+ * (e.g. AudioSystem::MUSIC).
* sampleRate: Track sampling rate in Hz.
* format: PCM sample format (e.g AudioSystem::PCM_16_BIT for signed
* 16 bits per sample).
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 69703b2..6f13fe0 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -26,6 +26,7 @@
#include <utils/IInterface.h>
#include <media/IAudioTrack.h>
#include <media/IAudioRecord.h>
+#include <media/IAudioFlingerClient.h>
namespace android {
@@ -64,11 +65,11 @@ public:
/* query the audio hardware state. This state never changes,
* and therefore can be cached.
*/
- virtual uint32_t sampleRate() const = 0;
- virtual int channelCount() const = 0;
- virtual int format() const = 0;
- virtual size_t frameCount() const = 0;
- virtual uint32_t latency() const = 0;
+ virtual uint32_t sampleRate(int output) const = 0;
+ virtual int channelCount(int output) const = 0;
+ virtual int format(int output) const = 0;
+ virtual size_t frameCount(int output) const = 0;
+ virtual uint32_t latency(int output) const = 0;
/* set/get the audio hardware state. This will probably be used by
* the preference panel, mostly.
@@ -107,6 +108,18 @@ public:
// Temporary interface, do not use
// TODO: Replace with a more generic key:value get/set mechanism
virtual status_t setParameter(const char* key, const char* value) = 0;
+
+ // register a current process for audio output change notifications
+ virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
+
+ // retrieve the audio recording buffer size
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0;
+
+ // force AudioFlinger thread out of standby
+ virtual void wakeUp() = 0;
+
+ // is A2DP output enabled
+ virtual bool isA2dpEnabled() const = 0;
};
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
new file mode 100644
index 0000000..c3deb0b
--- /dev/null
+++ b/include/media/IAudioFlingerClient.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_IAUDIOFLINGERCLIENT_H
+#define ANDROID_IAUDIOFLINGERCLIENT_H
+
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IAudioFlingerClient : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(AudioFlingerClient);
+
+ // Notifies a change of audio output from/to hardware to/from A2DP.
+ virtual void a2dpEnabledChanged(bool enabled) = 0;
+
+};
+
+
+// ----------------------------------------------------------------------------
+
+class BnAudioFlingerClient : public BnInterface<IAudioFlingerClient>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAUDIOFLINGERCLIENT_H
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 49e45d1..64d3a40 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -24,6 +24,7 @@ namespace android {
class ISurface;
class ICamera;
+class IMediaPlayerClient;
class IMediaRecorder: public IInterface
{
@@ -38,8 +39,11 @@ public:
virtual status_t setVideoEncoder(int ve) = 0;
virtual status_t setAudioEncoder(int ae) = 0;
virtual status_t setOutputFile(const char* path) = 0;
+ virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
virtual status_t setVideoSize(int width, int height) = 0;
virtual status_t setVideoFrameRate(int frames_per_second) = 0;
+ virtual status_t setParameters(const String8& params) = 0;
+ virtual status_t setListener(const sp<IMediaPlayerClient>& listener) = 0;
virtual status_t prepare() = 0;
virtual status_t getMaxAmplitude(int* max) = 0;
virtual status_t start() = 0;
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
index 4268170..16764a9 100644
--- a/include/media/JetPlayer.h
+++ b/include/media/JetPlayer.h
@@ -33,9 +33,12 @@ class JetPlayer {
public:
- static const int JET_USERID_UPDATE = 1;
- static const int JET_NUMQUEUEDSEGMENT_UPDATE = 2;
- static const int JET_PAUSE_UPDATE = 3;
+ // to keep in sync with the JetPlayer class constants
+ // defined in frameworks/base/media/java/android/media/JetPlayer.java
+ static const int JET_EVENT = 1;
+ static const int JET_USERID_UPDATE = 2;
+ static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
+ static const int JET_PAUSE_UPDATE = 4;
JetPlayer(jobject javaJetPlayer,
int maxTracks = 32,
@@ -44,7 +47,8 @@ public:
int init();
int release();
- int openFile(const char* url);
+ int loadFromFile(const char* url);
+ int loadFromFD(const int fd, const long long offset, const long long length);
int closeFile();
int play();
int pause();
@@ -53,6 +57,7 @@ public:
int setMuteFlags(EAS_U32 muteFlags, bool sync);
int setMuteFlag(int trackNum, bool muteFlag, bool sync);
int triggerClip(int clipId);
+ int clearQueue();
void setEventCallback(jetevent_callback callback);
@@ -62,7 +67,8 @@ public:
private:
static int renderThread(void*);
int render();
- void fireEventOnStatusChange();
+ void fireUpdateOnStatusChange();
+ void fireEventsFromJetQueue();
JetPlayer() {} // no default constructor
void dump();
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 30e4578..7f0e7b3 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -17,9 +17,6 @@
#ifndef ANDROID_MEDIAPLAYERINTERFACE_H
#define ANDROID_MEDIAPLAYERINTERFACE_H
-#include <pthread.h>
-#include <signal.h>
-
#ifdef __cplusplus
#include <ui/ISurface.h>
@@ -74,7 +71,6 @@ public:
virtual ~MediaPlayerBase() {}
virtual status_t initCheck() = 0;
virtual bool hardwareOutput() = 0;
- virtual status_t setSigBusHandlerStructTLSKey(pthread_key_t key) { return 0; }
virtual status_t setDataSource(const char *url) = 0;
virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
virtual status_t setVideoSurface(const sp<ISurface>& surface) = 0;
@@ -125,34 +121,6 @@ public:
#endif // __cplusplus
-// A thread can set the thread local variable identified by the pthread_key_t
-// that was passed to the player using the setSigBusHandlerStructTLSKey()
-// method to the address of the following structure.
-// If 'handlesigbus' is non-NULL, the function it points to will be called,
-// and if it returns 0, the signal will be assumed to have been handled,
-// and no other action will be taken. If it returns non-zero, the old SIGBUS
-// handler will be called.
-// If 'handlesigbus is NULL, then sigbusvar must be non NULL. The system's
-// SIGBUS handler will map an accessible page filled with zeroes at the
-// location that caused the original fault, set the variable pointed to by
-// sigbusvar to a non-zero value, and exit (which causes the operation to
-// be retried, which should now succeed).
-// If base and len are non zero, which is strongly recommended, they will
-// be used as additional constraints on the signal handler. That is, when
-// specified, the fault address must be in the range specified by base and
-// len in order for handlesigbus() to be called or sigbusvar to be set.
-// If the fault address is outside of the range, the old SIGBUS handler
-// will be called.
-struct mediasigbushandler {
- int (*handlesigbus)(siginfo_t *, struct mediasigbushandler *);
- int *sigbusvar;
- char *base;
- int len;
- // these next two are free for application use
- struct mediasigbushandler *next;
- void *data;
-};
-
#endif // ANDROID_MEDIAPLAYERINTERFACE_H
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index 5fee0d6..0c71932 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -19,6 +19,7 @@
#define ANDROID_PVMEDIARECORDER_H
#include <media/mediarecorder.h>
+#include <media/IMediaPlayerClient.h>
namespace android {
@@ -43,6 +44,9 @@ public:
status_t setCamera(const sp<ICamera>& camera);
status_t setPreviewSurface(const sp<ISurface>& surface);
status_t setOutputFile(const char *path);
+ status_t setOutputFile(int fd, int64_t offset, int64_t length);
+ status_t setParameters(const String8& params);
+ status_t setListener(const sp<IMediaPlayerClient>& listener);
status_t prepare();
status_t start();
status_t stop();
diff --git a/include/media/PVPlayer.h b/include/media/PVPlayer.h
index 5f302ed..8122df6 100644
--- a/include/media/PVPlayer.h
+++ b/include/media/PVPlayer.h
@@ -20,6 +20,12 @@
#include <utils/Errors.h>
#include <media/MediaPlayerInterface.h>
+#define MAX_OPENCORE_INSTANCES 25
+
+#ifdef MAX_OPENCORE_INSTANCES
+#include <cutils/atomic.h>
+#endif
+
class PlayerDriver;
namespace android {
@@ -31,7 +37,6 @@ public:
virtual ~PVPlayer();
virtual status_t initCheck();
- virtual status_t setSigBusHandlerStructTLSKey(pthread_key_t key);
virtual status_t setDataSource(const char *url);
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
virtual status_t setVideoSurface(const sp<ISurface>& surface);
@@ -48,8 +53,8 @@ public:
virtual status_t setLooping(int loop);
virtual player_type playerType() { return PV_PLAYER; }
- // make available to PlayerDriver
- void sendEvent(int msg, int ext1=0, int ext2=0) { MediaPlayerBase::sendEvent(msg, ext1, ext2); }
+ // make available to PlayerDriver
+ void sendEvent(int msg, int ext1=0, int ext2=0) { MediaPlayerBase::sendEvent(msg, ext1, ext2); }
private:
static void do_nothing(status_t s, void *cookie, bool cancelled) { }
@@ -62,10 +67,13 @@ private:
char * mDataSourcePath;
bool mIsDataSourceSet;
sp<ISurface> mSurface;
- void * mMemBase;
- off_t mMemSize;
+ int mSharedFd;
status_t mInit;
int mDuration;
+
+#ifdef MAX_OPENCORE_INSTANCES
+ static volatile int32_t sNumInstances;
+#endif
};
}; // namespace android
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index 0cfdeec7..ec64e4d 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -85,8 +85,6 @@ private:
TONE_RESTARTING //
};
- static const unsigned int NUM_PCM_BUFFERS = 2; // Number of AudioTrack pcm buffers
-
static const unsigned int TONEGEN_MAX_WAVES = 3;
static const unsigned int TONEGEN_MAX_SEGMENTS = 4; // Maximun number of elenemts in
static const unsigned int TONEGEN_INF = 0xFFFFFFFF; // Represents infinite time duration
@@ -127,7 +125,6 @@ private:
const ToneDescriptor *mpNewToneDesc; // pointer to next active tone descriptor
int mSamplingRate; // AudioFlinger Sampling rate
- int mBufferSize; // PCM buffer size in frames
AudioTrack *mpAudioTrack; // Pointer to audio track used for playback
Mutex mLock; // Mutex to control concurent access to ToneGenerator object from audio callback and application API
Mutex mCbkCondLock; // Mutex associated to mWaitCbkCond
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 7288445..58906d1 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -34,11 +34,72 @@ enum media_event_type {
MEDIA_SEEK_COMPLETE = 4,
MEDIA_SET_VIDEO_SIZE = 5,
MEDIA_ERROR = 100,
+ MEDIA_INFO = 200,
};
-typedef int media_error_type;
-const media_error_type MEDIA_ERROR_UNKNOWN = 1;
-const media_error_type MEDIA_ERROR_SERVER_DIED = 100;
+// Generic error codes for the media player framework. Errors are fatal, the
+// playback must abort.
+//
+// Errors are communicated back to the client using the
+// MediaPlayerListener::notify method defined below.
+// In this situation, 'notify' is invoked with the following:
+// 'msg' is set to MEDIA_ERROR.
+// 'ext1' should be a value from the enum media_error_type.
+// 'ext2' contains an implementation dependant error code to provide
+// more details. Should default to 0 when not used.
+//
+// The codes are distributed as follow:
+// 0xx: Reserved
+// 1xx: Android Player errors. Something went wrong inside the MediaPlayer.
+// 2xx: Media errors (e.g Codec not supported). There is a problem with the
+// media itself.
+// 3xx: Runtime errors. Some extraordinary condition arose making the playback
+// impossible.
+//
+enum media_error_type {
+ // 0xx
+ MEDIA_ERROR_UNKNOWN = 1,
+ // 1xx
+ MEDIA_ERROR_SERVER_DIED = 100,
+ // 2xx
+ MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
+ // 3xx
+};
+
+
+// Info and warning codes for the media player framework. These are non fatal,
+// the playback is going on but there might be some user visible issues.
+//
+// Info and warning messages are communicated back to the client using the
+// MediaPlayerListener::notify method defined below. In this situation,
+// 'notify' is invoked with the following:
+// 'msg' is set to MEDIA_INFO.
+// 'ext1' should be a value from the enum media_info_type.
+// 'ext2' contains an implementation dependant error code to provide
+// more details. Should default to 0 when not used.
+//
+// The codes are distributed as follow:
+// 0xx: Reserved
+// 7xx: Android Player info/warning (e.g player lagging behind.)
+// 8xx: Media info/warning (e.g media badly interleaved.)
+//
+enum media_info_type {
+ // 0xx
+ MEDIA_INFO_UNKNOWN = 1,
+ // 7xx
+ // The video is too complex for the decoder: it can't decode frames fast
+ // enough. Possibly only the audio plays fine at this stage.
+ MEDIA_INFO_VIDEO_TRACK_LAGGING = 700,
+ // 8xx
+ // Bad interleaving means that a media has been improperly interleaved or not
+ // interleaved at all, e.g has all the video samples first then all the audio
+ // ones. Video is playing but a lot of disk seek may be happening.
+ MEDIA_INFO_BAD_INTERLEAVING = 800,
+ // The media is not seekable (e.g live stream).
+ MEDIA_INFO_NOT_SEEKABLE = 801,
+};
+
+
enum media_player_states {
MEDIA_PLAYER_STATE_ERROR = 0,
@@ -141,4 +202,3 @@ private:
}; // namespace android
#endif // ANDROID_MEDIAPLAYER_H
-
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index a901d32..78d7621 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -19,6 +19,7 @@
#define ANDROID_MEDIARECORDER_H
#include <utils.h>
+#include <media/IMediaPlayerClient.h>
namespace android {
@@ -87,7 +88,34 @@ enum media_recorder_states {
MEDIA_RECORDER_RECORDING = 1 << 4,
};
-class MediaRecorder
+// The "msg" code passed to the listener in notify.
+enum media_recorder_event_type {
+ MEDIA_RECORDER_EVENT_ERROR = 1,
+ MEDIA_RECORDER_EVENT_INFO = 2
+};
+
+enum media_recorder_error_type {
+ MEDIA_RECORDER_ERROR_UNKNOWN = 1
+};
+
+// The codes are distributed as follow:
+// 0xx: Reserved
+// 8xx: General info/warning
+//
+enum media_recorder_info_type {
+ MEDIA_RECORDER_INFO_UNKNOWN = 1,
+ MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800
+};
+
+// ----------------------------------------------------------------------------
+// ref-counted object for callbacks
+class MediaRecorderListener: virtual public RefBase
+{
+public:
+ virtual void notify(int msg, int ext1, int ext2) = 0;
+};
+
+class MediaRecorder : public BnMediaPlayerClient
{
public:
MediaRecorder();
@@ -102,8 +130,11 @@ public:
status_t setVideoEncoder(int ve);
status_t setAudioEncoder(int ae);
status_t setOutputFile(const char* path);
+ status_t setOutputFile(int fd, int64_t offset, int64_t length);
status_t setVideoSize(int width, int height);
status_t setVideoFrameRate(int frames_per_second);
+ status_t setParameters(const String8& params);
+ status_t setListener(const sp<MediaRecorderListener>& listener);
status_t prepare();
status_t getMaxAmplitude(int* max);
status_t start();
@@ -112,18 +143,22 @@ public:
status_t init();
status_t close();
status_t release();
+ void notify(int msg, int ext1, int ext2);
private:
void doCleanUp();
status_t doReset();
- sp<IMediaRecorder> mMediaRecorder;
- media_recorder_states mCurrentState;
- bool mIsAudioSourceSet;
- bool mIsVideoSourceSet;
- bool mIsAudioEncoderSet;
- bool mIsVideoEncoderSet;
- bool mIsOutputFileSet;
+ sp<IMediaRecorder> mMediaRecorder;
+ sp<MediaRecorderListener> mListener;
+ media_recorder_states mCurrentState;
+ bool mIsAudioSourceSet;
+ bool mIsVideoSourceSet;
+ bool mIsAudioEncoderSet;
+ bool mIsVideoEncoderSet;
+ bool mIsOutputFileSet;
+ Mutex mLock;
+ Mutex mNotifyLock;
};
}; // namespace android
diff --git a/include/media/thread_init.h b/include/media/thread_init.h
index 2c0c1f1..2feac86 100644
--- a/include/media/thread_init.h
+++ b/include/media/thread_init.h
@@ -19,7 +19,6 @@
bool InitializeForThread();
void UninitializeForThread();
-void keydestructor(void*);
#endif /* THREAD_INIT_H*/
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index 3056139..0c7ad46 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -28,6 +28,7 @@
#include <private/pixelflinger/ggl_context.h>
#include <GLES/gl.h>
+#include <GLES/glext.h>
namespace android {
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index 44acce5..e593fea 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -23,8 +23,8 @@
namespace android {
/*
- * A set of bit masks for specifying how the received frames from preview are
- * handled before the frame callback call.
+ * A set of bit masks for specifying how the received preview frames are
+ * handled before the previewCallback() call.
*
* The least significant 3 bits of an "int" value are used for this purpose:
*
@@ -34,10 +34,18 @@ namespace android {
* | |-----------> determine whether the callback is one-shot or not
* |-------------> determine whether the frame is copied out or not
*
+ * WARNING:
+ * When a frame is sent directly without copying, it is the frame receiver's
+ * responsiblity to make sure that the frame data won't get corrupted by
+ * subsequent preview frames filled by the camera. This flag is recommended
+ * only when copying out data brings significant performance price and the
+ * handling/processing of the received frame data is always faster than
+ * the preview frame rate so that data corruption won't occur.
+ *
* For instance,
* 1. 0x00 disables the callback. In this case, copy out and one shot bits
* are ignored.
- * 2. 0x01 enables a callback without copying out the recievied frames. A
+ * 2. 0x01 enables a callback without copying out the received frames. A
* typical use case is the Camcorder application to avoid making costly
* frame copies.
* 3. 0x05 is enabling a callback with frame copied out repeatedly. A typical
@@ -96,6 +104,18 @@ public:
// get preview state
bool previewEnabled();
+ // start recording mode, must call setPreviewDisplay first
+ status_t startRecording();
+
+ // stop recording mode
+ void stopRecording();
+
+ // get recording state
+ bool recordingEnabled();
+
+ // release a recording frame
+ void releaseRecordingFrame(const sp<IMemory>& mem);
+
// autoFocus - status returned from callback
status_t autoFocus();
@@ -111,20 +131,19 @@ public:
void setShutterCallback(shutter_callback cb, void *cookie);
void setRawCallback(frame_callback cb, void *cookie);
void setJpegCallback(frame_callback cb, void *cookie);
-
- void setFrameCallback(frame_callback cb,
- void *cookie,
- int frame_callback_flag = FRAME_CALLBACK_FLAG_NOOP);
-
+ void setRecordingCallback(frame_callback cb, void *cookie);
+ void setPreviewCallback(frame_callback cb, void *cookie, int preview_callback_flag = FRAME_CALLBACK_FLAG_NOOP);
void setErrorCallback(error_callback cb, void *cookie);
void setAutoFocusCallback(autofocus_callback cb, void *cookie);
+
// ICameraClient interface
virtual void shutterCallback();
virtual void rawCallback(const sp<IMemory>& picture);
virtual void jpegCallback(const sp<IMemory>& picture);
- virtual void frameCallback(const sp<IMemory>& frame);
+ virtual void previewCallback(const sp<IMemory>& frame);
virtual void errorCallback(status_t error);
virtual void autoFocusCallback(bool focused);
+ virtual void recordingCallback(const sp<IMemory>& frame);
sp<ICamera> remote();
@@ -155,8 +174,10 @@ private:
void *mRawCallbackCookie;
frame_callback mJpegCallback;
void *mJpegCallbackCookie;
- frame_callback mFrameCallback;
- void *mFrameCallbackCookie;
+ frame_callback mPreviewCallback;
+ void *mPreviewCallbackCookie;
+ frame_callback mRecordingCallback;
+ void *mRecordingCallbackCookie;
error_callback mErrorCallback;
void *mErrorCallbackCookie;
autofocus_callback mAutoFocusCallback;
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
index 2bd53dd..73036f0 100644
--- a/include/ui/CameraHardwareInterface.h
+++ b/include/ui/CameraHardwareInterface.h
@@ -20,12 +20,16 @@
#include <utils/IMemory.h>
#include <utils/RefBase.h>
#include <ui/CameraParameters.h>
+#include <ui/Overlay.h>
namespace android {
/** Callback for startPreview() */
typedef void (*preview_callback)(const sp<IMemory>& mem, void* user);
+/** Callback for startRecord() */
+typedef void (*recording_callback)(const sp<IMemory>& mem, void* user);
+
/** Callback for takePicture() */
typedef void (*shutter_callback)(void* user);
@@ -83,12 +87,20 @@ public:
/** Return the IMemoryHeap for the preview image heap */
virtual sp<IMemoryHeap> getPreviewHeap() const = 0;
+ /** Return the IMemoryHeap for the raw image heap */
+ virtual sp<IMemoryHeap> getRawHeap() const = 0;
+
/**
* Start preview mode. When a preview image is available
* preview_callback is called with the user parameter. The
* call back parameter may be null.
*/
virtual status_t startPreview(preview_callback cb, void* user) = 0;
+ /**
+ * Only used if overlays are used for camera preview.
+ */
+ virtual bool useOverlay() {return false;}
+ virtual status_t setOverlay(const sp<Overlay> &overlay) {return BAD_VALUE;}
/**
* Stop a previously started preview.
@@ -101,6 +113,29 @@ public:
virtual bool previewEnabled() = 0;
/**
+ * Start record mode. When a record image is available recording_callback()
+ * is called with the user parameter. Every record frame must be released
+ * by calling releaseRecordingFrame().
+ */
+ virtual status_t startRecording(recording_callback cb, void* user) = 0;
+
+ /**
+ * Stop a previously started recording.
+ */
+ virtual void stopRecording() = 0;
+
+ /**
+ * Returns true if recording is enabled.
+ */
+ virtual bool recordingEnabled() = 0;
+
+ /**
+ * Release a record frame previously returned by the recording_callback()
+ * passed to startRecord().
+ */
+ virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
+
+ /**
* Start auto focus, the callback routine is called
* once when focusing is complete. autoFocus() will
* be called again if another auto focus is needed.
diff --git a/include/ui/CameraParameters.h b/include/ui/CameraParameters.h
index e35a054..9ca1806 100644
--- a/include/ui/CameraParameters.h
+++ b/include/ui/CameraParameters.h
@@ -29,6 +29,12 @@ public:
CameraParameters(const String8 &params) { unflatten(params); }
~CameraParameters();
+ enum {
+ CAMERA_ORIENTATION_UNKNOWN = 0,
+ CAMERA_ORIENTATION_PORTRAIT = 1,
+ CAMERA_ORIENTATION_LANDSCAPE = 2,
+ };
+
String8 flatten() const;
void unflatten(const String8 &params);
@@ -57,6 +63,9 @@ public:
void setPictureFormat(const char *format);
const char *getPictureFormat() const;
+ int getOrientation() const;
+ void setOrientation(int orientation);
+
void dump() const;
status_t dump(int fd, const Vector<String16>& args) const;
diff --git a/include/ui/EGLDisplaySurface.h b/include/ui/EGLDisplaySurface.h
index 0190e09..a8b5853 100644
--- a/include/ui/EGLDisplaySurface.h
+++ b/include/ui/EGLDisplaySurface.h
@@ -27,7 +27,10 @@
#include <pixelflinger/pixelflinger.h>
#include <linux/fb.h>
+#include <EGL/egl.h>
+
struct copybit_device_t;
+struct copybit_image_t;
// ---------------------------------------------------------------------------
namespace android {
@@ -44,17 +47,17 @@ public:
int32_t getPageFlipCount() const;
void copyFrontToBack(const Region& copyback);
+ void copyFrontToImage(const copybit_image_t& dst);
+ void copyBackToImage(const copybit_image_t& dst);
+ void setSwapRectangle(int l, int t, int w, int h);
+
private:
static void hook_incRef(NativeWindowType window);
static void hook_decRef(NativeWindowType window);
static uint32_t hook_swapBuffers(NativeWindowType window);
- static void hook_setSwapRectangle(NativeWindowType window, int l, int t, int w, int h);
- static uint32_t hook_nextBuffer(NativeWindowType window);
uint32_t swapBuffers();
- uint32_t nextBuffer();
- void setSwapRectangle(int l, int t, int w, int h);
status_t mapFrameBuffer();
diff --git a/include/ui/EGLNativeSurface.h b/include/ui/EGLNativeSurface.h
index c303cd8..7964e7c 100644
--- a/include/ui/EGLNativeSurface.h
+++ b/include/ui/EGLNativeSurface.h
@@ -23,7 +23,7 @@
#include <cutils/atomic.h>
#include <utils/RefBase.h>
-#include <GLES/eglnatives.h>
+#include <EGL/eglnatives.h>
// ---------------------------------------------------------------------------
namespace android {
diff --git a/include/ui/EGLNativeWindowSurface.h b/include/ui/EGLNativeWindowSurface.h
index 058479a..3494234 100644
--- a/include/ui/EGLNativeWindowSurface.h
+++ b/include/ui/EGLNativeWindowSurface.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <ui/EGLNativeSurface.h>
+#include <EGL/egl.h>
// ---------------------------------------------------------------------------
namespace android {
@@ -33,18 +34,16 @@ public:
EGLNativeWindowSurface(const sp<Surface>& surface);
~EGLNativeWindowSurface();
+ void setSwapRectangle(int l, int t, int w, int h);
+
private:
static void hook_incRef(NativeWindowType window);
static void hook_decRef(NativeWindowType window);
static uint32_t hook_swapBuffers(NativeWindowType window);
- static uint32_t hook_nextBuffer(NativeWindowType window);
- static void hook_setSwapRectangle(NativeWindowType window, int l, int t, int w, int h);
static void hook_connect(NativeWindowType window);
static void hook_disconnect(NativeWindowType window);
uint32_t swapBuffers();
- uint32_t nextBuffer();
- void setSwapRectangle(int l, int t, int w, int h);
void connect();
void disconnect();
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index 017c145..3848d8c 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -76,6 +76,9 @@ public:
DEVICE_REMOVED = 0x20000000
};
+ // examine key input devices for specific framework keycode support
+ bool hasKeys(size_t numCodes, int32_t* keyCodes, uint8_t* outFlags);
+
virtual bool getEvent(int32_t* outDeviceId, int32_t* outType,
int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
int32_t* outValue, nsecs_t* outWhen);
@@ -100,6 +103,7 @@ private:
const String8 path;
String8 name;
uint32_t classes;
+ uint8_t* keyBitmask;
KeyLayoutMap* layoutMap;
String8 keylayoutFilename;
device_t* next;
@@ -134,8 +138,6 @@ private:
#ifdef EV_SW
int32_t mSwitches[SW_MAX+1];
#endif
-
- KeyLayoutMap * mLayoutMap;
};
}; // namespace android
diff --git a/include/ui/ICamera.h b/include/ui/ICamera.h
index ea2fcee..241fb63 100644
--- a/include/ui/ICamera.h
+++ b/include/ui/ICamera.h
@@ -48,9 +48,9 @@ public:
// pass the buffered ISurface to the camera service
virtual status_t setPreviewDisplay(const sp<ISurface>& surface) = 0;
- // set the frame callback flag to affect how the received frames from
+ // set the preview callback flag to affect how the received frames from
// preview are handled.
- virtual void setFrameCallbackFlag(int frame_callback_flag) = 0;
+ virtual void setPreviewCallbackFlag(int flag) = 0;
// start preview mode, must call setPreviewDisplay first
virtual status_t startPreview() = 0;
@@ -61,6 +61,18 @@ public:
// get preview state
virtual bool previewEnabled() = 0;
+ // start recording mode
+ virtual status_t startRecording() = 0;
+
+ // stop recording mode
+ virtual void stopRecording() = 0;
+
+ // get recording state
+ virtual bool recordingEnabled() = 0;
+
+ // release a recording frame
+ virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
+
// auto focus
virtual status_t autoFocus() = 0;
diff --git a/include/ui/ICameraClient.h b/include/ui/ICameraClient.h
index a286b8e..73b951c 100644
--- a/include/ui/ICameraClient.h
+++ b/include/ui/ICameraClient.h
@@ -32,9 +32,10 @@ public:
virtual void shutterCallback() = 0;
virtual void rawCallback(const sp<IMemory>& picture) = 0;
virtual void jpegCallback(const sp<IMemory>& picture) = 0;
- virtual void frameCallback(const sp<IMemory>& frame) = 0;
+ virtual void previewCallback(const sp<IMemory>& frame) = 0;
virtual void errorCallback(status_t error) = 0;
virtual void autoFocusCallback(bool focused) = 0;
+ virtual void recordingCallback(const sp<IMemory>& frame) = 0;
};
diff --git a/include/ui/ICameraService.h b/include/ui/ICameraService.h
index dfd8923..c652c51 100644
--- a/include/ui/ICameraService.h
+++ b/include/ui/ICameraService.h
@@ -28,7 +28,7 @@ namespace android {
class ICameraService : public IInterface
{
-protected:
+public:
enum {
CONNECT = IBinder::FIRST_CALL_TRANSACTION,
};
diff --git a/include/ui/ISurface.h b/include/ui/ISurface.h
index 9a7383c..87b320f 100644
--- a/include/ui/ISurface.h
+++ b/include/ui/ISurface.h
@@ -25,6 +25,8 @@
#include <utils/RefBase.h>
#include <ui/PixelFormat.h>
+#include <hardware/hardware.h>
+
namespace android {
typedef int32_t SurfaceID;
@@ -34,11 +36,48 @@ class OverlayRef;
class ISurface : public IInterface
{
+protected:
+ enum {
+ REGISTER_BUFFERS = IBinder::FIRST_CALL_TRANSACTION,
+ UNREGISTER_BUFFERS,
+ POST_BUFFER, // one-way transaction
+ CREATE_OVERLAY,
+ };
+
public:
DECLARE_META_INTERFACE(Surface);
- virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& heap) = 0;
+
+ class BufferHeap {
+ public:
+ enum {
+ /* rotate source image 90 degrees */
+ ROT_90 = HAL_TRANSFORM_ROT_90,
+ };
+ BufferHeap();
+
+ BufferHeap(uint32_t w, uint32_t h,
+ int32_t hor_stride, int32_t ver_stride,
+ PixelFormat format, const sp<IMemoryHeap>& heap);
+
+ BufferHeap(uint32_t w, uint32_t h,
+ int32_t hor_stride, int32_t ver_stride,
+ PixelFormat format, uint32_t transform, uint32_t flags,
+ const sp<IMemoryHeap>& heap);
+
+ ~BufferHeap();
+
+ uint32_t w;
+ uint32_t h;
+ int32_t hor_stride;
+ int32_t ver_stride;
+ PixelFormat format;
+ uint32_t transform;
+ uint32_t flags;
+ sp<IMemoryHeap> heap;
+ };
+
+ virtual status_t registerBuffers(const BufferHeap& buffers) = 0;
virtual void postBuffer(ssize_t offset) = 0; // one-way
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index 53c1188..efa6d2b 100644
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -113,6 +113,7 @@ static const KeycodeLabel KEYCODES[] = {
{ "PREVIOUSSONG", 88 },
{ "REWIND", 89 },
{ "FORWARD", 90 },
+ { "MUTE", 91 },
// NOTE: If you add a new keycode here you must also add it to:
// (enum KeyCode, in this file)
@@ -216,7 +217,8 @@ typedef enum KeyCode {
kKeyCodeNextSong = 87,
kKeyCodePreviousSong = 88,
kKeyCodeRewind = 89,
- kKeyCodeForward = 90
+ kKeyCodeForward = 90,
+ kKeyCodeMute = 91
} KeyCode;
static const KeycodeLabel FLAGS[] = {
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
index b65c959..14af823 100644
--- a/include/ui/PixelFormat.h
+++ b/include/ui/PixelFormat.h
@@ -71,6 +71,10 @@ enum {
PIXEL_FORMAT_YCbCr_422_SP= GGL_PIXEL_FORMAT_YCbCr_422_SP,
PIXEL_FORMAT_YCbCr_420_SP= GGL_PIXEL_FORMAT_YCbCr_420_SP,
+ PIXEL_FORMAT_YCbCr_422_P = GGL_PIXEL_FORMAT_YCbCr_422_P,
+ PIXEL_FORMAT_YCbCr_420_P = GGL_PIXEL_FORMAT_YCbCr_420_P,
+ PIXEL_FORMAT_YCbCr_422_I = GGL_PIXEL_FORMAT_YCbCr_422_I,
+ PIXEL_FORMAT_YCbCr_420_I = GGL_PIXEL_FORMAT_YCbCr_420_I,
// New formats can be added if they're also defined in
// pixelflinger/format.h
@@ -80,7 +84,19 @@ typedef int32_t PixelFormat;
struct PixelFormatInfo
{
+ enum { // components
+ ALPHA = 1,
+ RGB = 2,
+ RGBA = 3,
+ LUMINANCE = 4,
+ LUMINANCE_ALPHA = 5,
+ Y_CB_CR_SP = 6,
+ Y_CB_CR_P = 7,
+ Y_CB_CR_I = 8,
+ };
+
inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
+ size_t getScanlineSize(unsigned int width) const;
size_t version;
PixelFormat format;
size_t bytesPerPixel;
@@ -93,7 +109,9 @@ struct PixelFormatInfo
uint8_t l_green;
uint8_t h_blue;
uint8_t l_blue;
- uint32_t reserved[2];
+ uint8_t components;
+ uint8_t reserved0[3];
+ uint32_t reserved1;
};
// Consider caching the results of these functions are they're not
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 2d56e3e..7d3fcf2 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -223,7 +223,7 @@ struct Res_value
{
// Number of bytes in this structure.
uint16_t size;
-
+
// Always set to 0.
uint8_t res0;
@@ -1101,16 +1101,22 @@ struct ResTable_config
return false;
}
- // Return true if 'this' can be considered a match for the parameters in
+ // Return true if 'this' can be considered a match for the parameters in
// 'settings'.
+ // Note this is asymetric. A default piece of data will match every request
+ // but a request for the default should not match odd specifics
+ // (ie, request with no mcc should not match a particular mcc's data)
+ // settings is the requested settings
inline bool match(const ResTable_config& settings) const {
if (imsi != 0) {
- if (settings.mcc != 0 && mcc != 0
- && mcc != settings.mcc) {
+ if ((settings.mcc != 0 && mcc != 0
+ && mcc != settings.mcc) ||
+ (settings.mcc == 0 && mcc != 0)) {
return false;
}
- if (settings.mnc != 0 && mnc != 0
- && mnc != settings.mnc) {
+ if ((settings.mnc != 0 && mnc != 0
+ && mnc != settings.mnc) ||
+ (settings.mnc == 0 && mnc != 0)) {
return false;
}
}
@@ -1131,10 +1137,8 @@ struct ResTable_config
&& orientation != settings.orientation) {
return false;
}
- if (settings.density != 0 && density != 0
- && density != settings.density) {
- return false;
- }
+ // Density not taken into account, always match, no matter what
+ // density is specified for the resource
if (settings.touchscreen != 0 && touchscreen != 0
&& touchscreen != settings.touchscreen) {
return false;
@@ -1464,11 +1468,11 @@ public:
* @return ssize_t Either a >= 0 table index or a negative error code.
*/
ssize_t getResource(uint32_t resID, Res_value* outValue, bool mayBeBag=false,
- uint32_t* outSpecFlags=NULL) const;
+ uint32_t* outSpecFlags=NULL, ResTable_config* outConfig=NULL) const;
inline ssize_t getResource(const ResTable_ref& res, Res_value* outValue,
uint32_t* outSpecFlags=NULL) const {
- return getResource(res.ident, outValue, outSpecFlags);
+ return getResource(res.ident, outValue, false, outSpecFlags, NULL);
}
ssize_t resolveReference(Res_value* inOutValue,
diff --git a/include/utils/logger.h b/include/utils/logger.h
deleted file mode 100644
index 3a08019..0000000
--- a/include/utils/logger.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* utils/logger.h
-**
-** Copyright 2007, The Android Open Source Project
-**
-** This file is dual licensed. It may be redistributed and/or modified
-** under the terms of the Apache 2.0 License OR version 2 of the GNU
-** General Public License.
-*/
-
-#ifndef _UTILS_LOGGER_H
-#define _UTILS_LOGGER_H
-
-#include <stdint.h>
-
-struct logger_entry {
- uint16_t len; /* length of the payload */
- uint16_t __pad; /* no matter what, we get 2 bytes of padding */
- int32_t pid; /* generating process's pid */
- int32_t tid; /* generating process's tid */
- int32_t sec; /* seconds since Epoch */
- int32_t nsec; /* nanoseconds */
- char msg[0]; /* the entry's payload */
-};
-
-#define LOGGER_LOG_MAIN "log/main"
-#define LOGGER_LOG_RADIO "log/radio"
-#define LOGGER_LOG_EVENTS "log/events"
-
-#define LOGGER_ENTRY_MAX_LEN (4*1024)
-#define LOGGER_ENTRY_MAX_PAYLOAD \
- (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
-
-#ifdef HAVE_IOCTL
-
-#include <sys/ioctl.h>
-
-#define __LOGGERIO 0xAE
-
-#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
-#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
-#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
-#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
-
-#endif // HAVE_IOCTL
-
-#endif /* _UTILS_LOGGER_H */
diff --git a/include/utils/threads.h b/include/utils/threads.h
index 7dca810..8d8d46a 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -249,41 +249,6 @@ private:
/*
- * Read/write lock. The resource can have multiple readers or one writer,
- * but can't be read and written at the same time.
- *
- * The same thread should not call a lock function while it already has
- * a lock. (Should be okay for multiple readers.)
- */
-class ReadWriteLock {
-public:
- ReadWriteLock()
- : mNumReaders(0), mNumWriters(0)
- {}
- ~ReadWriteLock() {}
-
- void lockForRead();
- bool tryLockForRead();
- void unlockForRead();
-
- void lockForWrite();
- bool tryLockForWrite();
- void unlockForWrite();
-
-private:
- int mNumReaders;
- int mNumWriters;
-
- Mutex mLock;
- Condition mReadWaiter;
- Condition mWriteWaiter;
-#if defined(PRINT_RENDER_TIMES)
- DurationTimer mDebugTimer;
-#endif
-};
-
-
-/*
* This is our spiffy thread object!
*/
diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/libs/audioflinger/A2dpAudioInterface.cpp
index c8c8431..2974e32 100644
--- a/libs/audioflinger/A2dpAudioInterface.cpp
+++ b/libs/audioflinger/A2dpAudioInterface.cpp
@@ -48,7 +48,6 @@ AudioStreamOut* A2dpAudioInterface::openOutputStream(
int format, int channelCount, uint32_t sampleRate, status_t *status)
{
LOGD("A2dpAudioInterface::openOutputStream %d, %d, %d\n", format, channelCount, sampleRate);
- Mutex::Autolock lock(mLock);
status_t err = 0;
// only one output stream allowed
@@ -72,7 +71,8 @@ AudioStreamOut* A2dpAudioInterface::openOutputStream(
}
AudioStreamIn* A2dpAudioInterface::openInputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ int format, int channelCount, uint32_t sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics)
{
if (status)
*status = -1;
@@ -99,6 +99,10 @@ status_t A2dpAudioInterface::setParameter(const char *key, const char *value)
if (strcmp(key, "a2dp_sink_address") == 0) {
return mOutput->setAddress(value);
}
+ if (strcmp(key, "bluetooth_enabled") == 0 &&
+ strcmp(value, "false") == 0) {
+ return mOutput->close();
+ }
return 0;
}
@@ -126,11 +130,11 @@ status_t A2dpAudioInterface::dump(int fd, const Vector<String16>& args)
// ----------------------------------------------------------------------------
A2dpAudioInterface::A2dpAudioStreamOut::A2dpAudioStreamOut() :
- mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL),
- mInitialized(false)
+ mFd(-1), mStandby(true), mStartCount(0), mRetryCount(0), mData(NULL)
{
// use any address by default
- strncpy(mA2dpAddress, "00:00:00:00:00:00", sizeof(mA2dpAddress));
+ strcpy(mA2dpAddress, "00:00:00:00:00:00");
+ init();
}
status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
@@ -154,23 +158,17 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::set(
A2dpAudioInterface::A2dpAudioStreamOut::~A2dpAudioStreamOut()
{
- if (mData)
- a2dp_cleanup(mData);
+ close();
}
ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t bytes)
{
- status_t status = NO_INIT;
- size_t remaining = bytes;
+ Mutex::Autolock lock(mLock);
- if (!mInitialized) {
- status = a2dp_init(mA2dpAddress, 44100, 2, &mData);
- if (status < 0) {
- LOGE("a2dp_init failed err: %d\n", status);
- goto Error;
- }
- mInitialized = true;
- }
+ size_t remaining = bytes;
+ status_t status = init();
+ if (status < 0)
+ goto Error;
while (remaining > 0) {
status = a2dp_write(mData, buffer, remaining);
@@ -186,17 +184,34 @@ ssize_t A2dpAudioInterface::A2dpAudioStreamOut::write(const void* buffer, size_t
return bytes;
-Error:
+Error:
// Simulate audio output timing in case of error
usleep(bytes * 1000000 / frameSize() / sampleRate());
return status;
}
+status_t A2dpAudioInterface::A2dpAudioStreamOut::init()
+{
+ if (!mData) {
+ status_t status = a2dp_init(44100, 2, &mData);
+ if (status < 0) {
+ LOGE("a2dp_init failed err: %d\n", status);
+ mData = NULL;
+ return status;
+ }
+ a2dp_set_sink(mData, mA2dpAddress);
+ }
+
+ return 0;
+}
+
status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
{
int result = 0;
+ Mutex::Autolock lock(mLock);
+
if (!mStandby) {
result = a2dp_stop(mData);
if (result == 0)
@@ -208,19 +223,24 @@ status_t A2dpAudioInterface::A2dpAudioStreamOut::standby()
status_t A2dpAudioInterface::A2dpAudioStreamOut::setAddress(const char* address)
{
- if (strlen(address) < sizeof(mA2dpAddress))
+ Mutex::Autolock lock(mLock);
+
+ if (strlen(address) != strlen("00:00:00:00:00:00"))
return -EINVAL;
- if (strcmp(address, mA2dpAddress)) {
- strcpy(mA2dpAddress, address);
-
- if (mInitialized) {
- a2dp_cleanup(mData);
- mData = NULL;
- mInitialized = false;
- }
+ strcpy(mA2dpAddress, address);
+ if (mData)
+ a2dp_set_sink(mData, mA2dpAddress);
+
+ return NO_ERROR;
+}
+
+status_t A2dpAudioInterface::A2dpAudioStreamOut::close()
+{
+ if (mData) {
+ a2dp_cleanup(mData);
+ mData = NULL;
}
-
return NO_ERROR;
}
diff --git a/libs/audioflinger/A2dpAudioInterface.h b/libs/audioflinger/A2dpAudioInterface.h
index 2197d0e..99614dc 100644
--- a/libs/audioflinger/A2dpAudioInterface.h
+++ b/libs/audioflinger/A2dpAudioInterface.h
@@ -58,7 +58,8 @@ public:
int format,
int channelCount,
uint32_t sampleRate,
- status_t *status);
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
protected:
virtual status_t doRouting();
@@ -77,7 +78,7 @@ private:
virtual size_t bufferSize() const { return 512 * 20; }
virtual int channelCount() const { return 2; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
- virtual uint32_t latency() const { return ((1000*channelCount()*bufferSize())/frameSize())/sampleRate() + 200; }
+ virtual uint32_t latency() const { return ((1000*bufferSize())/frameSize())/sampleRate() + 200; }
virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
status_t standby();
@@ -85,6 +86,8 @@ private:
private:
friend class A2dpAudioInterface;
+ status_t init();
+ status_t close();
status_t setAddress(const char* address);
private:
@@ -94,10 +97,9 @@ private:
int mRetryCount;
char mA2dpAddress[20];
void* mData;
- bool mInitialized;
+ Mutex mLock;
};
- Mutex mLock;
A2dpAudioStreamOut* mOutput;
};
diff --git a/libs/audioflinger/AudioDumpInterface.h b/libs/audioflinger/AudioDumpInterface.h
index 42204d6..9a94102 100644
--- a/libs/audioflinger/AudioDumpInterface.h
+++ b/libs/audioflinger/AudioDumpInterface.h
@@ -78,8 +78,9 @@ public:
virtual status_t setParameter(const char* key, const char* value)
{return mFinalInterface->setParameter(key, value);}
- virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status)
- {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status);}
+ virtual AudioStreamIn* openInputStream( int format, int channelCount, uint32_t sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics)
+ {return mFinalInterface->openInputStream( format, channelCount, sampleRate, status, acoustics);}
virtual status_t dump(int fd, const Vector<String16>& args) { return mFinalInterface->dumpState(fd, args); }
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 918b01f..3c81a47 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -47,6 +47,15 @@
#include "A2dpAudioInterface.h"
#endif
+// ----------------------------------------------------------------------------
+// the sim build doesn't have gettid
+
+#ifndef HAVE_GETTID
+# define gettid getpid
+#endif
+
+// ----------------------------------------------------------------------------
+
namespace android {
//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
@@ -59,6 +68,16 @@ static const float MAX_GAIN = 4096.0f;
static const int8_t kMaxTrackRetries = 50;
static const int8_t kMaxTrackStartupRetries = 50;
+static const int kStartSleepTime = 30000;
+static const int kStopSleepTime = 30000;
+
+static const int kDumpLockRetries = 50;
+static const int kDumpLockSleep = 20000;
+
+// Maximum number of pending buffers allocated by OutputTrack::write()
+static const uint8_t kMaxOutputTrackBuffers = 5;
+
+
#define AUDIOFLINGER_SECURITY_ENABLED 1
// ----------------------------------------------------------------------------
@@ -98,13 +117,10 @@ static bool settingsAllowed() {
// ----------------------------------------------------------------------------
AudioFlinger::AudioFlinger()
- : BnAudioFlinger(), Thread(false),
- mMasterVolume(0), mMasterMute(true), mHardwareAudioMixer(0), mA2dpAudioMixer(0),
- mAudioMixer(0), mAudioHardware(0), mA2dpAudioInterface(0), mHardwareOutput(0),
- mA2dpOutput(0), mOutput(0), mRequestedOutput(0), mAudioRecordThread(0),
- mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
- mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
- mInWrite(false), mA2dpDisableCount(0), mA2dpSuppressed(false)
+ : BnAudioFlinger(),
+ mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotifyA2dpChange(false),
+ mForcedSpeakerCount(0), mA2dpDisableCount(0), mA2dpSuppressed(false), mForcedRoute(0),
+ mRouteRestoreTime(0), mMusicMuteSaved(false)
{
mHardwareStatus = AUDIO_HW_IDLE;
mAudioHardware = AudioHardwareInterface::create();
@@ -113,57 +129,51 @@ AudioFlinger::AudioFlinger()
// open 16-bit output stream for s/w mixer
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
status_t status;
- mHardwareOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+ AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
mHardwareStatus = AUDIO_HW_IDLE;
- if (mHardwareOutput) {
- mHardwareAudioMixer = new AudioMixer(getOutputFrameCount(mHardwareOutput), mHardwareOutput->sampleRate());
- mRequestedOutput = mHardwareOutput;
- doSetOutput(mHardwareOutput);
-
- // FIXME - this should come from settings
- setMasterVolume(1.0f);
- setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
- setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
- setMode(AudioSystem::MODE_NORMAL);
- mMasterMute = false;
+ if (hwOutput) {
+ mHardwareMixerThread = new MixerThread(this, hwOutput, AudioSystem::AUDIO_OUTPUT_HARDWARE);
} else {
- LOGE("Failed to initialize output stream, status: %d", status);
+ LOGE("Failed to initialize hardware output stream, status: %d", status);
}
#ifdef WITH_A2DP
// Create A2DP interface
mA2dpAudioInterface = new A2dpAudioInterface();
- mA2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
- mA2dpAudioMixer = new AudioMixer(getOutputFrameCount(mA2dpOutput), mA2dpOutput->sampleRate());
-
- // create a buffer big enough for both hardware and A2DP audio output.
- size_t hwFrameCount = getOutputFrameCount(mHardwareOutput);
- size_t a2dpFrameCount = getOutputFrameCount(mA2dpOutput);
- size_t frameCount = (hwFrameCount > a2dpFrameCount ? hwFrameCount : a2dpFrameCount);
-#else
- size_t frameCount = getOutputFrameCount(mHardwareOutput);
+ AudioStreamOut *a2dpOutput = mA2dpAudioInterface->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);
+ if (a2dpOutput) {
+ mA2dpMixerThread = new MixerThread(this, a2dpOutput, AudioSystem::AUDIO_OUTPUT_A2DP);
+ if (hwOutput) {
+ uint32_t frameCount = ((a2dpOutput->bufferSize()/a2dpOutput->frameSize()) * hwOutput->sampleRate()) / a2dpOutput->sampleRate();
+ MixerThread::OutputTrack *a2dpOutTrack = new MixerThread::OutputTrack(mA2dpMixerThread,
+ hwOutput->sampleRate(),
+ AudioSystem::PCM_16_BIT,
+ hwOutput->channelCount(),
+ frameCount);
+ mHardwareMixerThread->setOuputTrack(a2dpOutTrack);
+ }
+ } else {
+ LOGE("Failed to initialize A2DP output stream, status: %d", status);
+ }
#endif
- // FIXME - Current mixer implementation only supports stereo output: Always
- // Allocate a stereo buffer even if HW output is mono.
- mMixBuffer = new int16_t[frameCount * 2];
- memset(mMixBuffer, 0, frameCount * 2 * sizeof(int16_t));
-
+
+ // FIXME - this should come from settings
+ setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+ setRouting(AudioSystem::MODE_RINGTONE, AudioSystem::ROUTE_SPEAKER, AudioSystem::ROUTE_ALL);
+ setRouting(AudioSystem::MODE_IN_CALL, AudioSystem::ROUTE_EARPIECE, AudioSystem::ROUTE_ALL);
+ setMode(AudioSystem::MODE_NORMAL);
+
+ setMasterVolume(1.0f);
+ setMasterMute(false);
+
// Start record thread
- mAudioRecordThread = new AudioRecordThread(mAudioHardware);
+ mAudioRecordThread = new AudioRecordThread(mAudioHardware, this);
if (mAudioRecordThread != 0) {
mAudioRecordThread->run("AudioRecordThread", PRIORITY_URGENT_AUDIO);
}
} else {
LOGE("Couldn't even initialize the stubbed audio hardware!");
}
-
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.audio.silent", value, "0");
- if (atoi(value)) {
- LOGD("Silence is golden");
- mMasterMute = true;
- }
}
AudioFlinger::~AudioFlinger()
@@ -172,59 +182,72 @@ AudioFlinger::~AudioFlinger()
mAudioRecordThread->exit();
mAudioRecordThread.clear();
}
+ mHardwareMixerThread.clear();
delete mAudioHardware;
// deleting mA2dpAudioInterface also deletes mA2dpOutput;
+#ifdef WITH_A2DP
+ mA2dpMixerThread.clear();
delete mA2dpAudioInterface;
- delete [] mMixBuffer;
- delete mHardwareAudioMixer;
- delete mA2dpAudioMixer;
-}
-
-void AudioFlinger::setOutput(AudioStreamOut* output)
-{
- mRequestedOutput = output;
+#endif
}
-void AudioFlinger::doSetOutput(AudioStreamOut* output)
+
+#ifdef WITH_A2DP
+// setA2dpEnabled_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::setA2dpEnabled_l(bool enable)
{
- mSampleRate = output->sampleRate();
- mChannelCount = output->channelCount();
+ SortedVector < sp<MixerThread::Track> > tracks;
+ SortedVector < wp<MixerThread::Track> > activeTracks;
+
+ LOGV_IF(enable, "set output to A2DP\n");
+ LOGV_IF(!enable, "set output to hardware audio\n");
- // FIXME - Current mixer implementation only supports stereo output
- if (mChannelCount == 1) {
- LOGE("Invalid audio hardware channel count");
+ // Transfer tracks playing on MUSIC stream from one mixer to the other
+ if (enable) {
+ mHardwareMixerThread->getTracks_l(tracks, activeTracks);
+ mA2dpMixerThread->putTracks_l(tracks, activeTracks);
+ } else {
+ mA2dpMixerThread->getTracks_l(tracks, activeTracks);
+ mHardwareMixerThread->putTracks_l(tracks, activeTracks);
}
- mFormat = output->format();
- mFrameCount = getOutputFrameCount(output);
- mAudioMixer = (output == mA2dpOutput ? mA2dpAudioMixer : mHardwareAudioMixer);
- mOutput = output;
+ mA2dpEnabled = enable;
+ mNotifyA2dpChange = true;
+ mWaitWorkCV.broadcast();
}
-size_t AudioFlinger::getOutputFrameCount(AudioStreamOut* output)
+// checkA2dpEnabledChange_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::checkA2dpEnabledChange_l()
{
- return output->bufferSize() / output->channelCount() / sizeof(int16_t);
+ if (mNotifyA2dpChange) {
+ // Notify AudioSystem of the A2DP activation/deactivation
+ size_t size = mNotificationClients.size();
+ for (size_t i = 0; i < size; i++) {
+ sp<IBinder> binder = mNotificationClients.itemAt(i).promote();
+ if (binder != NULL) {
+ LOGV("Notifying output change to client %p", binder.get());
+ sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+ client->a2dpEnabledChanged(mA2dpEnabled);
+ }
+ }
+ mNotifyA2dpChange = false;
+ }
}
+#endif // WITH_A2DP
-#ifdef WITH_A2DP
-bool AudioFlinger::streamDisablesA2dp(int streamType)
+bool AudioFlinger::streamForcedToSpeaker(int streamType)
{
- return (streamType == AudioTrack::SYSTEM ||
- streamType == AudioTrack::RING ||
- streamType == AudioTrack::ALARM ||
- streamType == AudioTrack::NOTIFICATION);
+ // NOTE that streams listed here must not be routed to A2DP by default:
+ // AudioSystem::routedToA2dpOutput(streamType) == false
+ return (streamType == AudioSystem::RING ||
+ streamType == AudioSystem::ALARM ||
+ streamType == AudioSystem::NOTIFICATION);
}
-void AudioFlinger::setA2dpEnabled(bool enable)
+bool AudioFlinger::streamDisablesA2dp(int streamType)
{
- if (enable) {
- LOGD("set output to A2DP\n");
- setOutput(mA2dpOutput);
- } else {
- LOGD("set output to hardware audio\n");
- setOutput(mHardwareOutput);
- }
+ return (streamType == AudioSystem::VOICE_CALL ||
+ streamType == AudioSystem::BLUETOOTH_SCO);
}
-#endif // WITH_A2DP
status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
{
@@ -247,13 +270,672 @@ status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
return NO_ERROR;
}
-status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args)
+
+status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ int hardwareStatus = mHardwareStatus;
+
+ if (hardwareStatus == AUDIO_HW_IDLE && mHardwareMixerThread->mStandby) {
+ hardwareStatus = AUDIO_HW_STANDBY;
+ }
+ snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, SIZE, "Permission Denial: "
+ "can't dump AudioFlinger from pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::dump(int fd, const Vector<String16>& 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);
+ }
+
+ dumpClients(fd, args);
+ dumpInternals(fd, args);
+ mHardwareMixerThread->dump(fd, args);
+#ifdef WITH_A2DP
+ mA2dpMixerThread->dump(fd, args);
+#endif
+
+ // dump record client
+ if (mAudioRecordThread != 0) mAudioRecordThread->dump(fd, args);
+
+ if (mAudioHardware) {
+ mAudioHardware->dumpState(fd, args);
+ }
+ if (locked) mLock.unlock();
+ }
+ return NO_ERROR;
+}
+
+// IAudioFlinger interface
+
+
+sp<IAudioTrack> AudioFlinger::createTrack(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags,
+ const sp<IMemory>& sharedBuffer,
+ status_t *status)
+{
+ sp<MixerThread::Track> track;
+ sp<TrackHandle> trackHandle;
+ sp<Client> client;
+ wp<Client> wclient;
+ status_t lStatus;
+
+ if (streamType >= AudioSystem::NUM_STREAM_TYPES) {
+ LOGE("invalid stream type");
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+
+ {
+ Mutex::Autolock _l(mLock);
+
+ wclient = mClients.valueFor(pid);
+
+ if (wclient != NULL) {
+ client = wclient.promote();
+ } else {
+ client = new Client(this, pid);
+ mClients.add(pid, client);
+ }
+#ifdef WITH_A2DP
+ if (isA2dpEnabled() && AudioSystem::routedToA2dpOutput(streamType)) {
+ track = mA2dpMixerThread->createTrack_l(client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer, &lStatus);
+ } else
+#endif
+ {
+ track = mHardwareMixerThread->createTrack_l(client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer, &lStatus);
+ }
+ }
+ if (lStatus == NO_ERROR) {
+ trackHandle = new TrackHandle(track);
+ } else {
+ track.clear();
+ }
+
+Exit:
+ if(status) {
+ *status = lStatus;
+ }
+ return trackHandle;
+}
+
+uint32_t AudioFlinger::sampleRate(int output) const
+{
+#ifdef WITH_A2DP
+ if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+ return mA2dpMixerThread->sampleRate();
+ }
+#endif
+ return mHardwareMixerThread->sampleRate();
+}
+
+int AudioFlinger::channelCount(int output) const
+{
+#ifdef WITH_A2DP
+ if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+ return mA2dpMixerThread->channelCount();
+ }
+#endif
+ return mHardwareMixerThread->channelCount();
+}
+
+int AudioFlinger::format(int output) const
+{
+#ifdef WITH_A2DP
+ if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+ return mA2dpMixerThread->format();
+ }
+#endif
+ return mHardwareMixerThread->format();
+}
+
+size_t AudioFlinger::frameCount(int output) const
+{
+#ifdef WITH_A2DP
+ if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+ return mA2dpMixerThread->frameCount();
+ }
+#endif
+ return mHardwareMixerThread->frameCount();
+}
+
+uint32_t AudioFlinger::latency(int output) const
+{
+#ifdef WITH_A2DP
+ if (output == AudioSystem::AUDIO_OUTPUT_A2DP) {
+ return mA2dpMixerThread->latency();
+ }
+#endif
+ return mHardwareMixerThread->latency();
+}
+
+status_t AudioFlinger::setMasterVolume(float value)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ // when hw supports master volume, don't scale in sw mixer
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
+ value = 1.0f;
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ mHardwareMixerThread->setMasterVolume(value);
+#ifdef WITH_A2DP
+ mA2dpMixerThread->setMasterVolume(value);
+#endif
+
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
+{
+ status_t err = NO_ERROR;
+
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) {
+ LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask);
+ return BAD_VALUE;
+ }
+
+#ifdef WITH_A2DP
+ LOGD("setRouting %d %d %d, tid %d, calling tid %d\n", mode, routes, mask, gettid(), IPCThreadState::self()->getCallingPid());
+ if (mode == AudioSystem::MODE_NORMAL &&
+ (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
+ AutoMutex lock(&mLock);
+
+ bool enableA2dp = false;
+ if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
+ enableA2dp = true;
+ }
+ if (mA2dpDisableCount > 0) {
+ mA2dpSuppressed = enableA2dp;
+ } else {
+ setA2dpEnabled_l(enableA2dp);
+ }
+ LOGV("setOutput done\n");
+ }
+#endif
+
+ // do nothing if only A2DP routing is affected
+ mask &= ~AudioSystem::ROUTE_BLUETOOTH_A2DP;
+ if (mask) {
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_GET_ROUTING;
+ uint32_t r;
+ err = mAudioHardware->getRouting(mode, &r);
+ if (err == NO_ERROR) {
+ r = (r & ~mask) | (routes & mask);
+ if (mode == AudioSystem::MODE_NORMAL ||
+ (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+ mSavedRoute = r;
+ r |= mForcedRoute;
+ LOGV("setRouting mSavedRoute %08x mForcedRoute %08x\n", mSavedRoute, mForcedRoute);
+ }
+ mHardwareStatus = AUDIO_HW_SET_ROUTING;
+ err = mAudioHardware->setRouting(mode, r);
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ }
+ return err;
+}
+
+uint32_t AudioFlinger::getRouting(int mode) const
+{
+ uint32_t routes = 0;
+ if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
+ if (mode == AudioSystem::MODE_NORMAL ||
+ (mode == AudioSystem::MODE_CURRENT && getMode() == AudioSystem::MODE_NORMAL)) {
+ routes = mSavedRoute;
+ } else {
+ mHardwareStatus = AUDIO_HW_GET_ROUTING;
+ mAudioHardware->getRouting(mode, &routes);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ }
+ } else {
+ LOGW("Illegal value: getRouting(%d)", mode);
+ }
+ return routes;
+}
+
+status_t AudioFlinger::setMode(int mode)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) {
+ LOGW("Illegal value: setMode(%d)", mode);
+ return BAD_VALUE;
+ }
+
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_MODE;
+ status_t ret = mAudioHardware->setMode(mode);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return ret;
+}
+
+int AudioFlinger::getMode() const
+{
+ int mode = AudioSystem::MODE_INVALID;
+ mHardwareStatus = AUDIO_HW_SET_MODE;
+ mAudioHardware->getMode(&mode);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return mode;
+}
+
+status_t AudioFlinger::setMicMute(bool state)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
+ status_t ret = mAudioHardware->setMicMute(state);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return ret;
+}
+
+bool AudioFlinger::getMicMute() const
+{
+ bool state = AudioSystem::MODE_INVALID;
+ mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
+ mAudioHardware->getMicMute(&state);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return state;
+}
+
+status_t AudioFlinger::setMasterMute(bool muted)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ mHardwareMixerThread->setMasterMute(muted);
+#ifdef WITH_A2DP
+ mA2dpMixerThread->setMasterMute(muted);
+#endif
+ return NO_ERROR;
+}
+
+float AudioFlinger::masterVolume() const
+{
+ return mHardwareMixerThread->masterVolume();
+}
+
+bool AudioFlinger::masterMute() const
+{
+ return mHardwareMixerThread->masterMute();
+}
+
+status_t AudioFlinger::setStreamVolume(int stream, float value)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+
+ status_t ret = NO_ERROR;
+
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ float hwValue = value;
+ if (stream == AudioSystem::VOICE_CALL) {
+ hwValue = (float)AudioSystem::logToLinear(value)/100.0f;
+ // FIXME: This is a temporary fix to re-base the internally
+ // generated in-call audio so that it is never muted, which is
+ // already the case for the hardware routed in-call audio.
+ // When audio stream handling is reworked, this should be
+ // addressed more cleanly. Fixes #1324; see discussion at
+ // http://review.source.android.com/8224
+ value = value * 0.99 + 0.01;
+ } else { // (type == AudioSystem::BLUETOOTH_SCO)
+ hwValue = 1.0f;
+ }
+
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
+ ret = mAudioHardware->setVoiceVolume(hwValue);
+ mHardwareStatus = AUDIO_HW_IDLE;
+
+ }
+
+ mHardwareMixerThread->setStreamVolume(stream, value);
+#ifdef WITH_A2DP
+ mA2dpMixerThread->setStreamVolume(stream, value);
+#endif
+
+ return ret;
+}
+
+status_t AudioFlinger::setStreamMute(int stream, bool muted)
+{
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+ return BAD_VALUE;
+ }
+
+#ifdef WITH_A2DP
+ mA2dpMixerThread->setStreamMute(stream, muted);
+#endif
+ if (stream == AudioSystem::MUSIC)
+ {
+ AutoMutex lock(&mHardwareLock);
+ if (mForcedRoute != 0)
+ mMusicMuteSaved = muted;
+ else
+ mHardwareMixerThread->setStreamMute(stream, muted);
+ } else {
+ mHardwareMixerThread->setStreamMute(stream, muted);
+ }
+
+
+
+ return NO_ERROR;
+}
+
+float AudioFlinger::streamVolume(int stream) const
+{
+ if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+ return 0.0f;
+ }
+ float value = mHardwareMixerThread->streamVolume(stream);
+
+ if (stream == AudioSystem::VOICE_CALL) {
+ // FIXME: Re-base internally generated in-call audio,
+ // reverse of above in setStreamVolume.
+ value = (value - 0.01) / 0.99;
+ }
+
+ return value;
+}
+
+bool AudioFlinger::streamMute(int stream) const
+{
+ if (uint32_t(stream) >= AudioSystem::NUM_STREAM_TYPES) {
+ return true;
+ }
+
+ if (stream == AudioSystem::MUSIC && mForcedRoute != 0)
+ {
+ return mMusicMuteSaved;
+ }
+ return mHardwareMixerThread->streamMute(stream);
+}
+
+bool AudioFlinger::isMusicActive() const
+{
+ #ifdef WITH_A2DP
+ if (isA2dpEnabled()) {
+ return mA2dpMixerThread->isMusicActive();
+ }
+ #endif
+ return mHardwareMixerThread->isMusicActive();
+}
+
+status_t AudioFlinger::setParameter(const char* key, const char* value)
+{
+ status_t result, result2;
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_SET_PARAMETER;
+
+ LOGV("setParameter() key %s, value %s, tid %d, calling tid %d", key, value, gettid(), IPCThreadState::self()->getCallingPid());
+ result = mAudioHardware->setParameter(key, value);
+ if (mA2dpAudioInterface) {
+ result2 = mA2dpAudioInterface->setParameter(key, value);
+ if (result2)
+ result = result2;
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return result;
+}
+
+size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ return mAudioHardware->getInputBufferSize(sampleRate, format, channelCount);
+}
+
+void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
+{
+
+ LOGV("registerClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());
+ Mutex::Autolock _l(mLock);
+
+ sp<IBinder> binder = client->asBinder();
+ if (mNotificationClients.indexOf(binder) < 0) {
+ LOGV("Adding notification client %p", binder.get());
+ binder->linkToDeath(this);
+ mNotificationClients.add(binder);
+ client->a2dpEnabledChanged(isA2dpEnabled());
+ }
+}
+
+void AudioFlinger::binderDied(const wp<IBinder>& who) {
+
+ LOGV("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid());
+ Mutex::Autolock _l(mLock);
+
+ IBinder *binder = who.unsafe_get();
+
+ if (binder != NULL) {
+ int index = mNotificationClients.indexOf(binder);
+ if (index >= 0) {
+ LOGV("Removing notification client %p", binder);
+ mNotificationClients.removeAt(index);
+ }
+ }
+}
+
+void AudioFlinger::removeClient(pid_t pid)
+{
+ LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
+ Mutex::Autolock _l(mLock);
+ mClients.removeItem(pid);
+}
+
+bool AudioFlinger::isA2dpEnabled() const
+{
+ return mA2dpEnabled;
+}
+
+void AudioFlinger::handleForcedSpeakerRoute(int command)
+{
+ switch(command) {
+ case ACTIVE_TRACK_ADDED:
+ {
+ AutoMutex lock(mHardwareLock);
+ if (mForcedSpeakerCount++ == 0) {
+ mRouteRestoreTime = 0;
+ mMusicMuteSaved = mHardwareMixerThread->streamMute(AudioSystem::MUSIC);
+ if (mForcedRoute == 0 && !(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+ LOGV("Route forced to Speaker ON %08x", mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+ mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, true);
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ mAudioHardware->setMasterVolume(0);
+ usleep(mHardwareMixerThread->latency()*1000);
+ mHardwareStatus = AUDIO_HW_SET_ROUTING;
+ mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute | AudioSystem::ROUTE_SPEAKER);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ // delay track start so that audio hardware has time to siwtch routes
+ usleep(kStartSleepTime);
+ mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+ mAudioHardware->setMasterVolume(mHardwareMixerThread->masterVolume());
+ mHardwareStatus = AUDIO_HW_IDLE;
+ }
+ mForcedRoute = AudioSystem::ROUTE_SPEAKER;
+ }
+ LOGV("mForcedSpeakerCount incremented to %d", mForcedSpeakerCount);
+ }
+ break;
+ case ACTIVE_TRACK_REMOVED:
+ {
+ AutoMutex lock(mHardwareLock);
+ if (mForcedSpeakerCount > 0){
+ if (--mForcedSpeakerCount == 0) {
+ mRouteRestoreTime = systemTime() + milliseconds(kStopSleepTime/1000);
+ }
+ LOGV("mForcedSpeakerCount decremented to %d", mForcedSpeakerCount);
+ } else {
+ LOGE("mForcedSpeakerCount is already zero");
+ }
+ }
+ break;
+ case CHECK_ROUTE_RESTORE_TIME:
+ case FORCE_ROUTE_RESTORE:
+ if (mRouteRestoreTime) {
+ AutoMutex lock(mHardwareLock);
+ if (mRouteRestoreTime &&
+ (systemTime() > mRouteRestoreTime || command == FORCE_ROUTE_RESTORE)) {
+ mHardwareMixerThread->setStreamMute(AudioSystem::MUSIC, mMusicMuteSaved);
+ mForcedRoute = 0;
+ if (!(mSavedRoute & AudioSystem::ROUTE_SPEAKER)) {
+ mHardwareStatus = AUDIO_HW_SET_ROUTING;
+ mAudioHardware->setRouting(AudioSystem::MODE_NORMAL, mSavedRoute);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ LOGV("Route forced to Speaker OFF %08x", mSavedRoute);
+ }
+ mRouteRestoreTime = 0;
+ }
+ }
+ break;
+ }
+}
+
+#ifdef WITH_A2DP
+// handleStreamDisablesA2dp_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::handleStreamDisablesA2dp_l(int command)
+{
+ 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");
+ }
+ }
+ break;
+ }
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType)
+ : Thread(false),
+ mAudioFlinger(audioFlinger), mAudioMixer(0), mOutput(output), mOutputType(outputType),
+ mSampleRate(0), mFrameCount(0), mChannelCount(0), mFormat(0), mMixBuffer(0),
+ mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mStandby(false),
+ mInWrite(false)
+{
+ mSampleRate = output->sampleRate();
+ mChannelCount = output->channelCount();
+
+ // FIXME - Current mixer implementation only supports stereo output
+ if (mChannelCount == 1) {
+ LOGE("Invalid audio hardware channel count");
+ }
+
+ mFormat = output->format();
+ mFrameCount = output->bufferSize() / output->channelCount() / sizeof(int16_t);
+ mAudioMixer = new AudioMixer(mFrameCount, output->sampleRate());
+
+ // FIXME - Current mixer implementation only supports stereo output: Always
+ // Allocate a stereo buffer even if HW output is mono.
+ mMixBuffer = new int16_t[mFrameCount * 2];
+ memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
+}
+
+AudioFlinger::MixerThread::~MixerThread()
+{
+ delete [] mMixBuffer;
+ delete mAudioMixer;
+}
+
+status_t AudioFlinger::MixerThread::dump(int fd, const Vector<String16>& args)
+{
+ dumpInternals(fd, args);
+ dumpTracks(fd, args);
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::MixerThread::dumpTracks(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- result.append("Tracks:\n");
+ snprintf(buffer, SIZE, "Output %d mixer thread tracks\n", mOutputType);
+ result.append(buffer);
result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
for (size_t i = 0; i < mTracks.size(); ++i) {
wp<Track> wTrack = mTracks[i];
@@ -266,7 +948,8 @@ status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args)
}
}
- result.append("Active Tracks:\n");
+ snprintf(buffer, SIZE, "Output %d mixer thread active tracks\n", mOutputType);
+ result.append(buffer);
result.append(" Name Clien Typ Fmt Chn Buf S M F SRate LeftV RighV Serv User\n");
for (size_t i = 0; i < mActiveTracks.size(); ++i) {
wp<Track> wTrack = mTracks[i];
@@ -282,13 +965,15 @@ status_t AudioFlinger::dumpTracks(int fd, const Vector<String16>& args)
return NO_ERROR;
}
-status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
+status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", audioMixer()->trackNames());
+ snprintf(buffer, SIZE, "Output %d mixer thread internals\n", mOutputType);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
result.append(buffer);
snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
result.append(buffer);
@@ -300,85 +985,86 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
result.append(buffer);
snprintf(buffer, SIZE, "standby: %d\n", mStandby);
result.append(buffer);
- snprintf(buffer, SIZE, "Hardware status: %d\n", mHardwareStatus);
- result.append(buffer);
write(fd, result.string(), result.size());
return NO_ERROR;
}
-status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- snprintf(buffer, SIZE, "Permission Denial: "
- "can't dump AudioFlinger from pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
- result.append(buffer);
- write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
-{
- if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
- dumpPermissionDenial(fd, args);
- } else {
- AutoMutex lock(&mLock);
-
- dumpClients(fd, args);
- dumpTracks(fd, args);
- dumpInternals(fd, args);
- if (mAudioHardware) {
- mAudioHardware->dumpState(fd, args);
- }
- }
- return NO_ERROR;
-}
-
// Thread virtuals
-bool AudioFlinger::threadLoop()
+bool AudioFlinger::MixerThread::threadLoop()
{
unsigned long sleepTime = kBufferRecoveryInUsecs;
int16_t* curBuf = mMixBuffer;
Vector< sp<Track> > tracksToRemove;
size_t enabledTracks = 0;
- nsecs_t standbyTime = systemTime();
+ nsecs_t standbyTime = systemTime();
+ size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
+ nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
+
+#ifdef WITH_A2DP
+ bool outputTrackActive = false;
+#endif
do {
enabledTracks = 0;
- { // scope for the mLock
+ { // scope for the AudioFlinger::mLock
- Mutex::Autolock _l(mLock);
+ Mutex::Autolock _l(mAudioFlinger->mLock);
+
+#ifdef WITH_A2DP
+ if (mOutputTrack != NULL && !mAudioFlinger->isA2dpEnabled()) {
+ if (outputTrackActive) {
+ mAudioFlinger->mLock.unlock();
+ mOutputTrack->stop();
+ mAudioFlinger->mLock.lock();
+ outputTrackActive = false;
+ }
+ }
+ mAudioFlinger->checkA2dpEnabledChange_l();
+#endif
+
const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
// put audio hardware into standby after short delay
if UNLIKELY(!activeTracks.size() && systemTime() > standbyTime) {
// wait until we have something to do...
- LOGV("Audio hardware entering standby\n");
- mHardwareStatus = AUDIO_HW_STANDBY;
+ LOGV("Audio hardware entering standby, output %d\n", mOutputType);
if (!mStandby) {
mOutput->standby();
mStandby = true;
}
- mHardwareStatus = AUDIO_HW_IDLE;
+
+#ifdef WITH_A2DP
+ if (outputTrackActive) {
+ mAudioFlinger->mLock.unlock();
+ mOutputTrack->stop();
+ mAudioFlinger->mLock.lock();
+ outputTrackActive = false;
+ }
+#endif
+ if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+ mAudioFlinger->handleForcedSpeakerRoute(FORCE_ROUTE_RESTORE);
+ }
// we're about to wait, flush the binder command buffer
IPCThreadState::self()->flushCommands();
- mWaitWorkCV.wait(mLock);
- LOGV("Audio hardware exiting standby\n");
+ mAudioFlinger->mWaitWorkCV.wait(mAudioFlinger->mLock);
+ LOGV("Audio hardware exiting standby, output %d\n", mOutputType);
+
+ if (mMasterMute == false) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.audio.silent", value, "0");
+ if (atoi(value)) {
+ LOGD("Silence is golden");
+ setMasterMute(true);
+ }
+ }
+
standbyTime = systemTime() + kStandbyTimeInNsecs;
continue;
}
- // check for change in output
- if (mRequestedOutput != mOutput) {
-
- // put current output into standby mode
- if (mOutput) mOutput->standby();
-
- // change output
- doSetOutput(mRequestedOutput);
+ // Forced route to speaker is handled by hardware mixer thread
+ if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+ mAudioFlinger->handleForcedSpeakerRoute(CHECK_ROUTE_RESTORE_TIME);
}
// find out which tracks need to be processed
@@ -396,7 +1082,7 @@ bool AudioFlinger::threadLoop()
if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&
!track->isPaused())
{
- //LOGD("u=%08x, s=%08x [OK]", u, s);
+ //LOGV("track %d u=%08x, s=%08x [OK]", track->name(), cblk->user, cblk->server);
// compute volume for this track
int16_t left, right;
@@ -451,7 +1137,7 @@ bool AudioFlinger::threadLoop()
track->mRetryCount = kMaxTrackRetries;
enabledTracks++;
} else {
- //LOGD("u=%08x, s=%08x [NOT READY]", u, s);
+ //LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
if (track->isStopped()) {
track->reset();
}
@@ -478,22 +1164,33 @@ bool AudioFlinger::threadLoop()
if (UNLIKELY(count)) {
for (size_t i=0 ; i<count ; i++) {
const sp<Track>& track = tracksToRemove[i];
- removeActiveTrack(track);
+ removeActiveTrack_l(track);
if (track->isTerminated()) {
mTracks.remove(track);
- mAudioMixer->deleteTrackName(track->mName);
+ deleteTrackName_l(track->mName);
}
}
- }
+ }
}
+
if (LIKELY(enabledTracks)) {
// mix buffers...
mAudioMixer->process(curBuf);
+#ifdef WITH_A2DP
+ if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+ if (!outputTrackActive) {
+ LOGV("starting output track in mixer for output %d", mOutputType);
+ mOutputTrack->start();
+ outputTrackActive = true;
+ }
+ mOutputTrack->write(curBuf, mFrameCount);
+ }
+#endif
+
// output audio to hardware
mLastWriteTime = systemTime();
mInWrite = true;
- size_t mixBufferSize = mFrameCount*mChannelCount*sizeof(int16_t);
mOutput->write(curBuf, mixBufferSize);
mNumWrites++;
mInWrite = false;
@@ -501,18 +1198,30 @@ bool AudioFlinger::threadLoop()
nsecs_t temp = systemTime();
standbyTime = temp + kStandbyTimeInNsecs;
nsecs_t delta = temp - mLastWriteTime;
- nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 2;
if (delta > maxPeriod) {
LOGW("write blocked for %llu msecs", ns2ms(delta));
mNumDelayedWrites++;
}
sleepTime = kBufferRecoveryInUsecs;
- } else {
+ } else {
+#ifdef WITH_A2DP
+ if (mOutputTrack != NULL && mAudioFlinger->isA2dpEnabled()) {
+ if (outputTrackActive) {
+ mOutputTrack->write(curBuf, 0);
+ if (mOutputTrack->bufferQueueEmpty()) {
+ mOutputTrack->stop();
+ outputTrackActive = false;
+ } else {
+ standbyTime = systemTime() + kStandbyTimeInNsecs;
+ }
+ }
+ }
+#endif
// There was nothing to mix this round, which means all
// active tracks were late. Sleep a little bit to give
// them another chance. If we're too late, the audio
// hardware will zero-fill for us.
- LOGV("no buffers - usleep(%lu)", sleepTime);
+ //LOGV("no buffers - usleep(%lu)", sleepTime);
usleep(sleepTime);
if (sleepTime < kMaxBufferRecoveryInUsecs) {
sleepTime += kBufferRecoveryInUsecs;
@@ -528,106 +1237,151 @@ bool AudioFlinger::threadLoop()
return false;
}
-status_t AudioFlinger::readyToRun()
+status_t AudioFlinger::MixerThread::readyToRun()
{
if (mSampleRate == 0) {
LOGE("No working audio driver found.");
return NO_INIT;
}
- LOGI("AudioFlinger's main thread ready to run.");
+ LOGI("AudioFlinger's thread ready to run for output %d", mOutputType);
return NO_ERROR;
}
-void AudioFlinger::onFirstRef()
+void AudioFlinger::MixerThread::onFirstRef()
{
- run("AudioFlinger", ANDROID_PRIORITY_URGENT_AUDIO);
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "Mixer Thread for output %d", mOutputType);
+
+ run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
}
-// IAudioFlinger interface
-sp<IAudioTrack> AudioFlinger::createTrack(
- pid_t pid,
+// MixerThread::createTrack_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack_l(
+ const sp<AudioFlinger::Client>& client,
int streamType,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
- uint32_t flags,
const sp<IMemory>& sharedBuffer,
status_t *status)
{
sp<Track> track;
- sp<TrackHandle> trackHandle;
- sp<Client> client;
- wp<Client> wclient;
status_t lStatus;
-
- if (streamType >= AudioTrack::NUM_STREAM_TYPES) {
- LOGE("invalid stream type");
+
+ // Resampler implementation limits input sampling rate to 2 x output sampling rate.
+ if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
+ LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate);
lStatus = BAD_VALUE;
goto Exit;
}
- // Resampler implementation limits input sampling rate to 2 x output sampling rate.
- if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) {
- LOGE("Sample rate out of range: %d", sampleRate);
- lStatus = BAD_VALUE;
+
+ if (mSampleRate == 0) {
+ LOGE("Audio driver not initialized.");
+ lStatus = NO_INIT;
goto Exit;
}
- {
- Mutex::Autolock _l(mLock);
+ track = new Track(this, client, streamType, sampleRate, format,
+ channelCount, frameCount, sharedBuffer);
+ if (track->getCblk() == NULL) {
+ lStatus = NO_MEMORY;
+ goto Exit;
+ }
+ mTracks.add(track);
+ lStatus = NO_ERROR;
- if (mSampleRate == 0) {
- LOGE("Audio driver not initialized.");
- lStatus = NO_INIT;
- goto Exit;
+Exit:
+ if(status) {
+ *status = lStatus;
+ }
+ return track;
+}
+
+// getTracks_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::getTracks_l(
+ SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks)
+{
+ size_t size = mTracks.size();
+ LOGV ("MixerThread::getTracks_l() for output %d, mTracks.size %d, mActiveTracks.size %d", mOutputType, mTracks.size(), mActiveTracks.size());
+ for (size_t i = 0; i < size; i++) {
+ sp<Track> t = mTracks[i];
+ if (AudioSystem::routedToA2dpOutput(t->mStreamType)) {
+ tracks.add(t);
+ int j = mActiveTracks.indexOf(t);
+ if (j >= 0) {
+ t = mActiveTracks[j].promote();
+ if (t != NULL) {
+ activeTracks.add(t);
+ }
+ }
}
+ }
- wclient = mClients.valueFor(pid);
+ size = activeTracks.size();
+ for (size_t i = 0; i < size; i++) {
+ removeActiveTrack_l(activeTracks[i]);
+ }
+
+ size = tracks.size();
+ for (size_t i = 0; i < size; i++) {
+ sp<Track> t = tracks[i];
+ mTracks.remove(t);
+ deleteTrackName_l(t->name());
+ }
+}
- if (wclient != NULL) {
- client = wclient.promote();
- } else {
- client = new Client(this, pid);
- mClients.add(pid, client);
- }
+// putTracks_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::putTracks_l(
+ SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks)
+{
- track = new Track(this, client, streamType, sampleRate, format,
- channelCount, frameCount, sharedBuffer);
- mTracks.add(track);
- trackHandle = new TrackHandle(track);
+ LOGV ("MixerThread::putTracks_l() for output %d, tracks.size %d, activeTracks.size %d", mOutputType, tracks.size(), activeTracks.size());
- lStatus = NO_ERROR;
- }
+ size_t size = tracks.size();
+ for (size_t i = 0; i < size ; i++) {
+ sp<Track> t = tracks[i];
+ int name = getTrackName_l();
-Exit:
- if(status) {
- *status = lStatus;
+ if (name < 0) return;
+
+ t->mName = name;
+ t->mMixerThread = this;
+ mTracks.add(t);
+
+ int j = activeTracks.indexOf(t);
+ if (j >= 0) {
+ addActiveTrack_l(t);
+ }
}
- return trackHandle;
}
-uint32_t AudioFlinger::sampleRate() const
+uint32_t AudioFlinger::MixerThread::sampleRate() const
{
return mSampleRate;
}
-int AudioFlinger::channelCount() const
+int AudioFlinger::MixerThread::channelCount() const
{
return mChannelCount;
}
-int AudioFlinger::format() const
+int AudioFlinger::MixerThread::format() const
{
return mFormat;
}
-size_t AudioFlinger::frameCount() const
+size_t AudioFlinger::MixerThread::frameCount() const
{
return mFrameCount;
}
-uint32_t AudioFlinger::latency() const
+uint32_t AudioFlinger::MixerThread::latency() const
{
if (mOutput) {
return mOutput->latency();
@@ -637,260 +1391,67 @@ uint32_t AudioFlinger::latency() const
}
}
-status_t AudioFlinger::setMasterVolume(float value)
+status_t AudioFlinger::MixerThread::setMasterVolume(float value)
{
- // check calling permissions
- if (!settingsAllowed()) {
- return PERMISSION_DENIED;
- }
-
- // when hw supports master volume, don't scale in sw mixer
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
- if (mAudioHardware->setMasterVolume(value) == NO_ERROR) {
- mMasterVolume = 1.0f;
- }
- else {
- mMasterVolume = value;
- }
- mHardwareStatus = AUDIO_HW_IDLE;
+ mMasterVolume = value;
return NO_ERROR;
}
-status_t AudioFlinger::setRouting(int mode, uint32_t routes, uint32_t mask)
-{
- status_t err = NO_ERROR;
-
- // check calling permissions
- if (!settingsAllowed()) {
- return PERMISSION_DENIED;
- }
- if ((mode < AudioSystem::MODE_CURRENT) || (mode >= AudioSystem::NUM_MODES)) {
- LOGW("Illegal value: setRouting(%d, %u, %u)", mode, routes, mask);
- return BAD_VALUE;
- }
-
-#ifdef WITH_A2DP
- LOGD("setRouting %d %d %d\n", mode, routes, mask);
- if (mode == AudioSystem::MODE_NORMAL &&
- (mask & AudioSystem::ROUTE_BLUETOOTH_A2DP)) {
- AutoMutex lock(&mLock);
-
- bool enableA2dp = false;
- if (routes & AudioSystem::ROUTE_BLUETOOTH_A2DP) {
- if (mA2dpDisableCount > 0)
- mA2dpSuppressed = true;
- else
- enableA2dp = true;
- }
- setA2dpEnabled(enableA2dp);
- LOGD("setOutput done\n");
- }
-#endif
-
- // do nothing if only A2DP routing is affected
- mask &= ~AudioSystem::ROUTE_BLUETOOTH_A2DP;
- if (mask) {
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_HW_GET_ROUTING;
- uint32_t r;
- err = mAudioHardware->getRouting(mode, &r);
- if (err == NO_ERROR) {
- r = (r & ~mask) | (routes & mask);
- mHardwareStatus = AUDIO_HW_SET_ROUTING;
- err = mAudioHardware->setRouting(mode, r);
- }
- mHardwareStatus = AUDIO_HW_IDLE;
- }
- return err;
-}
-
-uint32_t AudioFlinger::getRouting(int mode) const
-{
- uint32_t routes = 0;
- if ((mode >= AudioSystem::MODE_CURRENT) && (mode < AudioSystem::NUM_MODES)) {
- mHardwareStatus = AUDIO_HW_GET_ROUTING;
- mAudioHardware->getRouting(mode, &routes);
- mHardwareStatus = AUDIO_HW_IDLE;
- } else {
- LOGW("Illegal value: getRouting(%d)", mode);
- }
- return routes;
-}
-
-status_t AudioFlinger::setMode(int mode)
-{
- // check calling permissions
- if (!settingsAllowed()) {
- return PERMISSION_DENIED;
- }
- if ((mode < 0) || (mode >= AudioSystem::NUM_MODES)) {
- LOGW("Illegal value: setMode(%d)", mode);
- return BAD_VALUE;
- }
-
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_HW_SET_MODE;
- status_t ret = mAudioHardware->setMode(mode);
- mHardwareStatus = AUDIO_HW_IDLE;
- return ret;
-}
-
-int AudioFlinger::getMode() const
-{
- int mode = AudioSystem::MODE_INVALID;
- mHardwareStatus = AUDIO_HW_SET_MODE;
- mAudioHardware->getMode(&mode);
- mHardwareStatus = AUDIO_HW_IDLE;
- return mode;
-}
-
-status_t AudioFlinger::setMicMute(bool state)
-{
- // check calling permissions
- if (!settingsAllowed()) {
- return PERMISSION_DENIED;
- }
-
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
- status_t ret = mAudioHardware->setMicMute(state);
- mHardwareStatus = AUDIO_HW_IDLE;
- return ret;
-}
-
-bool AudioFlinger::getMicMute() const
+status_t AudioFlinger::MixerThread::setMasterMute(bool muted)
{
- bool state = AudioSystem::MODE_INVALID;
- mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
- mAudioHardware->getMicMute(&state);
- mHardwareStatus = AUDIO_HW_IDLE;
- return state;
-}
-
-status_t AudioFlinger::setMasterMute(bool muted)
-{
- // check calling permissions
- if (!settingsAllowed()) {
- return PERMISSION_DENIED;
- }
-
mMasterMute = muted;
return NO_ERROR;
}
-float AudioFlinger::masterVolume() const
+float AudioFlinger::MixerThread::masterVolume() const
{
return mMasterVolume;
}
-bool AudioFlinger::masterMute() const
+bool AudioFlinger::MixerThread::masterMute() const
{
return mMasterMute;
}
-status_t AudioFlinger::setStreamVolume(int stream, float value)
+status_t AudioFlinger::MixerThread::setStreamVolume(int stream, float value)
{
- // check calling permissions
- if (!settingsAllowed()) {
- return PERMISSION_DENIED;
- }
-
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
- return BAD_VALUE;
- }
-
- status_t ret = NO_ERROR;
- if (stream == AudioTrack::VOICE_CALL) {
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_SET_VOICE_VOLUME;
- ret = mAudioHardware->setVoiceVolume(value);
- mHardwareStatus = AUDIO_HW_IDLE;
- // FIXME: This is a temporary fix to re-base the internally
- // generated in-call audio so that it is never muted, which is
- // already the case for the hardware routed in-call audio.
- // When audio stream handling is reworked, this should be
- // addressed more cleanly. Fixes #1324; see discussion at
- // http://review.source.android.com/8224
- mStreamTypes[stream].volume = value * (1.0 - 1.0 / 6.0) + (1.0 / 6.0);
- } else {
- mStreamTypes[stream].volume = value;
- }
- return ret;
+ mStreamTypes[stream].volume = value;
+ return NO_ERROR;
}
-status_t AudioFlinger::setStreamMute(int stream, bool muted)
+status_t AudioFlinger::MixerThread::setStreamMute(int stream, bool muted)
{
- // check calling permissions
- if (!settingsAllowed()) {
- return PERMISSION_DENIED;
- }
-
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
- return BAD_VALUE;
- }
mStreamTypes[stream].mute = muted;
return NO_ERROR;
}
-float AudioFlinger::streamVolume(int stream) const
+float AudioFlinger::MixerThread::streamVolume(int stream) const
{
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
- return 0.0f;
- }
- if (stream == AudioTrack::VOICE_CALL) {
- // FIXME: Re-base internally generated in-call audio,
- // reverse of above in setStreamVolume.
- return (mStreamTypes[stream].volume - (1.0 / 6.0)) / (1.0 - 1.0 / 6.0);
- }
return mStreamTypes[stream].volume;
}
-bool AudioFlinger::streamMute(int stream) const
+bool AudioFlinger::MixerThread::streamMute(int stream) const
{
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) {
- return true;
- }
return mStreamTypes[stream].mute;
}
-bool AudioFlinger::isMusicActive() const
+bool AudioFlinger::MixerThread::isMusicActive() const
{
size_t count = mActiveTracks.size();
for (size_t i = 0 ; i < count ; ++i) {
sp<Track> t = mActiveTracks[i].promote();
if (t == 0) continue;
Track* const track = t.get();
- if (t->mStreamType == AudioTrack::MUSIC)
+ if (t->mStreamType == AudioSystem::MUSIC)
return true;
}
return false;
}
-status_t AudioFlinger::setParameter(const char* key, const char* value)
-{
- status_t result, result2;
- AutoMutex lock(mHardwareLock);
- mHardwareStatus = AUDIO_SET_PARAMETER;
- result = mAudioHardware->setParameter(key, value);
- if (mA2dpAudioInterface) {
- result2 = mA2dpAudioInterface->setParameter(key, value);
- if (result2)
- result = result2;
- }
- mHardwareStatus = AUDIO_HW_IDLE;
- return result;
-}
-
-void AudioFlinger::removeClient(pid_t pid)
-{
- Mutex::Autolock _l(mLock);
- mClients.removeItem(pid);
-}
-
-status_t AudioFlinger::addTrack(const sp<Track>& track)
+// addTrack_l() must be called with AudioFlinger::mLock held
+status_t AudioFlinger::MixerThread::addTrack_l(const sp<Track>& track)
{
- Mutex::Autolock _l(mLock);
+ status_t status = ALREADY_EXISTS;
// here the track could be either new, or restarted
// in both cases "unstop" the track
@@ -903,139 +1464,135 @@ status_t AudioFlinger::addTrack(const sp<Track>& track)
}
// set retry count for buffer fill
track->mRetryCount = kMaxTrackStartupRetries;
- LOGV("mWaitWorkCV.broadcast");
- mWaitWorkCV.broadcast();
-
if (mActiveTracks.indexOf(track) < 0) {
// the track is newly added, make sure it fills up all its
// buffers before playing. This is to ensure the client will
// effectively get the latency it requested.
track->mFillingUpStatus = Track::FS_FILLING;
track->mResetDone = false;
- addActiveTrack(track);
- return NO_ERROR;
+ addActiveTrack_l(track);
+ status = NO_ERROR;
}
- return ALREADY_EXISTS;
-}
+
+ LOGV("mWaitWorkCV.broadcast");
+ mAudioFlinger->mWaitWorkCV.broadcast();
-void AudioFlinger::removeTrack(wp<Track> track, int name)
-{
- Mutex::Autolock _l(mLock);
- sp<Track> t = track.promote();
- if (t!=NULL && (t->mState <= TrackBase::STOPPED)) {
- remove_track_l(track, name);
- }
+ return status;
}
-void AudioFlinger::remove_track_l(wp<Track> track, int name)
+// removeTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::removeTrack_l(wp<Track> track, int name)
{
sp<Track> t = track.promote();
- if (t!=NULL) {
+ if (t!=NULL && (t->mState <= TrackBase::STOPPED)) {
t->reset();
+ deleteTrackName_l(name);
+ removeActiveTrack_l(track);
+ mAudioFlinger->mWaitWorkCV.broadcast();
}
- audioMixer()->deleteTrackName(name);
- removeActiveTrack(track);
- mWaitWorkCV.broadcast();
}
-void AudioFlinger::destroyTrack(const sp<Track>& track)
+// destroyTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::destroyTrack_l(const sp<Track>& track)
{
- // NOTE: We're acquiring a strong reference on the track before
- // acquiring the lock, this is to make sure removing it from
- // mTracks won't cause the destructor to be called while the lock is
- // held (note that technically, 'track' could be a reference to an item
- // in mTracks, which is why we need to do this).
- sp<Track> keep(track);
- Mutex::Autolock _l(mLock);
track->mState = TrackBase::TERMINATED;
if (mActiveTracks.indexOf(track) < 0) {
LOGV("remove track (%d) and delete from mixer", track->name());
mTracks.remove(track);
- audioMixer()->deleteTrackName(keep->name());
+ deleteTrackName_l(track->name());
}
}
-void AudioFlinger::addActiveTrack(const wp<Track>& t)
+// addActiveTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::addActiveTrack_l(const wp<Track>& t)
{
mActiveTracks.add(t);
+ // Force routing to speaker for certain stream types
+ // The forced routing to speaker is managed by hardware mixer
+ if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+ sp<Track> track = t.promote();
+ if (track == NULL) return;
+
+ if (streamForcedToSpeaker(track->type())) {
+ mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
+ }
#ifdef WITH_A2DP
- // disable A2DP for certain stream types
- sp<Track> track = t.promote();
- if (streamDisablesA2dp(track->type())) {
- if (mA2dpDisableCount++ == 0 && isA2dpEnabled()) {
- setA2dpEnabled(false);
- mA2dpSuppressed = true;
- LOGD("mA2dpSuppressed = true\n");
+ // AudioFlinger::mLock must be locked before calling
+ // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+ if (streamDisablesA2dp(track->type())) {
+ mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED);
}
- LOGD("mA2dpDisableCount incremented to %d\n", mA2dpDisableCount);
- }
#endif
+ }
}
-void AudioFlinger::removeActiveTrack(const wp<Track>& t)
+// removeActiveTrack_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::removeActiveTrack_l(const wp<Track>& t)
{
mActiveTracks.remove(t);
+
+ // Force routing to speaker for certain stream types
+ // The forced routing to speaker is managed by hardware mixer
+ if (mOutputType == AudioSystem::AUDIO_OUTPUT_HARDWARE) {
+ sp<Track> track = t.promote();
+ if (track == NULL) return;
+
+ if (streamForcedToSpeaker(track->type())) {
+ mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
+ }
#ifdef WITH_A2DP
- // disable A2DP for certain stream types
- sp<Track> track = t.promote();
- if (streamDisablesA2dp(track->type())) {
- if (mA2dpDisableCount > 0) {
- mA2dpDisableCount--;
- if (mA2dpDisableCount == 0 && mA2dpSuppressed) {
- setA2dpEnabled(true);
- mA2dpSuppressed = false;
- }
- LOGD("mA2dpDisableCount decremented to %d\n", mA2dpDisableCount);
- } else
- LOGE("mA2dpDisableCount is already zero");
- }
+ // 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
+ }
}
-// ----------------------------------------------------------------------------
-
-AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
- : RefBase(),
- mAudioFlinger(audioFlinger),
- mMemoryDealer(new MemoryDealer(1024*1024)),
- mPid(pid)
+// getTrackName_l() must be called with AudioFlinger::mLock held
+int AudioFlinger::MixerThread::getTrackName_l()
{
- // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
+ return mAudioMixer->getTrackName();
}
-AudioFlinger::Client::~Client()
+// deleteTrackName_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::MixerThread::deleteTrackName_l(int name)
{
- mAudioFlinger->removeClient(mPid);
+ mAudioMixer->deleteTrackName(name);
}
-const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+size_t AudioFlinger::MixerThread::getOutputFrameCount()
{
- return mMemoryDealer;
+ return mOutput->bufferSize() / mOutput->channelCount() / sizeof(int16_t);
}
// ----------------------------------------------------------------------------
-AudioFlinger::TrackBase::TrackBase(
- const sp<AudioFlinger>& audioFlinger,
+// TrackBase constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::TrackBase::TrackBase(
+ const sp<MixerThread>& mixerThread,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
+ uint32_t flags,
const sp<IMemory>& sharedBuffer)
: RefBase(),
- mAudioFlinger(audioFlinger),
+ mMixerThread(mixerThread),
mClient(client),
mStreamType(streamType),
mFrameCount(0),
mState(IDLE),
mClientTid(-1),
mFormat(format),
- mFlags(0)
+ mFlags(flags & ~SYSTEM_FLAGS_MASK)
{
- mName = audioFlinger->audioMixer()->getTrackName();
+ mName = mixerThread->getTrackName_l();
+ LOGV("TrackBase contructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
if (mName < 0) {
LOGE("no more track names availlable");
return;
@@ -1043,7 +1600,6 @@ AudioFlinger::TrackBase::TrackBase(
LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
-
// LOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
size_t size = sizeof(audio_track_cblk_t);
size_t bufferSize = frameCount*channelCount*sizeof(int16_t);
@@ -1051,41 +1607,60 @@ AudioFlinger::TrackBase::TrackBase(
size += bufferSize;
}
- mCblkMemory = client->heap()->allocate(size);
- if (mCblkMemory != 0) {
- mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
- if (mCblk) { // construct the shared structure in-place.
- new(mCblk) audio_track_cblk_t();
- // clear all buffers
- mCblk->frameCount = frameCount;
- mCblk->sampleRate = sampleRate;
- mCblk->channels = channelCount;
- if (sharedBuffer == 0) {
- 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
- // written to buffer
- mCblk->flowControlFlag = 1;
- } else {
- mBuffer = sharedBuffer->pointer();
+ if (client != NULL) {
+ mCblkMemory = client->heap()->allocate(size);
+ if (mCblkMemory != 0) {
+ mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
+ if (mCblk) { // construct the shared structure in-place.
+ new(mCblk) audio_track_cblk_t();
+ // clear all buffers
+ mCblk->frameCount = frameCount;
+ mCblk->sampleRate = sampleRate;
+ mCblk->channels = channelCount;
+ if (sharedBuffer == 0) {
+ 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
+ // written to buffer
+ mCblk->flowControlFlag = 1;
+ } else {
+ mBuffer = sharedBuffer->pointer();
+ }
+ mBufferEnd = (uint8_t *)mBuffer + bufferSize;
}
- mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+ } else {
+ LOGE("not enough memory for AudioTrack size=%u", size);
+ client->heap()->dump("AudioTrack");
+ return;
}
- } else {
- LOGE("not enough memory for AudioTrack size=%u", size);
- client->heap()->dump("AudioTrack");
- return;
- }
+ } else {
+ mCblk = (audio_track_cblk_t *)(new uint8_t[size]);
+ if (mCblk) { // construct the shared structure in-place.
+ new(mCblk) audio_track_cblk_t();
+ // clear all buffers
+ mCblk->frameCount = frameCount;
+ mCblk->sampleRate = sampleRate;
+ mCblk->channels = 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
+ // written to buffer
+ mCblk->flowControlFlag = 1;
+ mBufferEnd = (uint8_t *)mBuffer + bufferSize;
+ }
+ }
}
-AudioFlinger::TrackBase::~TrackBase()
+AudioFlinger::MixerThread::TrackBase::~TrackBase()
{
- mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ if (mCblk) {
+ mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
+ }
mCblkMemory.clear(); // and free the shared memory
mClient.clear();
}
-void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+void AudioFlinger::MixerThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
{
buffer->raw = 0;
mFrameCount = buffer->frameCount;
@@ -1093,7 +1668,7 @@ void AudioFlinger::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
buffer->frameCount = 0;
}
-bool AudioFlinger::TrackBase::step() {
+bool AudioFlinger::MixerThread::TrackBase::step() {
bool result;
audio_track_cblk_t* cblk = this->cblk();
@@ -1105,31 +1680,31 @@ bool AudioFlinger::TrackBase::step() {
return result;
}
-void AudioFlinger::TrackBase::reset() {
+void AudioFlinger::MixerThread::TrackBase::reset() {
audio_track_cblk_t* cblk = this->cblk();
cblk->user = 0;
cblk->server = 0;
cblk->userBase = 0;
cblk->serverBase = 0;
- mFlags = 0;
+ mFlags &= (uint32_t)(~SYSTEM_FLAGS_MASK);
LOGV("TrackBase::reset");
}
-sp<IMemory> AudioFlinger::TrackBase::getCblk() const
+sp<IMemory> AudioFlinger::MixerThread::TrackBase::getCblk() const
{
return mCblkMemory;
}
-int AudioFlinger::TrackBase::sampleRate() const {
+int AudioFlinger::MixerThread::TrackBase::sampleRate() const {
return mCblk->sampleRate;
}
-int AudioFlinger::TrackBase::channelCount() const {
+int AudioFlinger::MixerThread::TrackBase::channelCount() const {
return mCblk->channels;
}
-void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
audio_track_cblk_t* cblk = this->cblk();
int16_t *bufferStart = (int16_t *)mBuffer + (offset-cblk->serverBase)*cblk->channels;
int16_t *bufferEnd = bufferStart + frames * cblk->channels;
@@ -1148,8 +1723,9 @@ void* AudioFlinger::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const
// ----------------------------------------------------------------------------
-AudioFlinger::Track::Track(
- const sp<AudioFlinger>& audioFlinger,
+// Track constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::Track::Track(
+ const sp<MixerThread>& mixerThread,
const sp<Client>& client,
int streamType,
uint32_t sampleRate,
@@ -1157,7 +1733,7 @@ AudioFlinger::Track::Track(
int channelCount,
int frameCount,
const sp<IMemory>& sharedBuffer)
- : TrackBase(audioFlinger, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer)
+ : TrackBase(mixerThread, client, streamType, sampleRate, format, channelCount, frameCount, 0, sharedBuffer)
{
mVolume[0] = 1.0f;
mVolume[1] = 1.0f;
@@ -1165,23 +1741,36 @@ AudioFlinger::Track::Track(
mSharedBuffer = sharedBuffer;
}
-AudioFlinger::Track::~Track()
+AudioFlinger::MixerThread::Track::~Track()
{
wp<Track> weak(this); // never create a strong ref from the dtor
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
mState = TERMINATED;
- mAudioFlinger->removeTrack(weak, mName);
+ mMixerThread->removeTrack_l(weak, mName);
}
-void AudioFlinger::Track::destroy()
+void AudioFlinger::MixerThread::Track::destroy()
{
- mAudioFlinger->destroyTrack(this);
+ // NOTE: destroyTrack_l() can remove a strong reference to this Track
+ // by removing it from mTracks vector, so there is a risk that this Tracks's
+ // desctructor is called. As the destructor needs to lock AudioFlinger::mLock,
+ // we must acquire a strong reference on this Track before locking AudioFlinger::mLock
+ // here so that the destructor is called only when exiting this function.
+ // On the other hand, as long as Track::destroy() is only called by
+ // TrackHandle destructor, the TrackHandle still holds a strong ref on
+ // this Track with its member mTrack.
+ sp<Track> keep(this);
+ { // scope for AudioFlinger::mLock
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+ mMixerThread->destroyTrack_l(this);
+ }
}
-void AudioFlinger::Track::dump(char* buffer, size_t size)
+void AudioFlinger::MixerThread::Track::dump(char* buffer, size_t size)
{
snprintf(buffer, size, " %5d %5d %3u %3u %3u %3u %1d %1d %1d %5u %5u %5u %04x %04x\n",
mName - AudioMixer::TRACK0,
- mClient->pid(),
+ (mClient == NULL) ? getpid() : mClient->pid(),
mStreamType,
mFormat,
mCblk->channels,
@@ -1196,7 +1785,7 @@ void AudioFlinger::Track::dump(char* buffer, size_t size)
mCblk->user);
}
-status_t AudioFlinger::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::MixerThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
{
audio_track_cblk_t* cblk = this->cblk();
uint32_t framesReady;
@@ -1236,53 +1825,55 @@ getNextBuffer_exit:
return NOT_ENOUGH_DATA;
}
-bool AudioFlinger::Track::isReady() const {
+bool AudioFlinger::MixerThread::Track::isReady() const {
if (mFillingUpStatus != FS_FILLING) return true;
if (mCblk->framesReady() >= mCblk->frameCount ||
mCblk->forceReady) {
mFillingUpStatus = FS_FILLED;
mCblk->forceReady = 0;
+ LOGV("Track::isReady() track %d for output %d", mName, mMixerThread->mOutputType);
return true;
}
return false;
}
-status_t AudioFlinger::Track::start()
+status_t AudioFlinger::MixerThread::Track::start()
{
- LOGV("start(%d)", mName);
- mAudioFlinger->addTrack(this);
+ LOGV("start(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+ mMixerThread->addTrack_l(this);
return NO_ERROR;
}
-void AudioFlinger::Track::stop()
+void AudioFlinger::MixerThread::Track::stop()
{
- LOGV("stop(%d)", mName);
- Mutex::Autolock _l(mAudioFlinger->mLock);
+ LOGV("stop(%d), calling thread %d for output %d", mName, IPCThreadState::self()->getCallingPid(), mMixerThread->mOutputType);
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
if (mState > STOPPED) {
mState = STOPPED;
// If the track is not active (PAUSED and buffers full), flush buffers
- if (mAudioFlinger->mActiveTracks.indexOf(this) < 0) {
+ if (mMixerThread->mActiveTracks.indexOf(this) < 0) {
reset();
}
LOGV("(> STOPPED) => STOPPED (%d)", mName);
}
}
-void AudioFlinger::Track::pause()
+void AudioFlinger::MixerThread::Track::pause()
{
- LOGV("pause(%d)", mName);
- Mutex::Autolock _l(mAudioFlinger->mLock);
+ LOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
if (mState == ACTIVE || mState == RESUMING) {
mState = PAUSING;
LOGV("ACTIVE/RESUMING => PAUSING (%d)", mName);
}
}
-void AudioFlinger::Track::flush()
+void AudioFlinger::MixerThread::Track::flush()
{
LOGV("flush(%d)", mName);
- Mutex::Autolock _l(mAudioFlinger->mLock);
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
return;
}
@@ -1298,7 +1889,7 @@ void AudioFlinger::Track::flush()
reset();
}
-void AudioFlinger::Track::reset()
+void AudioFlinger::MixerThread::Track::reset()
{
// Do not reset twice to avoid discarding data written just after a flush and before
// the audioflinger thread detects the track is stopped.
@@ -1313,12 +1904,12 @@ void AudioFlinger::Track::reset()
}
}
-void AudioFlinger::Track::mute(bool muted)
+void AudioFlinger::MixerThread::Track::mute(bool muted)
{
mMute = muted;
}
-void AudioFlinger::Track::setVolume(float left, float right)
+void AudioFlinger::MixerThread::Track::setVolume(float left, float right)
{
mVolume[0] = left;
mVolume[1] = right;
@@ -1326,7 +1917,292 @@ void AudioFlinger::Track::setVolume(float left, float right)
// ----------------------------------------------------------------------------
-AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::Track>& track)
+// RecordTrack constructor must be called with AudioFlinger::mLock held
+AudioFlinger::MixerThread::RecordTrack::RecordTrack(
+ const sp<MixerThread>& mixerThread,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags)
+ : TrackBase(mixerThread, client, streamType, sampleRate, format,
+ channelCount, frameCount, flags, 0),
+ mOverflow(false)
+{
+}
+
+AudioFlinger::MixerThread::RecordTrack::~RecordTrack()
+{
+ Mutex::Autolock _l(mMixerThread->mAudioFlinger->mLock);
+ mMixerThread->deleteTrackName_l(mName);
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ audio_track_cblk_t* cblk = this->cblk();
+ uint32_t framesAvail;
+ uint32_t framesReq = buffer->frameCount;
+
+ // Check if last stepServer failed, try to step now
+ if (mFlags & TrackBase::STEPSERVER_FAILED) {
+ if (!step()) goto getNextBuffer_exit;
+ LOGV("stepServer recovered");
+ mFlags &= ~TrackBase::STEPSERVER_FAILED;
+ }
+
+ framesAvail = cblk->framesAvailable_l();
+
+ if (LIKELY(framesAvail)) {
+ uint32_t s = cblk->server;
+ uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
+
+ if (framesReq > framesAvail) {
+ framesReq = framesAvail;
+ }
+ if (s + framesReq > bufferEnd) {
+ framesReq = bufferEnd - s;
+ }
+
+ buffer->raw = getBuffer(s, framesReq);
+ if (buffer->raw == 0) goto getNextBuffer_exit;
+
+ buffer->frameCount = framesReq;
+ return NO_ERROR;
+ }
+
+getNextBuffer_exit:
+ buffer->raw = 0;
+ buffer->frameCount = 0;
+ return NOT_ENOUGH_DATA;
+}
+
+status_t AudioFlinger::MixerThread::RecordTrack::start()
+{
+ return mMixerThread->mAudioFlinger->startRecord(this);
+}
+
+void AudioFlinger::MixerThread::RecordTrack::stop()
+{
+ mMixerThread->mAudioFlinger->stopRecord(this);
+ TrackBase::reset();
+ // Force overerrun condition to avoid false overrun callback until first data is
+ // read from buffer
+ mCblk->flowControlFlag = 1;
+}
+
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MixerThread::OutputTrack::OutputTrack(
+ const sp<MixerThread>& mixerThread,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount)
+ : Track(mixerThread, NULL, AudioSystem::SYSTEM, sampleRate, format, channelCount, frameCount, NULL),
+ mOutputMixerThread(mixerThread)
+{
+
+ mCblk->out = 1;
+ mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+ mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+ mOutBuffer.frameCount = 0;
+ mCblk->bufferTimeoutMs = 10;
+
+ LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p",
+ mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd);
+
+}
+
+AudioFlinger::MixerThread::OutputTrack::~OutputTrack()
+{
+ stop();
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::start()
+{
+ status_t status = Track::start();
+
+ mRetryCount = 127;
+ return status;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::stop()
+{
+ Track::stop();
+ clearBufferQueue();
+ mOutBuffer.frameCount = 0;
+}
+
+void AudioFlinger::MixerThread::OutputTrack::write(int16_t* data, uint32_t frames)
+{
+ Buffer *pInBuffer;
+ Buffer inBuffer;
+ uint32_t channels = mCblk->channels;
+
+ inBuffer.frameCount = frames;
+ inBuffer.i16 = data;
+
+ if (mCblk->user == 0) {
+ if (mOutputMixerThread->isMusicActive()) {
+ mCblk->forceReady = 1;
+ LOGV("OutputTrack::start() force ready");
+ } else if (mCblk->frameCount > frames){
+ if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+ uint32_t startFrames = (mCblk->frameCount - frames);
+ LOGV("OutputTrack::start() write %d frames", startFrames);
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[startFrames * channels];
+ pInBuffer->frameCount = startFrames;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memset(pInBuffer->raw, 0, startFrames * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ } else {
+ LOGW ("OutputTrack::write() no more buffers");
+ }
+ }
+ }
+
+ while (1) {
+ // First write pending buffers, then new data
+ if (mBufferQueue.size()) {
+ pInBuffer = mBufferQueue.itemAt(0);
+ } else {
+ pInBuffer = &inBuffer;
+ }
+
+ if (pInBuffer->frameCount == 0) {
+ break;
+ }
+
+ if (mOutBuffer.frameCount == 0) {
+ mOutBuffer.frameCount = pInBuffer->frameCount;
+ if (obtainBuffer(&mOutBuffer) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+ break;
+ }
+ }
+
+ uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount;
+ memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channels * sizeof(int16_t));
+ mCblk->stepUser(outFrames);
+ pInBuffer->frameCount -= outFrames;
+ pInBuffer->i16 += outFrames * channels;
+ mOutBuffer.frameCount -= outFrames;
+ mOutBuffer.i16 += outFrames * channels;
+
+ if (pInBuffer->frameCount == 0) {
+ if (mBufferQueue.size()) {
+ mBufferQueue.removeAt(0);
+ delete [] pInBuffer->mBuffer;
+ delete pInBuffer;
+ } else {
+ break;
+ }
+ }
+ }
+
+ // If we could not write all frames, allocate a buffer and queue it for next time.
+ if (inBuffer.frameCount) {
+ if (mBufferQueue.size() < kMaxOutputTrackBuffers) {
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channels];
+ pInBuffer->frameCount = inBuffer.frameCount;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ } else {
+ LOGW("OutputTrack::write() no more buffers");
+ }
+ }
+
+ // Calling write() with a 0 length buffer, means that no more data will be written:
+ // If no more buffers are pending, fill output track buffer to make sure it is started
+ // by output mixer.
+ if (frames == 0 && mBufferQueue.size() == 0 && mCblk->user < mCblk->frameCount) {
+ frames = mCblk->frameCount - mCblk->user;
+ pInBuffer = new Buffer;
+ pInBuffer->mBuffer = new int16_t[frames * channels];
+ pInBuffer->frameCount = frames;
+ pInBuffer->i16 = pInBuffer->mBuffer;
+ memset(pInBuffer->raw, 0, frames * channels * sizeof(int16_t));
+ mBufferQueue.add(pInBuffer);
+ }
+
+}
+
+status_t AudioFlinger::MixerThread::OutputTrack::obtainBuffer(AudioBufferProvider::Buffer* buffer)
+{
+ int active;
+ int timeout = 0;
+ status_t result;
+ audio_track_cblk_t* cblk = mCblk;
+ uint32_t framesReq = buffer->frameCount;
+
+ LOGV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server);
+ buffer->frameCount = 0;
+
+ uint32_t framesAvail = cblk->framesAvailable();
+
+ if (framesAvail == 0) {
+ return AudioTrack::NO_MORE_BUFFERS;
+ }
+
+ if (framesReq > framesAvail) {
+ framesReq = framesAvail;
+ }
+
+ uint32_t u = cblk->user;
+ uint32_t bufferEnd = cblk->userBase + cblk->frameCount;
+
+ if (u + framesReq > bufferEnd) {
+ framesReq = bufferEnd - u;
+ }
+
+ buffer->frameCount = framesReq;
+ buffer->raw = (void *)cblk->buffer(u);
+ return NO_ERROR;
+}
+
+
+void AudioFlinger::MixerThread::OutputTrack::clearBufferQueue()
+{
+ size_t size = mBufferQueue.size();
+ Buffer *pBuffer;
+
+ for (size_t i = 0; i < size; i++) {
+ pBuffer = mBufferQueue.itemAt(i);
+ delete [] pBuffer->mBuffer;
+ delete pBuffer;
+ }
+ mBufferQueue.clear();
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
+ : RefBase(),
+ mAudioFlinger(audioFlinger),
+ mMemoryDealer(new MemoryDealer(1024*1024)),
+ mPid(pid)
+{
+ // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
+}
+
+AudioFlinger::Client::~Client()
+{
+ mAudioFlinger->removeClient(mPid);
+}
+
+const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+{
+ return mMemoryDealer;
+}
+
+// ----------------------------------------------------------------------------
+
+AudioFlinger::TrackHandle::TrackHandle(const sp<AudioFlinger::MixerThread::Track>& track)
: BnAudioTrack(),
mTrack(track)
{
@@ -1386,8 +2262,7 @@ sp<IAudioRecord> AudioFlinger::openRecord(
uint32_t flags,
status_t *status)
{
- sp<AudioRecordThread> thread;
- sp<RecordTrack> recordTrack;
+ sp<MixerThread::RecordTrack> recordTrack;
sp<RecordHandle> recordHandle;
sp<Client> client;
wp<Client> wclient;
@@ -1414,12 +2289,6 @@ sp<IAudioRecord> AudioFlinger::openRecord(
goto Exit;
}
- if (mSampleRate == 0) {
- LOGE("Audio driver not initialized");
- lStatus = NO_INIT;
- goto Exit;
- }
-
if (mAudioRecordThread == 0) {
LOGE("Audio record thread not started");
lStatus = NO_INIT;
@@ -1436,7 +2305,7 @@ sp<IAudioRecord> AudioFlinger::openRecord(
}
// add client to list
- {
+ { // scope for mLock
Mutex::Autolock _l(mLock);
wclient = mClients.valueFor(pid);
if (wclient != NULL) {
@@ -1445,15 +2314,20 @@ sp<IAudioRecord> AudioFlinger::openRecord(
client = new Client(this, pid);
mClients.add(pid, client);
}
- }
- // frameCount must be a multiple of input buffer size
- inFrameCount = inputBufferSize/channelCount/sizeof(short);
- frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
-
- // create new record track and pass to record thread
- recordTrack = new RecordTrack(this, client, streamType, sampleRate,
- format, channelCount, frameCount);
+ // frameCount must be a multiple of input buffer size
+ inFrameCount = inputBufferSize/channelCount/sizeof(short);
+ frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
+
+ // create new record track. The record track uses one track in mHardwareMixerThread by convention.
+ recordTrack = new MixerThread::RecordTrack(mHardwareMixerThread, client, streamType, sampleRate,
+ format, channelCount, frameCount, flags);
+ }
+ if (recordTrack->getCblk() == NULL) {
+ recordTrack.clear();
+ lStatus = NO_MEMORY;
+ goto Exit;
+ }
// return to handle to client
recordHandle = new RecordHandle(recordTrack);
@@ -1466,97 +2340,22 @@ Exit:
return recordHandle;
}
-status_t AudioFlinger::startRecord(RecordTrack* recordTrack) {
+status_t AudioFlinger::startRecord(MixerThread::RecordTrack* recordTrack) {
if (mAudioRecordThread != 0) {
return mAudioRecordThread->start(recordTrack);
}
return NO_INIT;
}
-void AudioFlinger::stopRecord(RecordTrack* recordTrack) {
+void AudioFlinger::stopRecord(MixerThread::RecordTrack* recordTrack) {
if (mAudioRecordThread != 0) {
mAudioRecordThread->stop(recordTrack);
}
}
-
-// ----------------------------------------------------------------------------
-
-AudioFlinger::RecordTrack::RecordTrack(
- const sp<AudioFlinger>& audioFlinger,
- const sp<Client>& client,
- int streamType,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount)
- : TrackBase(audioFlinger, client, streamType, sampleRate, format,
- channelCount, frameCount, 0),
- mOverflow(false)
-{
-}
-
-AudioFlinger::RecordTrack::~RecordTrack()
-{
- mAudioFlinger->audioMixer()->deleteTrackName(mName);
-}
-
-status_t AudioFlinger::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
-{
- audio_track_cblk_t* cblk = this->cblk();
- uint32_t framesAvail;
- uint32_t framesReq = buffer->frameCount;
-
- // Check if last stepServer failed, try to step now
- if (mFlags & TrackBase::STEPSERVER_FAILED) {
- if (!step()) goto getNextBuffer_exit;
- LOGV("stepServer recovered");
- mFlags &= ~TrackBase::STEPSERVER_FAILED;
- }
-
- framesAvail = cblk->framesAvailable_l();
-
- if (LIKELY(framesAvail)) {
- uint32_t s = cblk->server;
- uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;
-
- if (framesReq > framesAvail) {
- framesReq = framesAvail;
- }
- if (s + framesReq > bufferEnd) {
- framesReq = bufferEnd - s;
- }
-
- buffer->raw = getBuffer(s, framesReq);
- if (buffer->raw == 0) goto getNextBuffer_exit;
-
- buffer->frameCount = framesReq;
- return NO_ERROR;
- }
-
-getNextBuffer_exit:
- buffer->raw = 0;
- buffer->frameCount = 0;
- return NOT_ENOUGH_DATA;
-}
-
-status_t AudioFlinger::RecordTrack::start()
-{
- return mAudioFlinger->startRecord(this);
-}
-
-void AudioFlinger::RecordTrack::stop()
-{
- mAudioFlinger->stopRecord(this);
- TrackBase::reset();
- // Force overerrun condition to avoid false overrun callback until first data is
- // read from buffer
- mCblk->flowControlFlag = 1;
-}
-
// ----------------------------------------------------------------------------
-AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordTrack>& recordTrack)
+AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::MixerThread::RecordTrack>& recordTrack)
: BnAudioRecord(),
mRecordTrack(recordTrack)
{
@@ -1588,8 +2387,10 @@ status_t AudioFlinger::RecordHandle::onTransact(
// ----------------------------------------------------------------------------
-AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware) :
+AudioFlinger::AudioRecordThread::AudioRecordThread(AudioHardwareInterface* audioHardware,
+ const sp<AudioFlinger>& audioFlinger) :
mAudioHardware(audioHardware),
+ mAudioFlinger(audioFlinger),
mActive(false)
{
}
@@ -1619,15 +2420,17 @@ bool AudioFlinger::AudioRecordThread::threadLoop()
input = 0;
}
mRecordTrack.clear();
+ mStopped.signal();
mWaitWorkCV.wait(mLock);
LOGV("AudioRecordThread: loop starting");
if (mRecordTrack != 0) {
input = mAudioHardware->openInputStream(mRecordTrack->format(),
- mRecordTrack->channelCount(),
- mRecordTrack->sampleRate(),
- &mStartStatus);
+ mRecordTrack->channelCount(),
+ mRecordTrack->sampleRate(),
+ &mStartStatus,
+ (AudioSystem::audio_in_acoustics)(mRecordTrack->mFlags >> 16));
if (input != 0) {
inBufferSize = input->bufferSize();
inFrameCount = inBufferSize/input->frameSize();
@@ -1643,12 +2446,14 @@ bool AudioFlinger::AudioRecordThread::threadLoop()
mWaitWorkCV.signal();
}
mLock.unlock();
- } else if (mRecordTrack != 0){
+ } else if (mRecordTrack != 0) {
buffer.frameCount = inFrameCount;
- if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+ if (LIKELY(mRecordTrack->getNextBuffer(&buffer) == NO_ERROR &&
+ (int)buffer.frameCount == inFrameCount)) {
LOGV("AudioRecordThread read: %d frames", buffer.frameCount);
- if (input->read(buffer.raw, inBufferSize) < 0) {
+ ssize_t bytesRead = input->read(buffer.raw, inBufferSize);
+ if (bytesRead < 0) {
LOGE("Error reading audio input");
sleep(1);
}
@@ -1677,7 +2482,7 @@ bool AudioFlinger::AudioRecordThread::threadLoop()
return false;
}
-status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)
+status_t AudioFlinger::AudioRecordThread::start(MixerThread::RecordTrack* recordTrack)
{
LOGV("AudioRecordThread::start");
AutoMutex lock(&mLock);
@@ -1690,6 +2495,19 @@ status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)
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();
@@ -1698,11 +2516,24 @@ status_t AudioFlinger::AudioRecordThread::start(RecordTrack* recordTrack)
return mStartStatus;
}
-void AudioFlinger::AudioRecordThread::stop(RecordTrack* recordTrack) {
+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);
}
}
@@ -1717,6 +2548,22 @@ void AudioFlinger::AudioRecordThread::exit()
requestExitAndWait();
}
+status_t AudioFlinger::AudioRecordThread::dump(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ pid_t pid = 0;
+
+ if (mRecordTrack != 0 && mRecordTrack->mClient != 0) {
+ snprintf(buffer, SIZE, "Record client pid: %d\n", mRecordTrack->mClient->pid());
+ result.append(buffer);
+ } else {
+ result.append("No record client\n");
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
status_t AudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 9ab362a..ab15947 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include <media/IAudioFlinger.h>
+#include <media/IAudioFlingerClient.h>
#include <media/IAudioTrack.h>
#include <media/IAudioRecord.h>
#include <media/AudioTrack.h>
@@ -32,6 +33,7 @@
#include <utils/MemoryDealer.h>
#include <utils/KeyedVector.h>
#include <utils/SortedVector.h>
+#include <utils/Vector.h>
#include <hardware_legacy/AudioHardwareInterface.h>
@@ -54,18 +56,13 @@ class AudioBuffer;
static const nsecs_t kStandbyTimeInNsecs = seconds(3);
-class AudioFlinger : public BnAudioFlinger, protected Thread
+class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient
{
public:
static void instantiate();
virtual status_t dump(int fd, const Vector<String16>& args);
- // Thread virtuals
- virtual bool threadLoop();
- virtual status_t readyToRun();
- virtual void onFirstRef();
-
// IAudioFlinger interface
virtual sp<IAudioTrack> createTrack(
pid_t pid,
@@ -78,11 +75,11 @@ public:
const sp<IMemory>& sharedBuffer,
status_t *status);
- virtual uint32_t sampleRate() const;
- virtual int channelCount() const;
- virtual int format() const;
- virtual size_t frameCount() const;
- virtual size_t latency() const;
+ virtual uint32_t sampleRate(int output) const;
+ virtual int channelCount(int output) const;
+ virtual int format(int output) const;
+ virtual size_t frameCount(int output) const;
+ virtual uint32_t latency(int output) const;
virtual status_t setMasterVolume(float value);
virtual status_t setMasterMute(bool muted);
@@ -107,8 +104,19 @@ public:
virtual bool isMusicActive() const;
+ virtual bool isA2dpEnabled() const;
+
virtual status_t setParameter(const char* key, const char* value);
+ virtual void registerClient(const sp<IAudioFlingerClient>& client);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+
+ virtual void wakeUp() { mWaitWorkCV.broadcast(); }
+
+ // IBinder::DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+
enum hardware_call_state {
AUDIO_HW_IDLE = 0,
AUDIO_HW_INIT,
@@ -149,23 +157,31 @@ private:
AudioFlinger();
virtual ~AudioFlinger();
- void setOutput(AudioStreamOut* output);
- void doSetOutput(AudioStreamOut* output);
- size_t getOutputFrameCount(AudioStreamOut* output);
+ void setOutput(int outputType);
+ void doSetOutput(int outputType);
#ifdef WITH_A2DP
+ void setA2dpEnabled_l(bool enable);
+ void checkA2dpEnabledChange_l();
+#endif
+ static bool streamForcedToSpeaker(int streamType);
static bool streamDisablesA2dp(int streamType);
- inline bool isA2dpEnabled() const {
- return (mRequestedOutput == mA2dpOutput ||
- (mOutput && mOutput == mA2dpOutput));
- }
- void setA2dpEnabled(bool enable);
+
+ // Management of forced route to speaker for certain track types.
+ enum force_speaker_command {
+ ACTIVE_TRACK_ADDED = 0,
+ ACTIVE_TRACK_REMOVED,
+ CHECK_ROUTE_RESTORE_TIME,
+ FORCE_ROUTE_RESTORE
+ };
+ void handleForcedSpeakerRoute(int command);
+#ifdef WITH_A2DP
+ void handleStreamDisablesA2dp_l(int command);
#endif
// Internal dump utilites.
status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
status_t dumpClients(int fd, const Vector<String16>& args);
- status_t dumpTracks(int fd, const Vector<String16>& args);
status_t dumpInternals(int fd, const Vector<String16>& args);
// --- Client ---
@@ -184,168 +200,347 @@ private:
};
- // --- Track ---
class TrackHandle;
class RecordHandle;
class AudioRecordThread;
- // base for record and playback
- class TrackBase : public AudioBufferProvider, public RefBase {
-
+
+ // --- MixerThread ---
+ class MixerThread : public Thread {
public:
- enum track_state {
- IDLE,
- TERMINATED,
- STOPPED,
- RESUMING,
- ACTIVE,
- PAUSING,
- PAUSED
+
+ // --- Track ---
+
+ // base for record and playback
+ class TrackBase : public AudioBufferProvider, public RefBase {
+
+ public:
+ enum track_state {
+ IDLE,
+ TERMINATED,
+ STOPPED,
+ RESUMING,
+ ACTIVE,
+ PAUSING,
+ PAUSED
+ };
+
+ enum track_flags {
+ STEPSERVER_FAILED = 0x01, // StepServer could not acquire cblk->lock mutex
+ SYSTEM_FLAGS_MASK = 0x0000ffffUL,
+ // The upper 16 bits are used for track-specific flags.
+ };
+
+ TrackBase(const sp<MixerThread>& mixerThread,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags,
+ const sp<IMemory>& sharedBuffer);
+ ~TrackBase();
+
+ virtual status_t start() = 0;
+ virtual void stop() = 0;
+ sp<IMemory> getCblk() const;
+
+ protected:
+ friend class MixerThread;
+ friend class RecordHandle;
+ friend class AudioRecordThread;
+
+ TrackBase(const TrackBase&);
+ TrackBase& operator = (const TrackBase&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
+ virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+
+ audio_track_cblk_t* cblk() const {
+ return mCblk;
+ }
+
+ int type() const {
+ return mStreamType;
+ }
+
+ int format() const {
+ return mFormat;
+ }
+
+ int channelCount() const ;
+
+ int sampleRate() const;
+
+ void* getBuffer(uint32_t offset, uint32_t frames) const;
+
+ int name() const {
+ return mName;
+ }
+
+ bool isStopped() const {
+ return mState == STOPPED;
+ }
+
+ bool isTerminated() const {
+ return mState == TERMINATED;
+ }
+
+ bool step();
+ void reset();
+
+ sp<MixerThread> mMixerThread;
+ sp<Client> mClient;
+ sp<IMemory> mCblkMemory;
+ audio_track_cblk_t* mCblk;
+ int mStreamType;
+ void* mBuffer;
+ void* mBufferEnd;
+ uint32_t mFrameCount;
+ int mName;
+ // we don't really need a lock for these
+ int mState;
+ int mClientTid;
+ uint8_t mFormat;
+ uint32_t mFlags;
};
- enum track_flags {
- STEPSERVER_FAILED = 0x01 // StepServer could not acquire cblk->lock mutex
+ // playback track
+ class Track : public TrackBase {
+ public:
+ Track( const sp<MixerThread>& mixerThread,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ const sp<IMemory>& sharedBuffer);
+ ~Track();
+
+ void dump(char* buffer, size_t size);
+ virtual status_t start();
+ virtual void stop();
+ void pause();
+
+ void flush();
+ void destroy();
+ void mute(bool);
+ void setVolume(float left, float right);
+
+ protected:
+ friend class MixerThread;
+ friend class AudioFlinger;
+ friend class AudioFlinger::TrackHandle;
+
+ Track(const Track&);
+ Track& operator = (const Track&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+ bool isMuted() const {
+ return (mMute || mMixerThread->mStreamTypes[mStreamType].mute);
+ }
+
+ bool isPausing() const {
+ return mState == PAUSING;
+ }
+
+ bool isPaused() const {
+ return mState == PAUSED;
+ }
+
+ bool isReady() const;
+
+ void setPaused() { mState = PAUSED; }
+ void reset();
+
+ // we don't really need a lock for these
+ float mVolume[2];
+ volatile bool mMute;
+ // FILLED state is used for suppressing volume ramp at begin of playing
+ enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
+ mutable uint8_t mFillingUpStatus;
+ int8_t mRetryCount;
+ sp<IMemory> mSharedBuffer;
+ bool mResetDone;
+ }; // end of Track
+
+ // record track
+ class RecordTrack : public TrackBase {
+ public:
+ RecordTrack(const sp<MixerThread>& mixerThread,
+ const sp<Client>& client,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount,
+ uint32_t flags);
+ ~RecordTrack();
+
+ virtual status_t start();
+ virtual void stop();
+
+ bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
+ bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
+
+ private:
+ friend class AudioFlinger;
+ friend class AudioFlinger::RecordHandle;
+ friend class AudioFlinger::AudioRecordThread;
+ friend class MixerThread;
+
+ RecordTrack(const Track&);
+ RecordTrack& operator = (const Track&);
+
+ virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+
+ bool mOverflow;
};
- TrackBase( const sp<AudioFlinger>& audioFlinger,
- const sp<Client>& client,
- int streamType,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount,
- const sp<IMemory>& sharedBuffer);
- ~TrackBase();
-
- virtual status_t start() = 0;
- virtual void stop() = 0;
- sp<IMemory> getCblk() const;
-
- protected:
- friend class AudioFlinger;
- friend class RecordHandle;
- friend class AudioRecordThread;
-
- TrackBase(const TrackBase&);
- TrackBase& operator = (const TrackBase&);
-
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
- virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
-
- audio_track_cblk_t* cblk() const {
- return mCblk;
- }
-
- int type() const {
- return mStreamType;
- }
-
- int format() const {
- return mFormat;
- }
-
- int channelCount() const ;
-
- int sampleRate() const;
-
- void* getBuffer(uint32_t offset, uint32_t frames) const;
-
- int name() const {
- return mName;
- }
-
- bool isStopped() const {
- return mState == STOPPED;
- }
-
- bool isTerminated() const {
- return mState == TERMINATED;
- }
-
- bool step();
- void reset();
-
- sp<AudioFlinger> mAudioFlinger;
- sp<Client> mClient;
- sp<IMemory> mCblkMemory;
- audio_track_cblk_t* mCblk;
- int mStreamType;
- void* mBuffer;
- void* mBufferEnd;
- uint32_t mFrameCount;
- int mName;
- // we don't really need a lock for these
- int mState;
- int mClientTid;
- uint8_t mFormat;
- uint8_t mFlags;
- };
-
- // playback track
- class Track : public TrackBase {
- public:
- Track( const sp<AudioFlinger>& audioFlinger,
- const sp<Client>& client,
+ // playback track
+ class OutputTrack : public Track {
+ public:
+
+ class Buffer: public AudioBufferProvider::Buffer {
+ public:
+ int16_t *mBuffer;
+ };
+
+ OutputTrack( const sp<MixerThread>& mixerThread,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int frameCount);
+ ~OutputTrack();
+
+ virtual status_t start();
+ virtual void stop();
+ void write(int16_t* data, uint32_t frames);
+ bool bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; }
+
+ private:
+
+ status_t obtainBuffer(AudioBufferProvider::Buffer* buffer);
+ void clearBufferQueue();
+
+ sp<MixerThread> mOutputMixerThread;
+ Vector < Buffer* > mBufferQueue;
+ AudioBufferProvider::Buffer mOutBuffer;
+ uint32_t mFramesWritten;
+
+ }; // end of OutputTrack
+
+ MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int outputType);
+ virtual ~MixerThread();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ // Thread virtuals
+ virtual bool threadLoop();
+ virtual status_t readyToRun();
+ virtual void onFirstRef();
+
+ virtual uint32_t sampleRate() const;
+ virtual int channelCount() const;
+ virtual int format() const;
+ virtual size_t frameCount() const;
+ virtual uint32_t latency() const;
+
+ virtual status_t setMasterVolume(float value);
+ virtual status_t setMasterMute(bool muted);
+
+ virtual float masterVolume() const;
+ virtual bool masterMute() const;
+
+ virtual status_t setStreamVolume(int stream, float value);
+ virtual status_t setStreamMute(int stream, bool muted);
+
+ virtual float streamVolume(int stream) const;
+ virtual bool streamMute(int stream) const;
+
+ bool isMusicActive() const;
+
+
+ sp<Track> createTrack_l(
+ const sp<AudioFlinger::Client>& client,
int streamType,
uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
- const sp<IMemory>& sharedBuffer);
- ~Track();
-
- void dump(char* buffer, size_t size);
- virtual status_t start();
- virtual void stop();
- void pause();
-
- void flush();
- void destroy();
- void mute(bool);
- void setVolume(float left, float right);
+ const sp<IMemory>& sharedBuffer,
+ status_t *status);
+
+ void getTracks_l(SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks);
+ void putTracks_l(SortedVector < sp<Track> >& tracks,
+ SortedVector < wp<Track> >& activeTracks);
+ void setOuputTrack(OutputTrack *track) { mOutputTrack = track; }
+
+ struct stream_type_t {
+ stream_type_t()
+ : volume(1.0f),
+ mute(false)
+ {
+ }
+ float volume;
+ bool mute;
+ };
private:
- friend class AudioFlinger;
- friend class TrackHandle;
-
- Track(const Track&);
- Track& operator = (const Track&);
-
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
- bool isMuted() const {
- return mMute;
- }
-
- bool isPausing() const {
- return mState == PAUSING;
- }
- bool isPaused() const {
- return mState == PAUSED;
- }
- bool isReady() const;
-
- void setPaused() { mState = PAUSED; }
- void reset();
-
- // we don't really need a lock for these
- float mVolume[2];
- volatile bool mMute;
- // FILLED state is used for suppressing volume ramp at begin of playing
- enum {FS_FILLING, FS_FILLED, FS_ACTIVE};
- mutable uint8_t mFillingUpStatus;
- int8_t mRetryCount;
- sp<IMemory> mSharedBuffer;
- bool mResetDone;
- }; // end of Track
+ friend class AudioFlinger;
+ friend class Track;
+ friend class TrackBase;
+ friend class RecordTrack;
+
+ MixerThread(const Client&);
+ MixerThread& operator = (const MixerThread&);
+
+ status_t addTrack_l(const sp<Track>& track);
+ void removeTrack_l(wp<Track> track, int name);
+ void destroyTrack_l(const sp<Track>& track);
+ int getTrackName_l();
+ void deleteTrackName_l(int name);
+ void addActiveTrack_l(const wp<Track>& t);
+ void removeActiveTrack_l(const wp<Track>& t);
+ size_t getOutputFrameCount();
+
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+ status_t dumpTracks(int fd, const Vector<String16>& args);
+
+ sp<AudioFlinger> mAudioFlinger;
+ SortedVector< wp<Track> > mActiveTracks;
+ SortedVector< sp<Track> > mTracks;
+ stream_type_t mStreamTypes[AudioSystem::NUM_STREAM_TYPES];
+ AudioMixer* mAudioMixer;
+ AudioStreamOut* mOutput;
+ int mOutputType;
+ uint32_t mSampleRate;
+ size_t mFrameCount;
+ int mChannelCount;
+ int mFormat;
+ int16_t* mMixBuffer;
+ float mMasterVolume;
+ bool mMasterMute;
+ nsecs_t mLastWriteTime;
+ int mNumWrites;
+ int mNumDelayedWrites;
+ bool mStandby;
+ bool mInWrite;
+ sp <OutputTrack> mOutputTrack;
+ };
+
friend class AudioBuffer;
class TrackHandle : public android::BnAudioTrack {
public:
- TrackHandle(const sp<Track>& track);
+ TrackHandle(const sp<MixerThread::Track>& track);
virtual ~TrackHandle();
virtual status_t start();
virtual void stop();
@@ -357,70 +552,20 @@ private:
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
- sp<Track> mTrack;
- };
-
- struct stream_type_t {
- stream_type_t()
- : volume(1.0f),
- mute(false)
- {
- }
- float volume;
- bool mute;
+ sp<MixerThread::Track> mTrack;
};
friend class Client;
- friend class Track;
+ friend class MixerThread::Track;
void removeClient(pid_t pid);
- status_t addTrack(const sp<Track>& track);
- void removeTrack(wp<Track> track, int name);
- void remove_track_l(wp<Track> track, int name);
- void destroyTrack(const sp<Track>& track);
- void addActiveTrack(const wp<Track>& track);
- void removeActiveTrack(const wp<Track>& track);
- AudioMixer* audioMixer() {
- return mAudioMixer;
- }
-
- // record track
- class RecordTrack : public TrackBase {
- public:
- RecordTrack( const sp<AudioFlinger>& audioFlinger,
- const sp<Client>& client,
- int streamType,
- uint32_t sampleRate,
- int format,
- int channelCount,
- int frameCount);
- ~RecordTrack();
-
- virtual status_t start();
- virtual void stop();
-
- bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
- bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
-
- private:
- friend class AudioFlinger;
- friend class RecordHandle;
- friend class AudioRecordThread;
-
- RecordTrack(const Track&);
- RecordTrack& operator = (const Track&);
-
- virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-
- bool mOverflow;
- };
class RecordHandle : public android::BnAudioRecord {
public:
- RecordHandle(const sp<RecordTrack>& recordTrack);
+ RecordHandle(const sp<MixerThread::RecordTrack>& recordTrack);
virtual ~RecordHandle();
virtual status_t start();
virtual void stop();
@@ -428,72 +573,66 @@ private:
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
- sp<RecordTrack> mRecordTrack;
+ sp<MixerThread::RecordTrack> mRecordTrack;
};
// record thread
class AudioRecordThread : public Thread
{
public:
- AudioRecordThread(AudioHardwareInterface* audioHardware);
+ AudioRecordThread(AudioHardwareInterface* audioHardware, const sp<AudioFlinger>& audioFlinger);
virtual ~AudioRecordThread();
virtual bool threadLoop();
virtual status_t readyToRun() { return NO_ERROR; }
virtual void onFirstRef() {}
- status_t start(RecordTrack* recordTrack);
- void stop(RecordTrack* recordTrack);
+ status_t start(MixerThread::RecordTrack* recordTrack);
+ void stop(MixerThread::RecordTrack* recordTrack);
void exit();
+ status_t dump(int fd, const Vector<String16>& args);
private:
AudioRecordThread();
AudioHardwareInterface *mAudioHardware;
- sp<RecordTrack> mRecordTrack;
+ sp<AudioFlinger> mAudioFlinger;
+ sp<MixerThread::RecordTrack> mRecordTrack;
Mutex mLock;
Condition mWaitWorkCV;
+ Condition mStopped;
volatile bool mActive;
status_t mStartStatus;
};
friend class AudioRecordThread;
+ friend class MixerThread;
+
+ status_t startRecord(MixerThread::RecordTrack* recordTrack);
+ void stopRecord(MixerThread::RecordTrack* recordTrack);
- status_t startRecord(RecordTrack* recordTrack);
- void stopRecord(RecordTrack* recordTrack);
+ mutable Mutex mHardwareLock;
+ mutable Mutex mLock;
+ mutable Condition mWaitWorkCV;
- mutable Mutex mHardwareLock;
- mutable Mutex mLock;
- mutable Condition mWaitWorkCV;
DefaultKeyedVector< pid_t, wp<Client> > mClients;
- SortedVector< wp<Track> > mActiveTracks;
- SortedVector< sp<Track> > mTracks;
- float mMasterVolume;
- uint32_t mMasterRouting;
- bool mMasterMute;
- stream_type_t mStreamTypes[AudioTrack::NUM_STREAM_TYPES];
-
- AudioMixer* mHardwareAudioMixer;
- AudioMixer* mA2dpAudioMixer;
- AudioMixer* mAudioMixer;
+
+ sp<MixerThread> mA2dpMixerThread;
+ sp<MixerThread> mHardwareMixerThread;
AudioHardwareInterface* mAudioHardware;
AudioHardwareInterface* mA2dpAudioInterface;
- AudioStreamOut* mHardwareOutput;
- AudioStreamOut* mA2dpOutput;
- AudioStreamOut* mOutput;
- AudioStreamOut* mRequestedOutput;
sp<AudioRecordThread> mAudioRecordThread;
- uint32_t mSampleRate;
- size_t mFrameCount;
- int mChannelCount;
- int mFormat;
- int16_t* mMixBuffer;
+ bool mA2dpEnabled;
+ bool mNotifyA2dpChange;
mutable int mHardwareStatus;
- nsecs_t mLastWriteTime;
- int mNumWrites;
- int mNumDelayedWrites;
- bool mStandby;
- bool mInWrite;
+ SortedVector< wp<IBinder> > mNotificationClients;
+ int mForcedSpeakerCount;
int mA2dpDisableCount;
+
+ // true if A2DP should resume when mA2dpDisableCount returns to zero
bool mA2dpSuppressed;
+ uint32_t mSavedRoute;
+ uint32_t mForcedRoute;
+ nsecs_t mRouteRestoreTime;
+ bool mMusicMuteSaved;
};
// ----------------------------------------------------------------------------
diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/libs/audioflinger/AudioHardwareGeneric.cpp
index e455186..62beada 100644
--- a/libs/audioflinger/AudioHardwareGeneric.cpp
+++ b/libs/audioflinger/AudioHardwareGeneric.cpp
@@ -93,7 +93,8 @@ void AudioHardwareGeneric::closeOutputStream(AudioStreamOutGeneric* out) {
}
AudioStreamIn* AudioHardwareGeneric::openInputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ int format, int channelCount, uint32_t sampleRate, status_t *status,
+ AudioSystem::audio_in_acoustics acoustics)
{
AutoMutex lock(mLock);
@@ -107,7 +108,7 @@ AudioStreamIn* AudioHardwareGeneric::openInputStream(
// create new output stream
AudioStreamInGeneric* in = new AudioStreamInGeneric();
- status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate);
+ status_t lStatus = in->set(this, mFd, format, channelCount, sampleRate, acoustics);
if (status) {
*status = lStatus;
}
@@ -246,7 +247,8 @@ status_t AudioStreamInGeneric::set(
int fd,
int format,
int channels,
- uint32_t rate)
+ uint32_t rate,
+ AudioSystem::audio_in_acoustics acoustics)
{
// FIXME: remove logging
LOGD("AudioStreamInGeneric::set(%p, %d, %d, %d, %u)", hw, fd, format, channels, rate);
diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/libs/audioflinger/AudioHardwareGeneric.h
index a7822e1..c949aa1 100644
--- a/libs/audioflinger/AudioHardwareGeneric.h
+++ b/libs/audioflinger/AudioHardwareGeneric.h
@@ -47,7 +47,7 @@ public:
virtual size_t bufferSize() const { return 4096; }
virtual int channelCount() const { return 2; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
- virtual uint32_t latency() const { return 0; }
+ virtual uint32_t latency() const { return 20; }
virtual status_t setVolume(float volume) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
virtual status_t standby();
@@ -69,7 +69,8 @@ public:
int mFd,
int format,
int channelCount,
- uint32_t sampleRate);
+ uint32_t sampleRate,
+ AudioSystem::audio_in_acoustics acoustics);
uint32_t sampleRate() const { return 8000; }
virtual size_t bufferSize() const { return 320; }
@@ -114,7 +115,8 @@ public:
int format,
int channelCount,
uint32_t sampleRate,
- status_t *status);
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
void closeOutputStream(AudioStreamOutGeneric* out);
void closeInputStream(AudioStreamInGeneric* in);
diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/libs/audioflinger/AudioHardwareStub.cpp
index e9f3d69..b13cb1c 100644
--- a/libs/audioflinger/AudioHardwareStub.cpp
+++ b/libs/audioflinger/AudioHardwareStub.cpp
@@ -56,10 +56,11 @@ AudioStreamOut* AudioHardwareStub::openOutputStream(
}
AudioStreamIn* AudioHardwareStub::openInputStream(
- int format, int channelCount, uint32_t sampleRate, status_t *status)
+ int format, int channelCount, uint32_t sampleRate,
+ status_t *status, AudioSystem::audio_in_acoustics acoustics)
{
AudioStreamInStub* in = new AudioStreamInStub();
- status_t lStatus = in->set(format, channelCount, sampleRate);
+ status_t lStatus = in->set(format, channelCount, sampleRate, acoustics);
if (status) {
*status = lStatus;
}
@@ -142,7 +143,8 @@ status_t AudioStreamOutStub::dump(int fd, const Vector<String16>& args)
// ----------------------------------------------------------------------------
-status_t AudioStreamInStub::set(int format, int channels, uint32_t rate)
+status_t AudioStreamInStub::set(int format, int channels, uint32_t rate,
+ AudioSystem::audio_in_acoustics acoustics)
{
if ((format == AudioSystem::PCM_16_BIT) &&
(channels == channelCount()) &&
diff --git a/libs/audioflinger/AudioHardwareStub.h b/libs/audioflinger/AudioHardwareStub.h
index 24736ed..d406424 100644
--- a/libs/audioflinger/AudioHardwareStub.h
+++ b/libs/audioflinger/AudioHardwareStub.h
@@ -43,7 +43,7 @@ public:
class AudioStreamInStub : public AudioStreamIn {
public:
- virtual status_t set(int format, int channelCount, uint32_t sampleRate);
+ virtual status_t set(int format, int channelCount, uint32_t sampleRate, AudioSystem::audio_in_acoustics acoustics);
virtual uint32_t sampleRate() const { return 8000; }
virtual size_t bufferSize() const { return 320; }
virtual int channelCount() const { return 1; }
@@ -81,7 +81,8 @@ public:
int format,
int channelCount,
uint32_t sampleRate,
- status_t *status);
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
protected:
virtual status_t doRouting() { return NO_ERROR; }
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index d14cebf..496e271 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -15,8 +15,8 @@ LOCAL_SRC_FILES:= \
LayerBlur.cpp \
LayerBitmap.cpp \
LayerDim.cpp \
- LayerScreenshot.cpp \
- RFBServer.cpp \
+ LayerOrientationAnim.cpp \
+ OrientationAnimation.cpp \
SurfaceFlinger.cpp \
Tokenizer.cpp \
Transform.cpp \
@@ -38,7 +38,8 @@ LOCAL_SHARED_LIBRARIES := \
libcorecg \
libsgl \
libpixelflinger \
- libGLES_CM
+ libEGL \
+ libGLESv1_CM
LOCAL_C_INCLUDES := \
$(call include-path-for, corecg graphics)
diff --git a/libs/surfaceflinger/BootAnimation.cpp b/libs/surfaceflinger/BootAnimation.cpp
index d18f59a..2b30336 100644
--- a/libs/surfaceflinger/BootAnimation.cpp
+++ b/libs/surfaceflinger/BootAnimation.cpp
@@ -39,7 +39,9 @@
#include <core/SkBitmap.h>
#include <images/SkImageDecoder.h>
-#include <GLES/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <EGL/eglext.h>
#include "BootAnimation.h"
@@ -47,32 +49,28 @@ namespace android {
// ---------------------------------------------------------------------------
-BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer)
-: Thread(false)
-{
+BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer) :
+ Thread(false) {
mSession = SurfaceComposerClient::clientForConnection(
composer->createConnection()->asBinder());
}
-BootAnimation::~BootAnimation()
-{
+BootAnimation::~BootAnimation() {
}
-void BootAnimation::onFirstRef()
-{
+void BootAnimation::onFirstRef() {
run("BootAnimation", PRIORITY_DISPLAY);
}
-const sp<SurfaceComposerClient>& BootAnimation::session() const
-{
+const sp<SurfaceComposerClient>& BootAnimation::session() const {
return mSession;
}
-status_t BootAnimation::initTexture(
- Texture* texture, AssetManager& assets, const char* name)
-{
+status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
+ const char* name) {
Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
- if (!asset) return NO_INIT;
+ if (!asset)
+ return NO_INIT;
SkBitmap bitmap;
SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
&bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode);
@@ -84,32 +82,32 @@ status_t BootAnimation::initTexture(
bitmap.lockPixels();
const int w = bitmap.width();
- const int h = bitmap.height();
+ const int h = bitmap.height();
const void* p = bitmap.getPixels();
-
+
GLint crop[4] = { 0, h, w, -h };
texture->w = w;
texture->h = h;
glGenTextures(1, &texture->name);
glBindTexture(GL_TEXTURE_2D, texture->name);
-
- switch(bitmap.getConfig()) {
+
+ switch (bitmap.getConfig()) {
case SkBitmap::kA8_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0,
- GL_ALPHA, GL_UNSIGNED_BYTE, p);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
+ GL_UNSIGNED_BYTE, p);
break;
case SkBitmap::kARGB_4444_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0,
- GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, p);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
+ GL_UNSIGNED_SHORT_4_4_4_4, p);
break;
case SkBitmap::kARGB_8888_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, p);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, p);
break;
case SkBitmap::kRGB_565_Config:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
+ GL_UNSIGNED_SHORT_5_6_5, p);
break;
default:
break;
@@ -123,8 +121,7 @@ status_t BootAnimation::initTexture(
return NO_ERROR;
}
-status_t BootAnimation::readyToRun()
-{
+status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
DisplayInfo dinfo;
@@ -133,32 +130,27 @@ status_t BootAnimation::readyToRun()
return -1;
// create the native surface
- sp<Surface> s = session()->createSurface(getpid(), 0,
- dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
+ sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h,
+ PIXEL_FORMAT_RGB_565);
session()->openTransaction();
s->setLayer(0x40000000);
session()->closeTransaction();
// initialize opengl and egl
- const EGLint attribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_DEPTH_SIZE, 0,
- EGL_NONE
- };
+ const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE };
EGLint w, h, dummy;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(display, NULL, NULL);
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
- surface = eglCreateWindowSurface(
- display, config, new EGLNativeWindowSurface(s), NULL);
-
+ mNativeWindowSurface = new EGLNativeWindowSurface(s);
+ surface = eglCreateWindowSurface(display, config,
+ mNativeWindowSurface.get(), NULL);
+
context = eglCreateContext(display, config, NULL, NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
@@ -167,7 +159,7 @@ status_t BootAnimation::readyToRun()
mContext = context;
mSurface = surface;
mWidth = w;
- mHeight= h;
+ mHeight = h;
mFlingerSurface = s;
// initialize GL
@@ -180,25 +172,21 @@ status_t BootAnimation::readyToRun()
return NO_ERROR;
}
-void BootAnimation::requestExit()
-{
+void BootAnimation::requestExit() {
mBarrier.open();
Thread::requestExit();
}
-bool BootAnimation::threadLoop()
-{
+bool BootAnimation::threadLoop() {
bool r = android();
- eglMakeCurrent(mDisplay, 0, 0, 0);
- eglDestroyContext(mDisplay, mContext);
+ eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroyContext(mDisplay, mContext);
eglDestroySurface(mDisplay, mSurface);
- eglTerminate(mDisplay);
+ mNativeWindowSurface.clear();
return r;
}
-
-bool BootAnimation::android()
-{
+bool BootAnimation::android() {
initTexture(&mAndroid[0], mAssets, "images/android_320x480.png");
initTexture(&mAndroid[1], mAssets, "images/boot_robot.png");
initTexture(&mAndroid[2], mAssets, "images/boot_robot_glow.png");
@@ -219,9 +207,9 @@ bool BootAnimation::android()
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
const int steps = 8;
- for (int i=1 ; i<steps ; i++) {
+ for (int i = 1; i < steps; i++) {
float fade = i / float(steps);
- glColor4f(1, 1, 1, fade*fade);
+ glColor4f(1, 1, 1, fade * fade);
glClear(GL_COLOR_BUFFER_BIT);
glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
eglSwapBuffers(mDisplay, mSurface);
@@ -232,79 +220,73 @@ bool BootAnimation::android()
glDisable(GL_BLEND);
glDrawTexiOES(0, 0, 0, mAndroid[0].w, mAndroid[0].h);
eglSwapBuffers(mDisplay, mSurface);
-
-
+
// update rect for the robot
const int x = mWidth - mAndroid[1].w - 33;
- const int y = (mHeight - mAndroid[1].h)/2 - 1;
- const Rect updateRect(x, y, x+mAndroid[1].w, y+mAndroid[1].h);
+ const int y = (mHeight - mAndroid[1].h) / 2 - 1;
+ const Rect updateRect(x, y, x + mAndroid[1].w, y + mAndroid[1].h);
// draw and update only what we need
- eglSwapRectangleANDROID(mDisplay, mSurface,
- updateRect.left, updateRect.top,
- updateRect.width(), updateRect.height());
+ mNativeWindowSurface->setSwapRectangle(updateRect.left,
+ updateRect.top, updateRect.width(), updateRect.height());
glEnable(GL_SCISSOR_TEST);
- glScissor(updateRect.left, mHeight-updateRect.bottom,
- updateRect.width(), updateRect.height());
+ glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
+ updateRect.height());
const nsecs_t startTime = systemTime();
- do
- {
+ do {
// glow speed and shape
nsecs_t time = systemTime() - startTime;
- float t = ((4.0f/(360.0f*us2ns(16667))) * time);
+ float t = ((4.0f / (360.0f * us2ns(16667))) * time);
t = t - floorf(t);
- const float fade = 0.5f + 0.5f*sinf(t * 2*M_PI);
+ const float fade = 0.5f + 0.5f * sinf(t * 2 * M_PI);
// fade the glow in and out
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[2].name);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColor4f(fade, fade, fade, fade);
- glDrawTexiOES(updateRect.left, mHeight-updateRect.bottom, 0,
+ glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0,
updateRect.width(), updateRect.height());
// draw the robot
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glDrawTexiOES(updateRect.left, mHeight-updateRect.bottom, 0,
+ glDrawTexiOES(updateRect.left, mHeight - updateRect.bottom, 0,
updateRect.width(), updateRect.height());
// make sure sleep a lot to not take too much CPU away from
// the boot process. With this "glow" animation there is no
// visible difference.
- usleep(16667*4);
+ usleep(16667 * 4);
eglSwapBuffers(mDisplay, mSurface);
} while (!exitPending());
-
-
+
glDeleteTextures(1, &mAndroid[0].name);
glDeleteTextures(1, &mAndroid[1].name);
glDeleteTextures(1, &mAndroid[2].name);
return false;
}
-
-bool BootAnimation::cylon()
-{
+bool BootAnimation::cylon() {
// initialize the textures...
- initTexture(&mLeftTrail, mAssets, "images/cylon_left.png");
+ initTexture(&mLeftTrail, mAssets, "images/cylon_left.png");
initTexture(&mRightTrail, mAssets, "images/cylon_right.png");
initTexture(&mBrightSpot, mAssets, "images/cylon_dot.png");
int w = mWidth;
int h = mHeight;
- const Point c(w/2 , h/2);
+ const Point c(w / 2, h / 2);
const GLint amplitude = 60;
- const int scx = c.x - amplitude - mBrightSpot.w/2;
- const int scy = c.y - mBrightSpot.h/2;
- const int scw = amplitude*2 + mBrightSpot.w;
+ const int scx = c.x - amplitude - mBrightSpot.w / 2;
+ const int scy = c.y - mBrightSpot.h / 2;
+ const int scw = amplitude * 2 + mBrightSpot.w;
const int sch = mBrightSpot.h;
- const Rect updateRect(scx, h-scy-sch, scx+scw, h-scy);
+ const Rect updateRect(scx, h - scy - sch, scx + scw, h - scy);
// erase screen
glDisable(GL_SCISSOR_TEST);
@@ -314,33 +296,29 @@ bool BootAnimation::cylon()
glClear(GL_COLOR_BUFFER_BIT);
- eglSwapRectangleANDROID(mDisplay, mSurface,
- updateRect.left, updateRect.top,
- updateRect.width(), updateRect.height());
+ mNativeWindowSurface->setSwapRectangle(updateRect.left,
+ updateRect.top, updateRect.width(), updateRect.height());
glEnable(GL_SCISSOR_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
// clear the screen to white
Point p;
float t = 0;
float alpha = 1.0f;
const nsecs_t startTime = systemTime();
nsecs_t fadeTime = 0;
-
- do
- {
+
+ do {
// Set scissor in interesting area
- glScissor(scx, scy, scw, sch);
+ glScissor(scx, scy, scw, sch);
// erase screen
glClear(GL_COLOR_BUFFER_BIT);
-
// compute wave
- const float a = (t * 2*M_PI) - M_PI/2;
+ const float a = (t * 2 * M_PI) - M_PI / 2;
const float sn = sinf(a);
const float cs = cosf(a);
GLint x = GLint(amplitude * sn);
@@ -350,50 +328,50 @@ bool BootAnimation::cylon()
if (derivative > 0) {
// vanishing trail...
- p.x = (-amplitude + c.x) - mBrightSpot.w/2;
- p.y = c.y-mLeftTrail.h/2;
- float fade = 2.0f*(0.5f-t);
+ p.x = (-amplitude + c.x) - mBrightSpot.w / 2;
+ p.y = c.y - mLeftTrail.h / 2;
+ float fade = 2.0f * (0.5f - t);
//fade *= fade;
glColor4f(fade, fade, fade, fade);
glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
// trail...
- p.x = (x + c.x) - (mRightTrail.w + mBrightSpot.w/2) + 16;
- p.y = c.y-mRightTrail.h/2;
- fade = t<0.25f ? t*4.0f : 1.0f;
+ p.x = (x + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16;
+ p.y = c.y - mRightTrail.h / 2;
+ fade = t < 0.25f ? t * 4.0f : 1.0f;
fade *= fade;
glColor4f(fade, fade, fade, fade);
glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
- } else {
+ } else {
// vanishing trail..
- p.x = (amplitude + c.x) - (mRightTrail.w + mBrightSpot.w/2) + 16;
- p.y = c.y-mRightTrail.h/2;
- float fade = 2.0f*(0.5f-(t-0.5f));
+ p.x = (amplitude + c.x) - (mRightTrail.w + mBrightSpot.w / 2) + 16;
+ p.y = c.y - mRightTrail.h / 2;
+ float fade = 2.0f * (0.5f - (t - 0.5f));
//fade *= fade;
glColor4f(fade, fade, fade, fade);
glBindTexture(GL_TEXTURE_2D, mRightTrail.name);
glDrawTexiOES(p.x, p.y, 0, mRightTrail.w, mRightTrail.h);
// trail...
- p.x = (x + c.x) - mBrightSpot.w/2;
- p.y = c.y-mLeftTrail.h/2;
- fade = t<0.5f+0.25f ? (t-0.5f)*4.0f : 1.0f;
+ p.x = (x + c.x) - mBrightSpot.w / 2;
+ p.y = c.y - mLeftTrail.h / 2;
+ fade = t < 0.5f + 0.25f ? (t - 0.5f) * 4.0f : 1.0f;
fade *= fade;
glColor4f(fade, fade, fade, fade);
glBindTexture(GL_TEXTURE_2D, mLeftTrail.name);
glDrawTexiOES(p.x, p.y, 0, mLeftTrail.w, mLeftTrail.h);
}
- const Point p( x + c.x-mBrightSpot.w/2, c.y-mBrightSpot.h/2 );
+ const Point p(x + c.x - mBrightSpot.w / 2, c.y - mBrightSpot.h / 2);
glBindTexture(GL_TEXTURE_2D, mBrightSpot.name);
- glColor4f(1,0.5,0.5,1);
+ glColor4f(1, 0.5, 0.5, 1);
glDrawTexiOES(p.x, p.y, 0, mBrightSpot.w, mBrightSpot.h);
// update animation
nsecs_t time = systemTime() - startTime;
- t = ((4.0f/(360.0f*us2ns(16667))) * time);
+ t = ((4.0f / (360.0f * us2ns(16667))) * time);
t = t - floorf(t);
eglSwapBuffers(mDisplay, mSurface);
@@ -406,7 +384,7 @@ bool BootAnimation::cylon()
alpha = 1.0f - ((float(time) * 6.0f) / float(s2ns(1)));
session()->openTransaction();
- mFlingerSurface->setAlpha(alpha*alpha);
+ mFlingerSurface->setAlpha(alpha * alpha);
session()->closeTransaction();
}
} while (alpha > 0);
@@ -421,4 +399,5 @@ bool BootAnimation::cylon()
// ---------------------------------------------------------------------------
-}; // namespace android
+}
+; // namespace android
diff --git a/libs/surfaceflinger/BootAnimation.h b/libs/surfaceflinger/BootAnimation.h
index a4a6d49..b20cea0 100644
--- a/libs/surfaceflinger/BootAnimation.h
+++ b/libs/surfaceflinger/BootAnimation.h
@@ -26,7 +26,8 @@
#include <ui/ISurfaceComposer.h>
#include <ui/SurfaceComposerClient.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
#include "Barrier.h"
@@ -35,6 +36,7 @@ class SkBitmap;
namespace android {
class AssetManager;
+class EGLNativeWindowSurface;
// ---------------------------------------------------------------------------
@@ -74,6 +76,7 @@ private:
EGLDisplay mContext;
EGLDisplay mSurface;
sp<Surface> mFlingerSurface;
+ sp<EGLNativeWindowSurface> mNativeWindowSurface;
Barrier mBarrier;
};
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 92588fa..f14d7e9 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -21,14 +21,16 @@
#include <string.h>
#include <math.h>
-#include <GLES/egl.h>
-
#include <cutils/properties.h>
#include <utils/Log.h>
#include <ui/EGLDisplaySurface.h>
+#include <GLES/gl.h>
+#include <EGL/eglext.h>
+
+
#include "DisplayHardware/DisplayHardware.h"
#include <hardware/copybit.h>
@@ -136,26 +138,19 @@ void DisplayHardware::init(uint32_t dpy)
const char* const egl_extensions = eglQueryString(
display, EGL_EXTENSIONS);
- const char* egl_extensions_config = egl_extensions;
-
- if (strstr(egl_extensions, "EGL_ANDROID_query_string_config")) {
- egl_extensions_config = eglQueryStringConfigANDROID(
- display, config, EGL_EXTENSIONS);
- }
-
LOGI("EGL informations:");
LOGI("# of configs : %d", numConfigs);
LOGI("vendor : %s", eglQueryString(display, EGL_VENDOR));
LOGI("version : %s", eglQueryString(display, EGL_VERSION));
LOGI("extensions: %s", egl_extensions);
- LOGI("ext/config: %s", egl_extensions_config);
LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
- if (strstr(egl_extensions_config, "EGL_ANDROID_swap_rectangle")) {
- mFlags |= SWAP_RECTANGLE_EXTENSION;
- // TODO: get the real "update_on_demand" behavior
- mFlags |= UPDATE_ON_DEMAND;
- }
+ // TODO: get this from the devfb driver (probably should be HAL module)
+ mFlags |= SWAP_RECTANGLE_EXTENSION;
+
+ // TODO: get the real "update_on_demand" behavior (probably should be HAL module)
+ mFlags |= UPDATE_ON_DEMAND;
+
if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
if (dummy == EGL_SLOW_CONFIG)
mFlags |= SLOW_CONFIG;
@@ -173,9 +168,6 @@ void DisplayHardware::init(uint32_t dpy)
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
if (dummy == EGL_BUFFER_PRESERVED) {
mFlags |= BUFFER_PRESERVED;
- if (strstr(egl_extensions_config, "EGL_ANDROID_copy_front_to_back")) {
- mFlags |= COPY_BACK_EXTENSION;
- }
}
}
@@ -330,8 +322,7 @@ void DisplayHardware::flip(const Region& dirty) const
if (mFlags & SWAP_RECTANGLE_EXTENSION) {
const Rect& b(newDirty.bounds());
- eglSwapRectangleANDROID(
- dpy, surface,
+ mDisplaySurface->setSwapRectangle(
b.left, b.top, b.width(), b.height());
}
@@ -352,3 +343,11 @@ void DisplayHardware::makeCurrent() const
{
eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
}
+
+void DisplayHardware::copyFrontToImage(const copybit_image_t& front) const {
+ mDisplaySurface->copyFrontToImage(front);
+}
+
+void DisplayHardware::copyBackToImage(const copybit_image_t& front) const {
+ mDisplaySurface->copyBackToImage(front);
+}
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index df97b60..550a4d1 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -22,7 +22,7 @@
#include <ui/PixelFormat.h>
#include <ui/Region.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
#include "DisplayHardware/DisplayHardwareBase.h"
@@ -39,7 +39,6 @@ class DisplayHardware : public DisplayHardwareBase
{
public:
enum {
- COPY_BACK_EXTENSION = 0x00000001,
DIRECT_TEXTURE = 0x00000002,
SWAP_RECTANGLE_EXTENSION= 0x00000004,
COPY_BITS_EXTENSION = 0x00000008,
@@ -80,6 +79,9 @@ public:
copybit_device_t* getBlitEngine() const { return mBlitEngine; }
overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
+ void copyFrontToImage(const copybit_image_t& front) const;
+ void copyBackToImage(const copybit_image_t& front) const;
+
Rect bounds() const {
return Rect(mWidth, mHeight);
}
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index bdefba3..0cf53f7 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -23,6 +23,11 @@
#include <utils/Errors.h>
#include <utils/Log.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <hardware/hardware.h>
+
#include "clz.h"
#include "LayerBase.h"
#include "LayerBlur.h"
@@ -111,6 +116,12 @@ void LayerBase::commitTransaction(bool skipSize) {
mDrawingState.h = h;
}
}
+void LayerBase::forceVisibilityTransaction() {
+ // this can be called without SurfaceFlinger.mStateLock, but if we
+ // can atomically increment the sequence number, it doesn't matter.
+ android_atomic_inc(&mCurrentState.sequence);
+ requestTransaction();
+}
bool LayerBase::requestTransaction() {
int32_t old = setTransactionFlags(eTransactionNeeded);
return ((old & eTransactionNeeded) == 0);
@@ -350,6 +361,10 @@ void LayerBase::draw(const Region& inClip) const
return;
}
}
+
+ // reset GL state
+ glEnable(GL_SCISSOR_TEST);
+
onDraw(clip);
/*
@@ -391,6 +406,7 @@ void LayerBase::clearWithOpenGL(const Region& clip) const
Rect r;
Region::iterator iterator(clip);
if (iterator) {
+ glEnable(GL_SCISSOR_TEST);
glVertexPointer(2, GL_FIXED, 0, mVertices);
while (iterator.iterate(&r)) {
const GLint sy = fbHeight - (r.top + r.height());
@@ -401,7 +417,7 @@ void LayerBase::clearWithOpenGL(const Region& clip) const
}
void LayerBase::drawWithOpenGL(const Region& clip,
- GLint textureName, const GGLSurface& t) const
+ GLint textureName, const GGLSurface& t, int transform) const
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t fbHeight = hw.getHeight();
@@ -473,6 +489,12 @@ void LayerBase::drawWithOpenGL(const Region& clip,
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
+
+ if (transform == HAL_TRANSFORM_ROT_90) {
+ glTranslatef(0, 1, 0);
+ glRotatef(-90, 0, 0, 1);
+ }
+
if (!(mFlags & DisplayHardware::NPOT_EXTENSION)) {
// find the smallest power-of-two that will accommodate our surface
GLuint tw = 1 << (31 - clz(t.width));
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 5e14dc85..a020f44 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -86,8 +86,8 @@ public:
uint32_t z;
uint8_t alpha;
uint8_t flags;
- uint8_t sequence; // changes when visible regions can change
- uint8_t reserved;
+ uint8_t reserved[2];
+ int32_t sequence; // changes when visible regions can change
uint32_t tint;
Transform transform;
Region transparentRegion;
@@ -104,11 +104,11 @@ public:
void commitTransaction(bool skipSize);
bool requestTransaction();
-
+ void forceVisibilityTransaction();
+
uint32_t getTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags);
- void validateVisibility(const Transform& globalTransform);
Rect visibleBounds() const;
void drawRegion(const Region& reg) const;
@@ -162,7 +162,12 @@ public:
* the bitmap (as opposed to the size of the drawing state).
*/
virtual Point getPhysicalSize() const;
-
+
+ /**
+ * validateVisibility - cache a bunch of things
+ */
+ virtual void validateVisibility(const Transform& globalTransform);
+
/**
* lockPageFlip - called each time the screen is redrawn and returns whether
* the visible regions need to be recomputed (this is a fairly heavy
@@ -188,10 +193,15 @@ public:
* needsBlending - true if this surface needs blending
*/
virtual bool needsBlending() const { return false; }
-
+
+ /**
+ * transformed -- true is this surface needs a to be transformed
+ */
+ virtual bool transformed() const { return mTransformed; }
+
/**
- * isSecure - true if this surface is secure, that is if it prevents a
- * screenshot to be taken,
+ * isSecure - true if this surface is secure, that is if it prevents
+ * screenshots or vns servers.
*/
virtual bool isSecure() const { return false; }
@@ -210,7 +220,6 @@ public:
}
int32_t getOrientation() const { return mOrientation; }
- bool transformed() const { return mTransformed; }
int tx() const { return mLeft; }
int ty() const { return mTop; }
@@ -221,7 +230,9 @@ protected:
GLuint createTexture() const;
void drawWithOpenGL(const Region& clip,
- GLint textureName, const GGLSurface& surface) const;
+ GLint textureName,
+ const GGLSurface& surface,
+ int transform = 0) const;
void clearWithOpenGL(const Region& clip) const;
@@ -320,8 +331,7 @@ public:
*params = mParams;
}
- virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& heap)
+ virtual status_t registerBuffers(const ISurface::BufferHeap& buffers)
{ return INVALID_OPERATION; }
virtual void postBuffer(ssize_t offset) { }
virtual void unregisterBuffers() { };
diff --git a/libs/surfaceflinger/LayerBitmap.cpp b/libs/surfaceflinger/LayerBitmap.cpp
index 7c98857..e844350 100644
--- a/libs/surfaceflinger/LayerBitmap.cpp
+++ b/libs/surfaceflinger/LayerBitmap.cpp
@@ -69,18 +69,15 @@ status_t LayerBitmap::setBits(uint32_t w, uint32_t h, uint32_t alignment,
return NO_ERROR;
}
+ PixelFormatInfo info;
+ getPixelFormatInfo(format, &info);
+
uint32_t allocFlags = MemoryDealer::PAGE_ALIGNED;
const uint32_t align = 4; // must match GL_UNPACK_ALIGNMENT
- const uint32_t Bpp = bytesPerPixel(format);
+ const uint32_t Bpp = info.bytesPerPixel;
uint32_t stride = (w + (alignment-1)) & ~(alignment-1);
stride = ((stride * Bpp + (align-1)) & ~(align-1)) / Bpp;
- size_t size = stride * h * Bpp;
- if (format == PIXEL_FORMAT_YCbCr_422_SP ||
- format == PIXEL_FORMAT_YCbCr_420_SP) {
- // in YUV planar, bitsPerPixel is for the Y plane
- size = (size * bitsPerPixel(format)) / 8;
- }
-
+ size_t size = info.getScanlineSize(stride) * h;
if (allocFlags & MemoryDealer::PAGE_ALIGNED) {
size_t pagesize = getpagesize();
size = (size + (pagesize-1)) & ~(pagesize-1);
diff --git a/libs/surfaceflinger/LayerBitmap.h b/libs/surfaceflinger/LayerBitmap.h
index 4c2eb50..9ad64c4 100644
--- a/libs/surfaceflinger/LayerBitmap.h
+++ b/libs/surfaceflinger/LayerBitmap.h
@@ -70,9 +70,6 @@ public:
void getBitmapSurface(copybit_image_t* img) const;
private:
- LayerBitmap(const LayerBitmap& rhs);
- LayerBitmap& operator = (const LayerBitmap& rhs);
-
sp<MemoryDealer> mAllocator;
sp<IMemory> mBitsMemory;
uint32_t mAllocFlags;
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index efadbcf..d3e456f 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -23,6 +23,9 @@
#include <utils/Errors.h>
#include <utils/Log.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
#include "BlurFilter.h"
#include "LayerBlur.h"
#include "SurfaceFlinger.h"
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index c9cebf4..00fab70 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -25,6 +25,9 @@
#include <utils/Log.h>
#include <utils/StopWatch.h>
+#include <utils/IPCThreadState.h>
+#include <utils/IServiceManager.h>
+
#include <ui/PixelFormat.h>
#include <ui/EGLDisplaySurface.h>
@@ -129,18 +132,24 @@ void LayerBuffer::onDraw(const Region& clip) const
}
}
+bool LayerBuffer::transformed() const
+{
+ sp<Source> source(getSource());
+ if (LIKELY(source != 0))
+ return source->transformed();
+ return false;
+}
+
/**
* This creates a "buffer" source for this surface
*/
-status_t LayerBuffer::registerBuffers(int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& memoryHeap)
+status_t LayerBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
{
Mutex::Autolock _l(mLock);
if (mSource != 0)
return INVALID_OPERATION;
- sp<BufferSource> source = new BufferSource(*this, w, h,
- hstride, vstride, format, memoryHeap);
+ sp<BufferSource> source = new BufferSource(*this, buffers);
status_t result = source->getStatus();
if (result == NO_ERROR) {
@@ -194,13 +203,39 @@ LayerBuffer::SurfaceBuffer::~SurfaceBuffer()
mOwner = 0;
}
-status_t LayerBuffer::SurfaceBuffer::registerBuffers(
- int w, int h, int hs, int vs,
- PixelFormat format, const sp<IMemoryHeap>& heap)
+status_t LayerBuffer::SurfaceBuffer::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case REGISTER_BUFFERS:
+ case UNREGISTER_BUFFERS:
+ case CREATE_OVERLAY:
+ {
+ // codes that require permission check
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int self_pid = getpid();
+ if (LIKELY(pid != self_pid)) {
+ // we're called from a different process, do the real check
+ if (!checkCallingPermission(
+ String16("android.permission.ACCESS_SURFACE_FLINGER")))
+ {
+ const int uid = ipc->getCallingUid();
+ LOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+ }
+ }
+ return LayerBaseClient::Surface::onTransact(code, data, reply, flags);
+}
+
+status_t LayerBuffer::SurfaceBuffer::registerBuffers(const ISurface::BufferHeap& buffers)
{
LayerBuffer* owner(getOwner());
if (owner)
- return owner->registerBuffers(w, h, hs, vs, format, heap);
+ return owner->registerBuffers(buffers);
return NO_INIT;
}
@@ -237,23 +272,20 @@ void LayerBuffer::SurfaceBuffer::disown()
// LayerBuffer::Buffer
// ============================================================================
-LayerBuffer::Buffer::Buffer(const sp<IMemoryHeap>& heap, ssize_t offset,
- int w, int h, int hs, int vs, int f)
-: mHeap(heap)
+LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset)
+ : mBufferHeap(buffers)
{
NativeBuffer& src(mNativeBuffer);
src.crop.l = 0;
src.crop.t = 0;
- src.crop.r = w;
- src.crop.b = h;
- src.img.w = hs ?: w;
- src.img.h = vs ?: h;
- src.img.format = f;
+ src.crop.r = buffers.w;
+ src.crop.b = buffers.h;
+ src.img.w = buffers.hor_stride ?: buffers.w;
+ src.img.h = buffers.ver_stride ?: buffers.h;
+ src.img.format = buffers.format;
src.img.offset = offset;
- src.img.base = heap->base();
- src.img.fd = heap->heapID();
- // FIXME: make sure this buffer lies within the heap, in which case, set
- // mHeap to null
+ src.img.base = buffers.heap->base();
+ src.img.fd = buffers.heap->heapID();
}
LayerBuffer::Buffer::~Buffer()
@@ -283,41 +315,55 @@ void LayerBuffer::Source::postBuffer(ssize_t offset) {
}
void LayerBuffer::Source::unregisterBuffers() {
}
+bool LayerBuffer::Source::transformed() const {
+ return mLayer.mTransformed;
+}
// ---------------------------------------------------------------------------
LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer,
- int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& memoryHeap)
- : Source(layer), mStatus(NO_ERROR), mTextureName(-1U)
+ const ISurface::BufferHeap& buffers)
+ : Source(layer), mStatus(NO_ERROR),
+ mBufferSize(0), mTextureName(-1U)
{
- if (memoryHeap == NULL) {
+ if (buffers.heap == NULL) {
// this is allowed, but in this case, it is illegal to receive
// postBuffer(). The surface just erases the framebuffer with
// fully transparent pixels.
- mHeap.clear();
- mWidth = w;
- mHeight = h;
+ mBufferHeap = buffers;
mLayer.setNeedsBlending(false);
return;
}
- status_t err = (memoryHeap->heapID() >= 0) ? NO_ERROR : NO_INIT;
+ status_t err = (buffers.heap->heapID() >= 0) ? NO_ERROR : NO_INIT;
if (err != NO_ERROR) {
+ LOGE("LayerBuffer::BufferSource: invalid heap (%s)", strerror(err));
mStatus = err;
return;
}
-
- // TODO: validate format/parameters
- mHeap = memoryHeap;
- mWidth = w;
- mHeight = h;
- mHStride = hstride;
- mVStride = vstride;
- mFormat = format;
+
PixelFormatInfo info;
- getPixelFormatInfo(format, &info);
- mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
+ err = getPixelFormatInfo(buffers.format, &info);
+ if (err != NO_ERROR) {
+ LOGE("LayerBuffer::BufferSource: invalid format %d (%s)",
+ buffers.format, strerror(err));
+ mStatus = err;
+ return;
+ }
+
+ if (buffers.hor_stride<0 || buffers.ver_stride<0) {
+ LOGE("LayerBuffer::BufferSource: invalid parameters "
+ "(w=%d, h=%d, xs=%d, ys=%d)",
+ buffers.w, buffers.h, buffers.hor_stride, buffers.ver_stride);
+ mStatus = BAD_VALUE;
+ return;
+ }
+
+ mBufferHeap = buffers;
+ mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);
+ mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
+ mLayer.forceVisibilityTransaction();
+
}
LayerBuffer::BufferSource::~BufferSource()
@@ -329,21 +375,24 @@ LayerBuffer::BufferSource::~BufferSource()
void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
{
- sp<IMemoryHeap> heap;
- int w, h, hs, vs, f;
+ ISurface::BufferHeap buffers;
{ // scope for the lock
Mutex::Autolock _l(mLock);
- w = mWidth;
- h = mHeight;
- hs= mHStride;
- vs= mVStride;
- f = mFormat;
- heap = mHeap;
+ buffers = mBufferHeap;
+ if (buffers.heap != 0) {
+ const size_t memorySize = buffers.heap->getSize();
+ if ((size_t(offset) + mBufferSize) > memorySize) {
+ LOGE("LayerBuffer::BufferSource::postBuffer() "
+ "invalid buffer (offset=%d, size=%d, heap-size=%d",
+ int(offset), int(mBufferSize), int(memorySize));
+ return;
+ }
+ }
}
sp<Buffer> buffer;
- if (heap != 0) {
- buffer = new LayerBuffer::Buffer(heap, offset, w, h, hs, vs, f);
+ if (buffers.heap != 0) {
+ buffer = new LayerBuffer::Buffer(buffers, offset);
if (buffer->getStatus() != NO_ERROR)
buffer.clear();
setBuffer(buffer);
@@ -354,7 +403,7 @@ void LayerBuffer::BufferSource::postBuffer(ssize_t offset)
void LayerBuffer::BufferSource::unregisterBuffers()
{
Mutex::Autolock _l(mLock);
- mHeap.clear();
+ mBufferHeap.heap.clear();
mBuffer.clear();
mLayer.invalidate();
}
@@ -371,6 +420,11 @@ void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
mBuffer = buffer;
}
+bool LayerBuffer::BufferSource::transformed() const
+{
+ return mBufferHeap.transform ? true : Source::transformed();
+}
+
void LayerBuffer::BufferSource::onDraw(const Region& clip) const
{
sp<Buffer> buffer(getBuffer());
@@ -417,7 +471,7 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
if (UNLIKELY(mTemporaryDealer == 0)) {
// allocate a memory-dealer for this the first time
mTemporaryDealer = mLayer.mFlinger->getSurfaceHeapManager()
- ->createHeap(ISurfaceComposer::eHardware);
+ ->createHeap(ISurfaceComposer::eHardware);
mTempBitmap.init(mTemporaryDealer);
}
@@ -447,16 +501,31 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
copybit_image_t dst;
hw.getDisplaySurface(&dst);
const copybit_rect_t& drect
- = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
+ = reinterpret_cast<const copybit_rect_t&>(transformedBounds);
const State& s(mLayer.drawingState());
region_iterator it(clip);
- copybit->set_parameter(copybit, COPYBIT_TRANSFORM, mLayer.getOrientation());
+
+ // pick the right orientation for this buffer
+ int orientation = mLayer.getOrientation();
+ if (UNLIKELY(mBufferHeap.transform)) {
+ Transform rot90;
+ GraphicPlane::orientationToTransfrom(
+ ISurfaceComposer::eOrientation90, 0, 0, &rot90);
+ const Transform& planeTransform(mLayer.graphicPlane(0).transform());
+ const Layer::State& s(mLayer.drawingState());
+ Transform tr(planeTransform * s.transform * rot90);
+ orientation = tr.getOrientation();
+ }
+
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
- copybit->set_parameter(copybit, COPYBIT_DITHER,
- s.flags & ISurfaceComposer::eLayerDither ?
- COPYBIT_ENABLE : COPYBIT_DISABLE);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
err = copybit->stretch(copybit,
&dst, &src.img, &drect, &src.crop, &it);
+ if (err != NO_ERROR) {
+ LOGE("copybit failed (%s)", strerror(err));
+ }
}
if (!can_use_copybit || err) {
@@ -475,10 +544,11 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
t.data = (GGLubyte*)(intptr_t(src.img.base) + src.img.offset);
const Region dirty(Rect(t.width, t.height));
mLayer.loadTexture(dirty, mTextureName, t, w, h);
- mLayer.drawWithOpenGL(clip, mTextureName, t);
+ mLayer.drawWithOpenGL(clip, mTextureName, t, mBufferHeap.transform);
}
}
+
// ---------------------------------------------------------------------------
LayerBuffer::OverlaySource::OverlaySource(LayerBuffer& layer,
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 6e3d49f..2dc77f1 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -22,7 +22,7 @@
#include <utils/IMemory.h>
#include <private/ui/LayerState.h>
-#include <GLES/eglnatives.h>
+#include <EGL/eglnatives.h>
#include "LayerBase.h"
#include "LayerBitmap.h"
@@ -46,6 +46,7 @@ class LayerBuffer : public LayerBaseClient
virtual void onVisibilityResolved(const Transform& planeTransform);
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
+ virtual bool transformed() const;
protected:
LayerBuffer& mLayer;
};
@@ -67,9 +68,9 @@ public:
virtual void onDraw(const Region& clip) const;
virtual uint32_t doTransaction(uint32_t flags);
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
+ virtual bool transformed() const;
- status_t registerBuffers(int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& heap);
+ status_t registerBuffers(const ISurface::BufferHeap& buffers);
void postBuffer(ssize_t offset);
void unregisterBuffers();
sp<OverlayRef> createOverlay(uint32_t w, uint32_t h, int32_t format);
@@ -89,10 +90,9 @@ private:
class Buffer : public LightRefBase<Buffer> {
public:
- Buffer(const sp<IMemoryHeap>& heap, ssize_t offset,
- int w, int h, int hs, int vs, int f);
+ Buffer(const ISurface::BufferHeap& buffers, ssize_t offset);
inline status_t getStatus() const {
- return mHeap!=0 ? NO_ERROR : NO_INIT;
+ return mBufferHeap.heap!=0 ? NO_ERROR : NO_INIT;
}
inline const NativeBuffer& getBuffer() const {
return mNativeBuffer;
@@ -103,15 +103,13 @@ private:
Buffer(const Buffer& rhs);
~Buffer();
private:
- sp<IMemoryHeap> mHeap;
- NativeBuffer mNativeBuffer;
+ ISurface::BufferHeap mBufferHeap;
+ NativeBuffer mNativeBuffer;
};
class BufferSource : public Source {
public:
- BufferSource(LayerBuffer& layer,
- int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& heap);
+ BufferSource(LayerBuffer& layer, const ISurface::BufferHeap& buffers);
virtual ~BufferSource();
status_t getStatus() const { return mStatus; }
@@ -121,16 +119,13 @@ private:
virtual void onDraw(const Region& clip) const;
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
+ virtual bool transformed() const;
private:
mutable Mutex mLock;
- sp<IMemoryHeap> mHeap;
sp<Buffer> mBuffer;
status_t mStatus;
- int mWidth;
- int mHeight;
- int mHStride;
- int mVStride;
- int mFormat;
+ ISurface::BufferHeap mBufferHeap;
+ size_t mBufferSize;
mutable sp<MemoryDealer> mTemporaryDealer;
mutable LayerBitmap mTempBitmap;
mutable GLuint mTextureName;
@@ -186,8 +181,9 @@ private:
public:
SurfaceBuffer(SurfaceID id, LayerBuffer* owner);
virtual ~SurfaceBuffer();
- virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& heap);
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+ virtual status_t registerBuffers(const ISurface::BufferHeap& buffers);
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
virtual sp<OverlayRef> createOverlay(
diff --git a/libs/surfaceflinger/LayerOrientationAnim.cpp b/libs/surfaceflinger/LayerOrientationAnim.cpp
new file mode 100644
index 0000000..2b72d7c
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnim.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <core/SkBitmap.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnim::typeInfo = LayerBase::typeInfo | 0x80;
+const char* const LayerOrientationAnim::typeID = "LayerOrientationAnim";
+
+// ---------------------------------------------------------------------------
+
+LayerOrientationAnim::LayerOrientationAnim(
+ SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const LayerBitmap& bitmap,
+ const LayerBitmap& bitmapIn)
+ : LayerBase(flinger, display), mAnim(anim),
+ mBitmap(bitmap), mBitmapIn(bitmapIn),
+ mTextureName(-1), mTextureNameIn(-1)
+{
+ mStartTime = systemTime();
+ mFinishTime = 0;
+ mOrientationCompleted = false;
+ mFirstRedraw = false;
+ mLastNormalizedTime = 0;
+ mLastScale = 0;
+ mNeedsBlending = false;
+}
+
+LayerOrientationAnim::~LayerOrientationAnim()
+{
+ if (mTextureName != -1U) {
+ LayerBase::deletedTextures.add(mTextureName);
+ }
+ if (mTextureNameIn != -1U) {
+ LayerBase::deletedTextures.add(mTextureNameIn);
+ }
+}
+
+bool LayerOrientationAnim::needsBlending() const
+{
+ return mNeedsBlending;
+}
+
+Point LayerOrientationAnim::getPhysicalSize() const
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnim::validateVisibility(const Transform&)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(s.transform);
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ mTransformedBounds = tr.makeBounds(w, h);
+ mLeft = tr.tx();
+ mTop = tr.ty();
+ transparentRegionScreen.clear();
+ mTransformed = true;
+ mCanUseCopyBit = false;
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
+ if (copybit) {
+ mCanUseCopyBit = true;
+ }
+}
+
+void LayerOrientationAnim::onOrientationCompleted()
+{
+ mFinishTime = systemTime();
+ mOrientationCompleted = true;
+ mFirstRedraw = true;
+ mNeedsBlending = true;
+ mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnim::onDraw(const Region& clip) const
+{
+ // Animation...
+ const float MIN_SCALE = 0.5f;
+ const float DURATION = ms2ns(200);
+ const float BOUNCES_PER_SECOND = 1.618f;
+ const float BOUNCES_AMPLITUDE = 1.0f/32.0f;
+
+ const nsecs_t now = systemTime();
+ float scale, alpha;
+
+ if (mOrientationCompleted) {
+ if (mFirstRedraw) {
+ mFirstRedraw = false;
+
+ // make a copy of what's on screen
+ copybit_image_t image;
+ mBitmapIn.getBitmapSurface(&image);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.copyBackToImage(image);
+
+ // and erase the screen for this round
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // FIXME: code below is gross
+ mNeedsBlending = false;
+ LayerOrientationAnim* self(const_cast<LayerOrientationAnim*>(this));
+ mFlinger->invalidateLayerVisibility(self);
+ }
+
+ // make sure pick-up where we left off
+ const float duration = DURATION * mLastNormalizedTime;
+ const float normalizedTime = (float(now - mFinishTime) / duration);
+ if (normalizedTime <= 1.0f) {
+ const float squaredTime = normalizedTime*normalizedTime;
+ scale = (1.0f - mLastScale)*squaredTime + mLastScale;
+ alpha = (1.0f - normalizedTime);
+ alpha *= alpha;
+ alpha *= alpha;
+ } else {
+ mAnim->onAnimationFinished();
+ scale = 1.0f;
+ alpha = 0.0f;
+ }
+ } else {
+ const float normalizedTime = float(now - mStartTime) / DURATION;
+ if (normalizedTime <= 1.0f) {
+ mLastNormalizedTime = normalizedTime;
+ const float squaredTime = normalizedTime*normalizedTime;
+ scale = (MIN_SCALE-1.0f)*squaredTime + 1.0f;
+ alpha = 1.0f;
+ } else {
+ mLastNormalizedTime = 1.0f;
+ const float to_seconds = DURATION / seconds(1);
+ const float phi = BOUNCES_PER_SECOND *
+ (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+ scale = MIN_SCALE + BOUNCES_AMPLITUDE * (1.0f - cosf(phi));
+ alpha = 1.0f;
+ }
+ mLastScale = scale;
+ }
+ drawScaled(scale, alpha);
+}
+
+void LayerOrientationAnim::drawScaled(float f, float alpha) const
+{
+ copybit_image_t dst;
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ hw.getDisplaySurface(&dst);
+
+ // clear screen
+ // TODO: with update on demand, we may be able
+ // to not erase the screen at all during the animation
+ if (!mOrientationCompleted) {
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ const int w = dst.w*f;
+ const int h = dst.h*f;
+ const int xc = uint32_t(dst.w-w)/2;
+ const int yc = uint32_t(dst.h-h)/2;
+ const copybit_rect_t drect = { xc, yc, xc+w, yc+h };
+
+ copybit_image_t src;
+ mBitmap.getBitmapSurface(&src);
+ const copybit_rect_t srect = { 0, 0, src.w, src.h };
+
+ int err = NO_ERROR;
+ const int can_use_copybit = canUseCopybit();
+ if (can_use_copybit) {
+ copybit_device_t* copybit = mFlinger->getBlitEngine();
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+
+ if (alpha < 1.0f) {
+ copybit_image_t srcIn;
+ mBitmapIn.getBitmapSurface(&srcIn);
+ region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+ err = copybit->stretch(copybit, &dst, &srcIn, &drect, &srect, &it);
+ }
+
+ if (!err && alpha > 0.0f) {
+ region_iterator it(Region(Rect( drect.l, drect.t, drect.r, drect.b )));
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, int(alpha*255));
+ err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+ }
+ LOGE_IF(err != NO_ERROR, "copybit failed (%s)", strerror(err));
+ }
+ if (!can_use_copybit || err) {
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.w;
+ t.height = src.h;
+ t.stride = src.w;
+ t.vstride= src.h;
+ t.format = src.format;
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+ Transform tr;
+ tr.set(f,0,0,f);
+ tr.set(xc, yc);
+
+ // FIXME: we should not access mVertices and mDrawingState like that,
+ // but since we control the animation, we know it's going to work okay.
+ // eventually we'd need a more formal way of doing things like this.
+ LayerOrientationAnim& self(const_cast<LayerOrientationAnim&>(*this));
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // Too slow to do this in software
+ self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+ }
+
+ if (alpha < 1.0f) {
+ copybit_image_t src;
+ mBitmapIn.getBitmapSurface(&src);
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureNameIn == -1LU)) {
+ mTextureNameIn = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureNameIn, t, w, h);
+ }
+ self.mDrawingState.alpha = 255;
+ const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
+ drawWithOpenGL(clip, mTextureName, t);
+ }
+
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureName, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alpha*255);
+ const Region clip(Rect( drect.l, drect.t, drect.r, drect.b ));
+ drawWithOpenGL(clip, mTextureName, t);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/LayerScreenshot.h b/libs/surfaceflinger/LayerOrientationAnim.h
index 2d9a8ec..73676859 100644
--- a/libs/surfaceflinger/LayerScreenshot.h
+++ b/libs/surfaceflinger/LayerOrientationAnim.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_LAYER_SCREENSHOT_H
-#define ANDROID_LAYER_SCREENSHOT_H
+#ifndef ANDROID_LAYER_ORIENTATION_ANIM_H
+#define ANDROID_LAYER_ORIENTATION_ANIM_H
#include <stdint.h>
#include <sys/types.h>
@@ -23,12 +23,14 @@
#include <utils/Parcel.h>
#include "LayerBase.h"
+#include "LayerBitmap.h"
namespace android {
// ---------------------------------------------------------------------------
+class OrientationAnimation;
-class LayerScreenshot : public LayerBase
+class LayerOrientationAnim : public LayerBase
{
public:
static const uint32_t typeInfo;
@@ -36,22 +38,38 @@ public:
virtual char const* getTypeID() const { return typeID; }
virtual uint32_t getTypeInfo() const { return typeInfo; }
- LayerScreenshot(SurfaceFlinger* flinger, DisplayID display);
- virtual ~LayerScreenshot();
+ LayerOrientationAnim(SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const LayerBitmap& zoomOut,
+ const LayerBitmap& zoomIn);
+ virtual ~LayerOrientationAnim();
+
+ void onOrientationCompleted();
virtual void onDraw(const Region& clip) const;
- virtual bool needsBlending() const { return true; }
+ virtual Point getPhysicalSize() const;
+ virtual void validateVisibility(const Transform& globalTransform);
+ virtual bool needsBlending() const;
virtual bool isSecure() const { return false; }
-
- void takeScreenshot(Mutex& lock, Parcel* reply);
-
private:
- mutable Condition mCV;
- Parcel* mReply;
+ void drawScaled(float scale, float alpha) const;
+
+ OrientationAnimation* mAnim;
+ LayerBitmap mBitmap;
+ LayerBitmap mBitmapIn;
+ nsecs_t mStartTime;
+ nsecs_t mFinishTime;
+ bool mOrientationCompleted;
+ mutable bool mFirstRedraw;
+ mutable float mLastNormalizedTime;
+ mutable float mLastScale;
+ mutable GLuint mTextureName;
+ mutable GLuint mTextureNameIn;
+ mutable bool mNeedsBlending;
};
// ---------------------------------------------------------------------------
}; // namespace android
-#endif // ANDROID_LAYER_SCREENSHOT_H
+#endif // ANDROID_LAYER_ORIENTATION_ANIM_H
diff --git a/libs/surfaceflinger/OrientationAnimation.cpp b/libs/surfaceflinger/OrientationAnimation.cpp
new file mode 100644
index 0000000..f6f1326
--- /dev/null
+++ b/libs/surfaceflinger/OrientationAnimation.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "LayerOrientationAnim.h"
+#include "OrientationAnimation.h"
+#include "SurfaceFlinger.h"
+#include "VRamHeap.h"
+
+#include "DisplayHardware/DisplayHardware.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+OrientationAnimation::OrientationAnimation(const sp<SurfaceFlinger>& flinger)
+ : mFlinger(flinger), mLayerOrientationAnim(NULL), mState(DONE)
+{
+ // allocate a memory-dealer for this the first time
+ mTemporaryDealer = mFlinger->getSurfaceHeapManager()->createHeap(
+ ISurfaceComposer::eHardware);
+}
+
+OrientationAnimation::~OrientationAnimation()
+{
+}
+
+void OrientationAnimation::onOrientationChanged()
+{
+ if (mState == DONE)
+ mState = PREPARE;
+}
+
+void OrientationAnimation::onAnimationFinished()
+{
+ if (mState != DONE)
+ mState = FINISH;
+}
+
+bool OrientationAnimation::run_impl()
+{
+ bool skip_frame;
+ switch (mState) {
+ default:
+ case DONE:
+ skip_frame = done();
+ break;
+ case PREPARE:
+ skip_frame = prepare();
+ break;
+ case PHASE1:
+ skip_frame = phase1();
+ break;
+ case PHASE2:
+ skip_frame = phase2();
+ break;
+ case FINISH:
+ skip_frame = finished();
+ break;
+ }
+ return skip_frame;
+}
+
+bool OrientationAnimation::done()
+{
+ if (mFlinger->isFrozen()) {
+ // we are not allowed to draw, but pause a bit to make sure
+ // apps don't end up using the whole CPU, if they depend on
+ // surfaceflinger for synchronization.
+ usleep(8333); // 8.3ms ~ 120fps
+ return true;
+ }
+ return false;
+}
+
+bool OrientationAnimation::prepare()
+{
+ mState = PHASE1;
+
+ const GraphicPlane& plane(mFlinger->graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ const uint32_t w = hw.getWidth();
+ const uint32_t h = hw.getHeight();
+
+ LayerBitmap bitmap;
+ bitmap.init(mTemporaryDealer);
+ bitmap.setBits(w, h, 1, hw.getFormat());
+
+ LayerBitmap bitmapIn;
+ bitmapIn.init(mTemporaryDealer);
+ bitmapIn.setBits(w, h, 1, hw.getFormat());
+
+ copybit_image_t front;
+ bitmap.getBitmapSurface(&front);
+ hw.copyFrontToImage(front);
+
+ LayerOrientationAnim* l = new LayerOrientationAnim(
+ mFlinger.get(), 0, this, bitmap, bitmapIn);
+ l->initStates(w, h, 0);
+ l->setLayer(INT_MAX-1);
+ mFlinger->addLayer(l);
+ mLayerOrientationAnim = l;
+ return true;
+}
+
+bool OrientationAnimation::phase1()
+{
+ if (mFlinger->isFrozen() == false) {
+ // start phase 2
+ mState = PHASE2;
+ mLayerOrientationAnim->onOrientationCompleted();
+ mLayerOrientationAnim->invalidate();
+ return true;
+
+ }
+ mLayerOrientationAnim->invalidate();
+ return false;
+}
+
+bool OrientationAnimation::phase2()
+{
+ // do the 2nd phase of the animation
+ mLayerOrientationAnim->invalidate();
+ return false;
+}
+
+bool OrientationAnimation::finished()
+{
+ mState = DONE;
+ mFlinger->removeLayer(mLayerOrientationAnim);
+ mLayerOrientationAnim = NULL;
+ return true;
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/libs/surfaceflinger/OrientationAnimation.h b/libs/surfaceflinger/OrientationAnimation.h
new file mode 100644
index 0000000..ba33fce
--- /dev/null
+++ b/libs/surfaceflinger/OrientationAnimation.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_ORIENTATION_ANIMATION_H
+#define ANDROID_ORIENTATION_ANIMATION_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+class SurfaceFlinger;
+class MemoryDealer;
+class LayerOrientationAnim;
+
+class OrientationAnimation
+{
+public:
+ OrientationAnimation(const sp<SurfaceFlinger>& flinger);
+ virtual ~OrientationAnimation();
+
+ void onOrientationChanged();
+ void onAnimationFinished();
+ inline bool run() {
+ if (LIKELY(mState == DONE))
+ return false;
+ return run_impl();
+ }
+
+private:
+ enum {
+ DONE = 0,
+ PREPARE,
+ PHASE1,
+ PHASE2,
+ FINISH
+ };
+
+ bool run_impl();
+ bool done();
+ bool prepare();
+ bool phase1();
+ bool phase2();
+ bool finished();
+
+ sp<SurfaceFlinger> mFlinger;
+ sp<MemoryDealer> mTemporaryDealer;
+ LayerOrientationAnim* mLayerOrientationAnim;
+ int mState;
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_ORIENTATION_ANIMATION_H
diff --git a/libs/surfaceflinger/RFBServer.cpp b/libs/surfaceflinger/RFBServer.cpp
deleted file mode 100644
index c2c1989..0000000
--- a/libs/surfaceflinger/RFBServer.cpp
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#define LOG_TAG "RFBServer"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-
-#include <netinet/in.h>
-
-#include <cutils/sockets.h>
-
-#include <utils/Log.h>
-#include <ui/Rect.h>
-
-#ifdef HAVE_ANDROID_OS
-#include <linux/input.h>
-#endif
-
-#include "RFBServer.h"
-#include "SurfaceFlinger.h"
-
-/* BUG=773511: this is a temporary hack required while developing the new
- set of "clean kernel headers" for the Bionic C library. */
-#ifndef KEY_STAR
-#define KEY_STAR 227
-#endif
-#ifndef KEY_SHARP
-#define KEY_SHARP 228
-#endif
-#ifndef KEY_SOFT1
-#define KEY_SOFT1 229
-#endif
-#ifndef KEY_SOFT2
-#define KEY_SOFT2 230
-#endif
-#ifndef KEY_CENTER
-#define KEY_CENTER 232
-#endif
-
-// ----------------------------------------------------------------------------
-
-#define DEBUG_MSG 0
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-const int VNC_PORT = 5900;
-
-RFBServer::RFBServer(uint32_t w, uint32_t h, android::PixelFormat format)
- : Thread(false), mFD(-1), mStatus(NO_INIT), mIoVec(0)
-{
- mFrameBuffer.version = sizeof(mFrameBuffer);
- mFrameBuffer.width = w;
- mFrameBuffer.height = h;
- mFrameBuffer.stride = w;
- mFrameBuffer.format = format;
- mFrameBuffer.data = 0;
-}
-
-RFBServer::~RFBServer()
-{
- if (mRobinThread != 0) {
- // ask the thread to exit first
- mRobinThread->exitAndWait();
- }
-
- free(mFrameBuffer.data);
-
- delete [] mIoVec;
-}
-
-void RFBServer::onFirstRef()
-{
- run("Batman");
-}
-
-status_t RFBServer::readyToRun()
-{
- LOGI("RFB server ready to run");
- return NO_ERROR;
-}
-
-bool RFBServer::threadLoop()
-{
- struct sockaddr addr;
- socklen_t alen;
- int serverfd = -1;
- int port = VNC_PORT;
-
- do {
- retry:
- if (serverfd < 0) {
- serverfd = socket_loopback_server(port, SOCK_STREAM);
- if (serverfd < 0) {
- if ((errno == EADDRINUSE) && (port < (VNC_PORT+10))) {
- LOGW("port %d already in use, trying %d", port, port+1);
- port++;
- goto retry;
- }
- LOGE("couldn't create socket, port=%d, error %d (%s)",
- port, errno, strerror(errno));
- sleep(1);
- break;
- }
- fcntl(serverfd, F_SETFD, FD_CLOEXEC);
- }
-
- alen = sizeof(addr);
- mFD = accept(serverfd, &addr, &alen);
-
- if (mFD < 0) {
- LOGE("couldn't accept(), error %d (%s)", errno, strerror(errno));
- // we could have run out of file descriptors, wait a bit and
- // try again.
- sleep(1);
- goto retry;
- }
- fcntl(mFD, F_SETFD, FD_CLOEXEC);
-
- // send protocol version and Authentication method
- mStatus = NO_ERROR;
- handshake(3, 3, Authentication::None);
-
- if (alive()) {
- // create the thread we use to send data to the client
- mRobinThread = new ServerThread(this);
- }
-
- while( alive() ) {
- // client message must be destroyed at each iteration
- // (most of the time this is a no-op)
- ClientMessage msg;
- waitForClientMessage(msg);
- if (alive()) {
- handleClientMessage(msg);
- }
- }
-
- } while( alive() );
-
- // free-up some resources
- if (mRobinThread != 0) {
- mRobinThread->exitAndWait();
- mRobinThread.clear();
- }
-
- free(mFrameBuffer.data);
- mFrameBuffer.data = 0;
-
- close(mFD);
- close(serverfd);
- mFD = -1;
-
- // we'll try again
- return true;
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::ServerThread::ServerThread(const sp<RFBServer>& receiver)
- : Thread(false), mReceiver(receiver)
-{
- LOGD("RFB Server Thread created");
-}
-
-RFBServer::ServerThread::~ServerThread()
-{
- LOGD("RFB Server Thread destroyed");
-}
-
-void RFBServer::ServerThread::onFirstRef()
-{
- mUpdateBarrier.close();
- run("Robin");
-}
-
-status_t RFBServer::ServerThread::readyToRun()
-{
- return NO_ERROR;
-}
-
-void RFBServer::ServerThread::wake()
-{
- mUpdateBarrier.open();
-}
-
-void RFBServer::ServerThread::exitAndWait()
-{
- requestExit();
- mUpdateBarrier.open();
- requestExitAndWait();
-}
-
-bool RFBServer::ServerThread::threadLoop()
-{
- sp<RFBServer> receiver(mReceiver.promote());
- if (receiver == 0)
- return false;
-
- // wait for something to do
- mUpdateBarrier.wait();
-
- // we're asked to quit, abort everything
- if (exitPending())
- return false;
-
- mUpdateBarrier.close();
-
- // process updates
- receiver->sendFrameBufferUpdates();
- return !exitPending();
-}
-
-// ----------------------------------------------------------------------------
-
-void RFBServer::handshake(uint8_t major, uint8_t minor, uint32_t auth)
-{
- ProtocolVersion protocolVersion(major, minor);
- if( !write(protocolVersion) )
- return;
-
- if ( !read(protocolVersion) )
- return;
-
- int maj, min;
- if ( protocolVersion.decode(maj, min) != NO_ERROR ) {
- mStatus = -1;
- return;
- }
-
-#if DEBUG_MSG
- LOGD("client protocol string: <%s>", (char*)protocolVersion.payload());
- LOGD("client wants protocol version %d.%d\n", maj, min);
-#endif
-
- Authentication authentication(auth);
- if( !write(authentication) )
- return;
-
- ClientInitialization clientInit;
- if ( !read(clientInit) )
- return;
-
-#if DEBUG_MSG
- LOGD("client initialization: sharedFlags = %d\n", clientInit.sharedFlags());
-#endif
-
- ServerInitialization serverInit("Android RFB");
- ServerInitialization::Payload& message(serverInit.message());
- message.framebufferWidth = htons(mFrameBuffer.width);
- message.framebufferHeight = htons(mFrameBuffer.height);
- message.serverPixelFormat.bitsPerPixel = 16;
- message.serverPixelFormat.depth = 16;
- message.serverPixelFormat.bigEndianFlag = 0;
- message.serverPixelFormat.trueColorFlag = 1;
- message.serverPixelFormat.redMax = htons((1<<5)-1);
- message.serverPixelFormat.greenMax = htons((1<<6)-1);
- message.serverPixelFormat.blueMax = htons((1<<5)-1);
- message.serverPixelFormat.redShift = 11;
- message.serverPixelFormat.greenShift = 5;
- message.serverPixelFormat.blueShift = 0;
-
- mIoVec = new iovec[mFrameBuffer.height];
-
- write(serverInit);
-}
-
-void RFBServer::handleClientMessage(const ClientMessage& msg)
-{
- switch(msg.type()) {
- case SET_PIXEL_FORMAT:
- handleSetPixelFormat(msg.messages().setPixelFormat);
- break;
- case SET_ENCODINGS:
- handleSetEncodings(msg.messages().setEncodings);
- break;
- case FRAME_BUFFER_UPDATE_REQ:
- handleFrameBufferUpdateReq(msg.messages().frameBufferUpdateRequest);
- break;
- case KEY_EVENT:
- handleKeyEvent(msg.messages().keyEvent);
- break;
- }
-}
-
-void RFBServer::handleSetPixelFormat(const SetPixelFormat& msg)
-{
- if (!validatePixelFormat(msg.pixelFormat)) {
- LOGE("The builtin VNC server only supports the RGB 565 pixel format");
- LOGD("requested pixel format:");
- LOGD("bitsPerPixel: %d", msg.pixelFormat.bitsPerPixel);
- LOGD("depth: %d", msg.pixelFormat.depth);
- LOGD("bigEndianFlag: %d", msg.pixelFormat.bigEndianFlag);
- LOGD("trueColorFlag: %d", msg.pixelFormat.trueColorFlag);
- LOGD("redmax: %d", ntohs(msg.pixelFormat.redMax));
- LOGD("bluemax: %d", ntohs(msg.pixelFormat.greenMax));
- LOGD("greenmax: %d", ntohs(msg.pixelFormat.blueMax));
- LOGD("redshift: %d", msg.pixelFormat.redShift);
- LOGD("greenshift: %d", msg.pixelFormat.greenShift);
- LOGD("blueshift: %d", msg.pixelFormat.blueShift);
- mStatus = -1;
- }
-}
-
-bool RFBServer::validatePixelFormat(const PixelFormat& pf)
-{
- if ((pf.bitsPerPixel != 16) || (pf.depth != 16))
- return false;
-
- if (pf.bigEndianFlag || !pf.trueColorFlag)
- return false;
-
- if (ntohs(pf.redMax)!=0x1F ||
- ntohs(pf.greenMax)!=0x3F ||
- ntohs(pf.blueMax)!=0x1F) {
- return false;
- }
-
- if (pf.redShift!=11 || pf.greenShift!=5 || pf.blueShift!=0)
- return false;
-
- return true;
-}
-
-void RFBServer::handleSetEncodings(const SetEncodings& msg)
-{
- /* From the RFB specification:
- Sets the encoding types in which pixel data can be sent by the server.
- The order of the encoding types given in this message is a hint by the
- client as to its preference (the first encoding specified being most
- preferred). The server may or may not choose to make use of this hint.
- Pixel data may always be sent in raw encoding even if not specified
- explicitly here.
- */
-
- LOGW("SetEncodings received. Only RAW is supported.");
-}
-
-void RFBServer::handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg)
-{
-#if DEBUG_MSG
- LOGD("handle FrameBufferUpdateRequest");
-#endif
-
- Rect r;
- r.left = ntohs(msg.x);
- r.top = ntohs(msg.y);
- r.right = r.left + ntohs(msg.width);
- r.bottom = r.top + ntohs(msg.height);
-
- Mutex::Autolock _l(mRegionLock);
- mClientRegionRequest.set(r);
- if (!msg.incremental)
- mDirtyRegion.orSelf(r);
-
- mRobinThread->wake();
-}
-
-void RFBServer::handleKeyEvent(const KeyEvent& msg)
-{
-#ifdef HAVE_ANDROID_OS
-
- int scancode = 0;
- int code = ntohl(msg.key);
-
- if (code>='0' && code<='9') {
- scancode = (code & 0xF) - 1;
- if (scancode<0) scancode += 10;
- scancode += KEY_1;
- } else if (code>=0xFF50 && code<=0xFF58) {
- static const uint16_t map[] =
- { KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN,
- KEY_SOFT1, KEY_SOFT2, KEY_END, 0 };
- scancode = map[code & 0xF];
- } else if (code>=0xFFE1 && code<=0xFFEE) {
- static const uint16_t map[] =
- { KEY_LEFTSHIFT, KEY_LEFTSHIFT,
- KEY_COMPOSE, KEY_COMPOSE,
- KEY_LEFTSHIFT, KEY_LEFTSHIFT,
- 0,0,
- KEY_LEFTALT, KEY_RIGHTALT,
- 0, 0, 0, 0 };
- scancode = map[code & 0xF];
- } else if ((code>='A' && code<='Z') || (code>='a' && code<='z')) {
- static const uint16_t map[] = {
- KEY_A, KEY_B, KEY_C, KEY_D, KEY_E,
- KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
- KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
- KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
- KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z };
- scancode = map[(code & 0x5F) - 'A'];
- } else {
- switch (code) {
- case 0x0003: scancode = KEY_CENTER; break;
- case 0x0020: scancode = KEY_SPACE; break;
- case 0x0023: scancode = KEY_SHARP; break;
- case 0x0033: scancode = KEY_SHARP; break;
- case 0x002C: scancode = KEY_COMMA; break;
- case 0x003C: scancode = KEY_COMMA; break;
- case 0x002E: scancode = KEY_DOT; break;
- case 0x003E: scancode = KEY_DOT; break;
- case 0x002F: scancode = KEY_SLASH; break;
- case 0x003F: scancode = KEY_SLASH; break;
- case 0x0032: scancode = KEY_EMAIL; break;
- case 0x0040: scancode = KEY_EMAIL; break;
- case 0xFF08: scancode = KEY_BACKSPACE; break;
- case 0xFF1B: scancode = KEY_BACK; break;
- case 0xFF09: scancode = KEY_TAB; break;
- case 0xFF0D: scancode = KEY_ENTER; break;
- case 0x002A: scancode = KEY_STAR; break;
- case 0xFFBE: scancode = KEY_SEND; break; // F1
- case 0xFFBF: scancode = KEY_END; break; // F2
- case 0xFFC0: scancode = KEY_HOME; break; // F3
- case 0xFFC5: scancode = KEY_POWER; break; // F8
- }
- }
-
-#if DEBUG_MSG
- LOGD("handle KeyEvent 0x%08x, %d, scancode=%d\n", code, msg.downFlag, scancode);
-#endif
-
- if (scancode) {
- mEventInjector.injectKey(uint16_t(scancode),
- msg.downFlag ? EventInjector::DOWN : EventInjector::UP);
- }
-#endif
-}
-
-void RFBServer::waitForClientMessage(ClientMessage& msg)
-{
- if ( !read(msg.payload(), 1) )
- return;
-
- switch(msg.type()) {
-
- case SET_PIXEL_FORMAT:
- read(msg.payload(1), sizeof(SetPixelFormat)-1);
- break;
-
- case FIX_COLOUR_MAP_ENTRIES:
- mStatus = UNKNOWN_ERROR;
- return;
-
- case SET_ENCODINGS:
- {
- if ( !read(msg.payload(1), sizeof(SetEncodings)-1) )
- return;
-
- size_t size = ntohs( msg.messages().setEncodings.numberOfEncodings ) * 4;
- if (msg.resize(sizeof(SetEncodings) + size) != NO_ERROR) {
- mStatus = NO_MEMORY;
- return;
- }
-
- if ( !read(msg.payload(sizeof(SetEncodings)), size) )
- return;
-
- break;
- }
-
- case FRAME_BUFFER_UPDATE_REQ:
- read(msg.payload(1), sizeof(FrameBufferUpdateRequest)-1);
- break;
-
- case KEY_EVENT:
- read(msg.payload(1), sizeof(KeyEvent)-1);
- break;
-
- case POINTER_EVENT:
- read(msg.payload(1), sizeof(PointerEvent)-1);
- break;
-
- case CLIENT_CUT_TEXT:
- {
- if ( !read(msg.payload(1), sizeof(ClientCutText)-1) )
- return;
-
- size_t size = ntohl( msg.messages().clientCutText.length );
- if (msg.resize(sizeof(ClientCutText) + size) != NO_ERROR) {
- mStatus = NO_MEMORY;
- return;
- }
-
- if ( !read(msg.payload(sizeof(SetEncodings)), size) )
- return;
-
- break;
- }
-
- default:
- LOGE("Unknown Message %d", msg.type());
- mStatus = UNKNOWN_ERROR;
- return;
- }
-}
-
-// ----------------------------------------------------------------------------
-
-bool RFBServer::write(const Message& msg)
-{
- write(msg.payload(), msg.size());
- return alive();
-}
-
-bool RFBServer::read(Message& msg)
-{
- read(msg.payload(), msg.size());
- return alive();
-}
-
-bool RFBServer::write(const void* buffer, int size)
-{
- int wr = ::write(mFD, buffer, size);
- if (wr != size) {
- //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
- mStatus = (wr == -1) ? errno : -1;
- }
- return alive();
-}
-
-bool RFBServer::read(void* buffer, int size)
-{
- int rd = ::read(mFD, buffer, size);
- if (rd != size) {
- //LOGE("read(%d) error %d (%s)", size, rd, strerror(errno));
- mStatus = (rd == -1) ? errno : -1;
- }
- return alive();
-}
-
-bool RFBServer::alive() const
-{
- return mStatus == 0;
-}
-
-bool RFBServer::isConnected() const
-{
- return alive();
-}
-
-// ----------------------------------------------------------------------------
-
-void RFBServer::frameBufferUpdated(const GGLSurface& front, const Region& reg)
-{
- Mutex::Autolock _l(mRegionLock);
-
- // update dirty region
- mDirtyRegion.orSelf(reg);
-
- // remember the front-buffer
- mFrontBuffer = front;
-
- // The client has not requested anything, don't do anything more
- if (mClientRegionRequest.isEmpty())
- return;
-
- // wake the sending thread up
- mRobinThread->wake();
-}
-
-void RFBServer::sendFrameBufferUpdates()
-{
- Vector<Rect> rects;
- size_t countRects;
- GGLSurface fb;
-
- { // Scope for the lock
- Mutex::Autolock _l(mRegionLock);
- if (mFrontBuffer.data == 0)
- return;
-
- const Region reg( mDirtyRegion.intersect(mClientRegionRequest) );
- if (reg.isEmpty())
- return;
-
- mDirtyRegion.subtractSelf(reg);
- countRects = reg.rects(rects);
-
- // copy the frame-buffer so we can stay responsive
- size_t bytesPerPix = bytesPerPixel(mFrameBuffer.format);
- size_t bpr = mFrameBuffer.stride * bytesPerPix;
- if (mFrameBuffer.data == 0) {
- mFrameBuffer.data = (GGLubyte*)malloc(bpr * mFrameBuffer.height);
- if (mFrameBuffer.data == 0)
- return;
- }
-
- memcpy(mFrameBuffer.data, mFrontBuffer.data, bpr*mFrameBuffer.height);
- fb = mFrameBuffer;
- }
-
- FrameBufferUpdate msgHeader;
- msgHeader.type = 0;
- msgHeader.numberOfRectangles = htons(countRects);
- write(&msgHeader, sizeof(msgHeader));
-
- Rectangle rectangle;
- for (size_t i=0 ; i<countRects ; i++) {
- const Rect& r = rects[i];
- rectangle.x = htons( r.left );
- rectangle.y = htons( r.top );
- rectangle.w = htons( r.width() );
- rectangle.h = htons( r.height() );
- rectangle.encoding = htons( SetEncodings::Raw );
- write(&rectangle, sizeof(rectangle));
- size_t h = r.height();
- size_t w = r.width();
- size_t bytesPerPix = bytesPerPixel(fb.format);
- size_t bpr = fb.stride * bytesPerPix;
- size_t bytes = w * bytesPerPix;
- size_t offset = (r.top * bpr) + (r.left * bytesPerPix);
- uint8_t* src = static_cast<uint8_t*>(fb.data) + offset;
- iovec* iov = mIoVec;
- while (h--) {
- iov->iov_base = src;
- iov->iov_len = bytes;
- src += bpr;
- iov++;
- }
- size_t iovcnt = iov - mIoVec;
- int wr = ::writev(mFD, mIoVec, iovcnt);
- if (wr < 0) {
- //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
- mStatus = errno;
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::Message::Message(size_t size)
- : mSize(size), mAllocatedSize(size)
-{
- mPayload = malloc(size);
-}
-
-RFBServer::Message::Message(void* payload, size_t size)
- : mPayload(payload), mSize(size), mAllocatedSize(0)
-{
-}
-
-RFBServer::Message::~Message()
-{
- if (mAllocatedSize)
- free(mPayload);
-}
-
-status_t RFBServer::Message::resize(size_t size)
-{
- if (size > mAllocatedSize) {
- void* newp;
- if (mAllocatedSize) {
- newp = realloc(mPayload, size);
- if (!newp) return NO_MEMORY;
- } else {
- newp = malloc(size);
- if (!newp) return NO_MEMORY;
- memcpy(newp, mPayload, mSize);
- mAllocatedSize = size;
- }
- mPayload = newp;
- }
- mSize = size;
- return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-RFBServer::EventInjector::EventInjector()
- : mFD(-1)
-{
-}
-
-RFBServer::EventInjector::~EventInjector()
-{
-}
-
-void RFBServer::EventInjector::injectKey(uint16_t code, uint16_t value)
-{
-#ifdef HAVE_ANDROID_OS
- // XXX: we need to open the right event device
- int version;
- mFD = open("/dev/input/event0", O_RDWR);
- ioctl(mFD, EVIOCGVERSION, &version);
-
- input_event ev;
- memset(&ev, 0, sizeof(ev));
- ev.type = EV_KEY;
- ev.code = code;
- ev.value = value;
- ::write(mFD, &ev, sizeof(ev));
-
- close(mFD);
- mFD = -1;
-#endif
-}
-
-
-}; // namespace android
-
diff --git a/libs/surfaceflinger/RFBServer.h b/libs/surfaceflinger/RFBServer.h
deleted file mode 100644
index 420912e..0000000
--- a/libs/surfaceflinger/RFBServer.h
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#ifndef ANDROID_RFB_SERVER_H
-#define ANDROID_RFB_SERVER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-
-#include <utils/Errors.h>
-#include <utils/threads.h>
-#include <ui/Region.h>
-#include <ui/PixelFormat.h>
-
-#include <pixelflinger/pixelflinger.h>
-
-#include "Barrier.h"
-
-namespace android {
-
-class SurfaceFlinger;
-
-class RFBServer : public Thread
-{
-public:
- RFBServer(uint32_t w, uint32_t h, android::PixelFormat format);
- virtual ~RFBServer();
-
- void frameBufferUpdated(const GGLSurface& front, const Region& reg);
- bool isConnected() const;
-
-private:
- typedef uint8_t card8;
- typedef uint16_t card16;
- typedef uint32_t card32;
-
- struct Message {
- Message(size_t size);
- virtual ~Message();
- void* payload(int offset=0) {
- return static_cast<char*>(mPayload)+offset;
- }
- void const * payload(int offset=0) const {
- return static_cast<char const *>(mPayload)+offset;
- }
- size_t size() const { return mSize; }
- protected:
- Message(void* payload, size_t size);
- status_t resize(size_t size);
- private:
- void* mPayload;
- size_t mSize;
- size_t mAllocatedSize;
- };
-
- struct ProtocolVersion : public Message {
- ProtocolVersion(uint8_t major, uint8_t minor)
- : Message(&messageData, 12) {
- char* p = static_cast<char*>(payload());
- snprintf(p, 13, "RFB %03u.%03u%c", major, minor, 0xA);
- }
- status_t decode(int& maj, int& min) {
- char* p = static_cast<char*>(payload());
- int n = sscanf(p, "RFB %03u.%03u", &maj, &min);
- return (n == 2) ? NO_ERROR : NOT_ENOUGH_DATA;
- }
- private:
- char messageData[12+1];
- };
-
- struct Authentication : public Message {
- enum { Failed=0, None=1, Vnc=2 };
- Authentication(int auth) : Message(&messageData, 4) {
- *static_cast<card32*>(payload()) = htonl(auth);
- }
- private:
- card32 messageData;
- };
-
- struct ClientInitialization : public Message {
- ClientInitialization() : Message(&messageData, 1) { }
- int sharedFlags() {
- return messageData;
- }
- private:
- card8 messageData;
- };
-
- struct PixelFormat {
- card8 bitsPerPixel;
- card8 depth;
- card8 bigEndianFlag;
- card8 trueColorFlag;
- card16 redMax;
- card16 greenMax;
- card16 blueMax;
- card8 redShift;
- card8 greenShift;
- card8 blueShift;
- uint8_t padding[3];
- } __attribute__((packed));
-
- struct ServerInitialization : public Message {
- ServerInitialization(char const * name)
- : Message(sizeof(Payload) + strlen(name))
- {
- const size_t nameLength = size() - sizeof(Payload);
- message().nameLength = htonl(nameLength);
- memcpy((char*)message().nameString, name,nameLength);
- }
- struct Payload {
- card16 framebufferWidth;
- card16 framebufferHeight;
- PixelFormat serverPixelFormat;
- card32 nameLength;
- card8 nameString[0];
- } __attribute__((packed));
- Payload& message() {
- return *static_cast<Payload*>(payload());
- }
- };
-
- // client messages...
-
- struct SetPixelFormat {
- card8 type;
- uint8_t padding[3];
- PixelFormat pixelFormat;
- } __attribute__((packed));
-
- struct SetEncodings {
- enum { Raw=0, CoR=1, RRE=2, CoRRE=4, Hextile=5 };
- card8 type;
- uint8_t padding;
- card16 numberOfEncodings;
- card32 encodings[0];
- } __attribute__((packed));
-
- struct FrameBufferUpdateRequest {
- card8 type;
- card8 incremental;
- card16 x;
- card16 y;
- card16 width;
- card16 height;
- } __attribute__((packed));
-
- struct KeyEvent {
- card8 type;
- card8 downFlag;
- uint8_t padding[2];
- card32 key;
- } __attribute__((packed));
-
- struct PointerEvent {
- card8 type;
- card8 buttonMask;
- card16 x;
- card16 y;
- } __attribute__((packed));
-
- struct ClientCutText {
- card8 type;
- uint8_t padding[3];
- card32 length;
- card8 text[0];
- } __attribute__((packed));
-
- union ClientMessages {
- card8 type;
- SetPixelFormat setPixelFormat;
- SetEncodings setEncodings;
- FrameBufferUpdateRequest frameBufferUpdateRequest;
- KeyEvent keyEvent;
- PointerEvent pointerEvent;
- ClientCutText clientCutText;
- };
-
- struct Rectangle {
- card16 x;
- card16 y;
- card16 w;
- card16 h;
- card32 encoding;
- } __attribute__((packed));
-
- struct FrameBufferUpdate {
- card8 type;
- uint8_t padding;
- card16 numberOfRectangles;
- Rectangle rectangles[0];
- } __attribute__((packed));
-
- enum {
- SET_PIXEL_FORMAT = 0,
- FIX_COLOUR_MAP_ENTRIES = 1,
- SET_ENCODINGS = 2,
- FRAME_BUFFER_UPDATE_REQ = 3,
- KEY_EVENT = 4,
- POINTER_EVENT = 5,
- CLIENT_CUT_TEXT = 6,
- };
-
- struct ClientMessage : public Message {
- ClientMessage()
- : Message(&messageData, sizeof(messageData)) {
- }
- const ClientMessages& messages() const {
- return *static_cast<ClientMessages const *>(payload());
- }
- const int type() const {
- return messages().type;
- }
- status_t resize(size_t size) {
- return Message::resize(size);
- }
-
- ClientMessages messageData;
- };
-
-
- class ServerThread : public Thread
- {
- friend class RFBServer;
- public:
- ServerThread(const sp<RFBServer>& receiver);
- virtual ~ServerThread();
- void wake();
- void exitAndWait();
- private:
- virtual bool threadLoop();
- virtual status_t readyToRun();
- virtual void onFirstRef();
- wp<RFBServer> mReceiver;
- bool (RFBServer::*mAction)();
- Barrier mUpdateBarrier;
- };
-
- class EventInjector {
- public:
- enum { UP=0, DOWN=1 };
- EventInjector();
- ~EventInjector();
- void injectKey(uint16_t code, uint16_t value);
- private:
- struct input_event {
- struct timeval time;
- uint16_t type;
- uint16_t code;
- uint32_t value;
- };
- int mFD;
- };
-
- void handshake(uint8_t major, uint8_t minor, uint32_t auth);
- void waitForClientMessage(ClientMessage& msg);
- void handleClientMessage(const ClientMessage& msg);
- void handleSetPixelFormat(const SetPixelFormat& msg);
- void handleSetEncodings(const SetEncodings& msg);
- void handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg);
- void handleKeyEvent(const KeyEvent& msg);
- void sendFrameBufferUpdates();
-
- bool validatePixelFormat(const PixelFormat& pf);
- bool alive() const;
- bool write(const Message& msg);
- bool read(Message& msg);
-
- bool write(const void* buffer, int size);
- bool read(void* buffer, int size);
-
- virtual bool threadLoop();
- virtual status_t readyToRun();
- virtual void onFirstRef();
-
- sp<ServerThread> mRobinThread;
-
- int mFD;
- int mStatus;
- iovec* mIoVec;
-
- EventInjector mEventInjector;
-
- Mutex mRegionLock;
- // This is the region requested by the client since the last
- // time we updated it
- Region mClientRegionRequest;
- // This is the region of the screen that needs to be sent to the
- // client since the last time we updated it.
- // Typically this is the dirty region, but not necessarily, for
- // instance if the client asked for a non incremental update.
- Region mDirtyRegion;
-
- GGLSurface mFrameBuffer;
- GGLSurface mFrontBuffer;
-};
-
-}; // namespace android
-
-#endif // ANDROID_RFB_SERVER_H
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 554e8e7..242d026 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -53,20 +53,15 @@
#include "LayerBuffer.h"
#include "LayerDim.h"
#include "LayerBitmap.h"
-#include "LayerScreenshot.h"
+#include "LayerOrientationAnim.h"
+#include "OrientationAnimation.h"
#include "SurfaceFlinger.h"
-#include "RFBServer.h"
#include "VRamHeap.h"
#include "DisplayHardware/DisplayHardware.h"
#include "GPUHardware/GPUHardware.h"
-// the VNC server even on local ports presents a significant
-// thread as it can allow an application to control and "see" other
-// applications, de-facto bypassing security permissions.
-#define ENABLE_VNC_SERVER 0
-
#define DISPLAY_COUNT 1
namespace android {
@@ -185,6 +180,7 @@ SurfaceFlinger::SurfaceFlinger()
mDeferReleaseConsole(false),
mFreezeDisplay(false),
mFreezeCount(0),
+ mFreezeDisplayTime(0),
mDebugRegion(0),
mDebugCpu(0),
mDebugFps(0),
@@ -225,6 +221,7 @@ void SurfaceFlinger::init()
SurfaceFlinger::~SurfaceFlinger()
{
glDeleteTextures(1, &mWormholeTexName);
+ delete mOrientationAnimation;
}
copybit_device_t* SurfaceFlinger::getBlitEngine() const
@@ -448,6 +445,8 @@ status_t SurfaceFlinger::readyToRun()
* We're now ready to accept clients...
*/
+ mOrientationAnimation = new OrientationAnimation(this);
+
// start CPU gauge display
if (mDebugCpu)
mCpuGauge = new CPUGauge(this, ms2ns(500));
@@ -456,9 +455,6 @@ status_t SurfaceFlinger::readyToRun()
if (mDebugNoBootAnimation == false)
mBootAnimation = new BootAnimation(this);
- if (ENABLE_VNC_SERVER)
- mRFBServer = new RFBServer(w, h, f);
-
return NO_ERROR;
}
@@ -472,17 +468,25 @@ void SurfaceFlinger::waitForEvent()
{
// wait for something to do
if (UNLIKELY(isFrozen())) {
- // wait 2 seconds
- int err = mSyncObject.wait(ms2ns(3000));
+ // wait 5 seconds
+ const nsecs_t freezeDisplayTimeout = ms2ns(5000);
+ const nsecs_t now = systemTime();
+ if (mFreezeDisplayTime == 0) {
+ mFreezeDisplayTime = now;
+ }
+ nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
+ int err = (waitTime > 0) ? mSyncObject.wait(waitTime) : TIMED_OUT;
if (err != NO_ERROR) {
if (isFrozen()) {
// we timed out and are still frozen
LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
mFreezeDisplay, mFreezeCount);
mFreezeCount = 0;
+ mFreezeDisplay = false;
}
}
} else {
+ mFreezeDisplayTime = 0;
mSyncObject.wait();
}
}
@@ -556,11 +560,8 @@ bool SurfaceFlinger::threadLoop()
void SurfaceFlinger::postFramebuffer()
{
- if (UNLIKELY(isFrozen())) {
- // we are not allowed to draw, but pause a bit to make sure
- // apps don't end up using the whole CPU, if they depend on
- // surfaceflinger for synchronization.
- usleep(8333); // 8.3ms ~ 120fps
+ const bool skip = mOrientationAnimation->run();
+ if (UNLIKELY(skip)) {
return;
}
@@ -571,18 +572,6 @@ void SurfaceFlinger::postFramebuffer()
debugShowFPS();
}
- if (UNLIKELY(ENABLE_VNC_SERVER &&
- mRFBServer!=0 && mRFBServer->isConnected())) {
- if (!mSecureFrameBuffer) {
- GGLSurface fb;
- // backbufer, is going to become the front buffer really soon
- hw.getDisplaySurface(&fb);
- if (LIKELY(fb.data != 0)) {
- mRFBServer->frameBufferUpdated(fb, mInvalidRegion);
- }
- }
- }
-
hw.flip(mInvalidRegion);
mInvalidRegion.clear();
@@ -685,18 +674,13 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
mVisibleRegionsDirty = true;
mDirtyRegion.set(hw.bounds());
+
+ mOrientationAnimation->onOrientationChanged();
}
if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
// freezing or unfreezing the display -> trigger animation if needed
mFreezeDisplay = mCurrentState.freezeDisplay;
- const nsecs_t now = systemTime();
- if (mFreezeDisplay) {
- mFreezeDisplayTime = now;
- } else {
- //LOGD("Screen was frozen for %llu us",
- // ns2us(now-mFreezeDisplayTime));
- }
}
// some layers might have been removed, so
@@ -875,19 +859,9 @@ void SurfaceFlinger::handleRepaint()
uint32_t flags = hw.getFlags();
if (flags & DisplayHardware::BUFFER_PRESERVED) {
- if (flags & DisplayHardware::COPY_BACK_EXTENSION) {
- // yay. nothing to do here.
- } else {
- if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
- // we need to fully redraw the part that will be updated
- mDirtyRegion.set(mInvalidRegion.bounds());
- } else {
- // TODO: we only need te redraw the part that had been drawn
- // the round before and is not drawn now
- }
- }
+ // here we assume DisplayHardware::flip()'s implementation
+ // performs the copy-back optimization.
} else {
- // COPY_BACK_EXTENSION makes no sense here
if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
// we need to fully redraw the part that will be updated
mDirtyRegion.set(mInvalidRegion.bounds());
@@ -1077,6 +1051,29 @@ void SurfaceFlinger::debugShowFPS() const
// XXX: mFPS has the value we want
}
+status_t SurfaceFlinger::addLayer(LayerBase* layer)
+{
+ Mutex::Autolock _l(mStateLock);
+ addLayer_l(layer);
+ setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeLayer(LayerBase* layer)
+{
+ Mutex::Autolock _l(mStateLock);
+ removeLayer_l(layer);
+ setTransactionFlags(eTransactionNeeded);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::invalidateLayerVisibility(LayerBase* layer)
+{
+ layer->forceVisibilityTransaction();
+ setTransactionFlags(eTraversalNeeded);
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::addLayer_l(LayerBase* layer)
{
ssize_t i = mCurrentState.layersSortedByZ.add(
@@ -1555,55 +1552,17 @@ status_t SurfaceFlinger::onTransact(
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
- if (code == 1012) {
- // take screen-shot of the front buffer
- if (UNLIKELY(checkCallingPermission(
- String16("android.permission.READ_FRAME_BUFFER")) == false))
- { // not allowed
- LOGE("Permission Denial: "
- "can't take screenshots from pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
- return PERMISSION_DENIED;
- }
-
- if (UNLIKELY(mSecureFrameBuffer)) {
- LOGE("A secure window is on screen: "
- "can't take screenshots from pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
- return PERMISSION_DENIED;
- }
-
- LOGI("Taking a screenshot...");
-
- LayerScreenshot* l = new LayerScreenshot(this, 0);
-
- Mutex::Autolock _l(mStateLock);
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- l->initStates(hw.getWidth(), hw.getHeight(), 0);
- l->setLayer(INT_MAX);
-
- addLayer_l(l);
- setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
-
- l->takeScreenshot(mStateLock, reply);
-
- removeLayer_l(l);
- setTransactionFlags(eTransactionNeeded);
- return NO_ERROR;
- } else {
- // HARDWARE_TEST stuff...
- if (UNLIKELY(checkCallingPermission(
- String16("android.permission.HARDWARE_TEST")) == false))
- { // not allowed
- LOGE("Permission Denial: pid=%d, uid=%d\n",
- IPCThreadState::self()->getCallingPid(),
- IPCThreadState::self()->getCallingUid());
- return PERMISSION_DENIED;
- }
- int n;
- switch (code) {
+ // HARDWARE_TEST stuff...
+ if (UNLIKELY(checkCallingPermission(
+ String16("android.permission.HARDWARE_TEST")) == false))
+ { // not allowed
+ LOGE("Permission Denial: pid=%d, uid=%d\n",
+ IPCThreadState::self()->getCallingPid(),
+ IPCThreadState::self()->getCallingUid());
+ return PERMISSION_DENIED;
+ }
+ int n;
+ switch (code) {
case 1000: // SHOW_CPU
n = data.readInt32();
mDebugCpu = n ? 1 : 0;
@@ -1636,8 +1595,8 @@ status_t SurfaceFlinger::onTransact(
const DisplayHardware& hw(graphicPlane(0).displayHardware());
mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe
signalEvent();
- }
- return NO_ERROR;
+ }
+ return NO_ERROR;
case 1005: // ask GPU revoke
mGPU->friendlyRevoke();
return NO_ERROR;
@@ -1653,13 +1612,12 @@ status_t SurfaceFlinger::onTransact(
reply->writeInt32(mDebugRegion);
reply->writeInt32(mDebugBackground);
return NO_ERROR;
- case 1013: { // screenshot
+ case 1013: {
Mutex::Autolock _l(mStateLock);
const DisplayHardware& hw(graphicPlane(0).displayHardware());
reply->writeInt32(hw.getPageFlipCount());
}
return NO_ERROR;
- }
}
}
return err;
@@ -1813,10 +1771,33 @@ void GraphicPlane::setTransform(const Transform& tr) {
mGlobalTransform = mOrientationTransform * mTransform;
}
-status_t GraphicPlane::setOrientation(int orientation)
-{
+status_t GraphicPlane::orientationToTransfrom(
+ int orientation, int w, int h, Transform* tr)
+{
float a, b, c, d, x, y;
+ switch (orientation) {
+ case ISurfaceComposer::eOrientationDefault:
+ a=1; b=0; c=0; d=1; x=0; y=0;
+ break;
+ case ISurfaceComposer::eOrientation90:
+ a=0; b=-1; c=1; d=0; x=w; y=0;
+ break;
+ case ISurfaceComposer::eOrientation180:
+ a=-1; b=0; c=0; d=-1; x=w; y=h;
+ break;
+ case ISurfaceComposer::eOrientation270:
+ a=0; b=1; c=-1; d=0; x=0; y=h;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ tr->set(a, b, c, d);
+ tr->set(x, y);
+ return NO_ERROR;
+}
+status_t GraphicPlane::setOrientation(int orientation)
+{
const DisplayHardware& hw(displayHardware());
const float w = hw.getWidth();
const float h = hw.getHeight();
@@ -1830,30 +1811,21 @@ status_t GraphicPlane::setOrientation(int orientation)
// If the rotation can be handled in hardware, this is where
// the magic should happen.
-
- switch (orientation) {
- case ISurfaceComposer::eOrientation90:
- a=0; b=-1; c=1; d=0; x=w; y=0;
- break;
- case ISurfaceComposer::eOrientation180:
- a=-1; b=0; c=0; d=-1; x=w; y=h;
- break;
- case ISurfaceComposer::eOrientation270:
- a=0; b=1; c=-1; d=0; x=0; y=h;
- break;
- case 42: {
+ if (UNLIKELY(orientation == 42)) {
+ float a, b, c, d, x, y;
const float r = (3.14159265f / 180.0f) * 42.0f;
const float si = sinf(r);
const float co = cosf(r);
a=co; b=-si; c=si; d=co;
x = si*(h*0.5f) + (1-co)*(w*0.5f);
y =-si*(w*0.5f) + (1-co)*(h*0.5f);
- } break;
- default:
- return BAD_VALUE;
+ mOrientationTransform.set(a, b, c, d);
+ mOrientationTransform.set(x, y);
+ } else {
+ GraphicPlane::orientationToTransfrom(orientation, w, h,
+ &mOrientationTransform);
}
- mOrientationTransform.set(a, b, c, d);
- mOrientationTransform.set(x, y);
+
mGlobalTransform = mOrientationTransform * mTransform;
return NO_ERROR;
}
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index a242f1a..f7d7764 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -35,11 +35,11 @@
#include <private/ui/LayerState.h>
#include <private/ui/SurfaceFlingerSynchro.h>
+#include "Barrier.h"
+#include "BootAnimation.h"
+#include "CPUGauge.h"
#include "Layer.h"
#include "Tokenizer.h"
-#include "CPUGauge.h"
-#include "BootAnimation.h"
-#include "Barrier.h"
struct copybit_device_t;
struct overlay_device_t;
@@ -48,16 +48,17 @@ namespace android {
// ---------------------------------------------------------------------------
-class BClient;
class Client;
+class BClient;
class DisplayHardware;
+class FreezeLock;
class GPUHardwareInterface;
class IGPUCallback;
class Layer;
class LayerBuffer;
-class RFBServer;
+class LayerOrientationAnim;
+class OrientationAnimation;
class SurfaceHeapManager;
-class FreezeLock;
typedef int32_t ClientID;
@@ -110,6 +111,8 @@ private:
class GraphicPlane
{
public:
+ static status_t orientationToTransfrom(int orientation, int w, int h,
+ Transform* tr);
GraphicPlane();
~GraphicPlane();
@@ -181,7 +184,12 @@ public:
copybit_device_t* getBlitEngine() const;
overlay_control_device_t* getOverlayEngine() const;
+
+ status_t removeLayer(LayerBase* layer);
+ status_t addLayer(LayerBase* layer);
+ status_t invalidateLayerVisibility(LayerBase* layer);
+
private:
friend class BClient;
friend class LayerBase;
@@ -337,7 +345,6 @@ private:
sp<GPUHardwareInterface> mGPU;
GLuint mWormholeTexName;
sp<BootAnimation> mBootAnimation;
- sp<RFBServer> mRFBServer;
nsecs_t mBootTime;
// Can only accessed from the main thread, these members
@@ -352,6 +359,8 @@ private:
bool mFreezeDisplay;
int32_t mFreezeCount;
nsecs_t mFreezeDisplayTime;
+ friend class OrientationAnimation;
+ OrientationAnimation* mOrientationAnimation;
// access protected by mDebugLock
mutable Mutex mDebugLock;
diff --git a/libs/surfaceflinger/VRamHeap.cpp b/libs/surfaceflinger/VRamHeap.cpp
index 77bc576..0ccd71f 100644
--- a/libs/surfaceflinger/VRamHeap.cpp
+++ b/libs/surfaceflinger/VRamHeap.cpp
@@ -35,8 +35,6 @@
#include <utils/MemoryHeapPmem.h>
#include <utils/MemoryHeapBase.h>
-#include <GLES/eglnatives.h>
-
#include "GPUHardware/GPUHardware.h"
#include "SurfaceFlinger.h"
#include "VRamHeap.h"
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 50c6008..b3cbda1 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -84,8 +84,10 @@ void Camera::init()
mRawCallbackCookie = 0;
mJpegCallback = 0;
mJpegCallbackCookie = 0;
- mFrameCallback = 0;
- mFrameCallbackCookie = 0;
+ mPreviewCallback = 0;
+ mPreviewCallbackCookie = 0;
+ mRecordingCallback = 0;
+ mRecordingCallbackCookie = 0;
mErrorCallback = 0;
mErrorCallbackCookie = 0;
mAutoFocusCallback = 0;
@@ -108,6 +110,8 @@ sp<Camera> Camera::connect()
if (c->mCamera != 0) {
c->mCamera->asBinder()->linkToDeath(c);
c->mStatus = NO_ERROR;
+ } else {
+ c.clear();
}
return c;
}
@@ -184,6 +188,15 @@ status_t Camera::startPreview()
return c->startPreview();
}
+// start recording mode, must call setPreviewDisplay first
+status_t Camera::startRecording()
+{
+ LOGV("startRecording");
+ sp <ICamera> c = mCamera;
+ if (c == 0) return NO_INIT;
+ return c->startRecording();
+}
+
// stop preview mode
void Camera::stopPreview()
{
@@ -193,6 +206,24 @@ void Camera::stopPreview()
c->stopPreview();
}
+// stop recording mode
+void Camera::stopRecording()
+{
+ LOGV("stopRecording");
+ sp <ICamera> c = mCamera;
+ if (c == 0) return;
+ c->stopRecording();
+}
+
+// release a recording frame
+void Camera::releaseRecordingFrame(const sp<IMemory>& mem)
+{
+ LOGV("releaseRecordingFrame");
+ sp <ICamera> c = mCamera;
+ if (c == 0) return;
+ c->releaseRecordingFrame(mem);
+}
+
// get preview state
bool Camera::previewEnabled()
{
@@ -202,6 +233,15 @@ bool Camera::previewEnabled()
return c->previewEnabled();
}
+// get recording state
+bool Camera::recordingEnabled()
+{
+ LOGV("recordingEnabled");
+ sp <ICamera> c = mCamera;
+ if (c == 0) return false;
+ return c->recordingEnabled();
+}
+
status_t Camera::autoFocus()
{
LOGV("autoFocus");
@@ -266,14 +306,21 @@ void Camera::setJpegCallback(frame_callback cb, void *cookie)
mJpegCallbackCookie = cookie;
}
-void Camera::setFrameCallback(frame_callback cb, void *cookie, int frame_callback_flag)
+void Camera::setPreviewCallback(frame_callback cb, void *cookie, int flag)
{
- LOGV("setFrameCallback");
- mFrameCallback = cb;
- mFrameCallbackCookie = cookie;
+ LOGV("setPreviewCallback");
+ mPreviewCallback = cb;
+ mPreviewCallbackCookie = cookie;
sp <ICamera> c = mCamera;
if (c == 0) return;
- mCamera->setFrameCallbackFlag(frame_callback_flag);
+ mCamera->setPreviewCallbackFlag(flag);
+}
+
+void Camera::setRecordingCallback(frame_callback cb, void *cookie)
+{
+ LOGV("setRecordingCallback");
+ mRecordingCallback = cb;
+ mRecordingCallbackCookie = cookie;
}
void Camera::setErrorCallback(error_callback cb, void *cookie)
@@ -316,12 +363,21 @@ void Camera::jpegCallback(const sp<IMemory>& picture)
}
}
-// callback from camera service when video frame is ready
-void Camera::frameCallback(const sp<IMemory>& frame)
+// callback from camera service when preview frame is ready
+void Camera::previewCallback(const sp<IMemory>& frame)
{
LOGV("frameCallback");
- if (mFrameCallback) {
- mFrameCallback(frame, mFrameCallbackCookie);
+ if (mPreviewCallback) {
+ mPreviewCallback(frame, mPreviewCallbackCookie);
+ }
+}
+
+// callback from camera service when a recording frame is ready
+void Camera::recordingCallback(const sp<IMemory>& frame)
+{
+ LOGV("recordingCallback");
+ if (mRecordingCallback) {
+ mRecordingCallback(frame, mRecordingCallbackCookie);
}
}
diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp
index 7ca77bb..6c25836 100644
--- a/libs/ui/CameraParameters.cpp
+++ b/libs/ui/CameraParameters.cpp
@@ -24,6 +24,9 @@
namespace android {
+static const char* portrait = "portrait";
+static const char* landscape = "landscape";
+
CameraParameters::CameraParameters()
: mMap()
{
@@ -182,6 +185,23 @@ void CameraParameters::setPreviewFormat(const char *format)
set("preview-format", format);
}
+int CameraParameters::getOrientation() const
+{
+ const char* orientation = get("orientation");
+ if (orientation && !strcmp(orientation, portrait))
+ return CAMERA_ORIENTATION_PORTRAIT;
+ return CAMERA_ORIENTATION_LANDSCAPE;
+}
+
+void CameraParameters::setOrientation(int orientation)
+{
+ if (orientation == CAMERA_ORIENTATION_PORTRAIT) {
+ set("preview-format", portrait);
+ } else {
+ set("preview-format", landscape);
+ }
+}
+
const char *CameraParameters::getPreviewFormat() const
{
return get("preview-format");
diff --git a/libs/ui/EGLDisplaySurface.cpp b/libs/ui/EGLDisplaySurface.cpp
index 44258a8..d06c98b 100644
--- a/libs/ui/EGLDisplaySurface.cpp
+++ b/libs/ui/EGLDisplaySurface.cpp
@@ -42,7 +42,7 @@
#include <linux/msm_mdp.h>
#endif
-#include <GLES/egl.h>
+#include <EGL/egl.h>
#include <pixelflinger/format.h>
@@ -71,8 +71,6 @@ EGLDisplaySurface::EGLDisplaySurface()
egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
- egl_native_window_t::setSwapRectangle = &EGLDisplaySurface::hook_setSwapRectangle;
- egl_native_window_t::nextBuffer = &EGLDisplaySurface::hook_nextBuffer;
egl_native_window_t::connect = 0;
egl_native_window_t::disconnect = 0;
@@ -136,15 +134,6 @@ uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) {
EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
return that->swapBuffers();
}
-uint32_t EGLDisplaySurface::hook_nextBuffer(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- return that->nextBuffer();
-}
-void EGLDisplaySurface::hook_setSwapRectangle(NativeWindowType window,
- int l, int t, int w, int h) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->setSwapRectangle(l, t, w, h);
-}
void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
{
@@ -249,15 +238,6 @@ int32_t EGLDisplaySurface::getPageFlipCount() const
return mPageFlipCount;
}
-uint32_t EGLDisplaySurface::nextBuffer()
-{
- // update the address of the buffer to draw to next
- const GGLSurface& buffer = mFb[mIndex];
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
- return 0;
-}
-
void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
{
#if HAVE_ANDROID_OS
@@ -318,6 +298,59 @@ void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
}
}
+void EGLDisplaySurface::copyFrontToImage(const copybit_image_t& dst)
+{
+#if HAVE_ANDROID_OS
+ if (mBlitEngine) {
+ copybit_image_t src = {
+ w: egl_native_window_t::stride,
+ h: egl_native_window_t::height,
+ format: egl_native_window_t::format,
+ offset: mFb[mIndex].data - mFb[0].data,
+ base: (void*)egl_native_window_t::base,
+ fd: egl_native_window_t::fd
+ };
+ region_iterator it(Region(Rect(
+ egl_native_window_t::width, egl_native_window_t::height)));
+ mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
+ } else
+#endif
+ {
+ uint8_t* const screen_src = mFb[ mIndex].data;
+ const size_t bpp = bytesPerPixel(egl_native_window_t::format);
+ const size_t bpr = egl_native_window_t::stride * bpp;
+ memcpy((char*)dst.base + dst.offset, screen_src,
+ bpr*egl_native_window_t::height);
+ }
+}
+
+void EGLDisplaySurface::copyBackToImage(const copybit_image_t& dst)
+{
+#if HAVE_ANDROID_OS
+ if (mBlitEngine) {
+ copybit_image_t src = {
+ w: egl_native_window_t::stride,
+ h: egl_native_window_t::height,
+ format: egl_native_window_t::format,
+ offset: mFb[1-mIndex].data - mFb[0].data,
+ base: (void*)egl_native_window_t::base,
+ fd: egl_native_window_t::fd
+ };
+ region_iterator it(Region(Rect(
+ egl_native_window_t::width, egl_native_window_t::height)));
+ mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
+ } else
+#endif
+ {
+ uint8_t* const screen_src = mFb[1-mIndex].data;
+ const size_t bpp = bytesPerPixel(egl_native_window_t::format);
+ const size_t bpr = egl_native_window_t::stride * bpp;
+ memcpy((char*)dst.base + dst.offset, screen_src,
+ bpr*egl_native_window_t::height);
+ }
+}
+
+
status_t EGLDisplaySurface::mapFrameBuffer()
{
char const * const device_template[] = {
diff --git a/libs/ui/EGLNativeWindowSurface.cpp b/libs/ui/EGLNativeWindowSurface.cpp
index d55fb70..f1071cf 100644
--- a/libs/ui/EGLNativeWindowSurface.cpp
+++ b/libs/ui/EGLNativeWindowSurface.cpp
@@ -28,7 +28,7 @@
#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
#include <pixelflinger/format.h>
@@ -48,8 +48,6 @@ EGLNativeWindowSurface::EGLNativeWindowSurface(const sp<Surface>& surface)
egl_native_window_t::incRef = &EGLNativeWindowSurface::hook_incRef;
egl_native_window_t::decRef = &EGLNativeWindowSurface::hook_decRef;
egl_native_window_t::swapBuffers = &EGLNativeWindowSurface::hook_swapBuffers;
- egl_native_window_t::nextBuffer = &EGLNativeWindowSurface::hook_nextBuffer;
- egl_native_window_t::setSwapRectangle = &EGLNativeWindowSurface::hook_setSwapRectangle;
egl_native_window_t::connect = &EGLNativeWindowSurface::hook_connect;
egl_native_window_t::disconnect = &EGLNativeWindowSurface::hook_disconnect;
@@ -98,18 +96,6 @@ uint32_t EGLNativeWindowSurface::hook_swapBuffers(NativeWindowType window)
return that->swapBuffers();
}
-uint32_t EGLNativeWindowSurface::hook_nextBuffer(NativeWindowType window)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- return that->nextBuffer();
-}
-
-void EGLNativeWindowSurface::hook_setSwapRectangle(NativeWindowType window, int l, int t, int w, int h)
-{
- EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
- that->setSwapRectangle(l, t, w, h);
-}
-
void EGLNativeWindowSurface::setSwapRectangle(int l, int t, int w, int h)
{
mSurface->setSwapRectangle(Rect(l, t, l+w, t+h));
@@ -138,17 +124,6 @@ uint32_t EGLNativeWindowSurface::swapBuffers()
return 0;
}
-uint32_t EGLNativeWindowSurface::nextBuffer()
-{
- const sp<Surface>& surface(mSurface);
- Surface::SurfaceInfo info;
- surface->nextBuffer(&info);
- // update the address of the buffer to draw to next
- egl_native_window_t::base = intptr_t(info.base);
- egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
- return 0;
-}
-
void EGLNativeWindowSurface::connect()
{
if (!mConnected) {
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 700aa3a..3b29b09 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -71,10 +71,11 @@ static inline int max(int v1, int v2)
EventHub::device_t::device_t(int32_t _id, const char* _path)
: id(_id), path(_path), classes(0)
- , layoutMap(new KeyLayoutMap()), next(NULL) {
+ , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
}
EventHub::device_t::~device_t() {
+ delete [] keyBitmask;
delete layoutMap;
}
@@ -403,6 +404,36 @@ bool EventHub::openPlatformInput(void)
return true;
}
+/*
+ * Inspect the known devices to determine whether physical keys exist for the given
+ * framework-domain key codes.
+ */
+bool EventHub::hasKeys(size_t numCodes, int32_t* keyCodes, uint8_t* outFlags) {
+ for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
+ outFlags[codeIndex] = 0;
+
+ // check each available hardware device for support for this keycode
+ Vector<int32_t> scanCodes;
+ for (int n = 0; (n < mFDCount) && (outFlags[codeIndex] == 0); n++) {
+ if (mDevices[n]) {
+ status_t err = mDevices[n]->layoutMap->findScancodes(keyCodes[codeIndex], &scanCodes);
+ if (!err) {
+ // check the possible scan codes identified by the layout map against the
+ // map of codes actually emitted by the driver
+ for (size_t sc = 0; sc < scanCodes.size(); sc++) {
+ if (test_bit(scanCodes[sc], mDevices[n]->keyBitmask)) {
+ outFlags[codeIndex] = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
// ----------------------------------------------------------------------------
int EventHub::open_device(const char *deviceName)
@@ -527,6 +558,16 @@ int EventHub::open_device(const char *deviceName)
break;
}
}
+ if ((device->classes & CLASS_KEYBOARD) != 0) {
+ device->keyBitmask = new uint8_t[(KEY_MAX+1)/8];
+ if (device->keyBitmask != NULL) {
+ memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
+ } else {
+ delete device;
+ LOGE("out of memory allocating key bitmask");
+ return -1;
+ }
+ }
}
if (test_bit(BTN_MOUSE, key_bitmask)) {
uint8_t rel_bitmask[(REL_MAX+1)/8];
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index 7b0922e..ab0fef1 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -28,7 +28,7 @@ namespace android {
enum {
DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
SET_PREVIEW_DISPLAY,
- SET_FRAME_CALLBACK_FLAG,
+ SET_PREVIEW_CALLBACK_FLAG,
START_PREVIEW,
STOP_PREVIEW,
AUTO_FOCUS,
@@ -38,7 +38,11 @@ enum {
CONNECT,
LOCK,
UNLOCK,
- PREVIEW_ENABLED
+ PREVIEW_ENABLED,
+ START_RECORDING,
+ STOP_RECORDING,
+ RECORDING_ENABLED,
+ RELEASE_RECORDING_FRAME,
};
class BpCamera: public BpInterface<ICamera>
@@ -69,15 +73,15 @@ public:
return reply.readInt32();
}
- // set the frame callback flag to affect how the received frames from
- // preview are handled.
- void setFrameCallbackFlag(int frame_callback_flag)
+ // set the preview callback flag to affect how the received frames from
+ // preview are handled. See Camera.h for details.
+ void setPreviewCallbackFlag(int flag)
{
- LOGV("setFrameCallbackFlag(%d)", frame_callback_flag);
+ LOGV("setPreviewCallbackFlag(%d)", flag);
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
- data.writeInt32(frame_callback_flag);
- remote()->transact(SET_FRAME_CALLBACK_FLAG, data, &reply);
+ data.writeInt32(flag);
+ remote()->transact(SET_PREVIEW_CALLBACK_FLAG, data, &reply);
}
// start preview mode, must call setPreviewDisplay first
@@ -90,6 +94,16 @@ public:
return reply.readInt32();
}
+ // start recording mode, must call setPreviewDisplay first
+ status_t startRecording()
+ {
+ LOGV("startRecording");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(START_RECORDING, data, &reply);
+ return reply.readInt32();
+ }
+
// stop preview mode
void stopPreview()
{
@@ -99,6 +113,24 @@ public:
remote()->transact(STOP_PREVIEW, data, &reply);
}
+ // stop recording mode
+ void stopRecording()
+ {
+ LOGV("stopRecording");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(STOP_RECORDING, data, &reply);
+ }
+
+ void releaseRecordingFrame(const sp<IMemory>& mem)
+ {
+ LOGV("releaseRecordingFrame");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ data.writeStrongBinder(mem->asBinder());
+ remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+ }
+
// check preview state
bool previewEnabled()
{
@@ -109,6 +141,16 @@ public:
return reply.readInt32();
}
+ // check recording state
+ bool recordingEnabled()
+ {
+ LOGV("recordingEnabled");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ remote()->transact(RECORDING_ENABLED, data, &reply);
+ return reply.readInt32();
+ }
+
// auto focus
status_t autoFocus()
{
@@ -202,11 +244,11 @@ status_t BnCamera::onTransact(
reply->writeInt32(setPreviewDisplay(surface));
return NO_ERROR;
} break;
- case SET_FRAME_CALLBACK_FLAG: {
- LOGV("SET_FRAME_CALLBACK_TYPE");
+ case SET_PREVIEW_CALLBACK_FLAG: {
+ LOGV("SET_PREVIEW_CALLBACK_TYPE");
CHECK_INTERFACE(ICamera, data, reply);
- int frame_callback_flag = data.readInt32();
- setFrameCallbackFlag(frame_callback_flag);
+ int callback_flag = data.readInt32();
+ setPreviewCallbackFlag(callback_flag);
return NO_ERROR;
} break;
case START_PREVIEW: {
@@ -215,18 +257,43 @@ status_t BnCamera::onTransact(
reply->writeInt32(startPreview());
return NO_ERROR;
} break;
+ case START_RECORDING: {
+ LOGV("START_RECORDING");
+ CHECK_INTERFACE(ICamera, data, reply);
+ reply->writeInt32(startRecording());
+ return NO_ERROR;
+ } break;
case STOP_PREVIEW: {
LOGV("STOP_PREVIEW");
CHECK_INTERFACE(ICamera, data, reply);
stopPreview();
return NO_ERROR;
} break;
+ case STOP_RECORDING: {
+ LOGV("STOP_RECORDING");
+ CHECK_INTERFACE(ICamera, data, reply);
+ stopRecording();
+ return NO_ERROR;
+ } break;
+ case RELEASE_RECORDING_FRAME: {
+ LOGV("RELEASE_RECORDING_FRAME");
+ CHECK_INTERFACE(ICamera, data, reply);
+ sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
+ releaseRecordingFrame(mem);
+ return NO_ERROR;
+ } break;
case PREVIEW_ENABLED: {
LOGV("PREVIEW_ENABLED");
CHECK_INTERFACE(ICamera, data, reply);
reply->writeInt32(previewEnabled());
return NO_ERROR;
} break;
+ case RECORDING_ENABLED: {
+ LOGV("RECORDING_ENABLED");
+ CHECK_INTERFACE(ICamera, data, reply);
+ reply->writeInt32(recordingEnabled());
+ return NO_ERROR;
+ } break;
case AUTO_FOCUS: {
LOGV("AUTO_FOCUS");
CHECK_INTERFACE(ICamera, data, reply);
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index c5d6d52..4bec9d2 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -28,9 +28,10 @@ enum {
SHUTTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
RAW_CALLBACK,
JPEG_CALLBACK,
- FRAME_CALLBACK,
+ PREVIEW_CALLBACK,
ERROR_CALLBACK,
- AUTOFOCUS_CALLBACK
+ AUTOFOCUS_CALLBACK,
+ RECORDING_CALLBACK,
};
class BpCameraClient: public BpInterface<ICameraClient>
@@ -70,14 +71,24 @@ public:
remote()->transact(JPEG_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
}
- // callback from camera service to app with video frame data
- void frameCallback(const sp<IMemory>& frame)
+ // callback from camera service to app with preview frame data
+ void previewCallback(const sp<IMemory>& frame)
{
- LOGV("frameCallback");
+ LOGV("previewCallback");
Parcel data, reply;
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
data.writeStrongBinder(frame->asBinder());
- remote()->transact(FRAME_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+ remote()->transact(PREVIEW_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ // callback from camera service to app with recording frame data
+ void recordingCallback(const sp<IMemory>& frame)
+ {
+ LOGV("recordingCallback");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+ data.writeStrongBinder(frame->asBinder());
+ remote()->transact(RECORDING_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
}
// callback from camera service to app to report error
@@ -135,11 +146,18 @@ status_t BnCameraClient::onTransact(
jpegCallback(picture);
return NO_ERROR;
} break;
- case FRAME_CALLBACK: {
- LOGV("FRAME_CALLBACK");
+ case PREVIEW_CALLBACK: {
+ LOGV("PREVIEW_CALLBACK");
+ CHECK_INTERFACE(ICameraClient, data, reply);
+ sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
+ previewCallback(frame);
+ return NO_ERROR;
+ } break;
+ case RECORDING_CALLBACK: {
+ LOGV("RECORDING_CALLBACK");
CHECK_INTERFACE(ICameraClient, data, reply);
sp<IMemory> frame = interface_cast<IMemory>(data.readStrongBinder());
- frameCallback(frame);
+ recordingCallback(frame);
return NO_ERROR;
} break;
case ERROR_CALLBACK: {
diff --git a/libs/ui/ISurface.cpp b/libs/ui/ISurface.cpp
index 6f3cd47..d5e9f81 100644
--- a/libs/ui/ISurface.cpp
+++ b/libs/ui/ISurface.cpp
@@ -27,12 +27,33 @@
namespace android {
-enum {
- REGISTER_BUFFERS = IBinder::FIRST_CALL_TRANSACTION,
- UNREGISTER_BUFFERS,
- POST_BUFFER, // one-way transaction
- CREATE_OVERLAY,
-};
+ISurface::BufferHeap::BufferHeap()
+ : w(0), h(0), hor_stride(0), ver_stride(0), format(0),
+ transform(0), flags(0)
+{
+}
+
+ISurface::BufferHeap::BufferHeap(uint32_t w, uint32_t h,
+ int32_t hor_stride, int32_t ver_stride,
+ PixelFormat format, const sp<IMemoryHeap>& heap)
+ : w(w), h(h), hor_stride(hor_stride), ver_stride(ver_stride),
+ format(format), transform(0), flags(0), heap(heap)
+{
+}
+
+ISurface::BufferHeap::BufferHeap(uint32_t w, uint32_t h,
+ int32_t hor_stride, int32_t ver_stride,
+ PixelFormat format, uint32_t transform, uint32_t flags,
+ const sp<IMemoryHeap>& heap)
+ : w(w), h(h), hor_stride(hor_stride), ver_stride(ver_stride),
+ format(format), transform(transform), flags(flags), heap(heap)
+{
+}
+
+
+ISurface::BufferHeap::~BufferHeap()
+{
+}
class BpSurface : public BpInterface<ISurface>
{
@@ -42,17 +63,18 @@ public:
{
}
- virtual status_t registerBuffers(int w, int h, int hstride, int vstride,
- PixelFormat format, const sp<IMemoryHeap>& heap)
+ virtual status_t registerBuffers(const BufferHeap& buffers)
{
Parcel data, reply;
data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
- data.writeInt32(w);
- data.writeInt32(h);
- data.writeInt32(hstride);
- data.writeInt32(vstride);
- data.writeInt32(format);
- data.writeStrongBinder(heap->asBinder());
+ data.writeInt32(buffers.w);
+ data.writeInt32(buffers.h);
+ data.writeInt32(buffers.hor_stride);
+ data.writeInt32(buffers.ver_stride);
+ data.writeInt32(buffers.format);
+ data.writeInt32(buffers.transform);
+ data.writeInt32(buffers.flags);
+ data.writeStrongBinder(buffers.heap->asBinder());
remote()->transact(REGISTER_BUFFERS, data, &reply);
status_t result = reply.readInt32();
return result;
@@ -102,13 +124,16 @@ status_t BnSurface::onTransact(
switch(code) {
case REGISTER_BUFFERS: {
CHECK_INTERFACE(ISurface, data, reply);
- int w = data.readInt32();
- int h = data.readInt32();
- int hs= data.readInt32();
- int vs= data.readInt32();
- PixelFormat f = data.readInt32();
- sp<IMemoryHeap> heap(interface_cast<IMemoryHeap>(data.readStrongBinder()));
- status_t err = registerBuffers(w,h,hs,vs,f,heap);
+ BufferHeap buffer;
+ buffer.w = data.readInt32();
+ buffer.h = data.readInt32();
+ buffer.hor_stride = data.readInt32();
+ buffer.ver_stride= data.readInt32();
+ buffer.format = data.readInt32();
+ buffer.transform = data.readInt32();
+ buffer.flags = data.readInt32();
+ buffer.heap = interface_cast<IMemoryHeap>(data.readStrongBinder());
+ status_t err = registerBuffers(buffer);
reply->writeInt32(err);
return NO_ERROR;
} break;
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
index 605c8ae..b65ed97 100644
--- a/libs/ui/PixelFormat.cpp
+++ b/libs/ui/PixelFormat.cpp
@@ -19,6 +19,18 @@
namespace android {
+size_t PixelFormatInfo::getScanlineSize(unsigned int width) const
+{
+ size_t size;
+ if ((components >= 6) && (components <= 8)) {
+ // YCbCr formats are differents.
+ size = (width * bitsPerPixel)>>3;
+ } else {
+ size = width * bytesPerPixel;
+ }
+ return size;
+}
+
ssize_t bytesPerPixel(PixelFormat format)
{
PixelFormatInfo info;
@@ -47,7 +59,25 @@ status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info)
if (!valid) {
return BAD_INDEX;
}
-
+
+ #define COMPONENT(name) \
+ case GGL_##name: info->components = PixelFormatInfo::name; break;
+
+ switch (i->components) {
+ COMPONENT(ALPHA)
+ COMPONENT(RGB)
+ COMPONENT(RGBA)
+ COMPONENT(LUMINANCE)
+ COMPONENT(LUMINANCE_ALPHA)
+ COMPONENT(Y_CB_CR_SP)
+ COMPONENT(Y_CB_CR_P)
+ COMPONENT(Y_CB_CR_I)
+ default:
+ return BAD_INDEX;
+ }
+
+ #undef COMPONENT
+
info->format = format;
info->bytesPerPixel = i->size;
info->bitsPerPixel = i->bitsPerPixel;
@@ -59,6 +89,7 @@ status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info)
info->l_green = i->gl;
info->h_blue = i->bh;
info->l_blue = i->bl;
+
return NO_ERROR;
}
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
index 26fb22a..2fdaa71 100644
--- a/libs/utils/CallStack.cpp
+++ b/libs/utils/CallStack.cpp
@@ -120,13 +120,18 @@ class MapInfo {
char name[];
};
- const char *map_to_name(uint64_t pc, const char* def) {
+ const char *map_to_name(uint64_t pc, const char* def, uint64_t* start) {
mapinfo* mi = getMapInfoList();
while(mi) {
- if ((pc >= mi->start) && (pc < mi->end))
+ if ((pc >= mi->start) && (pc < mi->end)) {
+ if (start)
+ *start = mi->start;
return mi->name;
+ }
mi = mi->next;
}
+ if (start)
+ *start = 0;
return def;
}
@@ -183,8 +188,15 @@ public:
}
}
- static const char *mapAddressToName(const void* pc, const char* def) {
- return sMapInfo.map_to_name((uint64_t)pc, def);
+ static const char *mapAddressToName(const void* pc, const char* def,
+ void const** start)
+ {
+ uint64_t s;
+ char const* name = sMapInfo.map_to_name(uint64_t(uintptr_t(pc)), def, &s);
+ if (start) {
+ *start = (void*)s;
+ }
+ return name;
}
};
@@ -297,8 +309,9 @@ String8 CallStack::toStringSingleLevel(const char* prefix, int32_t level) const
res.append(name);
res.append(tmp2);
} else {
- name = MapInfo::mapAddressToName(ip, "<unknown>");
- snprintf(tmp, 256, "pc %p %s", ip, name);
+ void const* start = 0;
+ name = MapInfo::mapAddressToName(ip, "<unknown>", &start);
+ snprintf(tmp, 256, "pc %08lx %s", uintptr_t(ip)-uintptr_t(start), name);
res.append(tmp);
}
res.append("\n");
diff --git a/libs/utils/Parcel.cpp b/libs/utils/Parcel.cpp
index 2962b25..4225e67 100644
--- a/libs/utils/Parcel.cpp
+++ b/libs/utils/Parcel.cpp
@@ -658,15 +658,20 @@ status_t Parcel::writeNativeHandle(const native_handle& handle)
status_t err;
err = writeInt32(handle.numFds);
if (err != NO_ERROR) return err;
-
+
err = writeInt32(handle.numInts);
if (err != NO_ERROR) return err;
-
+
for (int i=0 ; err==NO_ERROR && i<handle.numFds ; i++)
err = writeDupFileDescriptor(handle.data[i]);
-
+
+ if (err != NO_ERROR) {
+ LOGD("write native handle, write dup fd failed");
+ return err;
+ }
+
err = write(handle.data + handle.numFds, sizeof(int)*handle.numInts);
-
+
return err;
}
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 5a09fb4..2ad3bfe 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -176,7 +176,9 @@ size_t Res_png_9patch::serializedSize()
void* Res_png_9patch::serialize()
{
- void* newData = malloc(serializedSize());
+ // Use calloc since we're going to leave a few holes in the data
+ // and want this to run cleanly under valgrind
+ void* newData = calloc(1, serializedSize());
serialize(newData);
return newData;
}
@@ -1736,7 +1738,7 @@ bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const
}
ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag,
- uint32_t* outSpecFlags) const
+ uint32_t* outSpecFlags, ResTable_config* outConfig) const
{
if (mError != NO_ERROR) {
return mError;
@@ -1809,7 +1811,7 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
(const Res_value*)(((const uint8_t*)type) + offset);
ResTable_config thisConfig;
thisConfig.copyFromDtoH(type->config);
-
+
if (outSpecFlags != NULL) {
if (typeClass->typeSpecFlags != NULL) {
*outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
@@ -1834,6 +1836,9 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
outValue->res0 = bestValue->res0;
outValue->dataType = bestValue->dataType;
outValue->data = dtohl(bestValue->data);
+ if (outConfig != NULL) {
+ *outConfig = bestItem;
+ }
TABLE_NOISY(size_t len;
printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
bestPackage->header->index,
@@ -3147,13 +3152,13 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
const char16_t* pos = s;
while (pos < end && !failed) {
const char16_t* start = pos;
- end++;
+ pos++;
while (pos < end && *pos != '|') {
pos++;
}
- //printf("Looking for: %s\n", String8(start, pos-start).string());
+ //printf("Looking for: %s\n", String8(start, pos-start).string());
const bag_entry* bagi = bag;
- ssize_t i;
+ ssize_t i;
for (i=0; i<cnt; i++, bagi++) {
if (!Res_INTERNALID(bagi->map.name.ident)) {
//printf("Trying attr #%08x\n", bagi->map.name.ident);
@@ -3181,7 +3186,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
}
unlockBag(bag);
if (!failed) {
- //printf("Final flag value: 0x%lx\n", outValue->data);
+ //printf("Final flag value: 0x%lx\n", outValue->data);
return true;
}
}
@@ -3189,7 +3194,7 @@ bool ResTable::stringToValue(Res_value* outValue, String16* outString,
if (fromAccessor) {
if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
- //printf("Final flag value: 0x%lx\n", outValue->data);
+ //printf("Final flag value: 0x%lx\n", outValue->data);
return true;
}
}
@@ -3484,7 +3489,7 @@ ssize_t ResTable::getEntry(
ResTable_config thisConfig;
thisConfig.copyFromDtoH(thisType->config);
-
+
TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d lang:%c%c=%c%c cnt:%c%c=%c%c "
"orien:%d=%d touch:%d=%d density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d\n",
entryIndex, typeIndex+1, dtohl(thisType->config.size),
diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp
index 1f81cad..aef67f2 100644
--- a/libs/utils/String16.cpp
+++ b/libs/utils/String16.cpp
@@ -244,7 +244,6 @@ void terminate_string16()
// ---------------------------------------------------------------------------
-// Note: not dealing with generating surrogate pairs.
static char16_t* allocFromUTF8(const char* in, size_t len)
{
if (len == 0) return getEmptyString();
@@ -255,7 +254,10 @@ static char16_t* allocFromUTF8(const char* in, size_t len)
while (p < end) {
chars++;
- p += utf8_char_len(*p);
+ int utf8len = utf8_char_len(*p);
+ uint32_t codepoint = utf8_to_utf32((const uint8_t*)p, utf8len);
+ if (codepoint > 0xFFFF) chars++; // this will be a surrogate pair in utf16
+ p += utf8len;
}
SharedBuffer* buf = SharedBuffer::alloc((chars+1)*sizeof(char16_t));
@@ -265,7 +267,19 @@ static char16_t* allocFromUTF8(const char* in, size_t len)
char16_t* d = str;
while (p < end) {
size_t len = utf8_char_len(*p);
- *d++ = (char16_t)utf8_to_utf32((const uint8_t*)p, len);
+ uint32_t codepoint = utf8_to_utf32((const uint8_t*)p, len);
+
+ // Convert the UTF32 codepoint to one or more UTF16 codepoints
+ if (codepoint <= 0xFFFF) {
+ // Single UTF16 character
+ *d++ = (char16_t) codepoint;
+ } else {
+ // Multiple UTF16 characters with surrogates
+ codepoint = codepoint - 0x10000;
+ *d++ = (char16_t) ((codepoint >> 10) + 0xD800);
+ *d++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
+ }
+
p += len;
}
*d = 0;
@@ -388,7 +402,7 @@ status_t String16::setTo(const char16_t* other, size_t len)
->editResize((len+1)*sizeof(char16_t));
if (buf) {
char16_t* str = (char16_t*)buf->data();
- memcpy(str, other, len*sizeof(char16_t));
+ memmove(str, other, len*sizeof(char16_t));
str[len] = 0;
mString = str;
return NO_ERROR;
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
index ab843f6..c50d343 100644
--- a/libs/utils/String8.cpp
+++ b/libs/utils/String8.cpp
@@ -317,8 +317,10 @@ status_t String8::real_append(const char* other, size_t otherLen)
->editResize(myLen+otherLen+1);
if (buf) {
char* str = (char*)buf->data();
- memcpy(str+myLen, other, otherLen+1);
mString = str;
+ str += myLen;
+ memcpy(str, other, otherLen);
+ str[otherLen] = '\0';
return NO_ERROR;
}
return NO_MEMORY;
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 74271ba..9287c0b 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
#define LOG_TAG "libutils.threads"
#include <utils/threads.h>
@@ -838,146 +839,6 @@ void Condition::broadcast()
#error "condition variables not supported on this platform"
#endif
-
-/*
- * ===========================================================================
- * ReadWriteLock class
- * ===========================================================================
- */
-
-#if 0
-#pragma mark -
-#pragma mark ReadWriteLock
-#endif
-
-/*
- * Add a reader. Readers are nice. They share.
- */
-void ReadWriteLock::lockForRead()
-{
- mLock.lock();
- while (mNumWriters > 0) {
- LOG(LOG_DEBUG, "thread", "+++ lockForRead: waiting\n");
- mReadWaiter.wait(mLock);
- }
- assert(mNumWriters == 0);
- mNumReaders++;
-#if defined(PRINT_RENDER_TIMES)
- if (mNumReaders == 1)
- mDebugTimer.start();
-#endif
- mLock.unlock();
-}
-
-/*
- * Try to add a reader. If it doesn't work right away, return "false".
- */
-bool ReadWriteLock::tryLockForRead()
-{
- mLock.lock();
- if (mNumWriters > 0) {
- mLock.unlock();
- return false;
- }
- assert(mNumWriters == 0);
- mNumReaders++;
-#if defined(PRINT_RENDER_TIMES)
- if (mNumReaders == 1)
- mDebugTimer.start();
-#endif
- mLock.unlock();
- return true;
-}
-
-/*
- * Remove a reader.
- */
-void ReadWriteLock::unlockForRead()
-{
- mLock.lock();
- if (mNumReaders == 0) {
- LOG(LOG_WARN, "thread",
- "WARNING: unlockForRead requested, but not locked\n");
- return;
- }
- assert(mNumReaders > 0);
- assert(mNumWriters == 0);
- mNumReaders--;
- if (mNumReaders == 0) { // last reader?
-#if defined(PRINT_RENDER_TIMES)
- mDebugTimer.stop();
- printf(" rdlk held %.3f msec\n",
- (double) mDebugTimer.durationUsecs() / 1000.0);
-#endif
- //printf("+++ signaling writers (if any)\n");
- mWriteWaiter.signal(); // wake one writer (if any)
- }
- mLock.unlock();
-}
-
-/*
- * Add a writer. This requires exclusive access to the object.
- */
-void ReadWriteLock::lockForWrite()
-{
- mLock.lock();
- while (mNumReaders > 0 || mNumWriters > 0) {
- LOG(LOG_DEBUG, "thread", "+++ lockForWrite: waiting\n");
- mWriteWaiter.wait(mLock);
- }
- assert(mNumReaders == 0);
- assert(mNumWriters == 0);
- mNumWriters++;
-#if defined(PRINT_RENDER_TIMES)
- mDebugTimer.start();
-#endif
- mLock.unlock();
-}
-
-/*
- * Try to add a writer. If it doesn't work right away, return "false".
- */
-bool ReadWriteLock::tryLockForWrite()
-{
- mLock.lock();
- if (mNumReaders > 0 || mNumWriters > 0) {
- mLock.unlock();
- return false;
- }
- assert(mNumReaders == 0);
- assert(mNumWriters == 0);
- mNumWriters++;
-#if defined(PRINT_RENDER_TIMES)
- mDebugTimer.start();
-#endif
- mLock.unlock();
- return true;
-}
-
-/*
- * Remove a writer.
- */
-void ReadWriteLock::unlockForWrite()
-{
- mLock.lock();
- if (mNumWriters == 0) {
- LOG(LOG_WARN, "thread",
- "WARNING: unlockForWrite requested, but not locked\n");
- return;
- }
- assert(mNumWriters == 1);
- mNumWriters--;
-#if defined(PRINT_RENDER_TIMES)
- mDebugTimer.stop();
- //printf(" wrlk held %.3f msec\n",
- // (double) mDebugTimer.durationUsecs() / 1000.0);
-#endif
- // mWriteWaiter.signal(); // should other writers get first dibs?
- //printf("+++ signaling readers (if any)\n");
- mReadWaiter.broadcast(); // wake all readers (if any)
- mLock.unlock();
-}
-
// ----------------------------------------------------------------------------
#if 0
@@ -1025,6 +886,8 @@ status_t Thread::run(const char* name, int32_t priority, size_t stack)
// hold a strong reference on ourself
mHoldSelf = this;
+ mRunning = true;
+
bool res;
if (mCanCallJava) {
res = createThreadEtc(_threadLoop,
@@ -1038,14 +901,16 @@ status_t Thread::run(const char* name, int32_t priority, size_t stack)
mStatus = UNKNOWN_ERROR; // something happened!
mRunning = false;
mThread = thread_id_t(-1);
+ mHoldSelf.clear(); // "this" may have gone away after this.
+
+ return UNKNOWN_ERROR;
}
- if (mStatus < 0) {
- // something happened, don't leak
- mHoldSelf.clear();
- }
-
- return mStatus;
+ // Do not refer to mStatus here: The thread is already running (may, in fact
+ // already have exited with a valid mStatus result). The NO_ERROR indication
+ // here merely indicates successfully starting the thread and does not
+ // imply successful termination/execution.
+ return NO_ERROR;
}
int Thread::_threadLoop(void* user)
@@ -1055,20 +920,32 @@ int Thread::_threadLoop(void* user)
wp<Thread> weak(strong);
self->mHoldSelf.clear();
- // we're about to run...
- self->mStatus = self->readyToRun();
- if (self->mStatus!=NO_ERROR || self->mExitPending) {
- // pretend the thread never started...
- self->mExitPending = false;
- self->mRunning = false;
- return 0;
- }
-
- // thread is running now
- self->mRunning = true;
+ bool first = true;
do {
- bool result = self->threadLoop();
+ bool result;
+ if (first) {
+ first = false;
+ self->mStatus = self->readyToRun();
+ result = (self->mStatus == NO_ERROR);
+
+ if (result && !self->mExitPending) {
+ // Binder threads (and maybe others) rely on threadLoop
+ // running at least once after a successful ::readyToRun()
+ // (unless, of course, the thread has already been asked to exit
+ // at that point).
+ // This is because threads are essentially used like this:
+ // (new ThreadSubclass())->run();
+ // The caller therefore does not retain a strong reference to
+ // the thread and the thread would simply disappear after the
+ // successful ::readyToRun() call instead of entering the
+ // threadLoop at least once.
+ result = self->threadLoop();
+ }
+ } else {
+ result = self->threadLoop();
+ }
+
if (result == false || self->mExitPending) {
self->mExitPending = true;
self->mLock.lock();
@@ -1095,24 +972,23 @@ void Thread::requestExit()
status_t Thread::requestExitAndWait()
{
- if (mStatus == OK) {
-
- if (mThread == getThreadId()) {
- LOGW(
- "Thread (this=%p): don't call waitForExit() from this "
- "Thread object's thread. It's a guaranteed deadlock!",
- this);
- return WOULD_BLOCK;
- }
-
- requestExit();
+ if (mThread == getThreadId()) {
+ LOGW(
+ "Thread (this=%p): don't call waitForExit() from this "
+ "Thread object's thread. It's a guaranteed deadlock!",
+ this);
- Mutex::Autolock _l(mLock);
- while (mRunning == true) {
- mThreadExitedCondition.wait(mLock);
- }
- mExitPending = false;
+ return WOULD_BLOCK;
}
+
+ requestExit();
+
+ Mutex::Autolock _l(mLock);
+ while (mRunning == true) {
+ mThreadExitedCondition.wait(mLock);
+ }
+ mExitPending = false;
+
return mStatus;
}
diff --git a/location/data/Android.mk b/location/data/Android.mk
index befd792..794e6c7 100644
--- a/location/data/Android.mk
+++ b/location/data/Android.mk
@@ -13,7 +13,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := nmea
-LOCAL_MODULE_TAGS := development
+LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(local_target_dir)/gps
@@ -27,7 +27,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := location
-LOCAL_MODULE_TAGS := development
+LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(local_target_dir)/gps
@@ -41,7 +41,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := properties
-LOCAL_MODULE_TAGS := development
+LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(local_target_dir)/gps
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index d381f6e..aacf857 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -19,6 +19,7 @@ package android.location;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Printer;
import java.text.DecimalFormat;
import java.util.StringTokenizer;
@@ -81,6 +82,16 @@ public class Location implements Parcelable {
// Scratchpad
private float[] mResults = new float[2];
+ public void dump(Printer pw, String prefix) {
+ pw.println(prefix + "mProvider=" + mProvider + " mTime=" + mTime);
+ pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
+ pw.println(prefix + "mHasAltitude=" + mHasAltitude + " mAltitude=" + mAltitude);
+ pw.println(prefix + "mHasSpeed=" + mHasSpeed + " mSpeed=" + mSpeed);
+ pw.println(prefix + "mHasBearing=" + mHasBearing + " mBearing=" + mBearing);
+ pw.println(prefix + "mHasAccuracy=" + mHasAccuracy + " mAccuracy=" + mAccuracy);
+ pw.println(prefix + "mExtras=" + mExtras);
+ }
+
/**
* Constructs a new Location. By default, time, latitude,
* longitude, and numSatellites are 0; hasAltitude, hasSpeed, and
diff --git a/location/java/com/android/internal/location/CellState.java b/location/java/com/android/internal/location/CellState.java
index 8f6ca1f..eb6535e 100644
--- a/location/java/com/android/internal/location/CellState.java
+++ b/location/java/com/android/internal/location/CellState.java
@@ -168,15 +168,8 @@ public class CellState {
}
}
- public void updateRadioType(TelephonyManager telephonyManager) {
- // Get radio type
- int radioType = telephonyManager.getNetworkType();
- if (radioType == TelephonyManager.NETWORK_TYPE_GPRS ||
- radioType == TelephonyManager.NETWORK_TYPE_EDGE) {
- mRadioType = RADIO_TYPE_GPRS;
- } else if (radioType == TelephonyManager.NETWORK_TYPE_UMTS) {
- mRadioType = RADIO_TYPE_WCDMA;
- }
+ public void updateRadioType(int radioType) {
+ mRadioType = radioType;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "updateRadioType(): " + mLac +"," + mCid + "," + mMnc +"," + mMcc + "," +
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index c6f13c9..6672e29 100644
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -164,16 +164,15 @@ public class GpsLocationProvider extends LocationProviderImpl {
// current setting - 5 minutes
private static final long RETRY_INTERVAL = 5*60*1000;
- private LocationCollector mCollector;
+ private ILocationCollector mCollector;
public static boolean isSupported() {
return native_is_supported();
}
- public GpsLocationProvider(Context context, LocationCollector collector) {
+ public GpsLocationProvider(Context context) {
super(LocationManager.GPS_PROVIDER);
mContext = context;
- mCollector = collector;
mProperties = new Properties();
try {
@@ -183,10 +182,14 @@ public class GpsLocationProvider extends LocationProviderImpl {
stream.close();
mNtpServer = mProperties.getProperty("NTP_SERVER", null);
} catch (IOException e) {
- Log.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE, e);
+ Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
}
}
+ public void setLocationCollector(ILocationCollector collector) {
+ mCollector = collector;
+ }
+
/**
* Returns true if the provider requires access to a
* data network (e.g., the Internet), false otherwise.
@@ -623,7 +626,8 @@ public class GpsLocationProvider extends LocationProviderImpl {
}
// Send to collector
- if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
+ if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG
+ && mCollector != null) {
mCollector.updateLocation(mLocation);
}
}
@@ -644,7 +648,7 @@ public class GpsLocationProvider extends LocationProviderImpl {
if (Config.LOGV) Log.v(TAG, "reportStatus status: " + status);
boolean wasNavigating = mNavigating;
- mNavigating = (status == GPS_STATUS_SESSION_BEGIN || status == GPS_STATUS_ENGINE_ON);
+ mNavigating = (status == GPS_STATUS_SESSION_BEGIN);
if (wasNavigating != mNavigating) {
synchronized(mListeners) {
diff --git a/location/java/com/android/internal/location/ILocationCollector.java b/location/java/com/android/internal/location/ILocationCollector.java
new file mode 100644
index 0000000..8a7cdcc
--- /dev/null
+++ b/location/java/com/android/internal/location/ILocationCollector.java
@@ -0,0 +1,73 @@
+/*
+ * 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.internal.location;
+
+import android.location.Location;
+import android.net.wifi.ScanResult;
+
+import com.android.internal.location.CellState;
+
+import java.util.List;
+
+/**
+ * Listens for GPS and cell/wifi changes and anonymously uploads to server for
+ * improving quality of service of NetworkLocationProvider. This service is only enabled when
+ * the user has enabled the network location provider.
+ *
+ * {@hide}
+ */
+public interface ILocationCollector {
+ /**
+ * Updates GPS location if collection is enabled
+ *
+ * @param location location object
+ */
+ abstract public void updateLocation(Location location);
+
+ /**
+ * Updates wifi scan results if collection is enabled
+ *
+ * @param currentScanResults scan results
+ */
+ abstract public void updateWifiScanResults(List<ScanResult> currentScanResults);
+
+ /**
+ * Updates the status of the network location provider.
+ *
+ * @param enabled true if user has enabled network location based on Google's database
+ * of wifi points and cell towers.
+ */
+ abstract public void updateNetworkProviderStatus(boolean enabled);
+
+ /**
+ * Updates cell tower state. This is usually always up to date so should be uploaded
+ * each time a new location is available.
+ *
+ * @param newState cell state
+ */
+ abstract public void updateCellState(CellState newState);
+
+ /**
+ * Updates the battery health. Battery level is healthy if there is greater than
+ * {@link #MIN_BATTERY_LEVEL} percentage left or if the device is plugged in
+ *
+ * @param scale maximum scale for battery
+ * @param level current level
+ * @param plugged true if device is plugged in
+ */
+ abstract public void updateBatteryState(int scale, int level, boolean plugged);
+}
diff --git a/location/java/com/android/internal/location/INetworkLocationManager.java b/location/java/com/android/internal/location/INetworkLocationManager.java
new file mode 100644
index 0000000..d85ff0a
--- /dev/null
+++ b/location/java/com/android/internal/location/INetworkLocationManager.java
@@ -0,0 +1,37 @@
+ /*
+ * 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.internal.location;
+
+import android.content.Context;
+
+/**
+ * Used to register network location and collection services
+ * with the Location Manager Service.
+ *
+ * {@hide}
+ */
+public interface INetworkLocationManager {
+
+ /* callback to allow installation to occur in Location Manager's thread */
+ public interface InstallCallback {
+ void installNetworkLocationProvider(INetworkLocationManager manager);
+ }
+
+ void setInstallCallback(InstallCallback callback);
+ void setNetworkLocationProvider(INetworkLocationProvider provider);
+ void setLocationCollector(ILocationCollector collector);
+} \ No newline at end of file
diff --git a/location/java/com/android/internal/location/INetworkLocationProvider.java b/location/java/com/android/internal/location/INetworkLocationProvider.java
new file mode 100644
index 0000000..730cb48
--- /dev/null
+++ b/location/java/com/android/internal/location/INetworkLocationProvider.java
@@ -0,0 +1,95 @@
+/*
+ * 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.internal.location;
+
+import android.location.Address;
+import android.location.Location;
+import android.net.wifi.ScanResult;
+
+import com.google.common.io.protocol.ProtoBuf;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Interface for network location provider
+ *
+ * {@hide}
+ */
+public interface INetworkLocationProvider {
+
+ public interface Callback {
+
+ /**
+ * Callback function to notify of a received network location
+ *
+ * @param location location object that is received. may be null if not a valid location
+ * @param successful true if network query was successful, even if no location was found
+ */
+ void locationReceived(Location location, boolean successful);
+ }
+
+ /**
+ * Updates the current cell lock status.
+ *
+ * @param acquired true if a cell lock has been acquired
+ */
+ abstract public void updateCellLockStatus(boolean acquired);
+
+ /**
+ * Notifies the provider if Wifi has been enabled or disabled
+ * by the user
+ *
+ * @param enabled true if wifi is enabled; false otherwise
+ */
+ abstract public void updateWifiEnabledState(boolean enabled);
+
+ /**
+ * Notifies the provider that there are scan results available.
+ *
+ * @param scanResults list of wifi scan results
+ */
+ abstract public void updateWifiScanResults(List<ScanResult> scanResults);
+
+ /**
+ * Adds a list of application clients
+ * Only used by the NetworkLocationProvider
+ *
+ * @param applications list of package names
+ */
+ abstract public void addListener(String[] applications);
+
+ /**
+ * Removes a list of application clients
+ * Only used by the NetworkLocationProvider
+ *
+ * @param applications list of package names
+ */
+ abstract public void removeListener(String[] applications);
+
+
+ abstract public String getFromLocation(double latitude, double longitude, int maxResults,
+ String language, String country, String variant, String appName, List<Address> addrs);
+
+ abstract public String getFromLocationName(String locationName,
+ double lowerLeftLatitude, double lowerLeftLongitude,
+ double upperRightLatitude, double upperRightLongitude, int maxResults,
+ String language, String country, String variant, String appName, List<Address> addrs);
+
+}
diff --git a/location/java/com/android/internal/location/LocationCache.java b/location/java/com/android/internal/location/LocationCache.java
deleted file mode 100644
index 079c9c7..0000000
--- a/location/java/com/android/internal/location/LocationCache.java
+++ /dev/null
@@ -1,608 +0,0 @@
-// Copyright 2007 The Android Open Source Project
-
-package com.android.internal.location;
-
-import java.io.DataInput;
-import java.io.DataInputStream;
-import java.io.DataOutput;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import android.location.Location;
-import android.location.LocationManager;
-import android.net.wifi.ScanResult;
-import android.os.Bundle;
-import android.util.Log;
-
-/**
- * Data store to cache cell-id and wifi locations from the network
- *
- * {@hide}
- */
-public class LocationCache {
- private static final String TAG = "LocationCache";
-
- // Version of cell cache
- private static final int CACHE_DB_VERSION = 1;
-
- // Don't save cache more than once every minute
- private static final long SAVE_FREQUENCY = 60 * 1000;
-
- // Location of the cache file;
- private static final String mCellCacheFile = "cache.cell";
- private static final String mWifiCacheFile = "cache.wifi";
-
- // Maximum time (in millis) that a record is valid for, before it needs
- // to be refreshed from the server.
- private static final long MAX_CELL_REFRESH_RECORD_AGE = 12 * 60 * 60 * 1000; // 12 hours
- private static final long MAX_WIFI_REFRESH_RECORD_AGE = 48 * 60 * 60 * 1000; // 48 hours
-
- // Cache sizes
- private static final int MAX_CELL_RECORDS = 50;
- private static final int MAX_WIFI_RECORDS = 200;
-
- // Cache constants
- private static final long CELL_SMOOTHING_WINDOW = 30 * 1000; // 30 seconds
- private static final int WIFI_MIN_AP_REQUIRED = 2;
- private static final int WIFI_MAX_MISS_ALLOWED = 5;
- private static final int MAX_ACCURACY_ALLOWED = 5000; // 5km
-
- // Caches
- private final Cache<Record> mCellCache;
- private final Cache<Record> mWifiCache;
-
- // Currently calculated centroids
- private final LocationCentroid mCellCentroid = new LocationCentroid();
- private final LocationCentroid mWifiCentroid = new LocationCentroid();
-
- // Extra key and values
- private final String EXTRA_KEY_LOCATION_TYPE = "networkLocationType";
- private final String EXTRA_VALUE_LOCATION_TYPE_CELL = "cell";
- private final String EXTRA_VALUE_LOCATION_TYPE_WIFI = "wifi";
-
- public LocationCache() {
- mCellCache = new Cache<Record>(LocationManager.SYSTEM_DIR, mCellCacheFile,
- MAX_CELL_RECORDS, MAX_CELL_REFRESH_RECORD_AGE);
- mWifiCache = new Cache<Record>(LocationManager.SYSTEM_DIR, mWifiCacheFile,
- MAX_WIFI_RECORDS, MAX_WIFI_REFRESH_RECORD_AGE);
- }
-
- /**
- * Looks up network location on device cache
- *
- * @param cellState primary cell state
- * @param cellHistory history of cell states
- * @param scanResults wifi scan results
- * @param result location object to fill if location is found
- * @return true if cache was able to answer query (successfully or not), false if call to
- * server is required
- */
- public synchronized boolean lookup(CellState cellState, List<CellState> cellHistory,
- List<ScanResult> scanResults, Location result) {
-
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, "including cell:" + (cellState != null) +
- ", wifi:" + ((scanResults != null)? scanResults.size() : "null"));
- }
-
- long now = System.currentTimeMillis();
-
- mCellCentroid.reset();
- mWifiCentroid.reset();
-
- if (cellState != null && cellState.isValid()) {
- String primaryCellKey = getCellCacheKey(cellState.getMcc(), cellState.getMnc(),
- cellState.getLac(), cellState.getCid());
- Record record = mCellCache.lookup(primaryCellKey);
-
- // Relax MCC/MNC condition
- if (record == null) {
- primaryCellKey = getCellCacheKey(-1, -1, cellState.getLac(), cellState.getCid());
- record = mCellCache.lookup(primaryCellKey);
- }
-
- if (record == null) {
- // Make a server request if primary cell doesn't exist in DB
- return false;
- }
-
- if (record.isValid()) {
- mCellCentroid.addLocation(record.getLat(), record.getLng(), record.getAccuracy(),
- record.getConfidence());
- }
- }
-
- if (cellHistory != null) {
- for (CellState historicalCell : cellHistory) {
- // Cell location might need to be smoothed if you are on the border of two cells
- if (now - historicalCell.getTime() < CELL_SMOOTHING_WINDOW) {
- String historicalCellKey = getCellCacheKey(historicalCell.getMcc(),
- historicalCell.getMnc(), historicalCell.getLac(), historicalCell.getCid());
- Record record = mCellCache.lookup(historicalCellKey);
-
- // Relax MCC/MNC condition
- if (record == null) {
- historicalCellKey = getCellCacheKey(-1, -1, historicalCell.getLac(),
- historicalCell.getCid());
- record = mCellCache.lookup(historicalCellKey);
- }
-
- if (record != null && record.isValid()) {
- mCellCentroid.addLocation(record.getLat(), record.getLng(),
- record.getAccuracy(), record.getConfidence());
- }
- }
- }
- }
-
- if (scanResults != null) {
- int miss = 0;
- for (ScanResult scanResult : scanResults) {
- String wifiKey = scanResult.BSSID;
- Record record = mWifiCache.lookup(wifiKey);
- if (record == null) {
- miss++;
- } else {
- if (record.isValid()) {
- mWifiCentroid.addLocation(record.getLat(), record.getLng(),
- record.getAccuracy(), record.getConfidence());
- }
- }
- }
-
- if (mWifiCentroid.getNumber() >= WIFI_MIN_AP_REQUIRED) {
- // Try to return best out of the available cell or wifi location
- } else if (miss > Math.min(WIFI_MAX_MISS_ALLOWED, (scanResults.size()+1)/2)) {
- // Make a server request
- return false;
- } else {
- // Don't use wifi location, only consider using cell location
- mWifiCache.save();
- mWifiCentroid.reset();
- }
- }
-
- if (mCellCentroid.getNumber() > 0) {
- mCellCache.save();
- }
- if (mWifiCentroid.getNumber() > 0) {
- mWifiCache.save();
- }
-
- int cellAccuracy = mCellCentroid.getAccuracy();
- int wifiAccuracy = mWifiCentroid.getAccuracy();
-
- int cellConfidence = mCellCentroid.getConfidence();
- int wifiConfidence = mWifiCentroid.getConfidence();
-
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, "cellAccuracy:" + cellAccuracy+ ", wifiAccuracy:" + wifiAccuracy);
- }
-
- if ((mCellCentroid.getNumber() == 0 || cellAccuracy > MAX_ACCURACY_ALLOWED) &&
- (mWifiCentroid.getNumber() == 0 || wifiAccuracy > MAX_ACCURACY_ALLOWED)) {
- // Return invalid location if neither location is valid
- result.setAccuracy(-1);
-
- // don't make server request
- return true;
- }
-
- float[] distance = new float[1];
- Location.distanceBetween(mCellCentroid.getCentroidLat(), mCellCentroid.getCentroidLng(),
- mWifiCentroid.getCentroidLat(), mWifiCentroid.getCentroidLng(),
- distance);
-
- boolean consistent = distance[0] <= (cellAccuracy + wifiAccuracy);
-
- boolean useCell = true;
-
- if (consistent) {
- // If consistent locations, use one with greater accuracy
- useCell = (cellAccuracy <= wifiAccuracy);
- } else {
- // If inconsistent locations, use one with greater confidence
- useCell = (cellConfidence >= wifiConfidence);
- }
-
- if (useCell) {
- // Use cell results
- result.setAccuracy(cellAccuracy);
- result.setLatitude(mCellCentroid.getCentroidLat());
- result.setLongitude(mCellCentroid.getCentroidLng());
- result.setTime(now);
-
- Bundle extras = result.getExtras() == null ? new Bundle() : result.getExtras();
- extras.putString(EXTRA_KEY_LOCATION_TYPE, EXTRA_VALUE_LOCATION_TYPE_CELL);
- result.setExtras(extras);
-
- } else {
- // Use wifi results
- result.setAccuracy(wifiAccuracy);
- result.setLatitude(mWifiCentroid.getCentroidLat());
- result.setLongitude(mWifiCentroid.getCentroidLng());
- result.setTime(now);
-
- Bundle extras = result.getExtras() == null ? new Bundle() : result.getExtras();
- extras.putString(EXTRA_KEY_LOCATION_TYPE, EXTRA_VALUE_LOCATION_TYPE_WIFI);
- result.setExtras(extras);
-
- }
-
- // don't make a server request
- return true;
- }
-
- public synchronized void insert(int mcc, int mnc, int lac, int cid, double lat, double lng,
- int accuracy, int confidence, long time) {
- String key = getCellCacheKey(mcc, mnc, lac, cid);
- if (accuracy <= 0) {
- mCellCache.insert(key, new Record());
- } else {
- mCellCache.insert(key, new Record(accuracy, confidence, lat, lng, time));
- }
- }
-
- public synchronized void insert(String bssid, double lat, double lng, int accuracy,
- int confidence, long time) {
- if (accuracy <= 0) {
- mWifiCache.insert(bssid, new Record());
- } else {
- mWifiCache.insert(bssid, new Record(accuracy, confidence, lat, lng, time));
- }
- }
-
- public synchronized void save() {
- mCellCache.save();
- mWifiCache.save();
- }
-
- /**
- * Cell or Wifi location record
- */
- public static class Record {
-
- private final double lat;
- private final double lng;
- private final int accuracy;
- private final int confidence;
-
- // Time (since the epoch) of original reading.
- private final long originTime;
-
- public static Record read(DataInput dataInput) throws IOException {
- final int accuracy = dataInput.readInt();
- final int confidence = dataInput.readInt();
- final double lat = dataInput.readDouble();
- final double lng = dataInput.readDouble();
- final long readingTime = dataInput.readLong();
- return new Record(accuracy, confidence, lat, lng, readingTime);
- }
-
- /**
- * Creates an "invalid" record indicating there was no location data
- * available for the given data
- */
- public Record() {
- this(-1, 0, 0, 0, System.currentTimeMillis());
- }
-
- /**
- * Creates a Record
- *
- * @param accuracy acuracy in meters. If < 0, then this is an invalid record.
- * @param confidence confidence (0-100)
- * @param lat latitude
- * @param lng longitude
- * @param time Time of the original location reading from the server
- */
- public Record(int accuracy, int confidence, double lat, double lng, long time) {
- this.accuracy = accuracy;
- this.confidence = confidence;
- this.originTime = time;
- this.lat = lat;
- this.lng = lng;
- }
-
- public double getLat() {
- return lat;
- }
-
- public double getLng() {
- return lng;
- }
-
- public int getAccuracy() {
- return accuracy;
- }
-
- public int getConfidence() {
- return confidence;
- }
-
- public boolean isValid() {
- return accuracy > 0;
- }
-
- public long getTime() {
- return originTime;
- }
-
- public void write(DataOutput dataOut) throws IOException {
- dataOut.writeInt(accuracy);
- dataOut.writeInt(confidence);
- dataOut.writeDouble(lat);
- dataOut.writeDouble(lng);
- dataOut.writeLong(originTime);
- }
-
- @Override
- public String toString() {
- return lat + "," + lng + "," + originTime +"," + accuracy + "," + confidence;
- }
- }
-
- public class Cache<T> extends LinkedHashMap {
- private final long mMaxAge;
- private final int mCapacity;
- private final String mDir;
- private final String mFile;
- private long mLastSaveTime = 0;
-
- public Cache(String dir, String file, int capacity, long maxAge) {
- super(capacity + 1, 1.1f, true);
- this.mCapacity = capacity;
- this.mDir = dir;
- this.mFile = file;
- this.mMaxAge = maxAge;
- load();
- }
-
- private LocationCache.Record lookup(String key) {
- LocationCache.Record result = (LocationCache.Record) get(key);
-
- if (result == null) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, "lookup: " + key + " failed");
- }
- return null;
- }
-
- // Cache entry needs refresh
- if (result.getTime() + mMaxAge < System.currentTimeMillis()) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, "lookup: " + key + " expired");
- }
- return null;
- }
-
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, "lookup: " + key + " " + result.toString());
- }
-
- return result;
- }
-
- private void insert(String key, LocationCache.Record record) {
- remove(key);
- put(key, record);
-
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, "insert: " + key + " " + record.toString());
- }
- }
-
- @Override
- protected boolean removeEldestEntry(Map.Entry eldest) {
- // Remove cache entries when it has more than capacity
- return size() > mCapacity;
- }
-
- private void load() {
- FileInputStream istream;
- try {
- File f = new File(mDir, mFile);
- istream = new FileInputStream(f);
- } catch (FileNotFoundException e) {
- // No existing DB - return new CellCache
- return;
- }
-
- DataInputStream dataInput = new DataInputStream(istream);
-
- try {
- int version = dataInput.readUnsignedShort();
- if (version != CACHE_DB_VERSION) {
- // Ignore records - invalid version ID.
- dataInput.close();
- return;
- }
- int records = dataInput.readUnsignedShort();
-
- for (int i = 0; i < records; i++) {
- final String key = dataInput.readUTF();
- final LocationCache.Record record = LocationCache.Record.read(dataInput);
- //Log.d(TAG, key + " " + record.toString());
- put(key, record);
- }
-
- dataInput.close();
- } catch (IOException e) {
- // Something's corrupted - return a new CellCache
- }
- }
-
- private void save() {
- long now = System.currentTimeMillis();
- if (mLastSaveTime != 0 && (now - mLastSaveTime < SAVE_FREQUENCY)) {
- // Don't save to file more often than SAVE_FREQUENCY
- return;
- }
-
- FileOutputStream ostream;
-
- File systemDir = new File(mDir);
- if (!systemDir.exists()) {
- if (!systemDir.mkdirs()) {
- Log.e(TAG, "Cache.save(): couldn't create directory");
- return;
- }
- }
-
- try {
- File f = new File(mDir, mFile);
- ostream = new FileOutputStream(f);
- } catch (FileNotFoundException e) {
- Log.d(TAG, "Cache.save(): unable to create cache file", e);
- return;
- }
-
- DataOutputStream dataOut = new DataOutputStream(ostream);
- try {
- dataOut.writeShort(CACHE_DB_VERSION);
-
- dataOut.writeShort(size());
-
- for (Iterator iter = entrySet().iterator(); iter.hasNext();) {
- Map.Entry entry = (Map.Entry) iter.next();
- String key = (String) entry.getKey();
- LocationCache.Record record = (LocationCache.Record) entry.getValue();
- dataOut.writeUTF(key);
- record.write(dataOut);
- }
-
- dataOut.close();
- mLastSaveTime = now;
-
- } catch (IOException e) {
- Log.e(TAG, "Cache.save(): unable to write cache", e);
- // This should never happen
- }
- }
- }
-
- public class LocationCentroid {
-
- double mLatSum = 0;
- double mLngSum = 0;
- int mNumber = 0;
- int mConfidence = 0;
-
- double mCentroidLat = 0;
- double mCentroidLng = 0;
-
- // Probably never have to calculate centroid for more than 10 locations
- final static int MAX_SIZE = 10;
- double[] mLats = new double[MAX_SIZE];
- double[] mLngs = new double[MAX_SIZE];
- int[] mRadii = new int[MAX_SIZE];
-
- LocationCentroid() {
- reset();
- }
-
- public void reset() {
- mLatSum = 0;
- mLngSum = 0;
- mNumber = 0;
- mConfidence = 0;
-
- mCentroidLat = 0;
- mCentroidLng = 0;
-
- for (int i = 0; i < MAX_SIZE; i++) {
- mLats[i] = 0;
- mLngs[i] = 0;
- mRadii[i] = 0;
- }
- }
-
- public void addLocation(double lat, double lng, int accuracy, int confidence) {
- if (mNumber < MAX_SIZE && accuracy <= MAX_ACCURACY_ALLOWED) {
- mLatSum += lat;
- mLngSum += lng;
- if (confidence > mConfidence) {
- mConfidence = confidence;
- }
-
- mLats[mNumber] = lat;
- mLngs[mNumber] = lng;
- mRadii[mNumber] = accuracy;
- mNumber++;
- }
- }
-
- public int getNumber() {
- return mNumber;
- }
-
- public double getCentroidLat() {
- if (mCentroidLat == 0 && mNumber != 0) {
- mCentroidLat = mLatSum/mNumber;
- }
- return mCentroidLat;
- }
-
- public double getCentroidLng() {
- if (mCentroidLng == 0 && mNumber != 0) {
- mCentroidLng = mLngSum/mNumber;
- }
- return mCentroidLng;
- }
-
- public int getConfidence() {
- return mConfidence;
- }
-
- public int getAccuracy() {
- if (mNumber == 0) {
- return 0;
- }
-
- if (mNumber == 1) {
- return mRadii[0];
- }
-
- double cLat = getCentroidLat();
- double cLng = getCentroidLng();
-
- int meanDistanceSum = 0;
- int smallestCircle = MAX_ACCURACY_ALLOWED;
- int smallestCircleDistance = MAX_ACCURACY_ALLOWED;
- float[] distance = new float[1];
- boolean outlierExists = false;
-
- for (int i = 0; i < mNumber; i++) {
- Location.distanceBetween(cLat, cLng, mLats[i], mLngs[i], distance);
- meanDistanceSum += (int)distance[0];
- if (distance[0] > mRadii[i]) {
- outlierExists = true;
- }
- if (mRadii[i] < smallestCircle) {
- smallestCircle = mRadii[i];
- smallestCircleDistance = (int)distance[0];
- }
- }
-
- if (outlierExists) {
- return meanDistanceSum/mNumber;
- } else {
- return Math.max(smallestCircle, smallestCircleDistance);
- }
- }
-
- }
-
- private String getCellCacheKey(int mcc, int mnc, int lac, int cid) {
- return mcc + ":" + mnc + ":" + lac + ":" + cid;
- }
-
-}
diff --git a/location/java/com/android/internal/location/LocationCollector.java b/location/java/com/android/internal/location/LocationCollector.java
deleted file mode 100644
index 39f432f..0000000
--- a/location/java/com/android/internal/location/LocationCollector.java
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location;
-
-import com.android.internal.location.protocol.GDebugProfile;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-
-import android.location.Location;
-import android.net.wifi.ScanResult;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.util.Log;
-
-/**
- * Listens for GPS and cell/wifi changes and anonymously uploads to server for
- * improving quality of service of NetworkLocationProvider. This service is only enabled when
- * the user has enabled the network location provider.
- *
- * {@hide}
- */
-public class LocationCollector {
-
- private static final String TAG = "LocationCollector";
-
- // last location valid for 12 minutes
- private static final long MIN_VALID_LOCATION_TIME = 12 * 60 * 1000L;
-
- // don't send wifi more than every 10 min
- private static final long MIN_TIME_BETWEEN_WIFI_REPORTS = 10 * 60 * 1000L;
-
- // atleast 5 changed APs for wifi collection
- private static final int MIN_CHANGED_WIFI_POINTS = 5;
-
- // don't collect if distance moved less than 200 meters
- private static final int MIN_DISTANCE_BETWEEN_REPORTS = 200;
-
- // don't collect if battery level less than 20%
- private static final double MIN_BATTERY_LEVEL = 0.2;
-
- // if battery level is greater than 90% and plugged in, collect more frequently
- private static final double CHARGED_BATTERY_LEVEL = 0.9;
-
- // collect bursts every 15 minutes (running on battery)
- private static final long BURST_REST_TIME_ON_BATTERY = 15 * 60 * 1000L;
-
- // collect bursts every 8 minutes (when plugged in)
- private static final long BURST_REST_TIME_PLUGGED = 8 * 60 * 1000L;
-
- // collect burst samples every 12 seconds
- private static final int BURST_MEASUREMENT_INTERVAL = 12 * 1000;
-
- // collect 11 burst samples before resting (11 samples every 12 seconds = 2 minute bursts)
- private static final int BURST_NUM_SAMPLES = 11;
-
- // don't collect bursts if user in same loc for 2 bursts
- private static final int MAX_BURSTS_FROM_SAME_LOCATION = 2;
-
- // don't send more than 2 bursts if user hasn't moved more than 25 meters
- private static final int MIN_DISTANCE_BETWEEN_BURSTS = 25;
-
- // Cell State
- private CellState mCellState = null;
- private CellUploads mCellUploads = new CellUploads();
-
- // GPS state
- private Location mLastKnownLocation = null;
- private Location mLastUploadedLocation = null;
- private long mLastKnownLocationTime = 0;
- private long mLastUploadedLocationTime = 0;
-
- // Burst state
- private Location mLastBurstLocation = null;
- private long mLastBurstEndTime = 0;
- private long mCurrentBurstStartTime = 0;
- private int mCurrentBurstNumSamples = 0;
- private int mNumBurstsFromLastLocation = 0;
-
- // WiFi state
- private List<ScanResult> mWifiLastScanResults = null;
- private List<ScanResult> mWifiCurrentScanResults = null;
- private long mLastWifiScanElapsedTime = 0;
- private long mLastWifiScanRealTime = 0;
- private boolean mWifiUploadedWithoutLocation = false;
-
- // Collection state
- private boolean mNetworkProviderIsEnabled = true;
- private boolean mBatteryLevelIsHealthy = true;
- private boolean mBatteryChargedAndPlugged = false;
-
- // Location masf service
- private LocationMasfClient mMasfClient;
-
- public LocationCollector(LocationMasfClient masfClient) {
- mMasfClient = masfClient;
- }
-
- /**
- * Updates cell tower state. This is usually always up to date so should be uploaded
- * each time a new location is available.
- *
- * @param newState cell state
- */
- public synchronized void updateCellState(CellState newState) {
- if (newState == null) {
- throw new IllegalArgumentException("cell state is null");
- }
-
- if (!newState.isValid()) {
- return;
- }
-
- if (mCellState != null && mCellState.equals(newState)) {
- return;
- }
-
- mCellState = newState;
- log("updateCellState(): Updated to " + mCellState.getCid() + "," + mCellState.getLac());
-
- if (isCollectionEnabled()) {
- addToQueue(GDebugProfile.TRIGGER_CELL_CHANGE);
- }
- }
-
- /**
- * Updates GPS location if collection is enabled
- *
- * @param location location object
- */
- public synchronized void updateLocation(Location location) {
-
- // Don't do anything if collection is disabled
- if (!isCollectionEnabled()) {
- return;
- }
-
- long now = SystemClock.elapsedRealtime();
-
- // Update last known location
- if (mLastKnownLocation == null) {
- mLastKnownLocation = new Location(location);
- } else {
- mLastKnownLocation.set(location);
- }
- mLastKnownLocationTime = now;
-
- // Burst rest time depends on battery state
- long restTime = BURST_REST_TIME_ON_BATTERY;
- if (mBatteryChargedAndPlugged) {
- restTime = BURST_REST_TIME_PLUGGED;
- }
-
- int trigger;
-
- // In burst mode if either first burst or enough time has passed since last burst
- if (mLastBurstEndTime == 0 || (now - mLastBurstEndTime > restTime)) {
-
- // If location is too recent, then don't do anything!
- if (now - mLastUploadedLocationTime < BURST_MEASUREMENT_INTERVAL) {
- return;
- }
-
- int distanceFromLastBurst = -1;
- if (mLastBurstLocation != null) {
- distanceFromLastBurst = (int) mLastBurstLocation.distanceTo(location);
-
- // Too many bursts from same location, don't upload
- if (distanceFromLastBurst < MIN_DISTANCE_BETWEEN_BURSTS &&
- mNumBurstsFromLastLocation >= MAX_BURSTS_FROM_SAME_LOCATION) {
- log("NO UPLOAD: Too many bursts from same location.");
- return;
- }
- }
-
- if (mCurrentBurstStartTime == 0) {
- // Start the burst!
- mCurrentBurstStartTime = now;
- mCurrentBurstNumSamples = 1;
- trigger = GDebugProfile.TRIGGER_COLLECTION_START_BURST;
-
- } else if (now - mCurrentBurstStartTime > restTime) {
- // Burst got old, start a new one
- mCurrentBurstStartTime = now;
- mCurrentBurstNumSamples = 1;
- trigger = GDebugProfile.TRIGGER_COLLECTION_RESTART_BURST;
-
- } else if (mCurrentBurstNumSamples == BURST_NUM_SAMPLES - 1) {
- // Finished a burst
- mLastBurstEndTime = now;
- mCurrentBurstStartTime = 0;
- mCurrentBurstNumSamples = 0;
-
- // Make sure we don't upload too many bursts from same location
- if (mLastBurstLocation == null) {
- mLastBurstLocation = new Location(location);
- mNumBurstsFromLastLocation = 1;
- trigger = GDebugProfile.TRIGGER_COLLECTION_END_BURST;
-
- } else {
-
- if (distanceFromLastBurst != -1 &&
- distanceFromLastBurst < MIN_DISTANCE_BETWEEN_BURSTS) {
- // User hasnt moved much from last location, keep track of count,
- // don't update last burst loc
- mNumBurstsFromLastLocation++;
- trigger = GDebugProfile.TRIGGER_COLLECTION_END_BURST_AT_SAME_LOCATION;
-
- } else {
- // User has moved enough, update last burst loc
- mLastBurstLocation.set(location);
- mNumBurstsFromLastLocation = 1;
- trigger = GDebugProfile.TRIGGER_COLLECTION_END_BURST;
- }
- }
-
- } else {
- // Increment burst sample count
- mCurrentBurstNumSamples++;
- trigger = GDebugProfile.TRIGGER_COLLECTION_CONTINUE_BURST;
- }
-
- } else if (mLastUploadedLocation != null
- && (mLastUploadedLocation.distanceTo(location) > MIN_DISTANCE_BETWEEN_REPORTS)) {
- // If not in burst mode but has moved a reasonable distance, upload!
- trigger = GDebugProfile.TRIGGER_COLLECTION_MOVED_DISTANCE;
-
- } else {
- // Not in burst mode or hasn't moved enough
- log("NO UPLOAD: Not in burst or moving mode. Resting for " + restTime + " ms");
- return;
- }
-
- log("updateLocation(): Updated location with trigger " + trigger);
- addToQueue(trigger);
- }
-
- /**
- * Updates wifi scan results if collection is enabled
- *
- * @param currentScanResults scan results
- */
- public synchronized void updateWifiScanResults(List<ScanResult> currentScanResults) {
- if (!isCollectionEnabled()) {
- return;
- }
-
- if (currentScanResults == null || currentScanResults.size() == 0) {
- return;
- }
-
- long now = SystemClock.elapsedRealtime();
-
- // If wifi scan recently received, then don't upload
- if ((mLastWifiScanElapsedTime != 0)
- && ((now - mLastWifiScanElapsedTime) <= MIN_TIME_BETWEEN_WIFI_REPORTS)) {
- return;
- }
-
- if (mWifiCurrentScanResults == null) {
- mWifiCurrentScanResults = new ArrayList<ScanResult>();
- } else {
- mWifiCurrentScanResults.clear();
- }
- mWifiCurrentScanResults.addAll(currentScanResults);
-
- // If wifi has changed enough
- boolean wifiHasChanged = false;
-
- if (mWifiLastScanResults == null) {
- wifiHasChanged = true;
- } else {
- // Calculate the number of new AP points received
- HashSet<String> previous = new HashSet<String>();
- HashSet<String> current = new HashSet<String>();
- for (ScanResult s : mWifiLastScanResults) {
- previous.add(s.BSSID);
- }
- for (ScanResult s : mWifiCurrentScanResults) {
- current.add(s.BSSID);
- }
- current.removeAll(previous);
-
- if (current.size() >
- Math.min(MIN_CHANGED_WIFI_POINTS, ((mWifiCurrentScanResults.size()+1)/2))) {
- wifiHasChanged = true;
- }
- }
-
- if (!wifiHasChanged) {
- log("updateWifiScanResults(): Wifi results haven't changed much");
- return;
- }
-
- if (mWifiLastScanResults == null) {
- mWifiLastScanResults = new ArrayList<ScanResult>();
- } else {
- mWifiLastScanResults.clear();
- }
- mWifiLastScanResults.addAll(mWifiCurrentScanResults);
-
- mLastWifiScanElapsedTime = now;
- mLastWifiScanRealTime = System.currentTimeMillis();
-
- log("updateWifiScanResults(): Updated " + mWifiLastScanResults.size() + " APs");
- addToQueue(GDebugProfile.TRIGGER_WIFI_CHANGE);
- }
-
- /**
- * Updates the status of the network location provider.
- *
- * @param enabled true if user has enabled network location based on Google's database
- * of wifi points and cell towers.
- */
- public void updateNetworkProviderStatus(boolean enabled) {
- mNetworkProviderIsEnabled = enabled;
- }
-
- /**
- * Updates the battery health. Battery level is healthy if there is greater than
- * {@link #MIN_BATTERY_LEVEL} percentage left or if the device is plugged in
- *
- * @param scale maximum scale for battery
- * @param level current level
- * @param plugged true if device is plugged in
- */
- public void updateBatteryState(int scale, int level, boolean plugged) {
- mBatteryLevelIsHealthy = (plugged || (level >= (MIN_BATTERY_LEVEL * scale)));
- mBatteryChargedAndPlugged = (plugged && (level >= (CHARGED_BATTERY_LEVEL * scale)));
- }
-
- /**
- * Anonymous data collection is only enabled when the user has enabled the network
- * location provider, i.e. is making use of the service and if the device battery level
- * is healthy.
- *
- * Additionally, data collection will *never* happen if the system
- * property ro.com.google.locationfeatures is not set.
- *
- * @return true if anonymous location collection is enabled
- */
- private boolean isCollectionEnabled() {
- // This class provides a Google-specific location feature, so it's enabled only
- // when the system property ro.com.google.locationfeatures is set.
- if (!SystemProperties.get("ro.com.google.locationfeatures").equals("1")) {
- return false;
- }
- return mBatteryLevelIsHealthy && mNetworkProviderIsEnabled;
- }
-
- /**
- * Adds to the MASF request queue
- *
- * @param trigger the event that triggered this collection event
- */
- private synchronized void addToQueue(int trigger) {
-
- long now = SystemClock.elapsedRealtime();
-
- // Include location if:
- // It has been received in the last 12 minutes.
- boolean includeLocation = false;
- if (mLastKnownLocation != null &&
- (now - mLastKnownLocationTime <= MIN_VALID_LOCATION_TIME)) {
- includeLocation = true;
- }
-
- // Include wifi if:
- // Wifi is new OR
- // Wifi is old but last wifi upload was without location
- boolean includeWifi = false;
- if (trigger == GDebugProfile.TRIGGER_WIFI_CHANGE || (mWifiUploadedWithoutLocation &&
- includeLocation && (now - mLastWifiScanElapsedTime < MIN_VALID_LOCATION_TIME))) {
- includeWifi = true;
- mWifiUploadedWithoutLocation = !includeLocation;
- }
-
- // Include cell if:
- // Wifi or location information is already being included
- // The cell hasn't been uploaded with the same location recently
- boolean includeCell = false;
-
- if (mCellState != null && (includeWifi || includeLocation)) {
- includeCell = true;
-
- if (!includeWifi && includeLocation) {
- if (mCellUploads.contains(mCellState, mLastKnownLocation)) {
- includeCell = false;
- }
- }
- }
-
- if (!includeLocation && !includeWifi) {
- log("NO UPLOAD: includeLocation=false, includeWifi=false");
- return;
- } else if (!includeCell && trigger == GDebugProfile.TRIGGER_CELL_CHANGE) {
- log("NO UPLOAD: includeCell=false");
- return;
- } else {
- log("UPLOAD: includeLocation=" + includeLocation + ", includeWifi=" +
- includeWifi + ", includeCell=" + includeCell);
- }
-
- if (includeLocation) {
- // Update last uploaded location
- if (mLastUploadedLocation == null) {
- mLastUploadedLocation = new Location(mLastKnownLocation);
- } else {
- mLastUploadedLocation.set(mLastKnownLocation);
- }
- mLastUploadedLocationTime = now;
- }
-
- // Immediately send output if finishing a burst for live traffic requirements
- boolean immediate = false;
- if (trigger == GDebugProfile.TRIGGER_COLLECTION_END_BURST||
- trigger == GDebugProfile.TRIGGER_COLLECTION_END_BURST_AT_SAME_LOCATION) {
- immediate = true;
- }
-
- try {
- CellState cell = includeCell ? mCellState : null;
- List<ScanResult> wifi = includeWifi ? mWifiLastScanResults : null;
- Location loc = includeLocation ? mLastUploadedLocation : null;
-
- mMasfClient.queueCollectionReport(
- trigger, loc, cell, wifi, mLastWifiScanRealTime, immediate);
-
- } catch(Exception e) {
- Log.e(TAG, "addToQueue got exception:", e);
- }
- }
-
- private class CellUploads {
-
- private final int MIN_DISTANCE = MIN_DISTANCE_BETWEEN_REPORTS / 4; // 50 meters
- private final int SIZE = 5;
- private final String[] cells = new String[SIZE];
- private final boolean[] valid = new boolean[SIZE];
- private final double[] latitudes = new double[SIZE];
- private final double[] longitudes = new double[SIZE];
- private final float[] distance = new float[1];
- private int index = 0;
-
- private CellUploads() {
- for (int i = 0; i < SIZE; i++) {
- valid[i] = false;
- }
- }
-
- private boolean contains(CellState cellState, Location loc) {
- String cell =
- cellState.getCid() + ":" + cellState.getLac() + ":" +
- cellState.getMnc() + ":" + cellState.getMcc();
- double lat = loc.getLatitude();
- double lng = loc.getLongitude();
-
- for (int i = 0; i < SIZE; i++) {
- if (valid[i] && cells[i].equals(cell)) {
- Location.distanceBetween(latitudes[i], longitudes[i], lat, lng, distance);
- if (distance[0] < MIN_DISTANCE) {
- return true;
- }
- }
- }
- cells[index] = cell;
- latitudes[index] = lat;
- longitudes[index] = lng;
- valid[index] = true;
-
- index++;
- if (index == SIZE) {
- index = 0;
- }
- return false;
- }
- }
-
- private void log(String string) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, string);
- }
- }
-}
diff --git a/location/java/com/android/internal/location/LocationMasfClient.java b/location/java/com/android/internal/location/LocationMasfClient.java
deleted file mode 100644
index 179c630..0000000
--- a/location/java/com/android/internal/location/LocationMasfClient.java
+++ /dev/null
@@ -1,1194 +0,0 @@
-// Copyright 2008 The Android Open Source Project
-
-package com.android.internal.location;
-
-import com.google.common.Config;
-import com.google.common.android.AndroidConfig;
-import com.google.common.io.protocol.ProtoBuf;
-import com.google.masf.MobileServiceMux;
-import com.google.masf.ServiceCallback;
-import com.google.masf.protocol.PlainRequest;
-import com.google.masf.protocol.Request;
-
-import com.android.internal.location.protocol.GAddress;
-import com.android.internal.location.protocol.GAddressComponent;
-import com.android.internal.location.protocol.GAppProfile;
-import com.android.internal.location.protocol.GCell;
-import com.android.internal.location.protocol.GCellularPlatformProfile;
-import com.android.internal.location.protocol.GCellularProfile;
-import com.android.internal.location.protocol.GDebugProfile;
-import com.android.internal.location.protocol.GDeviceLocation;
-import com.android.internal.location.protocol.GFeature;
-import com.android.internal.location.protocol.GGeocodeRequest;
-import com.android.internal.location.protocol.GLatLng;
-import com.android.internal.location.protocol.GLocReply;
-import com.android.internal.location.protocol.GLocReplyElement;
-import com.android.internal.location.protocol.GLocRequest;
-import com.android.internal.location.protocol.GLocRequestElement;
-import com.android.internal.location.protocol.GLocation;
-import com.android.internal.location.protocol.GPlatformProfile;
-import com.android.internal.location.protocol.GPrefetchMode;
-import com.android.internal.location.protocol.GRectangle;
-import com.android.internal.location.protocol.GWifiDevice;
-import com.android.internal.location.protocol.GWifiProfile;
-import com.android.internal.location.protocol.GcellularMessageTypes;
-import com.android.internal.location.protocol.GdebugprofileMessageTypes;
-import com.android.internal.location.protocol.GlatlngMessageTypes;
-import com.android.internal.location.protocol.GlocationMessageTypes;
-import com.android.internal.location.protocol.GrectangleMessageTypes;
-import com.android.internal.location.protocol.GwifiMessageTypes;
-import com.android.internal.location.protocol.LocserverMessageTypes;
-import com.android.internal.location.protocol.ResponseCodes;
-
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Locale;
-
-import android.content.Context;
-import android.location.Address;
-import android.location.Location;
-import android.location.LocationManager;
-import android.net.wifi.ScanResult;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.EventLog;
-import android.util.Log;
-import android.telephony.NeighboringCellInfo;
-
-/**
- * Service to communicate to the Google Location Server (GLS) via MASF server
- *
- * {@hide}
- */
-public class LocationMasfClient {
-
- static final String TAG = "LocationMasfClient";
-
- // Address of the MASF server to connect to.
- private static final String MASF_SERVER_ADDRESS = "http://www.google.com/loc/m/api";
-
- // MobileServiceMux app/platform-specific values (application name matters!)
- private static final String APPLICATION_NAME = "location";
- private static final String APPLICATION_VERSION = "1.0";
- private static final String PLATFORM_ID = "android";
- private static final String DISTRIBUTION_CHANNEL = "android";
- private static String PLATFORM_BUILD = null;
-
- // Methods exposed by the MASF server
- private static final String REQUEST_QUERY_LOC = "g:loc/ql";
- private static final String REQUEST_UPLOAD_LOC = "g:loc/ul";
-
- // Max time to wait for request to end
- private static final long REQUEST_TIMEOUT = 5000;
-
- // Constant to divide Lat, Lng returned by server
- private static final double E7 = 10000000.0;
-
- // Max wifi points to include
- private static final int MAX_WIFI_TO_INCLUDE = 25;
-
- // Location of GLS cookie
- private static final String PLATFORM_KEY_FILE = "gls.platform.key";
- private String mPlatformKey;
-
- // Cell cache
- private LocationCache mLocationCache;
-
- // Location object that the cache manages
- private Location mLocation = new Location(LocationManager.NETWORK_PROVIDER);
-
- // ProtoBuf objects we can reuse for subsequent requests
- private final int MAX_COLLECTION_BUFFER_SIZE = 30;
- private final long MIN_COLLECTION_INTERVAL = 15 * 60 * 1000; // 15 minutes
- private ProtoBuf mPlatformProfile = null;
- private ProtoBuf mCellularPlatformProfile = null;
- private ProtoBuf mCurrentCollectionRequest = null;
- private long mLastCollectionUploadTime = 0;
-
- // Objects for current request
- private List<ScanResult> mWifiScanResults = new ArrayList<ScanResult>();
- private CellState mCellState = null;
- private List<CellState> mCellHistory;
-
- // This tag is used for the event log.
- private static final int COLLECTION_EVENT_LOG_TAG = 2740;
-
- // Extra values to designate whether location is from cache or network request
- private static final String EXTRA_KEY_LOCATION_SOURCE = "networkLocationSource";
- private static final String EXTRA_VALUE_LOCATION_SOURCE_CACHED = "cached";
- private static final String EXTRA_VALUE_LOCATION_SOURCE_SERVER = "server";
-
- // Maximum accuracy tolerated for a valid location
- private static final int MAX_ACCURACY_ALLOWED = 5000; // 5km
-
- // Indicates whether this is the first message after a device restart
- private boolean mDeviceRestart = true;
-
- /**
- * Initializes the MobileServiceMux. Must be called before using any other function in the
- * class.
- */
- public LocationMasfClient(Context context) {
- MobileServiceMux mux = MobileServiceMux.getSingleton();
- if (mux == null) {
- AndroidConfig config = new AndroidConfig(context);
- Config.setConfig(config);
-
- MobileServiceMux.initialize
- (MASF_SERVER_ADDRESS,
- APPLICATION_NAME,
- APPLICATION_VERSION,
- PLATFORM_ID,
- DISTRIBUTION_CHANNEL);
- }
- mLocationCache = new LocationCache();
-
- if (Build.FINGERPRINT != null) {
- PLATFORM_BUILD = PLATFORM_ID + "/" + Build.FINGERPRINT;
- } else {
- PLATFORM_BUILD = PLATFORM_ID;
- }
- }
-
- /**
- * Returns the location for the given cell or wifi information.
- *
- * @param apps list of apps requesting location
- * @param trigger event that triggered this network request
- * @param cellState cell tower state
- * @param cellHistory history of acquired cell states
- * @param scanResults list of wifi scan results
- * @param scanTime time at which wireless scan was triggered
- * @param callback function to call with received location
- */
- public synchronized void getNetworkLocation(Collection<String> apps, int trigger,
- CellState cellState, List<CellState> cellHistory, List<ScanResult> scanResults,
- long scanTime, NetworkLocationProvider.Callback callback) {
-
- final NetworkLocationProvider.Callback finalCallback = callback;
-
- boolean foundInCache =
- mLocationCache.lookup(cellState, cellHistory, scanResults, mLocation);
-
- if (foundInCache) {
-
- if (SystemClock.elapsedRealtime() - mLastCollectionUploadTime > MIN_COLLECTION_INTERVAL) {
- uploadCollectionReport(true);
- }
-
- Bundle extras = mLocation.getExtras() == null ? new Bundle() : mLocation.getExtras();
- extras.putString(EXTRA_KEY_LOCATION_SOURCE, EXTRA_VALUE_LOCATION_SOURCE_CACHED);
- mLocation.setExtras(extras);
-
- Log.d(TAG, "getNetworkLocation(): Returning cache location with accuracy " +
- mLocation.getAccuracy());
- finalCallback.locationReceived(mLocation, true);
- return;
- }
-
- Log.d(TAG, "getNetworkLocation(): Location not found in cache, making network request");
-
- // Copy over to objects for this request
- mWifiScanResults.clear();
- if (scanResults != null) {
- mWifiScanResults.addAll(scanResults);
- }
- mCellState = cellState;
- mCellHistory = cellHistory;
-
- // Create a RequestElement
- ProtoBuf requestElement = new ProtoBuf(LocserverMessageTypes.GLOC_REQUEST_ELEMENT);
-
- // Debug profile
- ProtoBuf debugProfile = new ProtoBuf(GdebugprofileMessageTypes.GDEBUG_PROFILE);
- requestElement.setProtoBuf(GLocRequestElement.DEBUG_PROFILE, debugProfile);
-
- if (mDeviceRestart) {
- debugProfile.setBool(GDebugProfile.DEVICE_RESTART, true);
- mDeviceRestart = false;
- }
-
- if (trigger != -1) {
- debugProfile.setInt(GDebugProfile.TRIGGER, trigger);
- }
-
- // Cellular profile
- if (mCellState != null && mCellState.isValid()) {
- ProtoBuf cellularProfile = new ProtoBuf(GcellularMessageTypes.GCELLULAR_PROFILE);
- cellularProfile.setLong(GCellularProfile.TIMESTAMP, mCellState.getTime());
- cellularProfile.setInt(GCellularProfile.PREFETCH_MODE,
- GPrefetchMode.PREFETCH_MODE_MORE_NEIGHBORS);
-
- // Primary cell
- ProtoBuf primaryCell = new ProtoBuf(GcellularMessageTypes.GCELL);
- primaryCell.setInt(GCell.LAC, mCellState.getLac());
- primaryCell.setInt(GCell.CELLID, mCellState.getCid());
-
- if ((mCellState.getMcc() != -1) && (mCellState.getMnc() != -1)) {
- primaryCell.setInt(GCell.MCC, mCellState.getMcc());
- primaryCell.setInt(GCell.MNC, mCellState.getMnc());
- }
-
- if (mCellState.getSignalStrength() != -1) {
- primaryCell.setInt(GCell.RSSI, mCellState.getSignalStrength());
- }
-
- cellularProfile.setProtoBuf(GCellularProfile.PRIMARY_CELL, primaryCell);
-
- // History of cells
- for (CellState c : cellHistory) {
- ProtoBuf pastCell = new ProtoBuf(GcellularMessageTypes.GCELL);
- pastCell.setInt(GCell.LAC, c.getLac());
- pastCell.setInt(GCell.CELLID, c.getCid());
- if ((c.getMcc() != -1) && (c.getMnc() != -1)) {
- pastCell.setInt(GCell.MCC, c.getMcc());
- pastCell.setInt(GCell.MNC, c.getMnc());
- }
-
- if (c.getSignalStrength() != -1) {
- pastCell.setInt(GCell.RSSI, c.getSignalStrength());
- }
-
- pastCell.setInt(GCell.AGE, (int)(mCellState.getTime() - c.getTime()));
- cellularProfile.addProtoBuf(GCellularProfile.HISTORICAL_CELLS, pastCell);
- }
-
- // Neighboring Cells
- addNeighborsToCellProfile(mCellState, cellularProfile);
-
- requestElement.setProtoBuf(GLocRequestElement.CELLULAR_PROFILE, cellularProfile);
- }
-
- // Wifi profile
- if (mWifiScanResults != null && mWifiScanResults.size() > 0) {
- ProtoBuf wifiProfile = new ProtoBuf(GwifiMessageTypes.GWIFI_PROFILE);
- wifiProfile.setLong(GWifiProfile.TIMESTAMP, scanTime);
- wifiProfile.setInt(GWifiProfile.PREFETCH_MODE,
- GPrefetchMode.PREFETCH_MODE_MORE_NEIGHBORS);
-
- int count = 0;
- for (ScanResult s : mWifiScanResults) {
- ProtoBuf wifiDevice = new ProtoBuf(GwifiMessageTypes.GWIFI_DEVICE);
- wifiDevice.setString(GWifiDevice.MAC, s.BSSID);
- wifiProfile.addProtoBuf(GWifiProfile.WIFI_DEVICES, wifiDevice);
- count++;
- if (count >= MAX_WIFI_TO_INCLUDE) {
- break;
- }
- }
-
- requestElement.setProtoBuf(GLocRequestElement.WIFI_PROFILE, wifiProfile);
- }
-
- // Request to send over wire
- ProtoBuf request = new ProtoBuf(LocserverMessageTypes.GLOC_REQUEST);
- request.addProtoBuf(GLocRequest.REQUEST_ELEMENTS, requestElement);
-
- // Create a Platform Profile
- ProtoBuf platformProfile = createPlatformProfile();
- if (mCellState != null && mCellState.isValid()) {
- // Include cellular platform Profile
- ProtoBuf cellularPlatform = createCellularPlatformProfile(mCellState);
- platformProfile.setProtoBuf(GPlatformProfile.CELLULAR_PLATFORM_PROFILE,
- cellularPlatform);
- }
- request.setProtoBuf(GLocRequest.PLATFORM_PROFILE, platformProfile);
-
- // Include App Profiles
- if (apps != null) {
- for (String app : apps) {
- ProtoBuf appProfile = new ProtoBuf(GlocationMessageTypes.GAPP_PROFILE);
- appProfile.setString(GAppProfile.APP_NAME, app);
- request.addProtoBuf(GLocRequest.APP_PROFILES, appProfile);
- }
- }
-
- // Queue any waiting collection events as well
- uploadCollectionReport(false);
-
- ByteArrayOutputStream payload = new ByteArrayOutputStream();
- try {
- request.outputTo(payload);
- } catch (IOException e) {
- Log.e(TAG, "getNetworkLocation(): unable to write request to payload", e);
- return;
- }
-
- // Creates request and a listener with a call back function
- ProtoBuf reply = new ProtoBuf(LocserverMessageTypes.GLOC_REPLY);
- Request plainRequest =
- new PlainRequest(REQUEST_QUERY_LOC, (short)0, payload.toByteArray());
-
- ProtoRequestListener listener = new ProtoRequestListener(reply, new ServiceCallback() {
- public void onRequestComplete(Object result) {
- ProtoBuf response = (ProtoBuf) result;
- boolean successful = parseNetworkLocationReply(response);
- finalCallback.locationReceived(mLocation, successful);
-
- }
- });
- plainRequest.setListener(listener);
-
- // Send request
- MobileServiceMux serviceMux = MobileServiceMux.getSingleton();
- serviceMux.submitRequest(plainRequest, true);
- }
-
- private synchronized boolean parseNetworkLocationReply(ProtoBuf response) {
- if (response == null) {
- Log.e(TAG, "getNetworkLocation(): response is null");
- return false;
- }
-
- int status1 = response.getInt(GLocReply.STATUS);
- if (status1 != ResponseCodes.STATUS_STATUS_SUCCESS) {
- Log.e(TAG, "getNetworkLocation(): RPC failed with status " + status1);
- return false;
- }
-
- if (response.has(GLocReply.PLATFORM_KEY)) {
- String platformKey = response.getString(GLocReply.PLATFORM_KEY);
- if (!TextUtils.isEmpty(platformKey)) {
- setPlatformKey(platformKey);
- }
- }
-
- if (!response.has(GLocReply.REPLY_ELEMENTS)) {
- Log.e(TAG, "getNetworkLocation(): no ReplyElement");
- return false;
- }
- ProtoBuf replyElement = response.getProtoBuf(GLocReply.REPLY_ELEMENTS);
-
- // Get prefetched data to add to the device cache
- Log.d(TAG, "getNetworkLocation(): Number of prefetched entries " +
- replyElement.getCount(GLocReplyElement.DEVICE_LOCATION));
- long now = System.currentTimeMillis();
- for (int i = 0; i < replyElement.getCount(GLocReplyElement.DEVICE_LOCATION); i++ ) {
- ProtoBuf device = replyElement.getProtoBuf(GLocReplyElement.DEVICE_LOCATION, i);
- double lat = 0;
- double lng = 0;
- int accuracy = -1;
- int confidence = -1;
- int locType = -1;
- if (device.has(GDeviceLocation.LOCATION)) {
- ProtoBuf deviceLocation = device.getProtoBuf(GDeviceLocation.LOCATION);
- if (deviceLocation.has(GLocation.ACCURACY) &&
- deviceLocation.has(GLocation.LAT_LNG)
- && deviceLocation.has(GLocation.CONFIDENCE)) {
- lat = deviceLocation.getProtoBuf(GLocation.LAT_LNG).
- getInt(GLatLng.LAT_E7) / E7;
- lng = deviceLocation.getProtoBuf(GLocation.LAT_LNG).
- getInt(GLatLng.LNG_E7) / E7;
- accuracy = deviceLocation.getInt(GLocation.ACCURACY);
- confidence = deviceLocation.getInt(GLocation.CONFIDENCE);
- }
- if (deviceLocation.has(GLocation.LOC_TYPE)) {
- locType = deviceLocation.getInt(GLocation.LOC_TYPE);
- }
- }
-
- // Get cell key
- if (device.has(GDeviceLocation.CELL) && locType != GLocation.LOCTYPE_TOWER_LOCATION) {
- ProtoBuf deviceCell = device.getProtoBuf(GDeviceLocation.CELL);
- int cid = deviceCell.getInt(GCell.CELLID);
- int lac = deviceCell.getInt(GCell.LAC);
- int mcc = -1;
- int mnc = -1;
- if (deviceCell.has(GCell.MNC) && deviceCell.has(GCell.MCC)) {
- mcc = deviceCell.getInt(GCell.MCC);
- mnc = deviceCell.getInt(GCell.MNC);
- }
- mLocationCache.
- insert(mcc, mnc, lac, cid, lat, lng, accuracy, confidence, now);
- }
-
- // Get wifi key
- if (device.has(GDeviceLocation.WIFI_DEVICE)) {
- ProtoBuf deviceWifi = device.getProtoBuf(GDeviceLocation.WIFI_DEVICE);
- String bssid = deviceWifi.getString(GWifiDevice.MAC);
- mLocationCache.insert(bssid, lat, lng, accuracy, confidence, now);
- }
- }
-
- mLocationCache.save();
-
- int status2 = replyElement.getInt(GLocReplyElement.STATUS);
- if (status2 != ResponseCodes.STATUS_STATUS_SUCCESS &&
- status2 != ResponseCodes.STATUS_STATUS_FAILED) {
- Log.e(TAG, "getNetworkLocation(): GLS failed with status " + status2);
- return false;
- }
-
- // For consistent results for user, always return cache computed location
- boolean foundInCache =
- mLocationCache.lookup(mCellState, mCellHistory, mWifiScanResults, mLocation);
-
- if (foundInCache) {
-
- Bundle extras = mLocation.getExtras() == null ? new Bundle() : mLocation.getExtras();
- extras.putString(EXTRA_KEY_LOCATION_SOURCE, EXTRA_VALUE_LOCATION_SOURCE_SERVER);
- mLocation.setExtras(extras);
-
- Log.d(TAG, "getNetworkLocation(): Returning network location with accuracy " +
- mLocation.getAccuracy());
- return true;
- }
-
- if (status2 == ResponseCodes.STATUS_STATUS_FAILED) {
- Log.e(TAG, "getNetworkLocation(): GLS does not have location");
- // We return true here since even though there is no location, there is no need to retry
- // since server doesn't have location
- return true;
- }
-
- // Get server computed location to return for now
- if (!replyElement.has(GLocReplyElement.LOCATION)) {
- Log.e(TAG, "getNetworkLocation(): no location in ReplyElement");
- return false;
- }
- ProtoBuf location = replyElement.getProtoBuf(GLocReplyElement.LOCATION);
-
- if (!location.has(GLocation.LAT_LNG)) {
- Log.e(TAG, "getNetworkLocation(): no Lat,Lng in location");
- return false;
- }
-
- ProtoBuf point = location.getProtoBuf(GLocation.LAT_LNG);
- double lat = point.getInt(GLatLng.LAT_E7) / E7;
- double lng = point.getInt(GLatLng.LNG_E7) / E7;
-
- int accuracy = 0;
- if (location.has(GLocation.ACCURACY)) {
- accuracy = location.getInt(GLocation.ACCURACY);
- }
-
- if (accuracy > MAX_ACCURACY_ALLOWED) {
- Log.e(TAG, "getNetworkLocation(): accuracy is too high " + accuracy);
- return false;
- }
-
- mLocation.setLatitude(lat);
- mLocation.setLongitude(lng);
- mLocation.setTime(System.currentTimeMillis());
- mLocation.setAccuracy(accuracy);
-
- Bundle extras = mLocation.getExtras() == null ? new Bundle() : mLocation.getExtras();
- extras.putString(EXTRA_KEY_LOCATION_SOURCE, EXTRA_VALUE_LOCATION_SOURCE_SERVER);
- mLocation.setExtras(extras);
-
- Log.e(TAG, "getNetworkLocation(): Returning *server* computed location with accuracy " +
- accuracy);
-
- return true;
- }
-
- /**
- * Gets a reverse geocoded location from the given lat,lng point. Also attaches the name
- * of the requesting application with the request
- *
- * @param locale locale for geocoded location
- * @param appPackageName name of the package, may be null
- * @param lat latitude
- * @param lng longitude
- * @param maxResults maximum number of addresses to return
- * @param addrs the list of addresses to fill up
- * @throws IOException if network is unavailable or some other issue
- */
- public void reverseGeocode(Locale locale, String appPackageName,
- double lat, double lng, int maxResults, List<Address> addrs) throws IOException {
-
- // Reverse geocoding request element
- ProtoBuf requestElement = new ProtoBuf(LocserverMessageTypes.GLOC_REQUEST_ELEMENT);
-
- ProtoBuf latlngElement = new ProtoBuf(GlatlngMessageTypes.GLAT_LNG);
- latlngElement.setInt(GLatLng.LAT_E7, (int)(lat * E7));
- latlngElement.setInt(GLatLng.LNG_E7, (int)(lng * E7));
-
- ProtoBuf locationElement = new ProtoBuf(GlocationMessageTypes.GLOCATION);
- locationElement.setProtoBuf(GLocation.LAT_LNG, latlngElement);
- locationElement.setLong(GLocation.TIMESTAMP, System.currentTimeMillis());
- requestElement.setProtoBuf(GLocRequestElement.LOCATION, locationElement);
-
- ProtoBuf geocodeElement =
- new ProtoBuf(LocserverMessageTypes.GGEOCODE_REQUEST);
- geocodeElement.setInt(GGeocodeRequest.NUM_FEATURE_LIMIT, maxResults);
- requestElement.setProtoBuf(GLocRequestElement.GEOCODE, geocodeElement);
-
- // Request to send over wire
- ProtoBuf request = new ProtoBuf(LocserverMessageTypes.GLOC_REQUEST);
- request.addProtoBuf(GLocRequest.REQUEST_ELEMENTS, requestElement);
-
- // Create platform profile
- ProtoBuf platformProfile = createPlatformProfile(locale);
- request.setProtoBuf(GLocRequest.PLATFORM_PROFILE, platformProfile);
-
- // Include app name
- if (appPackageName != null) {
- ProtoBuf appProfile = new ProtoBuf(GlocationMessageTypes.GAPP_PROFILE);
- appProfile.setString(GAppProfile.APP_NAME, appPackageName);
- request.setProtoBuf(GLocRequest.APP_PROFILES, appProfile);
- }
-
- // Queue any waiting collection events as well
- uploadCollectionReport(false);
-
- ByteArrayOutputStream payload = new ByteArrayOutputStream();
- try {
- request.outputTo(payload);
- } catch (IOException e) {
- Log.e(TAG, "reverseGeocode(): unable to write request to payload");
- throw e;
- }
-
- // Creates request and a listener with no callback function
- ProtoBuf reply = new ProtoBuf(LocserverMessageTypes.GLOC_REPLY);
- Request plainRequest =
- new PlainRequest(REQUEST_QUERY_LOC, (short)0, payload.toByteArray());
- ProtoRequestListener listener = new ProtoRequestListener(reply, null);
- plainRequest.setListener(listener);
-
- // Immediately send request and block for response until REQUEST_TIMEOUT
- MobileServiceMux serviceMux = MobileServiceMux.getSingleton();
- serviceMux.submitRequest(plainRequest, true);
- ProtoBuf response;
- try {
- response = (ProtoBuf)listener.getAsyncResult().get(REQUEST_TIMEOUT);
- } catch (InterruptedException e) {
- Log.e(TAG, "reverseGeocode(): response timeout");
- throw new IOException("response time-out");
- }
-
- if (response == null) {
- throw new IOException("Unable to parse response from server");
- }
-
- // Parse the response
- int status1 = response.getInt(GLocReply.STATUS);
- if (status1 != ResponseCodes.STATUS_STATUS_SUCCESS) {
- Log.e(TAG, "reverseGeocode(): RPC failed with status " + status1);
- throw new IOException("RPC failed with status " + status1);
- }
-
- if (response.has(GLocReply.PLATFORM_KEY)) {
- String platformKey = response.getString(GLocReply.PLATFORM_KEY);
- if (!TextUtils.isEmpty(platformKey)) {
- setPlatformKey(platformKey);
- }
- }
-
- if (!response.has(GLocReply.REPLY_ELEMENTS)) {
- Log.e(TAG, "reverseGeocode(): no ReplyElement");
- return;
- }
- ProtoBuf replyElement = response.getProtoBuf(GLocReply.REPLY_ELEMENTS);
-
- int status2 = replyElement.getInt(GLocReplyElement.STATUS);
- if (status2 != ResponseCodes.STATUS_STATUS_SUCCESS) {
- Log.e(TAG, "reverseGeocode(): GLS failed with status " + status2);
- return;
- }
-
- if (!replyElement.has(GLocReplyElement.LOCATION)) {
- Log.e(TAG, "reverseGeocode(): no location in ReplyElement");
- return;
- }
-
- ProtoBuf location = replyElement.getProtoBuf(GLocReplyElement.LOCATION);
- if (!location.has(GLocation.FEATURE)) {
- Log.e(TAG, "reverseGeocode(): no feature in GLocation");
- return;
- }
-
- getAddressFromProtoBuf(location, locale, addrs);
- }
-
- /**
- * Gets a forward geocoded location from the given location string. Also attaches the name
- * of the requesting application with the request
- *
- * Optionally, can specify the bounding box that the search results should be restricted to
- *
- * @param locale locale for geocoded location
- * @param appPackageName name of the package, may be null
- * @param locationString string to forward geocode
- * @param lowerLeftLatitude latitude of lower left point of bounding box
- * @param lowerLeftLongitude longitude of lower left point of bounding box
- * @param upperRightLatitude latitude of upper right point of bounding box
- * @param upperRightLongitude longitude of upper right point of bounding box
- * @param maxResults maximum number of results to return
- * @param addrs the list of addresses to fill up
- * @throws IOException if network is unavailable or some other issue
- */
- public void forwardGeocode(Locale locale, String appPackageName, String locationString,
- double lowerLeftLatitude, double lowerLeftLongitude,
- double upperRightLatitude, double upperRightLongitude, int maxResults, List<Address> addrs)
- throws IOException {
-
- // Forward geocoding request element
- ProtoBuf requestElement = new ProtoBuf(LocserverMessageTypes.GLOC_REQUEST_ELEMENT);
-
- ProtoBuf locationElement = new ProtoBuf(GlocationMessageTypes.GLOCATION);
- locationElement.setLong(GLocation.TIMESTAMP, System.currentTimeMillis());
- locationElement.setString(GLocation.LOCATION_STRING, locationString);
- requestElement.setProtoBuf(GLocRequestElement.LOCATION, locationElement);
-
- ProtoBuf geocodeElement =
- new ProtoBuf(LocserverMessageTypes.GGEOCODE_REQUEST);
- geocodeElement.setInt(GGeocodeRequest.NUM_FEATURE_LIMIT, maxResults);
-
- if (lowerLeftLatitude != 0 && lowerLeftLongitude !=0 &&
- upperRightLatitude !=0 && upperRightLongitude !=0) {
- ProtoBuf lowerLeft = new ProtoBuf(GlatlngMessageTypes.GLAT_LNG);
- lowerLeft.setInt(GLatLng.LAT_E7, (int)(lowerLeftLatitude * E7));
- lowerLeft.setInt(GLatLng.LNG_E7, (int)(lowerLeftLongitude * E7));
-
- ProtoBuf upperRight = new ProtoBuf(GlatlngMessageTypes.GLAT_LNG);
- upperRight.setInt(GLatLng.LAT_E7, (int)(upperRightLatitude * E7));
- upperRight.setInt(GLatLng.LNG_E7, (int)(upperRightLongitude * E7));
-
- ProtoBuf boundingBox = new ProtoBuf(GrectangleMessageTypes.GRECTANGLE);
- boundingBox.setProtoBuf(GRectangle.LOWER_LEFT, lowerLeft);
- boundingBox.setProtoBuf(GRectangle.UPPER_RIGHT, upperRight);
- geocodeElement.setProtoBuf(GGeocodeRequest.BOUNDING_BOX, boundingBox);
- }
- requestElement.setProtoBuf(GLocRequestElement.GEOCODE, geocodeElement);
-
- // Request to send over wire
- ProtoBuf request = new ProtoBuf(LocserverMessageTypes.GLOC_REQUEST);
- request.addProtoBuf(GLocRequest.REQUEST_ELEMENTS, requestElement);
-
- // Create platform profile
- ProtoBuf platformProfile = createPlatformProfile(locale);
- request.setProtoBuf(GLocRequest.PLATFORM_PROFILE, platformProfile);
-
- // Include app name
- if (appPackageName != null) {
- ProtoBuf appProfile = new ProtoBuf(GlocationMessageTypes.GAPP_PROFILE);
- appProfile.setString(GAppProfile.APP_NAME, appPackageName);
- request.setProtoBuf(GLocRequest.APP_PROFILES, appProfile);
- }
-
- // Queue any waiting collection events as well
- uploadCollectionReport(false);
-
- ByteArrayOutputStream payload = new ByteArrayOutputStream();
- try {
- request.outputTo(payload);
- } catch (IOException e) {
- Log.e(TAG, "forwardGeocode(): unable to write request to payload");
- throw e;
- }
-
- // Creates request and a listener with no callback function
- ProtoBuf reply = new ProtoBuf(LocserverMessageTypes.GLOC_REPLY);
- Request plainRequest =
- new PlainRequest(REQUEST_QUERY_LOC, (short)0, payload.toByteArray());
- ProtoRequestListener listener = new ProtoRequestListener(reply, null);
- plainRequest.setListener(listener);
-
- // Immediately send request and block for response until REQUEST_TIMEOUT
- MobileServiceMux serviceMux = MobileServiceMux.getSingleton();
- serviceMux.submitRequest(plainRequest, true);
- ProtoBuf response;
- try {
- response = (ProtoBuf)listener.getAsyncResult().get(REQUEST_TIMEOUT);
- } catch (InterruptedException e) {
- Log.e(TAG, "forwardGeocode(): response timeout");
- throw new IOException("response time-out");
- }
-
- if (response == null) {
- throw new IOException("Unable to parse response from server");
- }
-
- // Parse the response
- int status1 = response.getInt(GLocReply.STATUS);
- if (status1 != ResponseCodes.STATUS_STATUS_SUCCESS) {
- Log.e(TAG, "forwardGeocode(): RPC failed with status " + status1);
- throw new IOException("RPC failed with status " + status1);
- }
-
- if (response.has(GLocReply.PLATFORM_KEY)) {
- String platformKey = response.getString(GLocReply.PLATFORM_KEY);
- if (!TextUtils.isEmpty(platformKey)) {
- setPlatformKey(platformKey);
- }
- }
-
- if (!response.has(GLocReply.REPLY_ELEMENTS)) {
- Log.e(TAG, "forwardGeocode(): no ReplyElement");
- return;
- }
- ProtoBuf replyElement = response.getProtoBuf(GLocReply.REPLY_ELEMENTS);
-
- int status2 = replyElement.getInt(GLocReplyElement.STATUS);
- if (status2 != ResponseCodes.STATUS_STATUS_SUCCESS) {
- Log.e(TAG, "forwardGeocode(): GLS failed with status " + status2);
- return;
- }
-
- if (!replyElement.has(GLocReplyElement.LOCATION)) {
- Log.e(TAG, "forwardGeocode(): no location in ReplyElement");
- return;
- }
-
- ProtoBuf location = replyElement.getProtoBuf(GLocReplyElement.LOCATION);
- if (!location.has(GLocation.FEATURE)) {
- Log.e(TAG, "forwardGeocode(): no feature in GLocation");
- return;
- }
-
- getAddressFromProtoBuf(location, locale, addrs);
- }
-
- /**
- * Queues a location collection request to be sent to the server
- *
- * @param trigger what triggered this collection event
- * @param location last known location
- * @param cellState cell tower state
- * @param scanResults list of wifi points
- * @param scanTime real time at which wifi scan happened
- * @param immediate true if request should be sent immediately instead of being queued
- */
- public synchronized void queueCollectionReport(int trigger, Location location,
- CellState cellState, List<ScanResult> scanResults, long scanTime, boolean immediate) {
-
- // Create a RequestElement
- ProtoBuf requestElement = new ProtoBuf(LocserverMessageTypes.GLOC_REQUEST_ELEMENT);
-
- // Include debug profile
- ProtoBuf debugProfile = new ProtoBuf(GdebugprofileMessageTypes.GDEBUG_PROFILE);
- requestElement.setProtoBuf(GLocRequestElement.DEBUG_PROFILE, debugProfile);
-
- if (mDeviceRestart) {
- debugProfile.setBool(GDebugProfile.DEVICE_RESTART, true);
- mDeviceRestart = false;
- }
-
- if (trigger != -1) {
- debugProfile.setInt(GDebugProfile.TRIGGER, trigger);
- EventLog.writeEvent(COLLECTION_EVENT_LOG_TAG, trigger);
- }
-
- // Include cell profile
- if (cellState != null && cellState.isValid()) {
- ProtoBuf cellularProfile = new ProtoBuf(GcellularMessageTypes.GCELLULAR_PROFILE);
- cellularProfile.setLong(GCellularProfile.TIMESTAMP, cellState.getTime());
-
- // Primary cell
- ProtoBuf primaryCell = new ProtoBuf(GcellularMessageTypes.GCELL);
- primaryCell.setInt(GCell.LAC, cellState.getLac());
- primaryCell.setInt(GCell.CELLID, cellState.getCid());
- if ((cellState.getMcc() != -1) && (cellState.getMnc() != -1)) {
- primaryCell.setInt(GCell.MCC, cellState.getMcc());
- primaryCell.setInt(GCell.MNC, cellState.getMnc());
- }
-
- if (cellState.getSignalStrength() != -1) {
- primaryCell.setInt(GCell.RSSI, cellState.getSignalStrength());
- }
-
- cellularProfile.setProtoBuf(GCellularProfile.PRIMARY_CELL, primaryCell);
-
- // Cell neighbors
- addNeighborsToCellProfile(cellState, cellularProfile);
-
- requestElement.setProtoBuf(GLocRequestElement.CELLULAR_PROFILE, cellularProfile);
- }
-
- // Include Wifi profile
- if (scanResults != null && scanResults.size() > 0) {
- ProtoBuf wifiProfile = new ProtoBuf(GwifiMessageTypes.GWIFI_PROFILE);
- wifiProfile.setLong(GWifiProfile.TIMESTAMP, scanTime);
-
- int count = 0;
- for (ScanResult s : scanResults) {
- ProtoBuf wifiDevice = new ProtoBuf(GwifiMessageTypes.GWIFI_DEVICE);
- wifiDevice.setString(GWifiDevice.MAC, s.BSSID);
- wifiDevice.setString(GWifiDevice.SSID, s.SSID);
- wifiDevice.setInt(GWifiDevice.RSSI, s.level);
- wifiProfile.addProtoBuf(GWifiProfile.WIFI_DEVICES, wifiDevice);
- count++;
- if (count >= MAX_WIFI_TO_INCLUDE) {
- break;
- }
- }
-
- requestElement.setProtoBuf(GLocRequestElement.WIFI_PROFILE, wifiProfile);
- }
-
- // Location information
- if (location != null) {
- ProtoBuf latlngElement = new ProtoBuf(GlatlngMessageTypes.GLAT_LNG);
- latlngElement.setInt(GLatLng.LAT_E7, (int)(location.getLatitude() * E7));
- latlngElement.setInt(GLatLng.LNG_E7, (int)(location.getLongitude() * E7));
-
- ProtoBuf locationElement = new ProtoBuf(GlocationMessageTypes.GLOCATION);
- locationElement.setProtoBuf(GLocation.LAT_LNG, latlngElement);
- locationElement.setInt(GLocation.LOC_TYPE, GLocation.LOCTYPE_GPS);
- locationElement.setLong(GLocation.TIMESTAMP, location.getTime());
- if (location.hasAccuracy()) {
- locationElement.setInt(GLocation.ACCURACY, (int)location.getAccuracy());
- }
- if (location.hasSpeed()) {
- locationElement.setInt(GLocation.VELOCITY, (int)location.getSpeed());
- }
- if (location.hasBearing()) {
- locationElement.setInt(GLocation.HEADING, (int)location.getBearing());
- }
-
- requestElement.setProtoBuf(GLocRequestElement.LOCATION, locationElement);
- }
-
- if (mCurrentCollectionRequest == null) {
- mCurrentCollectionRequest = new ProtoBuf(LocserverMessageTypes.GLOC_REQUEST);
-
- // Create a Platform Profile
- ProtoBuf platformProfile = createPlatformProfile();
- if (cellState != null && cellState.isValid()) {
- ProtoBuf cellularPlatform = createCellularPlatformProfile(cellState);
- platformProfile.setProtoBuf(GPlatformProfile.CELLULAR_PLATFORM_PROFILE,
- cellularPlatform);
- }
-
- mCurrentCollectionRequest.setProtoBuf(GLocRequest.PLATFORM_PROFILE, platformProfile);
-
- } else {
-
- ProtoBuf platformProfile =
- mCurrentCollectionRequest.getProtoBuf(GLocRequest.PLATFORM_PROFILE);
- if (platformProfile == null) {
- platformProfile = createPlatformProfile();
- mCurrentCollectionRequest.setProtoBuf(
- GLocRequest.PLATFORM_PROFILE, platformProfile);
- }
-
- // Add cellular platform profile is not already included
- if (platformProfile.getProtoBuf(GPlatformProfile.CELLULAR_PLATFORM_PROFILE) == null &&
- cellState != null && cellState.isValid()) {
- ProtoBuf cellularPlatform = createCellularPlatformProfile(cellState);
- platformProfile.setProtoBuf(GPlatformProfile.CELLULAR_PLATFORM_PROFILE,
- cellularPlatform);
- }
- }
-
- mCurrentCollectionRequest.addProtoBuf(GLocRequest.REQUEST_ELEMENTS, requestElement);
-
- // Immediately upload collection events if buffer exceeds certain size
- if (mCurrentCollectionRequest.getCount(GLocRequest.REQUEST_ELEMENTS)
- >= MAX_COLLECTION_BUFFER_SIZE) {
- immediate = true;
- }
-
- if (immediate) {
- // Request to send over wire
- uploadCollectionReport(immediate);
- }
- }
-
- /**
- * Uploads the collection report either immediately or based on MASF's queueing logic.
- * Does not need a reply back
- *
- * @param immediate true if request should be sent immediately instead of being queued
- */
- private synchronized void uploadCollectionReport(boolean immediate) {
- // There may be nothing to upload
- if (mCurrentCollectionRequest == null ||
- mCurrentCollectionRequest.getCount(GLocRequest.REQUEST_ELEMENTS) == 0) {
- return;
- }
-
- ByteArrayOutputStream payload = new ByteArrayOutputStream();
- try {
- mCurrentCollectionRequest.outputTo(payload);
- } catch (IOException e) {
- Log.e(TAG, "uploadCollectionReport(): unable to write request to payload");
- return;
- }
-
- mLastCollectionUploadTime = SystemClock.elapsedRealtime();
-
- // Since this has already been written to the wire, we can clear this request
- int count = mCurrentCollectionRequest.getCount(GLocRequest.REQUEST_ELEMENTS);
- while (count > 0) {
- mCurrentCollectionRequest.remove(GLocRequest.REQUEST_ELEMENTS, count - 1);
- count--;
- }
-
- // Creates request and a listener with a call back function
- ProtoBuf reply = new ProtoBuf(LocserverMessageTypes.GLOC_REPLY);
- Request plainRequest =
- new PlainRequest(REQUEST_UPLOAD_LOC, (short)0, payload.toByteArray());
-
- ProtoRequestListener listener = new ProtoRequestListener(reply, new ServiceCallback() {
- public void onRequestComplete(Object result) {
- ProtoBuf response = (ProtoBuf) result;
-
- if (response == null) {
- Log.e(TAG, "uploadCollectionReport(): response is null");
- return;
- }
-
- int status1 = response.getInt(GLocReply.STATUS);
- if (status1 != ResponseCodes.STATUS_STATUS_SUCCESS) {
- Log.w(TAG, "uploadCollectionReport(): RPC failed with status " + status1);
- return;
- }
-
- if (response.has(GLocReply.PLATFORM_KEY)) {
- String platformKey = response.getString(GLocReply.PLATFORM_KEY);
- if (!TextUtils.isEmpty(platformKey)) {
- setPlatformKey(platformKey);
- }
- }
-
- if (!response.has(GLocReply.REPLY_ELEMENTS)) {
- Log.w(TAG, "uploadCollectionReport(): no ReplyElement");
- return;
- }
-
- int count = response.getCount(GLocReply.REPLY_ELEMENTS);
- for (int i = 0; i < count; i++) {
- ProtoBuf replyElement = response.getProtoBuf(GLocReply.REPLY_ELEMENTS, i);
- int status2 = replyElement.getInt(GLocReplyElement.STATUS);
- if (status2 != ResponseCodes.STATUS_STATUS_SUCCESS) {
- Log.w(TAG, "uploadCollectionReport(): GLS failed with " + status2);
- }
- }
-
- }
- });
- plainRequest.setListener(listener);
-
- // Send request
- MobileServiceMux serviceMux = MobileServiceMux.getSingleton();
- serviceMux.submitRequest(plainRequest, immediate);
-
- }
-
- private String getPlatformKey() {
- if (mPlatformKey != null) {
- return mPlatformKey;
- }
-
- try {
- File file = new File(LocationManager.SYSTEM_DIR, PLATFORM_KEY_FILE);
- FileInputStream istream = new FileInputStream(file);
- DataInputStream dataInput = new DataInputStream(istream);
- String platformKey = dataInput.readUTF();
- dataInput.close();
- mPlatformKey = platformKey;
- return mPlatformKey;
- } catch(FileNotFoundException e) {
- // No file, just ignore
- return null;
- } catch(IOException e) {
- // Unable to read from file, just ignore
- return null;
- }
- }
-
- private void setPlatformKey(String platformKey) {
- File systemDir = new File(LocationManager.SYSTEM_DIR);
- if (!systemDir.exists()) {
- if (!systemDir.mkdirs()) {
- Log.w(TAG, "setPlatformKey(): couldn't create directory");
- return;
- }
- }
-
- try {
- File file = new File(LocationManager.SYSTEM_DIR, PLATFORM_KEY_FILE);
- FileOutputStream ostream = new FileOutputStream(file);
- DataOutputStream dataOut = new DataOutputStream(ostream);
- dataOut.writeUTF(platformKey);
- dataOut.close();
- mPlatformKey = platformKey;
- } catch (FileNotFoundException e) {
- Log.w(TAG, "setPlatformKey(): unable to create platform key file");
- } catch (IOException e) {
- Log.w(TAG, "setPlatformKey(): unable to write to platform key");
- }
- }
-
- private ProtoBuf createPlatformProfile() {
- Locale locale = Locale.getDefault();
- return createPlatformProfile(locale);
- }
-
- private ProtoBuf createPlatformProfile(Locale locale) {
- if (mPlatformProfile == null) {
- mPlatformProfile = new ProtoBuf(GlocationMessageTypes.GPLATFORM_PROFILE);
- mPlatformProfile.setString(GPlatformProfile.VERSION, APPLICATION_VERSION);
- mPlatformProfile.setString(GPlatformProfile.PLATFORM, PLATFORM_BUILD);
- }
-
- // Add Locale
- if ((locale != null) && (locale.toString() != null)) {
- mPlatformProfile.setString(GPlatformProfile.LOCALE, locale.toString());
- }
-
- // Add Platform Key
- String platformKey = getPlatformKey();
- if (!TextUtils.isEmpty(platformKey)) {
- mPlatformProfile.setString(GPlatformProfile.PLATFORM_KEY, platformKey);
- }
-
- // Clear out cellular platform profile
- mPlatformProfile.setProtoBuf(GPlatformProfile.CELLULAR_PLATFORM_PROFILE, null);
-
- return mPlatformProfile;
- }
-
- private ProtoBuf createCellularPlatformProfile(CellState cellState) {
- // Radio type
- int radioType = -1;
- if (cellState.getRadioType() == CellState.RADIO_TYPE_GPRS) {
- radioType = GCellularPlatformProfile.RADIO_TYPE_GPRS;
- } else if (cellState.getRadioType() == CellState.RADIO_TYPE_CDMA) {
- radioType = GCellularPlatformProfile.RADIO_TYPE_CDMA;
- } else if (cellState.getRadioType() == CellState.RADIO_TYPE_WCDMA) {
- radioType = GCellularPlatformProfile.RADIO_TYPE_WCDMA;
- }
-
- if (mCellularPlatformProfile == null) {
- mCellularPlatformProfile =
- new ProtoBuf(GlocationMessageTypes.GCELLULAR_PLATFORM_PROFILE);
- }
-
- mCellularPlatformProfile.setInt(GCellularPlatformProfile.RADIO_TYPE, radioType);
- if ((cellState.getHomeMcc() != -1) && (cellState.getHomeMnc() != -1)) {
- mCellularPlatformProfile.setInt(GCellularPlatformProfile.HOME_MCC,
- cellState.getHomeMcc());
- mCellularPlatformProfile.setInt(GCellularPlatformProfile.HOME_MNC,
- cellState.getHomeMnc());
- }
- if (cellState.getCarrier() != null) {
- mCellularPlatformProfile.setString(GCellularPlatformProfile.CARRIER,
- cellState.getCarrier());
- }
-
- return mCellularPlatformProfile;
- }
-
- private void getAddressFromProtoBuf(ProtoBuf location, Locale locale, List<Address> addrs) {
-
- double lat = -1;
- double lng = -1;
-
- if (location.has(GLocation.LAT_LNG)) {
- ProtoBuf latlng = location.getProtoBuf(GLocation.LAT_LNG);
- lat = latlng.getInt(GLatLng.LAT_E7)/E7;
- lng = latlng.getInt(GLatLng.LNG_E7)/E7;
- }
-
- for (int a = 0; a < location.getCount(GLocation.FEATURE); a++) {
-
- Address output = new Address(locale);
-
- ProtoBuf feature = location.getProtoBuf(GLocation.FEATURE, a);
- output.setFeatureName(feature.getString(GFeature.NAME));
-
- if (feature.has(GFeature.CENTER)) {
- ProtoBuf center = feature.getProtoBuf(GFeature.CENTER);
- output.setLatitude(center.getInt(GLatLng.LAT_E7)/E7);
- output.setLongitude(center.getInt(GLatLng.LNG_E7)/E7);
-
- } else if (location.has(GLocation.LAT_LNG)) {
- output.setLatitude(lat);
- output.setLongitude(lng);
- }
-
- ProtoBuf address = feature.getProtoBuf(GFeature.ADDRESS);
-
- for (int i = 0; i < address.getCount(GAddress.FORMATTED_ADDRESS_LINE); i++) {
- String line = address.getString(GAddress.FORMATTED_ADDRESS_LINE, i);
- output.setAddressLine(i, line);
- }
-
- for (int i = 0; i < address.getCount(GAddress.COMPONENT); i++) {
- ProtoBuf component = address.getProtoBuf(GAddress.COMPONENT, i);
- int type = component.getInt(GAddressComponent.FEATURE_TYPE);
- String name = component.getString(GAddressComponent.NAME);
-
- switch(type) {
- case GFeature.FEATURE_TYPE_ADMINISTRATIVE_AREA :
- output.setAdminArea(name);
- break;
-
- case GFeature.FEATURE_TYPE_SUB_ADMINISTRATIVE_AREA :
- output.setSubAdminArea(name);
- break;
-
- case GFeature.FEATURE_TYPE_LOCALITY :
- output.setLocality(name);
- break;
-
- case GFeature.FEATURE_TYPE_THOROUGHFARE :
- output.setThoroughfare(name);
- break;
-
- case GFeature.FEATURE_TYPE_POST_CODE :
- output.setPostalCode(name);
- break;
-
- case GFeature.FEATURE_TYPE_COUNTRY :
- output.setCountryName(name);
- break;
-
- case GFeature.FEATURE_TYPE_COUNTRY_CODE :
- output.setCountryCode(name);
- break;
-
- default :
- if (android.util.Config.LOGD) {
- Log.d(TAG, "getAddressFromProtoBuf(): Ignore feature " + type + "," + name);
- }
- break;
- }
- }
-
- addrs.add(output);
- }
- }
-
- private void addNeighborsToCellProfile(CellState cellState, ProtoBuf cellularProfile) {
- List<CellState.NeighborCell> neighbors = cellState.getNeighbors();
-
- int mPrimaryMcc = cellState.getMcc();
- int mPrimaryMnc = cellState.getMnc();
-
- if (neighbors != null) {
- for (CellState.NeighborCell neighbor : neighbors) {
- ProtoBuf nCell = new ProtoBuf(GcellularMessageTypes.GCELL);
- nCell.setInt(GCell.CELLID, neighbor.getCid());
- nCell.setInt(GCell.LAC, neighbor.getLac());
- nCell.setInt(GCell.RSSI, neighbor.getRssi());
- if (neighbor.getPsc() != -1) {
- nCell.setInt(GCell.PRIMARY_SCRAMBLING_CODE, neighbor.getPsc());
- }
- if (mPrimaryMcc != -1) {
- nCell.setInt(GCell.MCC, mPrimaryMcc);
- }
- if (mPrimaryMnc != -1) {
- nCell.setInt(GCell.MNC, mPrimaryMnc);
- }
- cellularProfile.addProtoBuf(GCellularProfile.NEIGHBORS, nCell);
- }
- }
- }
-
-}
diff --git a/location/java/com/android/internal/location/NetworkLocationProvider.java b/location/java/com/android/internal/location/NetworkLocationProvider.java
deleted file mode 100644
index d0a59b9..0000000
--- a/location/java/com/android/internal/location/NetworkLocationProvider.java
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location;
-
-import com.android.internal.location.protocol.GDebugProfile;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-
-import android.content.Context;
-import android.location.Criteria;
-import android.location.Location;
-import android.location.LocationManager;
-import android.location.LocationProviderImpl;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiManager;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.util.Log;
-
-/**
- * A location provider which gets approximate location from Google's
- * database of cell-tower and wi-fi locations.
- *
- * <p> It is the responsibility of the LocationManagerService to
- * notify this class of any changes in the radio information
- * by calling {@link #updateCellState} and of data state
- * changes by calling {@link #updateNetworkState}
- *
- * <p> The LocationManagerService must also notify the provider
- * of Wifi updates using the {@link #updateWifiScanResults}
- * and {@link #updateWifiEnabledState}
- * methods.
- *
- * <p> The provider uses whichever radio is available - Cell
- * or WiFi. If neither is available, it does NOT attempt to
- * switch them on.
- *
- * {@hide}
- */
-public class NetworkLocationProvider extends LocationProviderImpl {
- private static final String TAG = "NetworkLocationProvider";
-
- // Wait at least 60 seconds between network queries
- private static final int MIN_NETWORK_RETRY_MILLIS = 60000;
-
- // Max time to wait for radio update
- private static final long MAX_TIME_TO_WAIT_FOR_RADIO = 5 * 1000; // 5 seconds
-
- // State of entire provider
- private int mStatus = AVAILABLE;
- private long mStatusUpdateTime = 0;
-
- // Network state
- private int mNetworkState = TEMPORARILY_UNAVAILABLE;
-
- // Cell state
- private static final int MAX_CELL_HISTORY_TO_KEEP = 4;
- private LinkedList<CellState> mCellHistory = new LinkedList<CellState>();
- private CellState mCellState = null;
- private long mLastCellStateChangeTime = 0;
- private long mLastCellLockTime = 0;
-
- // Wifi state
- private static final long MIN_TIME_BETWEEN_WIFI_REPORTS = 45 * 1000; // 45 seconds
- private List<ScanResult> mWifiLastScanResults = null;
- private long mLastWifiScanTriggerTime = 0;
- private long mLastWifiScanElapsedTime = 0;
- private long mLastWifiScanRealTime = 0;
- private long mWifiScanFrequency = MIN_TIME_BETWEEN_WIFI_REPORTS;
- private boolean mWifiEnabled = false;
-
- // Last known location state
- private Location mLocation = new Location(LocationManager.NETWORK_PROVIDER);
- private long mLastNetworkQueryTime = 0; // Last network request, successful or not
- private long mLastSuccessfulNetworkQueryTime = 0; // Last successful network query time
-
- // Is provider enabled by user -- ignored by this class
- private boolean mEnabled;
-
- // Is provider being used by an application
- private HashSet<String> mApplications = new HashSet<String>();
- private boolean mTracking = false;
-
- // Location masf service
- private LocationMasfClient mMasfClient;
-
- // Context of location manager service
- private Context mContext;
-
- public static boolean isSupported() {
- // This class provides a Google-specific location feature, so it's enabled only
- // when the system property ro.com.google.locationfeatures is set.
- if (!SystemProperties.get("ro.com.google.locationfeatures").equals("1")) {
- return false;
- }
-
- // Otherwise, assume cell location should work if we are not running in the emulator
- return !SystemProperties.get("ro.kernel.qemu").equals("1");
- }
-
- public NetworkLocationProvider(Context context, LocationMasfClient masfClient) {
- super(LocationManager.NETWORK_PROVIDER);
- mContext = context;
- mMasfClient = masfClient;
- }
-
- @Override
- public void updateNetworkState(int state) {
- if (state == mNetworkState) {
- return;
- }
- log("updateNetworkState(): Updating network state to " + state);
- mNetworkState = state;
-
- updateStatus(mNetworkState);
- }
-
- @Override
- public void updateCellState(CellState newState) {
- if (newState == null) {
- log("updateCellState(): Cell state is invalid");
- return;
- }
-
- if (mCellState != null && mCellState.equals(newState)) {
- log("updateCellState(): Cell state is the same");
- return;
- }
-
- // Add previous state to history
- if ((mCellState != null) && mCellState.isValid()) {
- if (mCellHistory.size() >= MAX_CELL_HISTORY_TO_KEEP) {
- mCellHistory.remove(0);
- }
- mCellHistory.add(mCellState);
- }
-
- mCellState = newState;
- log("updateCellState(): Received");
-
- mLastCellLockTime = 0;
- mLastCellStateChangeTime = SystemClock.elapsedRealtime();
- }
-
- public void updateCellLockStatus(boolean acquired) {
- if (acquired) {
- mLastCellLockTime = SystemClock.elapsedRealtime();
- } else {
- mLastCellLockTime = 0;
- }
- }
-
- @Override
- public boolean requiresNetwork() {
- return true;
- }
-
- @Override
- public boolean requiresSatellite() {
- return false;
- }
-
- @Override
- public boolean requiresCell() {
- return true;
- }
-
- @Override
- public boolean hasMonetaryCost() {
- return true;
- }
-
- @Override
- public boolean supportsAltitude() {
- return false;
- }
-
- @Override
- public boolean supportsSpeed() {
- return false;
- }
-
- @Override
- public boolean supportsBearing() {
- return false;
- }
-
- @Override
- public int getPowerRequirement() {
- return Criteria.POWER_LOW;
- }
-
- @Override
- public void enable() {
- // Nothing else needs to be done
- mEnabled = true;
- }
-
- @Override
- public void disable() {
- // Nothing else needs to be done
- mEnabled = false;
- }
-
- @Override
- public boolean isEnabled() {
- return mEnabled;
- }
-
- @Override
- public int getAccuracy() {
- return Criteria.ACCURACY_COARSE;
- }
-
- @Override
- public int getStatus(Bundle extras) {
- return mStatus;
- }
-
- @Override
- public long getStatusUpdateTime() {
- return mStatusUpdateTime;
- }
-
- @Override
- public void setMinTime(long minTime) {
- if (minTime < MIN_TIME_BETWEEN_WIFI_REPORTS) {
- mWifiScanFrequency = MIN_TIME_BETWEEN_WIFI_REPORTS;
- } else {
- mWifiScanFrequency = minTime;
- }
- super.setMinTime(minTime);
- }
-
- @Override
- public boolean getLocation(Location l) {
-
- long now = SystemClock.elapsedRealtime();
-
- // Trigger a wifi scan and wait for its results if necessary
- if ((mWifiEnabled) &&
- (mWifiLastScanResults == null ||
- ((now - mLastWifiScanElapsedTime) > mWifiScanFrequency))) {
-
- boolean fallback = false;
-
- // If scan has been recently triggered
- if (mLastWifiScanTriggerTime != 0 &&
- ((now - mLastWifiScanTriggerTime) < mWifiScanFrequency)) {
- if ((now - mLastWifiScanTriggerTime) > MAX_TIME_TO_WAIT_FOR_RADIO) {
- // If no results from last trigger available, use cell results
- // This will also trigger a new scan
- log("getLocation(): falling back to cell");
- fallback = true;
- } else {
- // Just wait for the Wifi results to be available
- return false;
- }
- }
-
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- log("getLocation(): triggering a wifi scan");
- mLastWifiScanTriggerTime = now;
- boolean succeeded = wifiManager.startScan();
- if (!succeeded) {
- log("getLocation(): wifi scan did not succeed");
- // Wifi trigger failed, use cell results
- fallback = true;
- }
-
- // Wait for scan results
- if (!fallback) {
- return false;
- }
- }
-
- // If waiting for cell location
- if (mLastCellLockTime != 0 && ((now - mLastCellLockTime) < MAX_TIME_TO_WAIT_FOR_RADIO)) {
- return false;
- }
-
- // Update Location
- // 1) If there has been a cell state change
- // 2) If there was no successful reply for last network request
- if (mLastCellStateChangeTime > mLastNetworkQueryTime) {
- updateLocation();
- return false;
-
- } else if ((mLastNetworkQueryTime != 0)
- && (mLastNetworkQueryTime > mLastSuccessfulNetworkQueryTime)
- && ((now - mLastNetworkQueryTime) > MIN_NETWORK_RETRY_MILLIS)) {
- updateLocation();
- return false;
- }
-
- if (mLocation != null && mLocation.getAccuracy() > 0) {
-
- // We could have a Cell Id location which hasn't changed in a
- // while because we haven't switched towers so if the last location
- // time + mWifiScanFrequency is less than current time update the
- // locations time.
- long currentTime = System.currentTimeMillis();
- if ((mLocation.getTime() + mWifiScanFrequency) < currentTime) {
- mLocation.setTime(currentTime);
- }
- l.set(mLocation);
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- public void enableLocationTracking(boolean enable) {
- if (enable == mTracking) {
- return;
- }
-
- log("enableLocationTracking(): " + enable);
- mTracking = enable;
-
- if (!enable) {
- // When disabling the location provider, be sure to clear out old location
- clearLocation();
- } else {
- // When enabling provider, force location
- forceLocation();
- }
- }
-
- @Override
- public boolean isLocationTracking() {
- return mTracking;
- }
-
- /**
- * Notifies the provider that there are scan results available.
- *
- * @param scanResults list of wifi scan results
- */
- public void updateWifiScanResults(List<ScanResult> scanResults) {
- if (!mTracking) {
- return;
- }
-
- long now = SystemClock.elapsedRealtime();
-
- if (scanResults == null) {
- mWifiLastScanResults = null;
- mLastWifiScanElapsedTime = now;
- mLastWifiScanRealTime = System.currentTimeMillis();
-
- log("updateWifIScanResults(): NULL APs");
-
- // Force cell location since no wifi results available
- if (mWifiEnabled) {
- mLastCellLockTime = 0;
- mLastCellStateChangeTime = SystemClock.elapsedRealtime();
- }
-
- } else if ((mWifiLastScanResults == null)
- || (mWifiLastScanResults.size() <= 2 && scanResults.size() > mWifiLastScanResults.size())
- || ((now - mLastWifiScanElapsedTime) > mWifiScanFrequency)) {
-
- if (mWifiLastScanResults == null) {
- mWifiLastScanResults = new ArrayList<ScanResult>();
- } else {
- mWifiLastScanResults.clear();
- }
- mWifiLastScanResults.addAll(scanResults);
- mLastWifiScanElapsedTime = now;
- mLastWifiScanRealTime = System.currentTimeMillis();
-
- log("updateWifIScanResults(): " + mWifiLastScanResults.size() + " APs");
- updateLocation();
-
- }
- }
-
- /**
- * Notifies the provider if Wifi has been enabled or disabled
- * by the user
- *
- * @param enabled true if wifi is enabled; false otherwise
- */
- public void updateWifiEnabledState(boolean enabled) {
- mWifiEnabled = enabled;
-
- log("updateWifiEnabledState(): " + enabled);
-
- // Force location update
- forceLocation();
- }
-
- public void addListener(String[] applications) {
- if (applications != null) {
- for (String app : applications) {
- String a = app.replaceAll("com.google.android.", "");
- a = a.replaceAll("com.android.", "");
- mApplications.add(a);
- log("addListener(): " + a);
- }
- }
- }
-
- public void removeListener(String[] applications) {
- if (applications != null) {
- for (String app : applications) {
- String a = app.replaceAll("com.google.android.", "");
- a = a.replaceAll("com.android.", "");
- mApplications.remove(a);
- log("removeListener(): " + a);
- }
- }
- }
-
- private void clearLocation() {
- mLocation.setAccuracy(-1);
- updateStatus(TEMPORARILY_UNAVAILABLE);
- }
-
- private void forceLocation() {
- if (mWifiEnabled) {
- // Force another wifi scan
- mWifiLastScanResults = null;
- mLastWifiScanTriggerTime = 0;
- mLastWifiScanElapsedTime = 0;
- mLastWifiScanRealTime = 0;
- } else {
- // Force another cell location request
- mLastCellLockTime = 0;
- mLastCellStateChangeTime = SystemClock.elapsedRealtime();
- }
- }
-
- private void updateStatus(int status) {
- if (status != mStatus) {
- mStatus = status;
- mStatusUpdateTime = SystemClock.elapsedRealtime();
- }
- }
-
- /**
- * Gets location from the server is applications are tracking this provider
- *
- */
- private void updateLocation() {
-
- // If not being tracked, no need to do anything.
- if (!mTracking) {
- return;
- }
-
- // If network is not available, can't do anything
- if (mNetworkState != AVAILABLE) {
- return;
- }
-
- final long now = SystemClock.elapsedRealtime();
-
- // There is a pending network request
- if ((mLastNetworkQueryTime != 0) &&
- (mLastNetworkQueryTime > mLastSuccessfulNetworkQueryTime) &&
- ((now - mLastNetworkQueryTime) <= MIN_NETWORK_RETRY_MILLIS)) {
- return;
- }
-
- // Don't include wifi points if they're too old
- List<ScanResult> scanResults = null;
- if (mWifiEnabled && (mWifiLastScanResults != null &&
- ((now - mLastWifiScanElapsedTime) < (mWifiScanFrequency + MAX_TIME_TO_WAIT_FOR_RADIO)))) {
- scanResults = mWifiLastScanResults;
- }
-
- // If no valid cell information available
- boolean noCell = mCellState == null || !mCellState.isValid();
-
- // If no valid wifi information available
- boolean noWifi = scanResults == null || (scanResults.size() == 0);
-
- // If no cell-id or wi-fi update, just return invalid location
- if (noCell && noWifi) {
- clearLocation();
- return;
- }
-
- // What kind of a network location request was it
- int trigger;
- if (!mWifiEnabled) {
- if (!noCell) {
- trigger = GDebugProfile.TRIGGER_CELL_AND_WIFI_CHANGE;
- } else {
- trigger = GDebugProfile.TRIGGER_WIFI_CHANGE;
- }
- } else {
- trigger = GDebugProfile.TRIGGER_CELL_CHANGE;
- }
-
- try {
- mLastNetworkQueryTime = now;
- mMasfClient.getNetworkLocation(mApplications, trigger, mCellState, mCellHistory,
- scanResults, mLastWifiScanRealTime, new Callback() {
- public void locationReceived(Location location, boolean networkSuccessful) {
- // If location is valid and not the same as previously known location
- if ((location != null) && (location.getAccuracy() > 0) &&
- (location.getTime() != mLocation.getTime())) {
- mLocation.set(location);
- updateStatus(AVAILABLE);
- } else {
- // Location is unavailable
- clearLocation();
- }
-
- // Even if no location is available, network request could have succeeded
- if (networkSuccessful) {
- mLastSuccessfulNetworkQueryTime = SystemClock.elapsedRealtime();
- }
-
- }
- });
- } catch(Exception e) {
- Log.e(TAG, "updateLocation got exception:", e);
- }
- }
-
- public interface Callback {
-
- /**
- * Callback function to notify of a received network location
- *
- * @param location location object that is received. may be null if not a valid location
- * @param successful true if network query was successful, even if no location was found
- */
- void locationReceived(Location location, boolean successful);
- }
-
- private void log(String log) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, log);
- }
- }
-
-}
diff --git a/location/java/com/android/internal/location/ProtoRequestListener.java b/location/java/com/android/internal/location/ProtoRequestListener.java
deleted file mode 100644
index d73cd05..0000000
--- a/location/java/com/android/internal/location/ProtoRequestListener.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2007 The Android Open Source Project
-
-package com.android.internal.location;
-
-import com.google.common.io.GoogleHttpConnection;
-import com.google.common.io.protocol.ProtoBuf;
-import com.google.masf.ServiceCallback;
-import com.google.masf.protocol.Request;
-import com.google.masf.protocol.Response;
-import com.google.masf.services.AsyncResult;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import android.util.Log;
-
-/**
- * Listener for protocol buffer requests
- *
- * {@hide}
- */
-
-public class ProtoRequestListener implements Request.Listener {
- private final static String TAG = "ProtoRequestListener";
- private AsyncResult result;
- private ProtoBuf protoResponse;
-
- /**
- * @return the asynchronous result object
- */
- public AsyncResult getAsyncResult() {
- return result;
- }
-
- /**
- * Constructor for a ProtoRequestListener
- *
- * @param protoResponse ProtoBuf with correct type to fill response with
- * @param callback function to call after completed request (may be null)
- */
- public ProtoRequestListener(ProtoBuf protoResponse, ServiceCallback callback) {
- this.result = new AsyncResult(callback);
- this.protoResponse = protoResponse;
- }
-
- public boolean requestComplete(Request request, Response response)
- throws IOException {
- InputStream is = response.getInputStream();
- if (response.getStatusCode() == GoogleHttpConnection.HTTP_OK) {
- protoResponse.parse(is);
- result.setResult(protoResponse);
- } else {
- result.setResult(null);
- }
- return true;
- }
-
- public void requestException(Request request, Exception exception) {
- Log.e(TAG, "requestException()", exception);
- }
-}
diff --git a/location/java/com/android/internal/location/protocol/GAddressComponent.java b/location/java/com/android/internal/location/protocol/GAddressComponent.java
deleted file mode 100644
index a06a23d..0000000
--- a/location/java/com/android/internal/location/protocol/GAddressComponent.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GAddressComponent {
- static final int NAME = 1;
- static final int FEATURE_TYPE = 2;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GAppProfile.java b/location/java/com/android/internal/location/protocol/GAppProfile.java
deleted file mode 100644
index e3332eb..0000000
--- a/location/java/com/android/internal/location/protocol/GAppProfile.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GAppProfile {
- static final int APP_NAME = 1;
- static final int APP_KEY = 2;
- static final int REQUEST_TYPE = 3;
- static final int SEARCH_TYPE = 4;
- static final int SEARCH_TERM = 5;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GCell.java b/location/java/com/android/internal/location/protocol/GCell.java
deleted file mode 100644
index 21d1c48..0000000
--- a/location/java/com/android/internal/location/protocol/GCell.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GCell {
- static final int LAC = 1;
- static final int CELLID = 2;
- static final int MNC = 3;
- static final int MCC = 4;
- static final int RSSI = 5;
- static final int AGE = 6;
- static final int TIMING_ADVANCE = 7;
- static final int PRIMARY_SCRAMBLING_CODE = 8;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GCellularPlatformProfile.java b/location/java/com/android/internal/location/protocol/GCellularPlatformProfile.java
deleted file mode 100644
index a17da20..0000000
--- a/location/java/com/android/internal/location/protocol/GCellularPlatformProfile.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GCellularPlatformProfile {
- static final int RADIO_TYPE_GPRS = 3;
- static final int RADIO_TYPE_CDMA = 4;
- static final int RADIO_TYPE_WCDMA = 5;
-
- static final int RADIO_TYPE = 1;
- static final int CARRIER = 2;
- static final int IP = 3;
- static final int HOME_MNC = 4;
- static final int HOME_MCC = 5;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GCellularProfile.java b/location/java/com/android/internal/location/protocol/GCellularProfile.java
deleted file mode 100644
index 8c85bf7..0000000
--- a/location/java/com/android/internal/location/protocol/GCellularProfile.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GCellularProfile {
- static final int PRIMARY_CELL = 1;
- static final int TIMESTAMP = 2;
- static final int NEIGHBORS = 3;
- static final int HISTORICAL_CELLS = 4;
- static final int PREFETCH_MODE = 5;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GDebugProfile.java b/location/java/com/android/internal/location/protocol/GDebugProfile.java
deleted file mode 100644
index b964387..0000000
--- a/location/java/com/android/internal/location/protocol/GDebugProfile.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GDebugProfile {
- static final int TRIGGER_CELL_CHANGE = 1;
- static final int TRIGGER_WIFI_CHANGE = 2;
- static final int TRIGGER_CELL_AND_WIFI_CHANGE = 3;
- static final int TRIGGER_GPS_CHANGE = 4;
- static final int TRIGGER_OTHER = 5;
- static final int TRIGGER_COLLECTION_START_BURST = 6;
- static final int TRIGGER_COLLECTION_RESTART_BURST = 7;
- static final int TRIGGER_COLLECTION_CONTINUE_BURST = 8;
- static final int TRIGGER_COLLECTION_END_BURST = 9;
- static final int TRIGGER_COLLECTION_END_BURST_AT_SAME_LOCATION = 10;
- static final int TRIGGER_COLLECTION_MOVED_DISTANCE = 11;
-
- static final int TRIGGER = 1;
- static final int ACTUAL_REQUEST = 2;
- static final int CACHE_LOCATION = 3;
- static final int DEVICE_RESTART = 4;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GDeviceLocation.java b/location/java/com/android/internal/location/protocol/GDeviceLocation.java
deleted file mode 100644
index 462ab07..0000000
--- a/location/java/com/android/internal/location/protocol/GDeviceLocation.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GDeviceLocation {
- static final int LOCATION = 1;
- static final int CELL = 2;
- static final int WIFI_DEVICE = 3;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GFeature.java b/location/java/com/android/internal/location/protocol/GFeature.java
deleted file mode 100644
index 73fc1b3..0000000
--- a/location/java/com/android/internal/location/protocol/GFeature.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GFeature {
- static final int NAME = 1;
- static final int FEATURE_TYPE = 2;
- static final int ADDRESS = 3;
- static final int BOUNDS = 4;
- static final int CENTER = 5;
-
- static final int FEATURE_TYPE_UNKNOWN_TYPE = 0;
- static final int FEATURE_TYPE_COUNTRY = 1;
- static final int FEATURE_TYPE_COUNTRY_CODE = 2;
- static final int FEATURE_TYPE_ADMINISTRATIVE_AREA = 3;
- static final int FEATURE_TYPE_SUB_ADMINISTRATIVE_AREA = 4;
- static final int FEATURE_TYPE_LOCALITY = 5;
- static final int FEATURE_TYPE_SUB_LOCALITY = 6;
- static final int FEATURE_TYPE_PREMISES = 7;
- static final int FEATURE_TYPE_THOROUGHFARE = 8;
- static final int FEATURE_TYPE_SUB_THOROUGHFARE = 9;
- static final int FEATURE_TYPE_POST_CODE = 10;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GGeocodeRequest.java b/location/java/com/android/internal/location/protocol/GGeocodeRequest.java
deleted file mode 100644
index 4d56cc0..0000000
--- a/location/java/com/android/internal/location/protocol/GGeocodeRequest.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GGeocodeRequest {
- static final int NUM_FEATURE_LIMIT = 1;
- static final int INCLUDE_BOUNDING_BOXES = 2;
- static final int BOUNDING_BOX = 3;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GGpsProfile.java b/location/java/com/android/internal/location/protocol/GGpsProfile.java
deleted file mode 100644
index be69eb0..0000000
--- a/location/java/com/android/internal/location/protocol/GGpsProfile.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GGpsProfile {
- static final int FIX_QUALITY_INVALID = 0;
- static final int FIX_QUALITY_GPS_FIX = 1;
- static final int FIX_QUALITY_DGPS_FIX = 2;
-
- static final int GPS_FIX_TYPE = 1;
- static final int PDOP = 2;
- static final int HDOP = 3;
- static final int VDOP = 4;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GLocReply.java b/location/java/com/android/internal/location/protocol/GLocReply.java
deleted file mode 100644
index 7a0504f..0000000
--- a/location/java/com/android/internal/location/protocol/GLocReply.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GLocReply {
- static final int STATUS = 1;
- static final int REPLY_ELEMENTS = 2;
- static final int PLATFORM_KEY = 3;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GLocReplyElement.java b/location/java/com/android/internal/location/protocol/GLocReplyElement.java
deleted file mode 100644
index bc47fcf..0000000
--- a/location/java/com/android/internal/location/protocol/GLocReplyElement.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GLocReplyElement {
- static final int STATUS = 1;
- static final int LOCATION = 2;
- static final int DEVICE_LOCATION = 3;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GLocRequest.java b/location/java/com/android/internal/location/protocol/GLocRequest.java
deleted file mode 100644
index 7761c11..0000000
--- a/location/java/com/android/internal/location/protocol/GLocRequest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GLocRequest {
- static final int PLATFORM_PROFILE = 1;
- static final int APP_PROFILES = 2;
- static final int USER_PROFILE = 3;
- static final int REQUEST_ELEMENTS = 4;
- static final int MASF_CLIENT_INFO = 257;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GLocRequestElement.java b/location/java/com/android/internal/location/protocol/GLocRequestElement.java
deleted file mode 100644
index d758953..0000000
--- a/location/java/com/android/internal/location/protocol/GLocRequestElement.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GLocRequestElement {
- static final int CELLULAR_PROFILE = 1;
- static final int WIFI_PROFILE = 2;
- static final int LOCATION = 3;
- static final int GEOCODE = 4;
- static final int DEBUG_PROFILE = 99;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GLocation.java b/location/java/com/android/internal/location/protocol/GLocation.java
deleted file mode 100644
index 9a1eb1f..0000000
--- a/location/java/com/android/internal/location/protocol/GLocation.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GLocation {
- static final int LOCTYPE_GPS = 0;
- static final int LOCTYPE_MAPCENTER = 1;
- static final int LOCTYPE_CENTROID = 2;
- static final int LOCTYPE_TOWER_LOCATION = 3;
-
- static final int LAT_LNG = 1;
- static final int SOURCE = 2;
- static final int ACCURACY = 3;
- static final int CONFIDENCE = 4;
- static final int FEATURE = 5;
- static final int TIMESTAMP = 6;
- static final int OBSOLETE = 7;
- static final int LOC_TYPE = 8;
- static final int MISC = 9;
- static final int ALTITUDE = 10;
- static final int VERTICAL_ACCURACY = 11;
- static final int VELOCITY = 12;
- static final int HEADING = 13;
- static final int GPS_PROFILE = 14;
- static final int LOCATION_STRING = 15;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GPlatformProfile.java b/location/java/com/android/internal/location/protocol/GPlatformProfile.java
deleted file mode 100644
index 32a1f8f..0000000
--- a/location/java/com/android/internal/location/protocol/GPlatformProfile.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GPlatformProfile {
- static final int VERSION = 1;
- static final int PLATFORM = 2;
- static final int PLATFORM_KEY = 3;
- static final int DISTRIBUTION_CHANNEL = 4;
- static final int LOCALE = 5;
- static final int CELLULAR_PLATFORM_PROFILE = 6;
- static final int WIFI_PLATFORM_PROFILE = 7;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GPrefetchMode.java b/location/java/com/android/internal/location/protocol/GPrefetchMode.java
deleted file mode 100644
index 041b686..0000000
--- a/location/java/com/android/internal/location/protocol/GPrefetchMode.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GPrefetchMode {
- static final int PREFETCH_MODE_NO_PREFETCH = 0;
- static final int PREFETCH_MODE_REQUESTED_NEIGHBORS_ONLY = 1;
- static final int PREFETCH_MODE_MORE_NEIGHBORS = 2;
-
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GRectangle.java b/location/java/com/android/internal/location/protocol/GRectangle.java
deleted file mode 100644
index b8412e6..0000000
--- a/location/java/com/android/internal/location/protocol/GRectangle.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GRectangle {
- static final int LOWER_LEFT = 1;
- static final int UPPER_RIGHT = 2;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GUserProfile.java b/location/java/com/android/internal/location/protocol/GUserProfile.java
deleted file mode 100644
index 2ce962c..0000000
--- a/location/java/com/android/internal/location/protocol/GUserProfile.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GUserProfile {
- static final int USER_NAME = 1;
- static final int AUTH_TOKEN = 2;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GWifiDevice.java b/location/java/com/android/internal/location/protocol/GWifiDevice.java
deleted file mode 100644
index 62bd03a..0000000
--- a/location/java/com/android/internal/location/protocol/GWifiDevice.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GWifiDevice {
- static final int MAC = 1;
- static final int SSID = 2;
- static final int CHANNEL = 3;
- static final int RSSI = 4;
- static final int NOISE = 5;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GWifiPlatformProfile.java b/location/java/com/android/internal/location/protocol/GWifiPlatformProfile.java
deleted file mode 100644
index 7f1efcb..0000000
--- a/location/java/com/android/internal/location/protocol/GWifiPlatformProfile.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GWifiPlatformProfile {
- static final int RADIO_TYPE_WIFI802_11_A = 1;
- static final int RADIO_TYPE_WIFI802_11_B = 2;
- static final int RADIO_TYPE_WIFI802_11_G = 3;
- static final int RADIO_TYPE_WIFI802_11_N = 4;
-
- static final int SCANNER_MAC = 1;
- static final int SCANNER_IP = 2;
- static final int RADIO_TYPE = 3;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GWifiProfile.java b/location/java/com/android/internal/location/protocol/GWifiProfile.java
deleted file mode 100644
index e731027..0000000
--- a/location/java/com/android/internal/location/protocol/GWifiProfile.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface GWifiProfile {
- static final int TIMESTAMP = 1;
- static final int WIFI_DEVICES = 2;
- static final int PREFETCH_MODE = 3;
-}
-
diff --git a/location/java/com/android/internal/location/protocol/GaddressMessageTypes.java b/location/java/com/android/internal/location/protocol/GaddressMessageTypes.java
deleted file mode 100644
index 7b6ffd0..0000000
--- a/location/java/com/android/internal/location/protocol/GaddressMessageTypes.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-import com.google.common.io.protocol.ProtoBufType;
-
-public class GaddressMessageTypes {
- public static final ProtoBufType GADDRESS = new ProtoBufType();
- public static final ProtoBufType GADDRESS_COMPONENT = new ProtoBufType();
-
- static {
- GADDRESS
- .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_DATA,
- GAddress.FORMATTED_ADDRESS_LINE, null)
- .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_MESSAGE,
- GAddress.COMPONENT, GADDRESS_COMPONENT);
-
- GADDRESS_COMPONENT
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_DATA,
- GAddressComponent.NAME, null)
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_INT32,
- GAddressComponent.FEATURE_TYPE, null);
-
- }
-}
diff --git a/location/java/com/android/internal/location/protocol/GcellularMessageTypes.java b/location/java/com/android/internal/location/protocol/GcellularMessageTypes.java
deleted file mode 100644
index 37a6d52..0000000
--- a/location/java/com/android/internal/location/protocol/GcellularMessageTypes.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-import com.google.common.io.protocol.ProtoBufType;
-
-public class GcellularMessageTypes {
- public static final ProtoBufType GCELL = new ProtoBufType();
- public static final ProtoBufType GCELLULAR_PROFILE = new ProtoBufType();
-
- static {
- GCELL
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_INT32,
- GCell.LAC, null)
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_INT32,
- GCell.CELLID, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GCell.MNC, new Long(-1))
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GCell.MCC, new Long(-1))
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GCell.RSSI, new Long(-9999))
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GCell.AGE, new Long(0))
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GCell.TIMING_ADVANCE, new Long(-1))
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GCell.PRIMARY_SCRAMBLING_CODE, null);
-
- GCELLULAR_PROFILE
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_MESSAGE,
- GCellularProfile.PRIMARY_CELL, GCELL)
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_INT64,
- GCellularProfile.TIMESTAMP, null)
- .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_MESSAGE,
- GCellularProfile.NEIGHBORS, GCELL)
- .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_MESSAGE,
- GCellularProfile.HISTORICAL_CELLS, GCELL)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GCellularProfile.PREFETCH_MODE, null);
-
- }
-}
diff --git a/location/java/com/android/internal/location/protocol/GdebugprofileMessageTypes.java b/location/java/com/android/internal/location/protocol/GdebugprofileMessageTypes.java
deleted file mode 100644
index 9a51efe..0000000
--- a/location/java/com/android/internal/location/protocol/GdebugprofileMessageTypes.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-import com.google.common.io.protocol.ProtoBuf;
-import com.google.common.io.protocol.ProtoBufType;
-
-public class GdebugprofileMessageTypes {
- public static final ProtoBufType GDEBUG_PROFILE = new ProtoBufType();
-
- static {
- GDEBUG_PROFILE
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GDebugProfile.TRIGGER, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_BOOL,
- GDebugProfile.ACTUAL_REQUEST, ProtoBuf.TRUE)
- .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_MESSAGE,
- GDebugProfile.CACHE_LOCATION, GlocationMessageTypes.GDEVICE_LOCATION)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_BOOL,
- GDebugProfile.DEVICE_RESTART, ProtoBuf.FALSE);
-
- }
-}
diff --git a/location/java/com/android/internal/location/protocol/GfeatureMessageTypes.java b/location/java/com/android/internal/location/protocol/GfeatureMessageTypes.java
deleted file mode 100644
index 24b182a..0000000
--- a/location/java/com/android/internal/location/protocol/GfeatureMessageTypes.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-import com.google.common.io.protocol.ProtoBufType;
-
-public class GfeatureMessageTypes {
- public static final ProtoBufType GFEATURE_TYPE = new ProtoBufType();
- public static final ProtoBufType GFEATURE = new ProtoBufType();
-
- static {
- GFEATURE
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_DATA,
- GFeature.NAME, null)
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_INT32,
- GFeature.FEATURE_TYPE, null)
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_MESSAGE,
- GFeature.ADDRESS, GaddressMessageTypes.GADDRESS)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GFeature.BOUNDS, GrectangleMessageTypes.GRECTANGLE)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GFeature.CENTER, GlatlngMessageTypes.GLAT_LNG);
-
- }
-}
diff --git a/location/java/com/android/internal/location/protocol/GlocationMessageTypes.java b/location/java/com/android/internal/location/protocol/GlocationMessageTypes.java
deleted file mode 100644
index 067d47c..0000000
--- a/location/java/com/android/internal/location/protocol/GlocationMessageTypes.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-import com.google.common.io.protocol.ProtoBufType;
-
-public class GlocationMessageTypes {
- public static final ProtoBufType GGPS_PROFILE = new ProtoBufType();
- public static final ProtoBufType GLOCATION = new ProtoBufType();
- public static final ProtoBufType GDEVICE_LOCATION = new ProtoBufType();
- public static final ProtoBufType GCELLULAR_PLATFORM_PROFILE = new ProtoBufType();
- public static final ProtoBufType GWIFI_PLATFORM_PROFILE = new ProtoBufType();
- public static final ProtoBufType GPREFETCH_MODE = new ProtoBufType();
- public static final ProtoBufType GPLATFORM_PROFILE = new ProtoBufType();
- public static final ProtoBufType GAPP_PROFILE = new ProtoBufType();
- public static final ProtoBufType GUSER_PROFILE = new ProtoBufType();
-
- static {
- GGPS_PROFILE
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GGpsProfile.GPS_FIX_TYPE, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GGpsProfile.PDOP, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GGpsProfile.HDOP, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GGpsProfile.VDOP, null);
-
- GLOCATION
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GLocation.LAT_LNG, GlatlngMessageTypes.GLAT_LNG)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GLocation.SOURCE, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GLocation.ACCURACY, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GLocation.CONFIDENCE, null)
- .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_MESSAGE,
- GLocation.FEATURE, GfeatureMessageTypes.GFEATURE)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT64,
- GLocation.TIMESTAMP, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_BOOL,
- GLocation.OBSOLETE, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GLocation.LOC_TYPE, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GLocation.MISC, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GLocation.ALTITUDE, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GLocation.VERTICAL_ACCURACY, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GLocation.VELOCITY, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GLocation.HEADING, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GLocation.GPS_PROFILE, GGPS_PROFILE)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GLocation.LOCATION_STRING, null);
-
- GDEVICE_LOCATION
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GDeviceLocation.LOCATION, GLOCATION)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GDeviceLocation.CELL, GcellularMessageTypes.GCELL)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GDeviceLocation.WIFI_DEVICE, GwifiMessageTypes.GWIFI_DEVICE);
-
- GCELLULAR_PLATFORM_PROFILE
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GCellularPlatformProfile.RADIO_TYPE, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GCellularPlatformProfile.CARRIER, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GCellularPlatformProfile.IP, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GCellularPlatformProfile.HOME_MNC, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GCellularPlatformProfile.HOME_MCC, null);
-
- GWIFI_PLATFORM_PROFILE
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GWifiPlatformProfile.SCANNER_MAC, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GWifiPlatformProfile.SCANNER_IP, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GWifiPlatformProfile.RADIO_TYPE, null);
-
- GPLATFORM_PROFILE
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_DATA,
- GPlatformProfile.VERSION, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GPlatformProfile.PLATFORM, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GPlatformProfile.PLATFORM_KEY, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GPlatformProfile.DISTRIBUTION_CHANNEL, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GPlatformProfile.LOCALE, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GPlatformProfile.CELLULAR_PLATFORM_PROFILE, GCELLULAR_PLATFORM_PROFILE)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GPlatformProfile.WIFI_PLATFORM_PROFILE, GWIFI_PLATFORM_PROFILE);
-
- GAPP_PROFILE
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GAppProfile.APP_NAME, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GAppProfile.APP_KEY, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GAppProfile.REQUEST_TYPE, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GAppProfile.SEARCH_TYPE, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GAppProfile.SEARCH_TERM, null);
-
- GUSER_PROFILE
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GUserProfile.USER_NAME, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GUserProfile.AUTH_TOKEN, null);
-
- }
-}
diff --git a/location/java/com/android/internal/location/protocol/GwifiMessageTypes.java b/location/java/com/android/internal/location/protocol/GwifiMessageTypes.java
deleted file mode 100644
index cd7119b..0000000
--- a/location/java/com/android/internal/location/protocol/GwifiMessageTypes.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-import com.google.common.io.protocol.ProtoBufType;
-
-public class GwifiMessageTypes {
- public static final ProtoBufType GWIFI_DEVICE = new ProtoBufType();
- public static final ProtoBufType GWIFI_PROFILE = new ProtoBufType();
-
- static {
- GWIFI_DEVICE
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_DATA,
- GWifiDevice.MAC, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GWifiDevice.SSID, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GWifiDevice.CHANNEL, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GWifiDevice.RSSI, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GWifiDevice.NOISE, null);
-
- GWIFI_PROFILE
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_INT64,
- GWifiProfile.TIMESTAMP, null)
- .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_MESSAGE,
- GWifiProfile.WIFI_DEVICES, GWIFI_DEVICE)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_INT32,
- GWifiProfile.PREFETCH_MODE, null);
-
- }
-}
diff --git a/location/java/com/android/internal/location/protocol/LocserverMessageTypes.java b/location/java/com/android/internal/location/protocol/LocserverMessageTypes.java
deleted file mode 100644
index 8ffd004..0000000
--- a/location/java/com/android/internal/location/protocol/LocserverMessageTypes.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-import com.google.common.io.protocol.ProtoBuf;
-import com.google.common.io.protocol.ProtoBufType;
-
-public class LocserverMessageTypes {
- public static final ProtoBufType RESPONSE_CODES = new ProtoBufType();
- public static final ProtoBufType GLOC_REQUEST_ELEMENT = new ProtoBufType();
- public static final ProtoBufType GLOC_REQUEST = new ProtoBufType();
- public static final ProtoBufType GGEOCODE_REQUEST = new ProtoBufType();
- public static final ProtoBufType GLOC_REPLY_ELEMENT = new ProtoBufType();
- public static final ProtoBufType GLOC_REPLY = new ProtoBufType();
-
- static {
- GLOC_REQUEST_ELEMENT
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GLocRequestElement.CELLULAR_PROFILE, GcellularMessageTypes.GCELLULAR_PROFILE)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GLocRequestElement.WIFI_PROFILE, GwifiMessageTypes.GWIFI_PROFILE)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GLocRequestElement.LOCATION, GlocationMessageTypes.GLOCATION)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GLocRequestElement.GEOCODE, GGEOCODE_REQUEST)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GLocRequestElement.DEBUG_PROFILE, GdebugprofileMessageTypes.GDEBUG_PROFILE);
-
- GLOC_REQUEST
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_MESSAGE,
- GLocRequest.PLATFORM_PROFILE, GlocationMessageTypes.GPLATFORM_PROFILE)
- .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_MESSAGE,
- GLocRequest.APP_PROFILES, GlocationMessageTypes.GAPP_PROFILE)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GLocRequest.USER_PROFILE, GlocationMessageTypes.GUSER_PROFILE)
- .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_MESSAGE,
- GLocRequest.REQUEST_ELEMENTS, GLOC_REQUEST_ELEMENT)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GLocRequest.MASF_CLIENT_INFO, null);
-
- GGEOCODE_REQUEST
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_FIXED32,
- GGeocodeRequest.NUM_FEATURE_LIMIT, new Long(1))
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_BOOL,
- GGeocodeRequest.INCLUDE_BOUNDING_BOXES, ProtoBuf.FALSE)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GGeocodeRequest.BOUNDING_BOX, GrectangleMessageTypes.GRECTANGLE);
-
- GLOC_REPLY_ELEMENT
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_INT32,
- GLocReplyElement.STATUS, null)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_MESSAGE,
- GLocReplyElement.LOCATION, GlocationMessageTypes.GLOCATION)
- .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_MESSAGE,
- GLocReplyElement.DEVICE_LOCATION, GlocationMessageTypes.GDEVICE_LOCATION);
-
- GLOC_REPLY
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_INT32,
- GLocReply.STATUS, null)
- .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_MESSAGE,
- GLocReply.REPLY_ELEMENTS, GLOC_REPLY_ELEMENT)
- .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_DATA,
- GLocReply.PLATFORM_KEY, null);
-
- }
-}
diff --git a/location/java/com/android/internal/location/protocol/ResponseCodes.java b/location/java/com/android/internal/location/protocol/ResponseCodes.java
deleted file mode 100644
index 2ea9318..0000000
--- a/location/java/com/android/internal/location/protocol/ResponseCodes.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.location.protocol;
-
-public interface ResponseCodes {
- static final int STATUS_STATUS_SUCCESS = 0;
- static final int STATUS_STATUS_FAILED = 1;
- static final int STATUS_AUTHORIZATION_REJECTED = 2;
- static final int STATUS_NO_SOURCE_EXISTS = 3;
- static final int STATUS_SIGNAL_TOO_WEAK = 4;
- static final int STATUS_INVALID_REQUEST = 5;
- static final int STATUS_INVALID_NUM_REQUESTS = 6;
- static final int STATUS_INVALID_USERLOCATION_FORMAT = 7;
- static final int STATUS_INVALID_OPERATION_CODE = 8;
- static final int STATUS_INVALID_MAC_STRING_FORMAT = 9;
- static final int STATUS_INVALID_CELLID_STRING_FORMAT = 10;
- static final int STATUS_NON_EXISTENT_AP = 11;
- static final int STATUS_NON_EXISTENT_CELLID = 12;
- static final int STATUS_STATUS_FAILED_NO_SOURCE = 13;
- static final int STATUS_STATUS_FAILED_NO_SAVE = 14;
- static final int STATUS_PLATFORM_KEY_EXPIRED = 15;
- static final int STATUS_NO_STORE_EXISTS = 16;
- static final int STATUS_NO_CELLIDDATA_FOR_UPDATE = 17;
- static final int STATUS_NON_SUPPORTED_OPERATION_IN_UPDATE = 18;
- static final int STATUS_NON_SUPPORTED_OPERATION = 19;
- static final int STATUS_STATUS_FAILED_NO_GEOCODE = 20;
- static final int STATUS_BLACKLISTED_IP_CELLID = 100;
- static final int STATUS_BLACKLISTED_IP_WIFI = 101;
-
-}
-
diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java
index 0620f32..35f0409 100644
--- a/media/java/android/media/AsyncPlayer.java
+++ b/media/java/android/media/AsyncPlayer.java
@@ -22,6 +22,7 @@ import android.os.PowerManager;
import android.util.Log;
import java.io.IOException;
+import java.lang.IllegalStateException;
/**
* Plays a series of audio URIs, but does all the hard work on another thread
@@ -71,20 +72,20 @@ public class AsyncPlayer {
// is playing, let it continue until we're done, so there
// is less of a glitch.
MediaPlayer player = new MediaPlayer();
- player.setDataSource(cmd.context, cmd.uri);
player.setAudioStreamType(cmd.stream);
+ player.setDataSource(cmd.context, cmd.uri);
player.setLooping(cmd.looping);
player.prepare();
+ player.start();
if (mPlayer != null) {
- // stop the previous one.
- mPlayer.stop();
mPlayer.release();
}
- player.start();
mPlayer = player;
}
catch (IOException e) {
Log.w(mTag, "error loading sound for " + cmd.uri, e);
+ } catch (IllegalStateException e) {
+ Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
}
break;
case STOP:
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index c857e17..0732b61 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -18,9 +18,9 @@ package android.media;
/**
* The AudioFormat class is used to access a number of audio format and
- * channel configuration constants.
+ * channel configuration constants. They are for instance used
+ * in __link AudioTrack} and __link AudioRecord}.
*
- * {@hide Pending API council review}
*/
public class AudioFormat {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 52cf69f..077d016 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -49,37 +49,60 @@ public class AudioManager {
private static boolean localLOGV = DEBUG || android.util.Config.LOGV;
/**
+ * Broadcast intent, a hint for applications that audio is about to become
+ * 'noisy' due to a change in audio outputs. For example, this intent may
+ * be sent when a wired headset is unplugged, or when an A2DP audio
+ * sink is disconnected, and the audio system is about to automatically
+ * switch audio route to the speaker. Applications that are controlling
+ * audio streams may consider pausing, reducing volume or some other action
+ * on receipt of this intent so as not to surprise the user with audio
+ * from the speaker.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
+
+ /**
* Sticky broadcast intent action indicating that the ringer mode has
* changed. Includes the new ringer mode.
- *
+ *
* @see #EXTRA_RINGER_MODE
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
-
+
/**
* The new ringer mode.
- *
+ *
* @see #RINGER_MODE_CHANGED_ACTION
* @see #RINGER_MODE_NORMAL
* @see #RINGER_MODE_SILENT
* @see #RINGER_MODE_VIBRATE
*/
public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
-
+
/**
* Broadcast intent action indicating that the vibrate setting has
* changed. Includes the vibrate type and its new setting.
- *
+ *
* @see #EXTRA_VIBRATE_TYPE
* @see #EXTRA_VIBRATE_SETTING
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String VIBRATE_SETTING_CHANGED_ACTION = "android.media.VIBRATE_SETTING_CHANGED";
-
+
+ /**
+ * @hide Broadcast intent when the volume for a particular stream type changes.
+ * Includes the stream and the new volume
+ *
+ * @see #EXTRA_VOLUME_STREAM_TYPE
+ * @see #EXTRA_VOLUME_STREAM_VALUE
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
+
/**
* The new vibrate setting for a particular type.
- *
+ *
* @see #VIBRATE_SETTING_CHANGED_ACTION
* @see #EXTRA_VIBRATE_TYPE
* @see #VIBRATE_SETTING_ON
@@ -87,21 +110,32 @@ public class AudioManager {
* @see #VIBRATE_SETTING_ONLY_SILENT
*/
public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
-
+
/**
* The vibrate type whose setting has changed.
- *
+ *
* @see #VIBRATE_SETTING_CHANGED_ACTION
* @see #VIBRATE_TYPE_NOTIFICATION
* @see #VIBRATE_TYPE_RINGER
*/
public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
-
+
+ /**
+ * @hide The stream type for the volume changed intent.
+ */
+ public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
+
+ /**
+ * @hide The volume associated with the stream for the volume changed intent.
+ */
+ public static final String EXTRA_VOLUME_STREAM_VALUE =
+ "android.media.EXTRA_VOLUME_STREAM_VALUE";
+
/** The audio stream for phone calls */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
/** The audio stream for system sounds */
public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
- /** The audio stream for the phone ring and message alerts */
+ /** The audio stream for the phone ring */
public static final int STREAM_RING = AudioSystem.STREAM_RING;
/** The audio stream for music playback */
public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
@@ -109,6 +143,8 @@ public class AudioManager {
public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
/** The audio stream for notifications */
public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
+ /** @hide The audio stream for phone calls when connected to bluetooth */
+ public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
/** Number of audio streams */
/**
* @deprecated Use AudioSystem.getNumStreamTypes() instead
@@ -123,9 +159,10 @@ public class AudioManager {
8, // STREAM_RING
16, // STREAM_MUSIC
8, // STREAM_ALARM
- 8 // STREAM_NOTIFICATION
- };
-
+ 8, // STREAM_NOTIFICATION
+ 15, // STREAM_BLUETOOTH_SCO
+ };
+
/** @hide Default volume index values for audio streams */
public static final int[] DEFAULT_STREAM_VOLUME = new int[] {
4, // STREAM_VOICE_CALL
@@ -133,12 +170,13 @@ public class AudioManager {
5, // STREAM_RING
11, // STREAM_MUSIC
6, // STREAM_ALARM
- 5 // STREAM_NOTIFICATION
- };
-
+ 5, // STREAM_NOTIFICATION
+ 7 // STREAM_BLUETOOTH_SCO
+ };
+
/**
* Increase the ringer volume.
- *
+ *
* @see #adjustVolume(int, int)
* @see #adjustStreamVolume(int, int, int)
*/
@@ -146,7 +184,7 @@ public class AudioManager {
/**
* Decrease the ringer volume.
- *
+ *
* @see #adjustVolume(int, int)
* @see #adjustStreamVolume(int, int, int)
*/
@@ -155,17 +193,17 @@ public class AudioManager {
/**
* Maintain the previous ringer volume. This may be useful when needing to
* show the volume toast without actually modifying the volume.
- *
+ *
* @see #adjustVolume(int, int)
* @see #adjustStreamVolume(int, int, int)
*/
public static final int ADJUST_SAME = 0;
// Flags should be powers of 2!
-
+
/**
* Show a toast containing the current volume.
- *
+ *
* @see #adjustStreamVolume(int, int, int)
* @see #adjustVolume(int, int)
* @see #setStreamVolume(int, int, int)
@@ -176,19 +214,18 @@ public class AudioManager {
/**
* Whether to include ringer modes as possible options when changing volume.
* For example, if true and volume level is 0 and the volume is adjusted
- * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent
- * or vibrate mode.
+ * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
+ * vibrate mode.
* <p>
- * By default this is on for stream types that are affected by the ringer
- * mode (for example, the ring stream type). If this flag is included, this
- * behavior will be present regardless of the stream type being affected by
- * the ringer mode.
+ * 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)
*/
public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1;
-
+
/**
* Whether to play a sound when changing the volume.
* <p>
@@ -197,28 +234,28 @@ public class AudioManager {
* in some cases (for example, the decided stream type is not
* {@link AudioManager#STREAM_RING}, or the volume is being adjusted
* downward).
- *
+ *
* @see #adjustStreamVolume(int, int, int)
* @see #adjustVolume(int, int)
* @see #setStreamVolume(int, int, int)
*/
public static final int FLAG_PLAY_SOUND = 1 << 2;
-
+
/**
* Removes any sounds/vibrate that may be in the queue, or are playing (related to
* changing volume).
*/
public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3;
-
+
/**
* Whether to vibrate if going into the vibrate ringer mode.
*/
public static final int FLAG_VIBRATE = 1 << 4;
-
+
/**
* Ringer mode that will be silent and will not vibrate. (This overrides the
* vibrate setting.)
- *
+ *
* @see #setRingerMode(int)
* @see #getRingerMode()
*/
@@ -228,7 +265,7 @@ public class AudioManager {
* Ringer mode that will be silent and will vibrate. (This will cause the
* phone ringer to always vibrate, but the notification vibrate to only
* vibrate if set.)
- *
+ *
* @see #setRingerMode(int)
* @see #getRingerMode()
*/
@@ -238,7 +275,7 @@ public class AudioManager {
* Ringer mode that may be audible and may vibrate. It will be audible if
* the volume before changing out of this mode was audible. It will vibrate
* if the vibrate setting is on.
- *
+ *
* @see #setRingerMode(int)
* @see #getRingerMode()
*/
@@ -246,53 +283,53 @@ public class AudioManager {
/**
* Vibrate type that corresponds to the ringer.
- *
+ *
* @see #setVibrateSetting(int, int)
* @see #getVibrateSetting(int)
* @see #shouldVibrate(int)
*/
public static final int VIBRATE_TYPE_RINGER = 0;
-
+
/**
* Vibrate type that corresponds to notifications.
- *
+ *
* @see #setVibrateSetting(int, int)
* @see #getVibrateSetting(int)
* @see #shouldVibrate(int)
*/
public static final int VIBRATE_TYPE_NOTIFICATION = 1;
-
+
/**
* Vibrate setting that suggests to never vibrate.
- *
+ *
* @see #setVibrateSetting(int, int)
* @see #getVibrateSetting(int)
*/
public static final int VIBRATE_SETTING_OFF = 0;
-
+
/**
* Vibrate setting that suggests to vibrate when possible.
- *
+ *
* @see #setVibrateSetting(int, int)
* @see #getVibrateSetting(int)
*/
public static final int VIBRATE_SETTING_ON = 1;
-
+
/**
* Vibrate setting that suggests to only vibrate when in the vibrate ringer
* mode.
- *
+ *
* @see #setVibrateSetting(int, int)
* @see #getVibrateSetting(int)
*/
public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
-
+
/**
* Suggests using the default stream type. This may not be used in all
* places a stream type is needed.
*/
public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
-
+
private static IAudioService sService;
/**
@@ -315,8 +352,8 @@ public class AudioManager {
/**
* Adjusts the volume of a particular stream by one step in a direction.
- *
- * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
+ *
+ * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
* {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC} or
* {@link #STREAM_ALARM}
* @param direction The direction to adjust the volume. One of
@@ -340,7 +377,7 @@ public class AudioManager {
* active, it will have the highest priority regardless of if the in-call
* screen is showing. Another example, if music is playing in the background
* and a call is not active, the music stream will be adjusted.
- *
+ *
* @param direction The direction to adjust the volume. One of
* {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
* {@link #ADJUST_SAME}.
@@ -361,7 +398,7 @@ public class AudioManager {
/**
* Adjusts the volume of the most relevant stream, or the given fallback
* stream.
- *
+ *
* @param direction The direction to adjust the volume. One of
* {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
* {@link #ADJUST_SAME}.
@@ -380,10 +417,10 @@ public class AudioManager {
Log.e(TAG, "Dead object in adjustVolume", e);
}
}
-
+
/**
* Returns the current ringtone mode.
- *
+ *
* @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
* {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
* @see #setRingerMode(int)
@@ -400,7 +437,7 @@ public class AudioManager {
/**
* Returns the maximum volume index for a particular stream.
- *
+ *
* @param streamType The stream type whose maximum volume index is returned.
* @return The maximum valid volume index for the stream.
* @see #getStreamVolume(int)
@@ -417,7 +454,7 @@ public class AudioManager {
/**
* Returns the current volume index for a particular stream.
- *
+ *
* @param streamType The stream type whose volume index is returned.
* @return The current volume index for the stream.
* @see #getStreamMaxVolume(int)
@@ -439,7 +476,7 @@ public class AudioManager {
* Silent mode will mute the volume and will not vibrate. Vibrate mode will
* mute the volume and vibrate. Normal mode will be audible and may vibrate
* according to user settings.
- *
+ *
* @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
* {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
* @see #getRingerMode()
@@ -455,7 +492,7 @@ public class AudioManager {
/**
* Sets the volume index for a particular stream.
- *
+ *
* @param streamType The stream whose volume index should be set.
* @param index The volume index to set. See
* {@link #getStreamMaxVolume(int)} for the largest valid value.
@@ -471,7 +508,7 @@ public class AudioManager {
Log.e(TAG, "Dead object in setStreamVolume", e);
}
}
-
+
/**
* Solo or unsolo a particular stream. All other streams are muted.
* <p>
@@ -479,13 +516,13 @@ public class AudioManager {
* with an active solo request on a stream dies, all streams that were muted
* because of this request will be unmuted automatically.
* <p>
- * The solo requests for a given stream are cumulative: the AudioManager
+ * The solo requests for a given stream are cumulative: the AudioManager
* can receive several solo requests from one or more clients and the stream
* will be unsoloed only when the same number of unsolo requests are received.
* <p>
- * For a better user experience, applications MUST unsolo a soloed stream
+ * For a better user experience, applications MUST unsolo a soloed stream
* in onPause() and solo is again in onResume() if appropriate.
- *
+ *
* @param streamType The stream to be soloed/unsoloed.
* @param state The required solo state: true for solo ON, false for solo OFF
*/
@@ -497,7 +534,7 @@ public class AudioManager {
Log.e(TAG, "Dead object in setStreamSolo", e);
}
}
-
+
/**
* Mute or unmute an audio stream.
* <p>
@@ -505,13 +542,13 @@ public class AudioManager {
* with an active mute request on a stream dies, this stream will be unmuted
* automatically.
* <p>
- * The mute requests for a given stream are cumulative: the AudioManager
+ * The mute requests for a given stream are cumulative: the AudioManager
* can receive several mute requests from one or more clients and the stream
* will be unmuted only when the same number of unmute requests are received.
* <p>
- * For a better user experience, applications MUST unmute a muted stream
+ * For a better user experience, applications MUST unmute a muted stream
* in onPause() and mute is again in onResume() if appropriate.
- *
+ *
* @param streamType The stream to be muted/unmuted.
* @param state The required mute state: true for mute ON, false for mute OFF
*/
@@ -532,7 +569,7 @@ public class AudioManager {
* vibrate. The notification manager will not vibrate if the policy doesn't
* allow it, so the client should always set a vibrate pattern and let the
* notification manager control whether or not to actually vibrate.
- *
+ *
* @param vibrateType The type of vibrate. One of
* {@link #VIBRATE_TYPE_NOTIFICATION} or
* {@link #VIBRATE_TYPE_RINGER}.
@@ -550,13 +587,13 @@ public class AudioManager {
return false;
}
}
-
+
/**
* Returns whether the user's vibrate setting for a vibrate type.
* <p>
* This shouldn't be needed by most clients that want to vibrate, instead
* see {@link #shouldVibrate(int)}.
- *
+ *
* @param vibrateType The type of vibrate. One of
* {@link #VIBRATE_TYPE_NOTIFICATION} or
* {@link #VIBRATE_TYPE_RINGER}.
@@ -578,7 +615,7 @@ public class AudioManager {
/**
* Sets the setting for when the vibrate type should vibrate.
- *
+ *
* @param vibrateType The type of vibrate. One of
* {@link #VIBRATE_TYPE_NOTIFICATION} or
* {@link #VIBRATE_TYPE_RINGER}.
@@ -597,11 +634,11 @@ public class AudioManager {
Log.e(TAG, "Dead object in setVibrateSetting", e);
}
}
-
+
/**
* Sets the speakerphone on or off.
*
- * @param on set <var>true</var> to turn on speakerphone;
+ * @param on set <var>true</var> to turn on speakerphone;
* <var>false</var> to turn it off
*/
public void setSpeakerphoneOn(boolean on){
@@ -620,17 +657,17 @@ public class AudioManager {
/**
* Sets audio routing to the Bluetooth headset on or off.
*
- * @param on set <var>true</var> to route SCO (voice) audio to/from Bluetooth
+ * @param on set <var>true</var> to route SCO (voice) audio to/from Bluetooth
* headset; <var>false</var> to route audio to/from phone earpiece
*/
public void setBluetoothScoOn(boolean on){
// Don't disable A2DP when turning off SCO.
// A2DP does not affect in-call routing.
- setRouting(MODE_RINGTONE,
+ setRouting(MODE_RINGTONE,
on ? ROUTE_BLUETOOTH_SCO: ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP);
- setRouting(MODE_NORMAL,
+ setRouting(MODE_NORMAL,
on ? ROUTE_BLUETOOTH_SCO: ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP);
- setRouting(MODE_IN_CALL,
+ setRouting(MODE_IN_CALL,
on ? ROUTE_BLUETOOTH_SCO: ROUTE_EARPIECE, ROUTE_ALL);
}
@@ -647,15 +684,15 @@ public class AudioManager {
/**
* Sets A2DP audio routing to the Bluetooth headset on or off.
*
- * @param on set <var>true</var> to route A2DP audio to/from Bluetooth
+ * @param on set <var>true</var> to route A2DP audio to/from Bluetooth
* headset; <var>false</var> disable A2DP audio
*/
public void setBluetoothA2dpOn(boolean on){
// the audio flinger chooses A2DP as a higher priority,
// so there is no need to disable other routes.
- setRouting(MODE_RINGTONE,
+ setRouting(MODE_RINGTONE,
on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP);
- setRouting(MODE_NORMAL,
+ setRouting(MODE_NORMAL,
on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP);
}
@@ -672,7 +709,7 @@ public class AudioManager {
/**
* Sets audio routing to the wired headset on or off.
*
- * @param on set <var>true</var> to route audio to/from wired
+ * @param on set <var>true</var> to route audio to/from wired
* headset; <var>false</var> disable wired headset audio
* @hide
*/
@@ -701,7 +738,7 @@ public class AudioManager {
/**
* Sets the microphone mute on or off.
*
- * @param on set <var>true</var> to mute the microphone;
+ * @param on set <var>true</var> to mute the microphone;
* <var>false</var> to turn mute off
*/
public void setMicrophoneMute(boolean on){
@@ -762,57 +799,57 @@ public class AudioManager {
/* modes for setMode/getMode/setRoute/getRoute */
/**
- * Audio harware modes.
- */
+ * Audio harware modes.
+ */
/**
- * Invalid audio mode.
- */
+ * Invalid audio mode.
+ */
public static final int MODE_INVALID = AudioSystem.MODE_INVALID;
/**
* Current audio mode. Used to apply audio routing to current mode.
- */
+ */
public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT;
/**
* Normal audio mode: not ringing and no call established.
- */
+ */
public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL;
/**
* Ringing audio mode. An incoming is being signaled.
- */
+ */
public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE;
/**
* In call audio mode. A call is established.
- */
+ */
public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL;
/* Routing bits for setRouting/getRouting API */
/**
* Routing audio output to earpiece
- */
+ */
public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
/**
* Routing audio output to spaker
- */
+ */
public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
/**
* @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
- */
+ */
@Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
/**
* Routing audio output to bluetooth SCO
- */
+ */
public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
/**
* Routing audio output to headset
- */
+ */
public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
/**
* Routing audio output to bluetooth A2DP
- */
+ */
public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
/**
* Used for mask parameter of {@link #setRouting(int,int,int)}.
- */
+ */
public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
/**
@@ -892,33 +929,57 @@ public class AudioManager {
/**
* Keyboard and direction pad click sound
* @see #playSoundEffect(int)
- */
+ */
public static final int FX_KEY_CLICK = 0;
/**
- * Focuse has moved up
+ * Focus has moved up
* @see #playSoundEffect(int)
- */
+ */
public static final int FX_FOCUS_NAVIGATION_UP = 1;
/**
- * Focuse has moved down
+ * Focus has moved down
* @see #playSoundEffect(int)
- */
+ */
public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
/**
- * Focuse has moved left
+ * Focus has moved left
* @see #playSoundEffect(int)
- */
+ */
public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
/**
- * Focuse has moved right
+ * Focus has moved right
* @see #playSoundEffect(int)
- */
+ */
public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
/**
- * @hide Number of sound effects
- */
- public static final int NUM_SOUND_EFFECTS = 5;
-
+ * 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;
+ /**
+ * @hide Number of sound effects
+ */
+ public static final int NUM_SOUND_EFFECTS = 9;
+
/**
* Plays a sound effect (Key clicks, lid open/close...)
* @param effectType The type of sound effect. One of
@@ -927,6 +988,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},
+ * NOTE: This version uses the UI settings to determine
+ * whether sounds are heard or not.
*/
public void playSoundEffect(int effectType) {
if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
@@ -946,15 +1014,46 @@ public class AudioManager {
}
/**
+ * Plays a sound effect (Key clicks, lid open/close...)
+ * @param effectType The type of sound effect. One of
+ * {@link #FX_KEY_CLICK},
+ * {@link #FX_FOCUS_NAVIGATION_UP},
+ * {@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},
+ * @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) {
+ return;
+ }
+
+ IAudioService service = getService();
+ try {
+ service.playSoundEffectVolume(effectType, volume);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in playSoundEffect"+e);
+ }
+ }
+
+ /**
* Settings has an in memory cache, so this is fast.
*/
private boolean querySoundEffectsEnabled() {
return Settings.System.getInt(mContext.getContentResolver(), Settings.System.SOUND_EFFECTS_ENABLED, 0) != 0;
}
-
-
+
+
/**
- * Load Sound effects.
+ * Load Sound effects.
* This method must be called when sound effects are enabled.
*/
public void loadSoundEffects() {
@@ -965,9 +1064,9 @@ public class AudioManager {
Log.e(TAG, "Dead object in loadSoundEffects"+e);
}
}
-
+
/**
- * Unload Sound effects.
+ * Unload Sound effects.
* This method can be called to free some memory when
* sound effects are disabled.
*/
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 7912003b..0ef7760 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -34,11 +34,14 @@ import android.util.Log;
* to record audio from the audio input hardware of the platform. This is
* achieved by "pulling" (reading) the data from the AudioRecord object. The
* application is responsible for polling the AudioRecord object in time using one of
- * the following three methods: {@link #read(byte[], int)}, {@link #read(short[], int)}
+ * the following three methods: {@link #read(byte[],int, int)}, {@link #read(short[], int, int)}
* or {@link #read(ByteBuffer, int)}. The choice of which method to use will be based
* on the audio data storage format that is the most convenient for the user of AudioRecord.
- *
- * {@hide Pending API council review}
+ * <p>Upon creation, an AudioRecord object initializes its associated audio buffer that it will
+ * fill with the new audio data. The size of this buffer, specified during the construction,
+ * determines how long an AudioRecord can record before "over-running" data that has not
+ * been read yet. Data should be from the audio hardware in chunks of sizes inferior to
+ * the total recording buffer size.
*/
public class AudioRecord
{
@@ -82,22 +85,22 @@ public class AudioRecord
*/
public static final int ERROR_INVALID_OPERATION = -3;
- private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT = -4;
- private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT = -5;
- private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT = -6;
- private static final int AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE = -7;
- private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED = -8;
+ private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT = -16;
+ private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELCOUNT = -17;
+ private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT = -18;
+ private static final int AUDIORECORD_ERROR_SETUP_INVALIDSTREAMTYPE = -19;
+ private static final int AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED = -20;
// Events:
// to keep in sync with frameworks/base/include/media/AudioRecord.h
/**
* Event id for when the recording head has reached a previously set marker.
*/
- protected static final int EVENT_MARKER = 2;
+ private static final int NATIVE_EVENT_MARKER = 2;
/**
* Event id for when the previously set update period has passed during recording.
*/
- protected static final int EVENT_NEW_POS = 3;
+ private static final int NATIVE_EVENT_NEW_POS = 3;
private final static String TAG = "AudioRecord-Java";
@@ -130,63 +133,63 @@ public class AudioRecord
/**
* The audio data sampling rate in Hz.
*/
- protected int mSampleRate = 22050;
+ private int mSampleRate = 22050;
/**
* The number of input audio channels (1 is mono, 2 is stereo)
*/
- protected int mChannelCount = 1;
+ private int mChannelCount = 1;
/**
* The current audio channel configuration
*/
- protected int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
/**
* The encoding of the audio samples.
- * @see #AudioFormat.ENCODING_PCM_8BIT
- * @see #AudioFormat.ENCODING_PCM_16BIT
+ * @see AudioFormat#ENCODING_PCM_8BIT
+ * @see AudioFormat#ENCODING_PCM_16BIT
*/
- protected int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
+ private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
/**
* Where the audio data is recorded from.
*/
- protected int mRecordSource = MediaRecorder.AudioSource.DEFAULT;
+ private int mRecordSource = MediaRecorder.AudioSource.DEFAULT;
/**
* Indicates the state of the AudioRecord instance.
*/
- protected int mState = STATE_UNINITIALIZED;
+ private int mState = STATE_UNINITIALIZED;
/**
* Indicates the recording state of the AudioRecord instance.
*/
- protected int mRecordingState = RECORDSTATE_STOPPED;
+ private int mRecordingState = RECORDSTATE_STOPPED;
/**
* Lock to make sure mRecordingState updates are reflecting the actual state of the object.
*/
- protected Object mRecordingStateLock = new Object();
+ private Object mRecordingStateLock = new Object();
/**
* The listener the AudioRecord notifies when a previously set marker is reached.
* @see #setMarkerReachedListener(OnMarkerReachedListener)
*/
- protected OnMarkerReachedListener mMarkerListener = null;
+ private OnMarkerReachedListener mMarkerListener = null;
/**
* Lock to protect marker listener updates against event notifications
*/
- protected final Object mMarkerListenerLock = new Object();
+ private final Object mMarkerListenerLock = new Object();
/**
* The listener the AudioRecord notifies periodically during recording.
* @see #setPeriodicNotificationListener(OnPeriodicNotificationListener)
*/
- protected OnPeriodicNotificationListener mPeriodicListener = null;
+ private OnPeriodicNotificationListener mPeriodicListener = null;
/**
* Lock to protect periodic listener updates against event notifications
*/
- protected final Object mPeriodicListenerLock = new Object();
+ private final Object mPeriodicListenerLock = new Object();
/**
* Handler for events coming from the native code
*/
- protected NativeEventHandler mNativeEventHandler = null;
+ private NativeEventHandler mNativeEventHandler = null;
/**
* Size of the native audio buffer.
*/
- protected int mNativeBufferSizeInBytes = 0;
+ private int mNativeBufferSizeInBytes = 0;
//---------------------------------------------------------
@@ -194,30 +197,30 @@ public class AudioRecord
//--------------------
/**
* Class constructor.
- * @param audioSource the recording source. See {@link MediaRecorder.AudioSource.DEFAULT}
- * and {@link MediaRecorder.AudioSource.MIC}.
+ * @param audioSource the recording source. See {@link MediaRecorder.AudioSource} for
+ * recording source definitions.
* @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
* not limited to) 44100, 22050 and 11025.
* @param channelConfig describes the configuration of the audio channels.
- * See {@link AudioFormat.CHANNEL_CONFIGURATION_MONO} and
- * {@link AudioFormat.CHANNEL_CONFIGURATION_STEREO}
+ * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
+ * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
* @param audioFormat the format in which the audio data is represented.
- * See {@link AudioFormat.ENCODING_PCM_16BIT} and
- * {@link AudioFormat.ENCODING_PCM_8BIT}
+ * See {@link AudioFormat#ENCODING_PCM_16BIT} and
+ * {@link AudioFormat#ENCODING_PCM_8BIT}
* @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
* to during the recording. New audio data can be read from this buffer in smaller chunks
* than this size.
* @throws java.lang.IllegalArgumentException
*/
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
- int blockSizeInBytes)
+ int bufferSizeInBytes)
throws IllegalArgumentException {
mState = STATE_UNINITIALIZED;
mRecordingState = RECORDSTATE_STOPPED;
audioParamCheck(audioSource, sampleRateInHz, channelConfig, audioFormat);
- audioBuffSizeCheck(blockSizeInBytes);
+ audioBuffSizeCheck(bufferSizeInBytes);
// native initialization
//TODO: update native initialization when information about hardware init failure
@@ -336,7 +339,11 @@ public class AudioRecord
* Releases the native AudioRecord resources.
*/
public void release() {
- stop();
+ try {
+ stop();
+ } catch(IllegalStateException ise) {
+ // don't raise an exception, we're releasing the resources.
+ }
native_release();
mState = STATE_UNINITIALIZED;
}
@@ -367,8 +374,8 @@ public class AudioRecord
}
/**
- * Returns the configured audio data format. See {@link #AudioFormat.ENCODING_PCM_16BIT}
- * and {@link #AudioFormat.ENCODING_PCM_8BIT}.
+ * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
+ * and {@link AudioFormat#ENCODING_PCM_8BIT}.
*/
public int getAudioFormat() {
return mAudioFormat;
@@ -376,8 +383,8 @@ public class AudioRecord
/**
* Returns the configured channel configuration.
- * See {@link #AudioFormat.CHANNEL_CONFIGURATION_MONO}
- * and {@link #AudioFormat.CHANNEL_CONFIGURATION_STEREO}.
+ * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO}
+ * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}.
*/
public int getChannelConfiguration() {
return mChannelConfiguration;
@@ -395,8 +402,8 @@ public class AudioRecord
* AudioRecord instance has been created to check if it was initialized
* properly. This ensures that the appropriate hardware resources have been
* acquired.
- * @see AudioRecord.STATE_INITIALIZED
- * @see AudioRecord.STATE_UNINITIALIZED
+ * @see AudioRecord#STATE_INITIALIZED
+ * @see AudioRecord#STATE_UNINITIALIZED
*/
public int getState() {
return mState;
@@ -404,8 +411,8 @@ public class AudioRecord
/**
* Returns the recording state of the AudioRecord instance.
- * @see AudioRecord.RECORDSTATE_STOPPED
- * @see AudioRecord.RECORDSTATE_RECORDING
+ * @see AudioRecord#RECORDSTATE_STOPPED
+ * @see AudioRecord#RECORDSTATE_RECORDING
*/
public int getRecordingState() {
return mRecordingState;
@@ -424,6 +431,56 @@ public class AudioRecord
public int getPositionNotificationPeriod() {
return native_get_pos_update_period();
}
+
+ /**
+ * {@hide}
+ * Returns the minimum buffer size required for the successful creation of an AudioRecord
+ * object.
+ * @param sampleRateInHz the sample rate expressed in Hertz.
+ * @param channelConfig describes the configuration of the audio channels.
+ * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
+ * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+ * @param audioFormat the format in which the audio data is represented.
+ * See {@link AudioFormat#ENCODING_PCM_16BIT}.
+ * @return {@link #ERROR_BAD_VALUE} if the recording parameters are not supported by the
+ * hardware, or an invalid parameter was passed,
+ * or {@link #ERROR} if the implementation was unable to query the hardware for its
+ * output properties,
+ * or the minimum buffer size expressed in of bytes.
+ */
+ static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
+ int channelCount = 0;
+ switch(channelConfig) {
+ case AudioFormat.CHANNEL_CONFIGURATION_DEFAULT:
+ case AudioFormat.CHANNEL_CONFIGURATION_MONO:
+ channelCount = 1;
+ break;
+ case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
+ channelCount = 2;
+ break;
+ case AudioFormat.CHANNEL_CONFIGURATION_INVALID:
+ default:
+ loge("getMinBufferSize(): Invalid channel configuration.");
+ return AudioRecord.ERROR_BAD_VALUE;
+ }
+
+ // PCM_8BIT is not supported at the moment
+ if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) {
+ loge("getMinBufferSize(): Invalid audio format.");
+ return AudioRecord.ERROR_BAD_VALUE;
+ }
+
+ int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
+ if (size == 0) {
+ return AudioRecord.ERROR_BAD_VALUE;
+ }
+ else if (size == -1) {
+ return AudioRecord.ERROR;
+ }
+ else {
+ return size;
+ }
+ }
//---------------------------------------------------------
@@ -472,16 +529,22 @@ public class AudioRecord
//--------------------
/**
* Reads audio data from the audio hardware for recording into a buffer.
- * @throws IllegalStateException
* @param audioData the array to which the recorded audio data is written.
* @param offsetInBytes index in audioData from which the data is written.
* @param sizeInBytes the number of requested bytes.
- * @return the number of bytes that were read. This will not exceed sizeInBytes
+ * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
+ * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+ * the parameters don't resolve to valid data and indexes.
+ * The number of bytes will not exceed sizeInBytes.
*/
- public int read(byte[] audioData, int offsetInBytes, int sizeInBytes)
- throws IllegalStateException {
+ public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) {
if (mState != STATE_INITIALIZED) {
- throw(new IllegalStateException("read() called on uninitialized AudioRecord."));
+ return ERROR_INVALID_OPERATION;
+ }
+
+ if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
+ || (offsetInBytes + sizeInBytes > audioData.length)) {
+ return ERROR_BAD_VALUE;
}
return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes);
@@ -490,16 +553,22 @@ public class AudioRecord
/**
* Reads audio data from the audio hardware for recording into a buffer.
- * @throws IllegalStateException
* @param audioData the array to which the recorded audio data is written.
* @param offsetInShorts index in audioData from which the data is written.
* @param sizeInShorts the number of requested shorts.
- * @return the number of shorts that were read. This will not exceed sizeInShorts
+ * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
+ * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+ * the parameters don't resolve to valid data and indexes.
+ * The number of shorts will not exceed sizeInShorts.
*/
- public int read(short[] audioData, int offsetInShorts, int sizeInShorts)
- throws IllegalStateException {
+ public int read(short[] audioData, int offsetInShorts, int sizeInShorts) {
if (mState != STATE_INITIALIZED) {
- throw(new IllegalStateException("read() called on uninitialized AudioRecord."));
+ return ERROR_INVALID_OPERATION;
+ }
+
+ if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
+ || (offsetInShorts + sizeInShorts > audioData.length)) {
+ return ERROR_BAD_VALUE;
}
return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts);
@@ -509,15 +578,20 @@ public class AudioRecord
/**
* Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
* is not a direct buffer, this method will always return 0.
- * @throws IllegalStateException
* @param audioBuffer the direct buffer to which the recorded audio data is written.
* @param sizeInBytes the number of requested bytes.
- * @return the number of bytes that were read. This will not exceed sizeInBytes.
+ * @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
+ * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+ * the parameters don't resolve to valid data and indexes.
+ * The number of bytes will not exceed sizeInBytes.
*/
- public int read(ByteBuffer audioBuffer, int sizeInBytes)
- throws IllegalStateException {
+ public int read(ByteBuffer audioBuffer, int sizeInBytes) {
if (mState != STATE_INITIALIZED) {
- throw(new IllegalStateException("read() called on uninitialized AudioRecord."));
+ return ERROR_INVALID_OPERATION;
+ }
+
+ if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
+ return ERROR_BAD_VALUE;
}
return native_read_in_direct_buffer(audioBuffer, sizeInBytes);
@@ -590,7 +664,7 @@ public class AudioRecord
* Called on the listener to notify it that the previously set marker has been reached
* by the recording head.
*/
- void onMarkerReached(AudioRecord track);
+ void onMarkerReached(AudioRecord recorder);
}
@@ -603,7 +677,7 @@ public class AudioRecord
* Called on the listener to periodically notify it that the recording head has reached
* a multiple of the notification period.
*/
- void onPeriodicNotification(AudioRecord track);
+ void onPeriodicNotification(AudioRecord recorder);
}
@@ -628,14 +702,14 @@ public class AudioRecord
return;
}
switch(msg.what) {
- case EVENT_MARKER:
+ case NATIVE_EVENT_MARKER:
synchronized (mMarkerListenerLock) {
if (mAudioRecord.mMarkerListener != null) {
mAudioRecord.mMarkerListener.onMarkerReached(mAudioRecord);
}
}
break;
- case EVENT_NEW_POS:
+ case NATIVE_EVENT_NEW_POS:
synchronized (mPeriodicListenerLock) {
if (mAudioRecord.mPeriodicListener != null) {
mAudioRecord.mPeriodicListener.onPeriodicNotification(mAudioRecord);
@@ -643,7 +717,7 @@ public class AudioRecord
}
break;
default:
- Log.e(TAG, "[ android.media.AudioTrack.NativeEventHandler ] " +
+ Log.e(TAG, "[ android.media.AudioRecord.NativeEventHandler ] " +
"Unknown event type: " + msg.what);
break;
}
@@ -658,14 +732,14 @@ public class AudioRecord
private static void postEventFromNative(Object audiorecord_ref,
int what, int arg1, int arg2, Object obj) {
//logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
- AudioRecord track = (AudioRecord)((WeakReference)audiorecord_ref).get();
- if (track == null) {
+ AudioRecord recorder = (AudioRecord)((WeakReference)audiorecord_ref).get();
+ if (recorder == null) {
return;
}
- if (track.mNativeEventHandler != null) {
- Message m = track.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
- track.mNativeEventHandler.sendMessage(m);
+ if (recorder.mNativeEventHandler != null) {
+ Message m = recorder.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
+ recorder.mNativeEventHandler.sendMessage(m);
}
}
@@ -699,6 +773,9 @@ public class AudioRecord
private native final int native_set_pos_update_period(int updatePeriod);
private native final int native_get_pos_update_period();
+
+ static private native final int native_get_min_buff_size(
+ int sampleRateInHz, int channelCount, int audioFormat);
//---------------------------------------------------------
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index b39e7bb..83ede0d 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -16,8 +16,7 @@
package android.media;
-import com.android.internal.telephony.ITelephony;
-
+import android.app.ActivityManagerNative;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -32,11 +31,13 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.provider.Settings.System;
import android.provider.Settings;
+import android.provider.Settings.System;
import android.util.Log;
import android.view.VolumePanel;
+import com.android.internal.telephony.ITelephony;
+
import java.io.IOException;
import java.util.ArrayList;
@@ -50,19 +51,19 @@ import java.util.ArrayList;
* volume and later persist to the database. Similarly, setting the ringer mode
* will update the state and broadcast a change and in a separate thread later
* persist the ringer mode.
- *
+ *
* @hide
*/
public class AudioService extends IAudioService.Stub {
-
+
private static final String TAG = "AudioService";
/** How long to delay before persisting a change in volume/ringer mode. */
private static final int PERSIST_DELAY = 3000;
-
+
private Context mContext;
private ContentResolver mContentResolver;
-
+
/** The UI */
private VolumePanel mVolumePanel;
@@ -75,7 +76,7 @@ public class AudioService extends IAudioService.Stub {
private static final int SENDMSG_NOOP = 1;
/** If the msg is already queued, queue this one and leave the old. */
private static final int SENDMSG_QUEUE = 2;
-
+
// AudioHandler message.whats
private static final int MSG_SET_SYSTEM_VOLUME = 0;
private static final int MSG_PERSIST_VOLUME = 1;
@@ -91,22 +92,26 @@ public class AudioService extends IAudioService.Stub {
private AudioHandler mAudioHandler;
/** @see VolumeStreamState */
private VolumeStreamState[] mStreamStates;
-
+
private boolean mMicMute;
private int mMode;
private int[] mRoutes = new int[AudioSystem.NUM_MODES];
private Object mSettingsLock = new Object();
private boolean mMediaServerOk;
-
+
private SoundPool mSoundPool;
private Object mSoundEffectsLock = new Object();
private static final int NUM_SOUNDPOOL_CHANNELS = 4;
- private static final float SOUND_EFFECT_VOLUME = 1.0f;
-
+ private static final int SOUND_EFFECT_VOLUME = 1000;
+
/* Sound effect file names */
private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
private static final String[] SOUND_EFFECT_FILES = new String[] {
- "Effect_Tick.ogg"
+ "Effect_Tick.ogg",
+ "KeypressStandard.ogg",
+ "KeypressSpacebar.ogg",
+ "KeypressDelete.ogg",
+ "KeypressReturn.ogg"
};
/* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
@@ -117,9 +122,13 @@ public class AudioService extends IAudioService.Stub {
{0, -1}, // FX_FOCUS_NAVIGATION_UP
{0, -1}, // FX_FOCUS_NAVIGATION_DOWN
{0, -1}, // FX_FOCUS_NAVIGATION_LEFT
- {0, -1} // FX_FOCUS_NAVIGATION_RIGHT
+ {0, -1}, // FX_FOCUS_NAVIGATION_RIGHT
+ {1, -1}, // FX_KEYPRESS_STANDARD
+ {2, -1}, // FX_KEYPRESS_SPACEBAR
+ {3, -1}, // FX_FOCUS_DELETE
+ {4, -1} // FX_FOCUS_RETURN
};
-
+
private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
public void onError(int error) {
switch (error) {
@@ -145,7 +154,7 @@ public class AudioService extends IAudioService.Stub {
* Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
* {@link AudioManager#RINGER_MODE_SILENT}, or
* {@link AudioManager#RINGER_MODE_VIBRATE}.
- */
+ */
private int mRingerMode;
/** @see System#MODE_RINGER_STREAMS_AFFECTED */
@@ -153,7 +162,7 @@ public class AudioService extends IAudioService.Stub {
/** @see System#MUTE_STREAMS_AFFECTED */
private int mMuteAffectedStreams;
-
+
/**
* Has multiple bits per vibrate type to indicate the type's vibrate
* setting. See {@link #setVibrateSetting(int, int)}.
@@ -162,26 +171,24 @@ public class AudioService extends IAudioService.Stub {
* type since it depends on the ringer mode. See {@link #shouldVibrate(int)}.
*/
private int mVibrateSetting;
-
+
///////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////
-
+
/** @hide */
public AudioService(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
mVolumePanel = new VolumePanel(context, this);
-
+
createAudioSystemThread();
createStreamStates();
readPersistedSettings();
readAudioSettings();
mMediaServerOk = true;
- AudioSystem.setErrorCallback(mAudioSystemCallback);
- if (Settings.System.getInt(mContentResolver, Settings.System.SOUND_EFFECTS_ENABLED, 0) == 1) {
- loadSoundEffects();
- }
+ AudioSystem.setErrorCallback(mAudioSystemCallback);
+ loadSoundEffects();
}
private void createAudioSystemThread() {
@@ -189,8 +196,8 @@ public class AudioService extends IAudioService.Stub {
mAudioSystemThread.start();
waitForAudioHandlerCreation();
}
-
- /** Waits for the volume handler to be created by the other thread. */
+
+ /** Waits for the volume handler to be created by the other thread. */
private void waitForAudioHandlerCreation() {
synchronized(this) {
while (mAudioHandler == null) {
@@ -203,37 +210,51 @@ public class AudioService extends IAudioService.Stub {
}
}
}
-
+
private void createStreamStates() {
- final int[] volumeLevelsPhone = createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]);
- final int[] volumeLevelsCoarse = createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]);
- final int[] volumeLevelsFine = createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
-
+ final int[] volumeLevelsPhone =
+ createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]);
+ final int[] volumeLevelsCoarse =
+ createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]);
+ final int[] volumeLevelsFine =
+ createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
+ final int[] volumeLevelsBtPhone =
+ createVolumeLevels(0,
+ AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_BLUETOOTH_SCO]);
+
int numStreamTypes = AudioSystem.getNumStreamTypes();
VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
-
+
for (int i = 0; i < numStreamTypes; i++) {
final int[] levels;
-
+
switch (i) {
-
+
case AudioSystem.STREAM_MUSIC:
levels = volumeLevelsFine;
break;
-
+
case AudioSystem.STREAM_VOICE_CALL:
levels = volumeLevelsPhone;
break;
-
+
+ case AudioSystem.STREAM_BLUETOOTH_SCO:
+ levels = volumeLevelsBtPhone;
+ break;
+
default:
levels = volumeLevelsCoarse;
break;
}
-
- streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[i], i, levels);
+
+ if (i == AudioSystem.STREAM_BLUETOOTH_SCO) {
+ streams[i] = new VolumeStreamState(AudioManager.DEFAULT_STREAM_VOLUME[i], i,levels);
+ } else {
+ streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[i], i, levels);
+ }
}
}
-
+
private static int[] createVolumeLevels(int offset, int numlevels) {
double curve = 1.0f; // 1.4f
int [] volumes = new int[numlevels + offset];
@@ -249,7 +270,7 @@ public class AudioService extends IAudioService.Stub {
}
return volumes;
}
-
+
private void readPersistedSettings() {
final ContentResolver cr = mContentResolver;
@@ -260,19 +281,19 @@ public class AudioService extends IAudioService.Stub {
mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0);
mMuteAffectedStreams = System.getInt(cr,
- System.MUTE_STREAMS_AFFECTED,
+ System.MUTE_STREAMS_AFFECTED,
((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM)));
-
+
// Each stream will read its own persisted settings
-
+
// Broadcast the sticky intent
broadcastRingerMode();
-
+
// Broadcast vibrate settings
broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
}
-
+
private void readAudioSettings() {
synchronized (mSettingsLock) {
mMicMute = AudioSystem.isMicrophoneMuted();
@@ -282,7 +303,7 @@ public class AudioService extends IAudioService.Stub {
}
}
}
-
+
private void applyAudioSettings() {
synchronized (mSettingsLock) {
AudioSystem.muteMicrophone(mMicMute);
@@ -291,69 +312,69 @@ public class AudioService extends IAudioService.Stub {
AudioSystem.setRouting(mode, mRoutes[mode], AudioSystem.ROUTE_ALL);
}
}
- }
-
+ }
+
///////////////////////////////////////////////////////////////////////////
// IPC methods
///////////////////////////////////////////////////////////////////////////
-
+
/** @see AudioManager#adjustVolume(int, int) */
public void adjustVolume(int direction, int flags) {
adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags);
}
-
+
/** @see AudioManager#adjustVolume(int, int, int) */
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
int streamType = getActiveStreamType(suggestedStreamType);
-
+
// Don't play sound on other streams
if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
}
-
+
adjustStreamVolume(streamType, direction, flags);
}
-
+
/** @see AudioManager#adjustStreamVolume(int, int, int) */
public void adjustStreamVolume(int streamType, int direction, int flags) {
ensureValidDirection(direction);
ensureValidStreamType(streamType);
-
+
boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1;
if (notificationsUseRingVolume && streamType == AudioManager.STREAM_NOTIFICATION) {
// Redirect the volume change to the ring stream
streamType = AudioManager.STREAM_RING;
}
-
+
VolumeStreamState streamState = mStreamStates[streamType];
- final int oldIndex = streamState.mIndex;
+ final int oldIndex = streamState.mIndex;
boolean adjustVolume = true;
-
+
// If either the client forces allowing ringer modes for this adjustment,
// or the stream type is one that is affected by ringer modes
if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0
- || isStreamAffectedByRingerMode(streamType)) {
+ || streamType == AudioManager.STREAM_RING) {
// Check if the ringer mode changes with this volume adjustment. If
- // it does, it will handle adjusting the volome, so we won't below
+ // it does, it will handle adjusting the volume, so we won't below
adjustVolume = checkForRingerModeChange(oldIndex, direction);
}
-
+
if (adjustVolume && streamState.adjustIndex(direction)) {
-
+
boolean alsoUpdateNotificationVolume = notificationsUseRingVolume &&
streamType == AudioManager.STREAM_RING;
if (alsoUpdateNotificationVolume) {
mStreamStates[AudioManager.STREAM_NOTIFICATION].adjustIndex(direction);
}
-
+
// Post message to set system volume (it in turn will post a message
// to persist). Do not change volume if stream is muted.
if (streamState.muteCount() == 0) {
sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
streamState, 0);
-
+
if (alsoUpdateNotificationVolume) {
sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, AudioManager.STREAM_NOTIFICATION,
SENDMSG_NOOP, 0, 0, mStreamStates[AudioManager.STREAM_NOTIFICATION], 0);
@@ -363,12 +384,44 @@ public class AudioService extends IAudioService.Stub {
// UI
mVolumePanel.postVolumeChanged(streamType, flags);
+ // Broadcast Intent
+ sendVolumeUpdate(streamType);
}
/** @see AudioManager#setStreamVolume(int, int, int) */
public void setStreamVolume(int streamType, int index, int flags) {
ensureValidStreamType(streamType);
-
+ syncRingerAndNotificationStreamVolume(streamType, index, false);
+
+ setStreamVolumeInt(streamType, index, false);
+
+ // UI, etc.
+ mVolumePanel.postVolumeChanged(streamType, flags);
+ // Broadcast Intent
+ sendVolumeUpdate(streamType);
+ }
+
+ private void sendVolumeUpdate(int streamType) {
+ Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
+ intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType));
+
+ // Currently, sending the intent only when the stream is BLUETOOTH_SCO
+ if (streamType == AudioManager.STREAM_BLUETOOTH_SCO) {
+ mContext.sendBroadcast(intent);
+ }
+ }
+
+ /**
+ * Sync the STREAM_RING and STREAM_NOTIFICATION volumes if mandated by the
+ * value in Settings.
+ *
+ * @param streamType Type of the stream
+ * @param index Volume index for the stream
+ * @param force If true, set the volume even if the current and desired
+ * volume as same
+ */
+ private void syncRingerAndNotificationStreamVolume(int streamType, int index, boolean force) {
boolean notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1;
if (notificationsUseRingVolume) {
@@ -378,23 +431,24 @@ public class AudioService extends IAudioService.Stub {
}
if (streamType == AudioManager.STREAM_RING) {
// One-off to sync notification volume to ringer volume
- setStreamVolumeInt(AudioManager.STREAM_NOTIFICATION, index);
+ setStreamVolumeInt(AudioManager.STREAM_NOTIFICATION, index, force);
}
}
-
- setStreamVolumeInt(streamType, index);
-
- // UI, etc.
- mVolumePanel.postVolumeChanged(streamType, flags);
}
+
/**
* Sets the stream state's index, and posts a message to set system volume.
* This will not call out to the UI. Assumes a valid stream type.
+ *
+ * @param streamType Type of the stream
+ * @param index Desired volume index of the stream
+ * @param force If true, set the volume even if the desired volume is same
+ * as the current volume.
*/
- private void setStreamVolumeInt(int streamType, int index) {
+ private void setStreamVolumeInt(int streamType, int index, boolean force) {
VolumeStreamState streamState = mStreamStates[streamType];
- if (streamState.setIndex(index)) {
+ if (streamState.setIndex(index) || force) {
// Post message to set system volume (it in turn will post a message
// to persist). Do not change volume if stream is muted.
if (streamState.muteCount() == 0) {
@@ -403,7 +457,7 @@ public class AudioService extends IAudioService.Stub {
}
}
}
-
+
/** @see AudioManager#setStreamSolo(int, boolean) */
public void setStreamSolo(int streamType, boolean state, IBinder cb) {
for (int stream = 0; stream < mStreamStates.length; stream++) {
@@ -412,7 +466,7 @@ public class AudioService extends IAudioService.Stub {
mStreamStates[stream].mute(cb, state);
}
}
-
+
/** @see AudioManager#setStreamMute(int, boolean) */
public void setStreamMute(int streamType, boolean state, IBinder cb) {
if (isStreamAffectedByMute(streamType)) {
@@ -441,32 +495,33 @@ public class AudioService extends IAudioService.Stub {
public void setRingerMode(int ringerMode) {
if (ringerMode != mRingerMode) {
mRingerMode = ringerMode;
-
+
// Adjust volumes via posting message
int numStreamTypes = AudioSystem.getNumStreamTypes();
if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (!isStreamAffectedByRingerMode(streamType)) continue;
// Bring back last audible volume
- setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex);
+ setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
+ false);
}
} else {
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (!isStreamAffectedByRingerMode(streamType)) continue;
// Either silent or vibrate, either way volume is 0
- setStreamVolumeInt(streamType, 0);
+ setStreamVolumeInt(streamType, 0, false);
}
}
-
+
// Send sticky broadcast
broadcastRingerMode();
-
+
// Post a persist ringer mode msg
sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG,
SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
}
}
-
+
/** @see AudioManager#shouldVibrate(int) */
public boolean shouldVibrate(int vibrateType) {
@@ -474,21 +529,21 @@ public class AudioService extends IAudioService.Stub {
case AudioManager.VIBRATE_SETTING_ON:
return mRingerMode != AudioManager.RINGER_MODE_SILENT;
-
+
case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
return mRingerMode == AudioManager.RINGER_MODE_VIBRATE;
-
+
case AudioManager.VIBRATE_SETTING_OFF:
- // Phone ringer should always vibrate in vibrate mode
+ // Phone ringer should always vibrate in vibrate mode
if (vibrateType == AudioManager.VIBRATE_TYPE_RINGER) {
return mRingerMode == AudioManager.RINGER_MODE_VIBRATE;
}
-
+
default:
return false;
}
}
-
+
/** @see AudioManager#getVibrateSetting(int) */
public int getVibrateSetting(int vibrateType) {
return (mVibrateSetting >> (vibrateType * 2)) & 3;
@@ -498,10 +553,10 @@ public class AudioService extends IAudioService.Stub {
public void setVibrateSetting(int vibrateType, int vibrateSetting) {
mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
-
+
// Broadcast change
broadcastVibrateSetting(vibrateType);
-
+
// Post message to set ringer mode (it in turn will post a message
// to persist)
sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0,
@@ -518,13 +573,13 @@ public class AudioService extends IAudioService.Stub {
// First clear the existing setting. Each vibrate type has two bits in
// the value. Note '3' is '11' in binary.
existingValue &= ~(3 << (vibrateType * 2));
-
+
// Set into the old value
existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
-
+
return existingValue;
}
-
+
/** @see AudioManager#setMicrophoneMute(boolean) */
public void setMicrophoneMute(boolean on) {
if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
@@ -534,15 +589,15 @@ public class AudioService extends IAudioService.Stub {
if (on != mMicMute) {
AudioSystem.muteMicrophone(on);
mMicMute = on;
- }
+ }
}
}
-
+
/** @see AudioManager#isMicrophoneMute() */
public boolean isMicrophoneMute() {
return mMicMute;
}
-
+
/** @see AudioManager#setMode(int) */
public void setMode(int mode) {
if (!checkAudioSettingsPermission("setMode()")) {
@@ -552,15 +607,19 @@ public class AudioService extends IAudioService.Stub {
if (mode != mMode) {
AudioSystem.setMode(mode);
mMode = mode;
- }
+ }
+ int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
+ int index = mStreamStates[streamType].mIndex;
+ syncRingerAndNotificationStreamVolume(streamType, index, true);
+ setStreamVolumeInt(streamType, index, true);
}
}
-
+
/** @see AudioManager#getMode() */
public int getMode() {
return mMode;
}
-
+
/** @see AudioManager#setRouting(int, int, int) */
public void setRouting(int mode, int routes, int mask) {
if (!checkAudioSettingsPermission("setRouting()")) {
@@ -570,10 +629,14 @@ public class AudioService extends IAudioService.Stub {
if ((mRoutes[mode] & mask) != (routes & mask)) {
AudioSystem.setRouting(mode, routes, mask);
mRoutes[mode] = (mRoutes[mode] & ~mask) | (routes & mask);
- }
+ }
+ int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
+ int index = mStreamStates[streamType].mIndex;
+ syncRingerAndNotificationStreamVolume(streamType, index, true);
+ setStreamVolumeInt(streamType, index, true);
}
}
-
+
/** @see AudioManager#getRouting(int) */
public int getRouting(int mode) {
return mRoutes[mode];
@@ -583,7 +646,7 @@ public class AudioService extends IAudioService.Stub {
public boolean isMusicActive() {
return AudioSystem.isMusicActive();
}
-
+
/** @see AudioManager#setParameter(String, String) */
public void setParameter(String key, String value) {
AudioSystem.setParameter(key, value);
@@ -591,13 +654,20 @@ public class AudioService extends IAudioService.Stub {
/** @see AudioManager#playSoundEffect(int) */
public void playSoundEffect(int effectType) {
- sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, effectType, 0,
- null, 0);
+ sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP,
+ effectType, SOUND_EFFECT_VOLUME, null, 0);
+ }
+
+ /** @see AudioManager#playSoundEffect(int, float) */
+ /* @hide FIXME: unhide before release */
+ public void playSoundEffectVolume(int effectType, float volume) {
+ sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP,
+ effectType, (int) (volume * 1000), null, 0);
}
/**
- * Loads samples into the soundpool.
- * This method must be called at when sound effects are enabled
+ * Loads samples into the soundpool.
+ * This method must be called at when sound effects are enabled
*/
public boolean loadSoundEffects() {
synchronized (mSoundEffectsLock) {
@@ -605,17 +675,17 @@ public class AudioService extends IAudioService.Stub {
if (mSoundPool == null) {
return false;
}
- /*
- * poolId table: The value -1 in this table indicates that corresponding
- * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
- * Once loaded, the value in poolId is the sample ID and the same
+ /*
+ * poolId table: The value -1 in this table indicates that corresponding
+ * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
+ * Once loaded, the value in poolId is the sample ID and the same
* sample can be reused for another effect using the same file.
- */
+ */
int[] poolId = new int[SOUND_EFFECT_FILES.length];
for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
poolId[fileIdx] = -1;
}
- /*
+ /*
* Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
* If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
* this indicates we have a valid sample loaded for this effect.
@@ -638,12 +708,12 @@ public class AudioService extends IAudioService.Stub {
}
}
}
-
+
return true;
}
/**
- * Unloads samples from the sound pool.
+ * Unloads samples from the sound pool.
* This method can be called to free some memory when
* sound effects are disabled.
*/
@@ -665,12 +735,12 @@ public class AudioService extends IAudioService.Stub {
mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
SOUND_EFFECT_FILES_MAP[effect][1] = -1;
poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
- }
+ }
}
mSoundPool = null;
}
}
-
+
///////////////////////////////////////////////////////////////////////////
// Internal methods
///////////////////////////////////////////////////////////////////////////
@@ -683,7 +753,7 @@ public class AudioService extends IAudioService.Stub {
private boolean checkForRingerModeChange(int oldIndex, int direction) {
boolean adjustVolumeIndex = true;
int newRingerMode = mRingerMode;
-
+
if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && oldIndex == 1
&& direction == AudioManager.ADJUST_LOWER) {
newRingerMode = AudioManager.RINGER_MODE_VIBRATE;
@@ -697,7 +767,7 @@ public class AudioService extends IAudioService.Stub {
&& mRingerMode == AudioManager.RINGER_MODE_SILENT) {
newRingerMode = AudioManager.RINGER_MODE_VIBRATE;
}
-
+
if (newRingerMode != mRingerMode) {
setRingerMode(newRingerMode);
@@ -708,18 +778,18 @@ public class AudioService extends IAudioService.Stub {
*/
adjustVolumeIndex = false;
}
-
+
return adjustVolumeIndex;
}
-
+
public boolean isStreamAffectedByRingerMode(int streamType) {
- return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
+ return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
}
-
+
public boolean isStreamAffectedByMute(int streamType) {
return (mMuteAffectedStreams & (1 << streamType)) != 0;
}
-
+
private void ensureValidDirection(int direction) {
if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
throw new IllegalArgumentException("Bad direction " + direction);
@@ -736,13 +806,15 @@ public class AudioService extends IAudioService.Stub {
boolean isOffhook = false;
try {
ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- isOffhook = phone.isOffhook();
+ if (phone != null) isOffhook = phone.isOffhook();
} catch (RemoteException e) {
Log.w(TAG, "Couldn't connect to phone service", e);
}
- // TODO: applications can influence this
- if (isOffhook) {
+ if ((getRouting(AudioSystem.MODE_IN_CALL) & AudioSystem.ROUTE_BLUETOOTH_SCO) != 0) {
+ // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
+ return AudioSystem.STREAM_BLUETOOTH_SCO;
+ } else if (isOffhook) {
// Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
return AudioSystem.STREAM_VOICE_CALL;
} else if (AudioSystem.isMusicActive()) {
@@ -756,29 +828,33 @@ public class AudioService extends IAudioService.Stub {
return suggestedStreamType;
}
}
-
+
private void broadcastRingerMode() {
// Send sticky broadcast
- Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
- broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode);
- long origCallerIdentityToken = Binder.clearCallingIdentity();
- mContext.sendStickyBroadcast(broadcast);
- Binder.restoreCallingIdentity(origCallerIdentityToken);
+ if (ActivityManagerNative.isSystemReady()) {
+ Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
+ broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode);
+ long origCallerIdentityToken = Binder.clearCallingIdentity();
+ mContext.sendStickyBroadcast(broadcast);
+ Binder.restoreCallingIdentity(origCallerIdentityToken);
+ }
}
-
+
private void broadcastVibrateSetting(int vibrateType) {
// Send broadcast
- Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
- broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
- broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
- mContext.sendBroadcast(broadcast);
+ if (ActivityManagerNative.isSystemReady()) {
+ Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
+ broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
+ broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
+ mContext.sendBroadcast(broadcast);
+ }
}
-
+
// Message helper methods
private static int getMsg(int baseMsg, int streamType) {
- return (baseMsg & 0xffff) | streamType << 16;
+ return (baseMsg & 0xffff) | streamType << 16;
}
-
+
private static int getMsgBase(int msg) {
return msg & 0xffff;
}
@@ -792,11 +868,11 @@ public class AudioService extends IAudioService.Stub {
} else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
return;
}
-
+
handler
.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
}
-
+
boolean checkAudioSettingsPermission(String method) {
if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
== PackageManager.PERMISSION_GRANTED) {
@@ -809,29 +885,29 @@ public class AudioService extends IAudioService.Stub {
return false;
}
-
+
///////////////////////////////////////////////////////////////////////////
// Inner classes
///////////////////////////////////////////////////////////////////////////
-
+
public class VolumeStreamState {
private final String mVolumeIndexSettingName;
- private final String mLastAudibleVolumeIndexSettingName;
+ private final String mLastAudibleVolumeIndexSettingName;
private final int mStreamType;
-
+
private final int[] mVolumes;
private int mIndex;
private int mLastAudibleIndex;
private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death
-
+
private VolumeStreamState(String settingName, int streamType, int[] volumes) {
-
+
mVolumeIndexSettingName = settingName;
mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
-
+
mStreamType = streamType;
mVolumes = volumes;
-
+
final ContentResolver cr = mContentResolver;
mIndex = getValidIndex(Settings.System.getInt(cr, mVolumeIndexSettingName, AudioManager.DEFAULT_STREAM_VOLUME[streamType]));
mLastAudibleIndex = getValidIndex(Settings.System.getInt(cr,
@@ -841,14 +917,31 @@ public class AudioService extends IAudioService.Stub {
mDeathHandlers = new ArrayList<VolumeDeathHandler>();
}
+ /**
+ * Constructor to be used when there is no setting associated with the VolumeStreamState.
+ *
+ * @param defaultVolume Default volume of the stream to use.
+ * @param streamType Type of the stream.
+ * @param volumes Volumes levels associated with this stream.
+ */
+ private VolumeStreamState(int defaultVolume, int streamType, int[] volumes) {
+ mVolumeIndexSettingName = null;
+ mLastAudibleVolumeIndexSettingName = null;
+ mIndex = mLastAudibleIndex = defaultVolume;
+ mStreamType = streamType;
+ mVolumes = volumes;
+ AudioSystem.setVolume(mStreamType, defaultVolume);
+ mDeathHandlers = new ArrayList<VolumeDeathHandler>();
+ }
+
public boolean adjustIndex(int deltaIndex) {
return setIndex(mIndex + deltaIndex);
}
-
+
public boolean setIndex(int index) {
int oldIndex = mIndex;
mIndex = getValidIndex(index);
-
+
if (oldIndex != mIndex) {
if (mIndex > 0) {
mLastAudibleIndex = mIndex;
@@ -858,11 +951,11 @@ public class AudioService extends IAudioService.Stub {
return false;
}
}
-
+
public int getMaxIndex() {
return mVolumes.length - 1;
}
-
+
public void mute(IBinder cb, boolean state) {
VolumeDeathHandler handler = getDeathHandler(cb, state);
if (handler == null) {
@@ -871,17 +964,17 @@ public class AudioService extends IAudioService.Stub {
}
handler.mute(state);
}
-
+
private int getValidIndex(int index) {
if (index < 0) {
return 0;
} else if (index >= mVolumes.length) {
return mVolumes.length - 1;
}
-
+
return index;
}
-
+
private class VolumeDeathHandler implements IBinder.DeathRecipient {
private IBinder mICallback; // To be notified of client's death
private int mMuteCount; // Number of active mutes for this client
@@ -924,7 +1017,7 @@ public class AudioService extends IAudioService.Stub {
mDeathHandlers.remove(this);
mICallback.unlinkToDeath(this, 0);
if (muteCount() == 0) {
- // If the stream is not mut any more, restore it's volume if
+ // If the stream is not mut any more, restore it's volume if
// ringer mode allows it
if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
setIndex(mLastAudibleIndex);
@@ -980,68 +1073,68 @@ public class AudioService extends IAudioService.Stub {
}
}
}
-
+
/** Thread that handles native AudioSystem control. */
private class AudioSystemThread extends Thread {
AudioSystemThread() {
super("AudioService");
}
-
+
@Override
public void run() {
// Set this thread up so the handler will work on it
Looper.prepare();
-
+
synchronized(AudioService.this) {
mAudioHandler = new AudioHandler();
// Notify that the handler has been created
AudioService.this.notify();
}
-
+
// Listen for volume change requests that are set by VolumePanel
Looper.loop();
}
}
-
+
/** Handles internal volume messages in separate volume thread. */
private class AudioHandler extends Handler {
-
+
private void setSystemVolume(VolumeStreamState streamState) {
-
+
// Adjust volume
AudioSystem
.setVolume(streamState.mStreamType, streamState.mVolumes[streamState.mIndex]);
-
+
// Post a persist volume msg
sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType,
SENDMSG_REPLACE, 0, 0, streamState, PERSIST_DELAY);
}
-
+
private void persistVolume(VolumeStreamState streamState) {
System.putInt(mContentResolver, streamState.mVolumeIndexSettingName,
streamState.mIndex);
System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName,
streamState.mLastAudibleIndex);
}
-
+
private void persistRingerMode() {
System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode);
}
-
+
private void persistVibrateSetting() {
System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting);
}
-
- private void playSoundEffect(int effectType) {
+
+ private void playSoundEffect(int effectType, int volume) {
synchronized (mSoundEffectsLock) {
if (mSoundPool == null) {
return;
}
if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
- mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], SOUND_EFFECT_VOLUME, SOUND_EFFECT_VOLUME,
- 0, 0, 1.0f);
+ float v = (float) volume / 1000.0f;
+ mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], v, v, 0, 0, 1.0f);
} else {
MediaPlayer mediaPlayer = new MediaPlayer();
if (mediaPlayer != null) {
@@ -1084,36 +1177,36 @@ public class AudioService extends IAudioService.Stub {
}
}
}
-
+
@Override
public void handleMessage(Message msg) {
int baseMsgWhat = getMsgBase(msg.what);
-
+
switch (baseMsgWhat) {
-
+
case MSG_SET_SYSTEM_VOLUME:
setSystemVolume((VolumeStreamState) msg.obj);
break;
-
+
case MSG_PERSIST_VOLUME:
persistVolume((VolumeStreamState) msg.obj);
break;
-
+
case MSG_PERSIST_RINGER_MODE:
persistRingerMode();
break;
-
+
case MSG_PERSIST_VIBRATE_SETTING:
persistVibrateSetting();
break;
-
+
case MSG_MEDIA_SERVER_DIED:
Log.e(TAG, "Media server died.");
- // Force creation of new IAudioflinger interface
+ // Force creation of new IAudioflinger interface
mMediaServerOk = false;
AudioSystem.getMode();
break;
-
+
case MSG_MEDIA_SERVER_STARTED:
Log.e(TAG, "Media server started.");
// Restore audio routing and stream volumes
@@ -1134,10 +1227,10 @@ public class AudioService extends IAudioService.Stub {
break;
case MSG_PLAY_SOUND_EFFECT:
- playSoundEffect(msg.arg1);
+ playSoundEffect(msg.arg1, msg.arg2);
break;
}
}
}
-
+
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 37100677..d0fa795 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -43,15 +43,17 @@ public class AudioSystem
public static final int STREAM_ALARM = 4;
/* The audio stream for notifications */
public static final int STREAM_NOTIFICATION = 5;
+ /* @hide The audio stream for phone calls when connected on bluetooth */
+ public static final int STREAM_BLUETOOTH_SCO = 6;
/**
* @deprecated Use {@link #numStreamTypes() instead}
*/
public static final int NUM_STREAMS = 5;
// Expose only the getter method publicly so we can change it in the future
- private static final int NUM_STREAM_TYPES = 6;
+ private static final int NUM_STREAM_TYPES = 7;
public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; }
-
+
/* max and min volume levels */
/* Maximum volume setting, for use with setVolume(int,int) */
public static final int MAX_VOLUME = 100;
@@ -78,7 +80,7 @@ public class AudioSystem
/*
* Sets the microphone mute on or off.
*
- * param on set <var>true</var> to mute the microphone;
+ * param on set <var>true</var> to mute the microphone;
* <var>false</var> to turn mute off
* return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR
*/
@@ -116,18 +118,18 @@ public class AudioSystem
public static final int MODE_RINGTONE = 1;
public static final int MODE_IN_CALL = 2;
public static final int NUM_MODES = 3;
-
+
/* Routing bits for setRouting/getRouting API */
public static final int ROUTE_EARPIECE = (1 << 0);
public static final int ROUTE_SPEAKER = (1 << 1);
-
- /** @deprecated use {@link #ROUTE_BLUETOOTH_SCO} */
+
+ /** @deprecated use {@link #ROUTE_BLUETOOTH_SCO} */
@Deprecated public static final int ROUTE_BLUETOOTH = (1 << 2);
public static final int ROUTE_BLUETOOTH_SCO = (1 << 2);
public static final int ROUTE_HEADSET = (1 << 3);
public static final int ROUTE_BLUETOOTH_A2DP = (1 << 4);
- public static final int ROUTE_ALL = 0xFFFFFFFF;
+ public static final int ROUTE_ALL = 0xFFFFFFFF;
/*
* Sets the audio routing for a specified mode
@@ -185,7 +187,7 @@ public class AudioSystem
public static final int AUDIO_STATUS_ERROR = 1;
/* Media server died. see ErrorCallback */
public static final int AUDIO_STATUS_SERVER_DIED = 100;
-
+
private static ErrorCallback mErrorCallback;
/*
@@ -211,7 +213,7 @@ public class AudioSystem
{
mErrorCallback = cb;
}
-
+
private static void errorCallbackFromNative(int error)
{
if (mErrorCallback != null) {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 2b7656f..316fa7a 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -30,12 +30,31 @@ import android.util.Log;
/**
* The AudioTrack class manages and plays a single audio resource for Java applications.
* It allows to stream PCM audio buffers to the audio hardware for playback. This is
- * be achieved by "pushing" the data to the AudioTrack object using the
- * {@link #write(byte[], int, int)} or {@link #write(short[], int, int)} method.
- * During construction, an AudioTrack object can be initialized with a given buffer.
- * This size determines how long an AudioTrack can play before running out of data.
- *
- * {@hide Pending API council review}
+ * achieved by "pushing" the data to the AudioTrack object using one of the
+ * {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods.
+ * <p>An AudioTrack instance can operate under two modes: static of streaming.<br>
+ * The Streaming mode consists in continuously writing data to the AudioTrack, using one
+ * of the write() methods. These are blocking and return when the data has been transferred
+ * from the Java layer to the native layer, and is queued for playback. The streaming mode
+ * is most useful when playing blocks of audio data that for instance are:
+ * <ul>
+ * <li>too big to fit in memory because of the duration of the sound to play,</li>
+ * <li>too big to fit in memory because of the characteristics of the audio data
+ * (high sampling rate, bits per sample ...)</li>
+ * <li>chosen, received or generated as the audio keeps playing.</li>
+ * </ul>
+ * The static mode is to be chosen when dealing with short sounds that fit in memory and
+ * that need to be played with the smallest latency possible. Static mode AudioTrack instances can
+ * play the sound without the need to transfer the audio data from Java to the audio hardware
+ * each time the sound is to be played. The static mode will therefore be preferred for UI and
+ * game sounds that are played often, and with the smallest overhead possible.
+ * <p>Upon creation, an AudioTrack object initializes its associated audio buffer.
+ * The size of this buffer, specified during the construction, determines how long an AudioTrack
+ * can play before running out of data.<br>
+ * For an AudioTrack using the static mode, this size is the maximum size of the sound that can
+ * be played from it.<br>
+ * For the streaming mode, data will be written to the hardware in chunks of
+ * sizes inferior to the total buffer size.
*/
public class AudioTrack
{
@@ -46,42 +65,41 @@ public class AudioTrack
private static final float VOLUME_MIN = 0.0f;
/** Maximum value for a channel volume */
private static final float VOLUME_MAX = 1.0f;
-
+
/** state of an AudioTrack this is stopped */
public static final int PLAYSTATE_STOPPED = 1; // matches SL_PLAYSTATE_STOPPED
/** state of an AudioTrack this is paused */
public static final int PLAYSTATE_PAUSED = 2; // matches SL_PLAYSTATE_PAUSED
/** state of an AudioTrack this is playing */
public static final int PLAYSTATE_PLAYING = 3; // matches SL_PLAYSTATE_PLAYING
-
- /**
- * Creation mode where audio data is transferred from Java to the native layer
+
+ /**
+ * Creation mode where audio data is transferred from Java to the native layer
* only once before the audio starts playing.
*/
public static final int MODE_STATIC = 0;
- /**
- * Creation mode where audio data is streamed from Java to the native layer
+ /**
+ * Creation mode where audio data is streamed from Java to the native layer
* as the audio is playing.
*/
public static final int MODE_STREAM = 1;
-
- /**
- * State of an AudioTrack that was not successfully initialized upon creation
+
+ /**
+ * State of an AudioTrack that was not successfully initialized upon creation
*/
public static final int STATE_UNINITIALIZED = 0;
- /**
+ /**
* State of an AudioTrack that is ready to be used.
*/
public static final int STATE_INITIALIZED = 1;
/**
- * State of a successfully initialized AudioTrack that uses static data,
+ * State of a successfully initialized AudioTrack that uses static data,
* but that hasn't received that data yet.
*/
public static final int STATE_NO_STATIC_DATA = 2;
-
- // to keep in sync with libs/android_runtime/android_media_AudioTrack.cpp
- // error codes
+ // Error codes:
+ // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
/**
* Denotes a successful operation.
*/
@@ -90,139 +108,137 @@ public class AudioTrack
* Denotes a generic operation failure.
*/
public static final int ERROR = -1;
- private static final int ERROR_NATIVESETUP_AUDIOSYSTEM = -2;
- private static final int ERROR_NATIVESETUP_INVALIDCHANNELCOUNT = -3;
- private static final int ERROR_NATIVESETUP_INVALIDFORMAT = -4;
- private static final int ERROR_NATIVESETUP_INVALIDSTREAMTYPE = -5;
- private static final int ERROR_NATIVESETUP_NATIVEINITFAILED = -6;
/**
* Denotes a failure due to the use of an invalid value.
*/
- public static final int ERROR_BAD_VALUE = -7;
+ public static final int ERROR_BAD_VALUE = -2;
/**
* Denotes a failure due to the improper use of a method.
*/
- public static final int ERROR_INVALID_OPERATION = -8;
- // events
+ public static final int ERROR_INVALID_OPERATION = -3;
+
+ private static final int ERROR_NATIVESETUP_AUDIOSYSTEM = -16;
+ private static final int ERROR_NATIVESETUP_INVALIDCHANNELCOUNT = -17;
+ private static final int ERROR_NATIVESETUP_INVALIDFORMAT = -18;
+ private static final int ERROR_NATIVESETUP_INVALIDSTREAMTYPE = -19;
+ private static final int ERROR_NATIVESETUP_NATIVEINITFAILED = -20;
+
+ // Events:
+ // to keep in sync with frameworks/base/include/media/AudioTrack.h
/**
* Event id for when the playback head has reached a previously set marker.
*/
- protected static final int NATIVE_EVENT_MARKER = 3;
+ private static final int NATIVE_EVENT_MARKER = 3;
/**
* Event id for when the previously set update period has passed during playback.
*/
- protected static final int NATIVE_EVENT_NEW_POS = 4;
-
+ private static final int NATIVE_EVENT_NEW_POS = 4;
+
private final static String TAG = "AudioTrack-Java";
-
+
//--------------------------------------------------------------------------
// Member variables
//--------------------
/**
* Indicates the state of the AudioTrack instance
*/
- protected int mState = STATE_UNINITIALIZED;
+ private int mState = STATE_UNINITIALIZED;
/**
* Indicates the play state of the AudioTrack instance
*/
- protected int mPlayState = PLAYSTATE_STOPPED;
+ private int mPlayState = PLAYSTATE_STOPPED;
/**
* Lock to make sure mPlayState updates are reflecting the actual state of the object.
*/
- protected final Object mPlayStateLock = new Object();
- /**
- * The listener the AudioTrack notifies previously set marker is reached.
- * @see #setMarkerReachedListener(OnMarkerReachedListener)
- */
- protected OnMarkerReachedListener mMarkerListener = null;
+ private final Object mPlayStateLock = new Object();
/**
- * Lock to protect marker listener updates against event notifications
+ * The listener the AudioTrack notifies when the playback position reaches a marker
+ * or for periodic updates during the progression of the playback head.
+ * @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
*/
- protected final Object mMarkerListenerLock = new Object();
+ private OnPlaybackPositionUpdateListener mPositionListener = null;
/**
- * The listener the AudioTrack notifies periodically during playback.
- * @see #setPeriodicNotificationListener(OnPeriodicNotificationListener)
+ * Lock to protect event listener updates against event notifications
*/
- protected OnPeriodicNotificationListener mPeriodicListener = null;
- /**
- * Lock to protect periodic listener updates against event notifications
- */
- protected final Object mPeriodicListenerLock = new Object();
+ private final Object mPositionListenerLock = new Object();
/**
* Size of the native audio buffer.
*/
- protected int mNativeBufferSizeInBytes = 0;
+ private int mNativeBufferSizeInBytes = 0;
/**
- * Handler for events coming from the native code
+ * Handler for marker events coming from the native code
*/
- protected NativeEventHandler mNativeEventHandler = null;
+ private NativeEventHandlerDelegate mEventHandlerDelegate = null;
/**
* The audio data sampling rate in Hz.
*/
- protected int mSampleRate = 22050;
+ private int mSampleRate = 22050;
/**
* The number of input audio channels (1 is mono, 2 is stereo)
*/
- protected int mChannelCount = 1;
+ private int mChannelCount = 1;
/**
* The type of the audio stream to play. See
- * {@link AudioManager.STREAM_VOICE_CALL}, {@link AudioManager.STREAM_SYSTEM},
- * {@link AudioManager.STREAM_RING}, {@link AudioManager.STREAM_MUSIC} and
- * {@link AudioManager.STREAM_ALARM}
+ * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
+ * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
+ * {@link AudioManager#STREAM_ALARM}
*/
- protected int mStreamType = AudioManager.STREAM_MUSIC;
+ private int mStreamType = AudioManager.STREAM_MUSIC;
/**
* The way audio is consumed by the hardware, streaming or static.
*/
- protected int mDataLoadMode = MODE_STREAM;
+ private int mDataLoadMode = MODE_STREAM;
/**
* The current audio channel configuration
*/
- protected int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ private int mChannelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
/**
* The encoding of the audio samples.
- * @see #AudioFormat.ENCODING_PCM_8BIT
- * @see #AudioFormat.ENCODING_PCM_16BIT
+ * @see AudioFormat#ENCODING_PCM_8BIT
+ * @see AudioFormat#ENCODING_PCM_16BIT
*/
- protected int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
+ private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
//--------------------------------
// Used exclusively by native code
//--------------------
- /**
- * Accessed by native methods: provides access to C++ AudioTrack object
+ /**
+ * Accessed by native methods: provides access to C++ AudioTrack object
*/
@SuppressWarnings("unused")
private int mNativeTrackInJavaObj;
- /**
+ /**
* Accessed by native methods: provides access to the JNI data (i.e. resources used by
* the native AudioTrack object, but not stored in it).
*/
@SuppressWarnings("unused")
private int mJniData;
-
-
+
+
//--------------------------------------------------------------------------
// Constructor, Finalize
//--------------------
/**
* Class constructor.
- * @param streamType the type of the audio stream. See
- * {@link AudioSystem.STREAM_VOICE_CALL}, {@link AudioSystem.STREAM_SYSTEM},
- * {@link AudioSystem.STREAM_RING}, {@link AudioSystem.STREAM_MUSIC} and
- * {@link AudioSystem.STREAM_ALARM}
+ * @param streamType the type of the audio stream. See
+
+ * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
+ * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
+ * {@link AudioManager#STREAM_ALARM}
* @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
* not limited to) 44100, 22050 and 11025.
- * @param channelConfig describes the configuration of the audio channels.
- * See {@link AudioFormat.CHANNEL_CONFIGURATION_MONO} and
- * {@link AudioFormat.CHANNEL_CONFIGURATION_STEREO}
- * @param audioFormat the format in which the audio data is represented.
- * See {@link AudioFormat.ENCODING_PCM_16BIT} and
- * {@link AudioFormat.ENCODING_PCM_8BIT}
+ * @param channelConfig describes the configuration of the audio channels.
+
+ * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
+ * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+
+ * @param audioFormat the format in which the audio data is represented.
+ * See {@link AudioFormat#ENCODING_PCM_16BIT} and
+ * {@link AudioFormat#ENCODING_PCM_8BIT}
* @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read
- * from for playback. If using the AudioTrack in streaming mode, you can write data into
+ * from for playback. If using the AudioTrack in streaming mode, you can write data into
* this buffer in smaller chunks than this size. If using the AudioTrack in static mode,
* this is the maximum size of the sound that will be played for this instance.
* @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
@@ -230,7 +246,7 @@ public class AudioTrack
*/
public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
int bufferSizeInBytes, int mode)
- throws IllegalArgumentException {
+ throws IllegalArgumentException {
mState = STATE_UNINITIALIZED;
audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode);
@@ -238,8 +254,8 @@ public class AudioTrack
audioBuffSizeCheck(bufferSizeInBytes);
// native initialization
- int initResult = native_setup(new WeakReference<AudioTrack>(this),
- mStreamType, mSampleRate, mChannelCount, mAudioFormat,
+ int initResult = native_setup(new WeakReference<AudioTrack>(this),
+ mStreamType, mSampleRate, mChannelCount, mAudioFormat,
mNativeBufferSizeInBytes, mDataLoadMode);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing AudioTrack.");
@@ -252,8 +268,8 @@ public class AudioTrack
mState = STATE_INITIALIZED;
}
}
-
-
+
+
// Convenience method for the constructor's parameter checks.
// This is where constructor IllegalArgumentException-s are thrown
// postconditions:
@@ -262,25 +278,27 @@ public class AudioTrack
// mAudioFormat is valid
// mSampleRate is valid
// mDataLoadMode is valid
- private void audioParamCheck(int streamType, int sampleRateInHz,
+ private void audioParamCheck(int streamType, int sampleRateInHz,
int channelConfig, int audioFormat, int mode) {
-
+
//--------------
// stream type
if( (streamType != AudioManager.STREAM_ALARM) && (streamType != AudioManager.STREAM_MUSIC)
&& (streamType != AudioManager.STREAM_RING) && (streamType != AudioManager.STREAM_SYSTEM)
- && (streamType != AudioManager.STREAM_VOICE_CALL) && (streamType != AudioManager.STREAM_NOTIFICATION) ) {
+ && (streamType != AudioManager.STREAM_VOICE_CALL)
+ && (streamType != AudioManager.STREAM_NOTIFICATION)
+ && (streamType != AudioManager.STREAM_BLUETOOTH_SCO)) {
throw (new IllegalArgumentException("Invalid stream type."));
} else {
mStreamType = streamType;
}
-
+
//--------------
// sample rate
if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
throw (new IllegalArgumentException(sampleRateInHz
+ "Hz is not a supported sample rate."));
- } else {
+ } else {
mSampleRate = sampleRateInHz;
}
@@ -314,10 +332,10 @@ public class AudioTrack
break;
default:
mAudioFormat = AudioFormat.ENCODING_INVALID;
- throw(new IllegalArgumentException("Unsupported sample encoding."
+ throw(new IllegalArgumentException("Unsupported sample encoding."
+ " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."));
}
-
+
//--------------
// audio load mode
if ( (mode != MODE_STREAM) && (mode != MODE_STATIC) ) {
@@ -326,8 +344,8 @@ public class AudioTrack
mDataLoadMode = mode;
}
}
-
-
+
+
// Convenience method for the contructor's audio buffer size check.
// preconditions:
// mChannelCount is valid
@@ -335,41 +353,29 @@ public class AudioTrack
// postcondition:
// mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
private void audioBuffSizeCheck(int audioBufferSize) {
- // NB: this section is only valid with PCM data.
+ // NB: this section is only valid with PCM data.
// To update when supporting compressed formats
- int frameSizeInBytes = mChannelCount
+ int frameSizeInBytes = mChannelCount
* (mAudioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
if ((audioBufferSize % frameSizeInBytes != 0) || (audioBufferSize < 1)) {
throw (new IllegalArgumentException("Invalid audio buffer size."));
}
-
+
mNativeBufferSizeInBytes = audioBufferSize;
}
-
-
- // Convenience method for the creation of the native event handler
- // It is called only when a non-null event listener is set.
- // precondition:
- // mNativeEventHandler is null
- private void createNativeEventHandler() {
- Looper looper;
- if ((looper = Looper.myLooper()) != null) {
- mNativeEventHandler = new NativeEventHandler(this, looper);
- } else if ((looper = Looper.getMainLooper()) != null) {
- mNativeEventHandler = new NativeEventHandler(this, looper);
- } else {
- mNativeEventHandler = null;
- }
- }
-
-
+
+
/**
* Releases the native AudioTrack resources.
*/
public void release() {
// even though native_release() stops the native AudioTrack, we need to stop
// AudioTrack subclasses too.
- stop();
+ try {
+ stop();
+ } catch(IllegalStateException ise) {
+ // don't raise an exception, we're releasing the resources.
+ }
native_release();
mState = STATE_UNINITIALIZED;
}
@@ -377,7 +383,7 @@ public class AudioTrack
@Override
protected void finalize() {
native_finalize();
- }
+ }
//--------------------------------------------------------------------------
// Getters
@@ -390,7 +396,7 @@ public class AudioTrack
static public float getMinVolume() {
return AudioTrack.VOLUME_MIN;
}
-
+
/**
* Returns the maximum valid volume value. Volume values set above this one will
* be clamped at this value.
@@ -398,37 +404,47 @@ public class AudioTrack
*/
static public float getMaxVolume() {
return AudioTrack.VOLUME_MAX;
- }
-
+ }
+
/**
* Returns the configured audio data sample rate in Hz
*/
public int getSampleRate() {
return mSampleRate;
}
+
+ /**
+ * @hide
+ * Returns the current playback rate in Hz. Note that this rate may differ from one set using
+ * {@link #setPlaybackRate(int)} as the value effectively set is implementation-dependent.
+ */
+ public int getPlaybackRate() {
+ return native_get_playback_rate();
+ }
/**
- * Returns the configured audio data format. See {@link #AudioFormat.ENCODING_PCM_16BIT}
- * and {@link #AudioFormat.ENCODING_PCM_8BIT}.
+ * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
+ * and {@link AudioFormat#ENCODING_PCM_8BIT}.
*/
public int getAudioFormat() {
return mAudioFormat;
}
-
+
/**
* Returns the type of audio stream this AudioTrack is configured for.
- * Compare the result against {@link AudioManager.STREAM_VOICE_CALL},
- * {@link AudioManager.STREAM_SYSTEM}, {@link AudioManager.STREAM_RING},
- * {@link AudioManager.STREAM_MUSIC} or {@link AudioManager.STREAM_ALARM}
+ * Compare the result against {@link AudioManager#STREAM_VOICE_CALL},
+ * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING},
+ * {@link AudioManager#STREAM_MUSIC} or {@link AudioManager#STREAM_ALARM}
*/
public int getStreamType() {
return mStreamType;
}
/**
- * Returns the configured channel configuration.
- * See {@link #AudioFormat.CHANNEL_CONFIGURATION_MONO}
- * and {@link #AudioFormat.CHANNEL_CONFIGURATION_STEREO}.
+ * Returns the configured channel configuration.
+
+ * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO}
+ * and {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}.
*/
public int getChannelConfiguration() {
return mChannelConfiguration;
@@ -443,19 +459,19 @@ public class AudioTrack
/**
* Returns the state of the AudioTrack instance. This is useful after the
- * AudioTrack instance has been created to check if it was initialized
+ * AudioTrack instance has been created to check if it was initialized
* properly. This ensures that the appropriate hardware resources have been
* acquired.
*/
public int getState() {
return mState;
}
-
+
/**
* Returns the playback state of the AudioTrack instance.
- * @see AudioTrack.PLAYSTATE_STOPPED
- * @see AudioTrack.PLAYSTATE_PAUSED
- * @see AudioTrack.PLAYSTATE_PLAYING
+ * @see #PLAYSTATE_STOPPED
+ * @see #PLAYSTATE_PAUSED
+ * @see #PLAYSTATE_PLAYING
*/
public int getPlayState() {
return mPlayState;
@@ -492,56 +508,100 @@ public class AudioTrack
/**
* Returns the hardware output sample rate
*/
- static public int getNativeOutputSampleRate() {
- return native_get_output_sample_rate();
+ static public int getNativeOutputSampleRate(int streamType) {
+ return native_get_output_sample_rate(streamType);
}
-
- //--------------------------------------------------------------------------
- // Initialization / configuration
- //--------------------
/**
- * Sets the listener the AudioTrack notifies when a previously set marker is reached.
- * @param listener
+ * {@hide}
+ * Returns the minimum buffer size required for the successful creation of an AudioTrack
+ * object to be created in the {@link #MODE_STREAM} mode.
+ * @param sampleRateInHz the sample rate expressed in Hertz.
+ * @param channelConfig describes the configuration of the audio channels.
+ * See {@link AudioFormat#CHANNEL_CONFIGURATION_MONO} and
+ * {@link AudioFormat#CHANNEL_CONFIGURATION_STEREO}
+ * @param audioFormat the format in which the audio data is represented.
+ * See {@link AudioFormat#ENCODING_PCM_16BIT} and
+ * {@link AudioFormat#ENCODING_PCM_8BIT}
+ * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
+ * or {@link #ERROR} if the implementation was unable to query the hardware for its output
+ * properties,
+ * or the minimum buffer size expressed in number of bytes.
*/
- public void setMarkerReachedListener(OnMarkerReachedListener listener) {
- synchronized (mMarkerListenerLock) {
- mMarkerListener = listener;
+ static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
+ int channelCount = 0;
+ switch(channelConfig) {
+ case AudioFormat.CHANNEL_CONFIGURATION_MONO:
+ channelCount = 1;
+ break;
+ case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
+ channelCount = 2;
+ break;
+ default:
+ loge("getMinBufferSize(): Invalid channel configuration.");
+ return AudioTrack.ERROR_BAD_VALUE;
}
- if ((listener != null) && (mNativeEventHandler == null)) {
- createNativeEventHandler();
+
+ if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
+ && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
+ loge("getMinBufferSize(): Invalid audio format.");
+ return AudioTrack.ERROR_BAD_VALUE;
+ }
+
+ if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
+ loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate.");
+ return AudioTrack.ERROR_BAD_VALUE;
+ }
+
+ int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
+ if ((size == -1) || (size == 0)) {
+ loge("getMinBufferSize(): error querying hardware");
+ return AudioTrack.ERROR;
+ }
+ else {
+ return size;
}
}
-
-
+
+
+ //--------------------------------------------------------------------------
+ // Initialization / configuration
+ //--------------------
/**
- * Sets the listener the AudioTrack notifies periodically during playback.
+ * Sets the listener the AudioTrack notifies when a previously set marker is reached or
+ * for each periodic playback head position update.
* @param listener
*/
- public void setPeriodicNotificationListener(OnPeriodicNotificationListener listener) {
- synchronized (mPeriodicListenerLock) {
- mPeriodicListener = listener;
+ public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener) {
+ setPlaybackPositionUpdateListener(listener, null);
+ }
+
+
+ public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener,
+ Handler handler) {
+ synchronized (mPositionListenerLock) {
+ mPositionListener = listener;
}
- if ((listener != null) && (mNativeEventHandler == null)) {
- createNativeEventHandler();
+ if (listener != null) {
+ mEventHandlerDelegate = new NativeEventHandlerDelegate(this, handler);
}
+
}
-
-
- /**
- * Sets the specified left/right output volume values on the AudioTrack. Values are clamped
+
+
+
+ /**
+ * Sets the specified left/right output volume values on the AudioTrack. Values are clamped
* to the ({@link #getMinVolume()}, {@link #getMaxVolume()}) interval if outside this range.
- * @param leftVolume output attenuation for the left channel. A value of 0.0f is silence,
+ * @param leftVolume output attenuation for the left channel. A value of 0.0f is silence,
* a value of 1.0f is no attenuation.
* @param rightVolume output attenuation for the right channel
- * @return {@link #SUCCESS}
- * @throws IllegalStateException
+ * @return error code or success, see {@link #SUCCESS},
+ * {@link #ERROR_INVALID_OPERATION}
*/
- public int setStereoVolume(float leftVolume, float rightVolume)
- throws IllegalStateException {
+ public int setStereoVolume(float leftVolume, float rightVolume) {
if (mState != STATE_INITIALIZED) {
- throw(new IllegalStateException("setStereoVolume() called on an "+
- "uninitialized AudioTrack."));
+ return ERROR_INVALID_OPERATION;
}
// clamp the volumes
@@ -559,84 +619,108 @@ public class AudioTrack
}
native_setVolume(leftVolume, rightVolume);
-
+
return SUCCESS;
}
-
-
+
+
/**
* Sets the playback sample rate for this track. This sets the sampling rate at which
* the audio data will be consumed and played back, not the original sampling rate of the
* content. Setting it to half the sample rate of the content will cause the playback to
* last twice as long, but will also result result in a negative pitch shift.
* The current implementation supports a maximum sample rate of twice the hardware output
- * sample rate (see {@link #getNativeOutputSampleRate()}). Use {@link #getSampleRate()} to
+ * sample rate (see {@link #getNativeOutputSampleRate(int)}). Use {@link #getSampleRate()} to
* check the rate actually used in hardware after potential clamping.
* @param sampleRateInHz
- * @return {@link #SUCCESS}
+ * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
+ * {@link #ERROR_INVALID_OPERATION}
*/
public int setPlaybackRate(int sampleRateInHz) {
+ if (mState != STATE_INITIALIZED) {
+ return ERROR_INVALID_OPERATION;
+ }
+ if (sampleRateInHz <= 0) {
+ return ERROR_BAD_VALUE;
+ }
native_set_playback_rate(sampleRateInHz);
return SUCCESS;
}
-
-
+
+
/**
- *
+ *
* @param markerInFrames marker in frames
* @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
- * {@link #ERROR_INVALID_OPERATION}
+ * {@link #ERROR_INVALID_OPERATION}
*/
public int setNotificationMarkerPosition(int markerInFrames) {
+ if (mState != STATE_INITIALIZED) {
+ return ERROR_INVALID_OPERATION;
+ }
return native_set_marker_pos(markerInFrames);
}
-
-
+
+
/**
* @param periodInFrames update period in frames
* @return error code or success, see {@link #SUCCESS}, {@link #ERROR_INVALID_OPERATION}
*/
public int setPositionNotificationPeriod(int periodInFrames) {
+ if (mState != STATE_INITIALIZED) {
+ return ERROR_INVALID_OPERATION;
+ }
return native_set_pos_update_period(periodInFrames);
}
-
-
+
+
/**
* Sets the playback head position. The track must be stopped for the position to be changed.
* @param positionInFrames playback head position in frames
- * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}
- * @throws java.lang.IllegalStateException if the track is not in
- * the {@link #PLAYSTATE_STOPPED} state.
+ * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
+ * {@link #ERROR_INVALID_OPERATION}
*/
- public int setPlaybackHeadPosition(int positionInFrames)
- throws IllegalStateException {
+ public int setPlaybackHeadPosition(int positionInFrames) {
synchronized(mPlayStateLock) {
- if(mPlayState == PLAYSTATE_STOPPED) {
+ if ((mPlayState == PLAYSTATE_STOPPED) || (mPlayState == PLAYSTATE_PAUSED)) {
return native_set_position(positionInFrames);
+ } else {
+ return ERROR_INVALID_OPERATION;
}
}
- throw(new IllegalStateException("setPlaybackHeadPosition() called on a track that is "+
- "not in the PLAYSTATE_STOPPED play state."));
}
-
+
/**
* Sets the loop points and the loop count. The loop can be infinite.
* @param startInFrames loop start marker in frames
* @param endInFrames loop end marker in frames
- * @param loopCount the number of times the loop is looped.
+ * @param loopCount the number of times the loop is looped.
* A value of -1 means infinite looping.
- * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}
+ * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
+ * {@link #ERROR_INVALID_OPERATION}
*/
public int setLoopPoints(int startInFrames, int endInFrames, int loopCount) {
+ if (mDataLoadMode == MODE_STREAM) {
+ return ERROR_INVALID_OPERATION;
+ }
return native_set_loop(startInFrames, endInFrames, loopCount);
}
+ /**
+ * Sets the initialization state of the instance. To be used in an AudioTrack subclass
+ * constructor to set a subclass-specific post-initialization state.
+ * @param state the state of the AudioTrack instance
+ */
+ protected void setState(int state) {
+ mState = state;
+ }
+
//---------------------------------------------------------
// Transport control methods
//--------------------
/**
- * Starts playing an AudioTrack.
+ * Starts playing an AudioTrack.
* @throws IllegalStateException
*/
public void play()
@@ -644,7 +728,7 @@ public class AudioTrack
if (mState != STATE_INITIALIZED) {
throw(new IllegalStateException("play() called on uninitialized AudioTrack."));
}
-
+
synchronized(mPlayStateLock) {
native_start();
mPlayState = PLAYSTATE_PLAYING;
@@ -671,7 +755,7 @@ public class AudioTrack
/**
* Pauses the playback of the audio data.
* @throws IllegalStateException
- */
+ */
public void pause()
throws IllegalStateException {
if (mState != STATE_INITIALIZED) {
@@ -685,25 +769,21 @@ public class AudioTrack
mPlayState = PLAYSTATE_PAUSED;
}
}
-
-
+
+
//---------------------------------------------------------
// Audio data supply
//--------------------
/**
* Flushes the audio data currently queued for playback.
- * @throws IllegalStateException
- */
- public void flush()
- throws IllegalStateException {
- if (mState != STATE_INITIALIZED) {
- throw(new IllegalStateException("flush() called on uninitialized AudioTrack."));
- }
- //logd("flush()");
+ */
- // flush the data in native layer
- native_flush();
+ public void flush() {
+ if (mState == STATE_INITIALIZED) {
+ // flush the data in native layer
+ native_flush();
+ }
}
@@ -712,53 +792,61 @@ public class AudioTrack
* @param audioData the array that holds the data to play.
* @param offsetInBytes the offset in audioData where the data to play starts.
* @param sizeInBytes the number of bytes to read in audioData after the offset.
- * @return the number of bytes that were written.
- * @throws IllegalStateException
- */
- public int write(byte[] audioData,int offsetInBytes, int sizeInBytes)
- throws IllegalStateException {
- if ((mDataLoadMode == MODE_STATIC)
+ * @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION}
+ * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+ * the parameters don't resolve to valid data and indexes.
+ */
+
+ public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) {
+ if ((mDataLoadMode == MODE_STATIC)
&& (mState == STATE_NO_STATIC_DATA)
&& (sizeInBytes > 0)) {
mState = STATE_INITIALIZED;
}
- //TODO check if future writes should be forbidden for static tracks
- // or: how to update data for static tracks?
if (mState != STATE_INITIALIZED) {
- throw(new IllegalStateException("write() called on uninitialized AudioTrack."));
+ return ERROR_INVALID_OPERATION;
}
- return native_write_byte(audioData, offsetInBytes, sizeInBytes);
+ if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
+ || (offsetInBytes + sizeInBytes > audioData.length)) {
+ return ERROR_BAD_VALUE;
+ }
+
+ return native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat);
}
-
-
+
+
/**
* Writes the audio data to the audio hardware for playback.
* @param audioData the array that holds the data to play.
* @param offsetInShorts the offset in audioData where the data to play starts.
* @param sizeInShorts the number of bytes to read in audioData after the offset.
- * @return the number of shorts that were written.
- * @throws IllegalStateException
- */
- public int write(short[] audioData, int offsetInShorts, int sizeInShorts)
- throws IllegalStateException {
- if ((mDataLoadMode == MODE_STATIC)
+ * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
+ * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+ * the parameters don't resolve to valid data and indexes.
+ */
+
+ public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
+ if ((mDataLoadMode == MODE_STATIC)
&& (mState == STATE_NO_STATIC_DATA)
&& (sizeInShorts > 0)) {
mState = STATE_INITIALIZED;
}
- //TODO check if future writes should be forbidden for static tracks
- // or: how to update data for static tracks?
-
+
if (mState != STATE_INITIALIZED) {
- throw(new IllegalStateException("write() called on uninitialized AudioTrack."));
+ return ERROR_INVALID_OPERATION;
+ }
+
+ if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
+ || (offsetInShorts + sizeInShorts > audioData.length)) {
+ return ERROR_BAD_VALUE;
}
- return native_write_short(audioData, offsetInShorts, sizeInShorts);
+ return native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
}
-
-
+
+
/**
* Notifies the native resource to reuse the audio data already loaded in the native
* layer. This call is only valid with AudioTrack instances that don't use the streaming
@@ -778,23 +866,16 @@ public class AudioTrack
// Interface definitions
//--------------------
/**
- * Interface definition for a callback to be invoked when an AudioTrack has
- * reached a notification marker set by setNotificationMarkerPosition().
+ * Interface definition for a callback to be invoked when the playback head position of
+ * an AudioTrack has reached a notification marker or has increased by a certain period.
*/
- public interface OnMarkerReachedListener {
+ public interface OnPlaybackPositionUpdateListener {
/**
* Called on the listener to notify it that the previously set marker has been reached
* by the playback head.
*/
void onMarkerReached(AudioTrack track);
- }
-
-
- /**
- * Interface definition for a callback to be invoked for each periodic AudioTrack
- * update during playback. The update interval is set by setPositionNotificationPeriod().
- */
- public interface OnPeriodicNotificationListener {
+
/**
* Called on the listener to periodically notify it that the playback head has reached
* a multiple of the notification period.
@@ -807,42 +888,63 @@ public class AudioTrack
// Inner classes
//--------------------
/**
- * Helper class to handle the forwarding of native events to the appropriate listeners
- */
- private class NativeEventHandler extends Handler
- {
- private AudioTrack mAudioTrack;
-
- public NativeEventHandler(AudioTrack mp, Looper looper) {
- super(looper);
- mAudioTrack = mp;
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (mAudioTrack == null) {
- return;
- }
- switch(msg.what) {
- case NATIVE_EVENT_MARKER:
- synchronized (mMarkerListenerLock) {
- if (mAudioTrack.mMarkerListener != null) {
- mAudioTrack.mMarkerListener.onMarkerReached(mAudioTrack);
- }
- }
- break;
- case NATIVE_EVENT_NEW_POS:
- synchronized (mPeriodicListenerLock) {
- if (mAudioTrack.mPeriodicListener != null) {
- mAudioTrack.mPeriodicListener.onPeriodicNotification(mAudioTrack);
- }
+ * Helper class to handle the forwarding of native events to the appropriate listener
+ * (potentially) handled in a different thread
+ */
+ private class NativeEventHandlerDelegate {
+ private final AudioTrack mAudioTrack;
+ private final Handler mHandler;
+
+ NativeEventHandlerDelegate(AudioTrack track, Handler handler) {
+ mAudioTrack = track;
+ // find the looper for our new event handler
+ Looper looper;
+ if (handler != null) {
+ looper = handler.getLooper();
+ } else {
+ // no given handler, look for main looper
+ if ((looper = Looper.myLooper()) == null) {
+ looper = Looper.getMainLooper();
}
- break;
- default:
- Log.e(TAG, "[ android.media.AudioTrack.NativeEventHandler ] " +
- "Unknown event type: " + msg.what);
- break;
}
+ // construct the event handler with this looper
+ if (looper != null) {
+ // implement the event handler delegate
+ mHandler = new Handler(looper) {
+ @Override
+ public void handleMessage(Message msg) {
+ if (mAudioTrack == null) {
+ return;
+ }
+ OnPlaybackPositionUpdateListener listener = null;
+ synchronized (mPositionListenerLock) {
+ listener = mAudioTrack.mPositionListener;
+ }
+ switch(msg.what) {
+ case NATIVE_EVENT_MARKER:
+ if (listener != null) {
+ listener.onMarkerReached(mAudioTrack);
+ }
+ break;
+ case NATIVE_EVENT_NEW_POS:
+ if (listener != null) {
+ listener.onPeriodicNotification(mAudioTrack);
+ }
+ break;
+ default:
+ Log.e(TAG, "[ android.media.AudioTrack.NativeEventHandler ] " +
+ "Unknown event type: " + msg.what);
+ break;
+ }
+ }
+ };
+ } else {
+ mHandler = null;
+ }
+ }
+
+ Handler getHandler() {
+ return mHandler;
}
}
@@ -858,28 +960,29 @@ public class AudioTrack
if (track == null) {
return;
}
-
- if (track.mNativeEventHandler != null) {
- Message m = track.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
- track.mNativeEventHandler.sendMessage(m);
+
+ if (track.mEventHandlerDelegate != null) {
+ Message m =
+ track.mEventHandlerDelegate.getHandler().obtainMessage(what, arg1, arg2, obj);
+ track.mEventHandlerDelegate.getHandler().sendMessage(m);
}
}
-
-
+
+
//---------------------------------------------------------
// Native methods called from the Java side
//--------------------
- private native final int native_setup(Object audiotrack_this,
- int streamType, int sampleRate, int nbChannels, int audioFormat,
+ private native final int native_setup(Object audiotrack_this,
+ int streamType, int sampleRate, int nbChannels, int audioFormat,
int buffSizeInBytes, int mode);
private native final void native_finalize();
-
+
private native final void native_release();
- private native final void native_start();
+ private native final void native_start();
private native final void native_stop();
@@ -887,34 +990,36 @@ public class AudioTrack
private native final void native_flush();
- private native final int native_write_byte(byte[] audioData,
- int offsetInBytes, int sizeInBytes);
-
- private native final int native_write_short(short[] audioData,
- int offsetInShorts, int sizeInShorts);
-
+ private native final int native_write_byte(byte[] audioData,
+ int offsetInBytes, int sizeInBytes, int format);
+
+ private native final int native_write_short(short[] audioData,
+ int offsetInShorts, int sizeInShorts, int format);
+
private native final int native_reload_static();
private native final int native_get_native_frame_count();
private native final void native_setVolume(float leftVolume, float rightVolume);
-
+
private native final void native_set_playback_rate(int sampleRateInHz);
private native final int native_get_playback_rate();
-
+
private native final int native_set_marker_pos(int marker);
private native final int native_get_marker_pos();
-
+
private native final int native_set_pos_update_period(int updatePeriod);
private native final int native_get_pos_update_period();
-
+
private native final int native_set_position(int position);
private native final int native_get_position();
-
+
private native final int native_set_loop(int start, int end, int loopCount);
-
- static private native final int native_get_output_sample_rate();
-
+
+ static private native final int native_get_output_sample_rate(int streamType);
+ static private native final int native_get_min_buff_size(
+ int sampleRateInHz, int channelConfig, int audioFormat);
+
//---------------------------------------------------------
// Utility methods
@@ -929,6 +1034,3 @@ public class AudioTrack
}
}
-
-
-
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 3e33d98..f5e242d 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -65,6 +65,8 @@ interface IAudioService {
oneway void playSoundEffect(int effectType);
+ oneway void playSoundEffectVolume(int effectType, float volume);
+
boolean loadSoundEffects();
oneway void unloadSoundEffects();
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index b9268d5..9de0eec 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -17,21 +17,22 @@
package android.media;
+import java.io.FileDescriptor;
import java.lang.ref.WeakReference;
import java.lang.CloneNotSupportedException;
+import android.content.res.AssetFileDescriptor;
import android.os.Looper;
import android.os.Handler;
import android.os.Message;
+import android.util.AndroidRuntimeException;
import android.util.Log;
/**
* JetPlayer provides access to JET content playback and control.
* <p>
* Use <code>JetPlayer.getJetPlayer()</code> to get an instance of this class.
- * There can only be one instance of this class at any one time.
*
- * @hide
*/
public class JetPlayer
{
@@ -39,15 +40,29 @@ public class JetPlayer
// Constants
//------------------------
/**
- * The maximum number of simultaneous tracks. Use {@link #getMaxTracks()} to
+ * The maximum number of simultaneous tracks. Use __link #getMaxTracks()} to
* access this value.
*/
- protected static int MAXTRACKS = 32;
+ private static int MAXTRACKS = 32;
- // These constants are to be kept in sync with the ones in include/media/JetPlayer.h
- protected static final int JET_USERID_UPDATE = 1;
- protected static final int JET_NUMQUEUEDSEGMENT_UPDATE = 2;
- protected static final int JET_PAUSE_UPDATE = 3;
+ // to keep in sync with the JetPlayer class constants
+ // defined in frameworks/base/include/media/JetPlayer.h
+ private static final int JET_EVENT = 1;
+ private static final int JET_USERID_UPDATE = 2;
+ private static final int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
+ private static final int JET_PAUSE_UPDATE = 4;
+
+ // to keep in sync with external/sonivox/arm-wt-22k/lib_src/jet_data.h
+ // Encoding of event information on 32 bits
+ private static final int JET_EVENT_VAL_MASK = 0x0000007f; // mask for value
+ private static final int JET_EVENT_CTRL_MASK = 0x00003f80; // mask for controller
+ private static final int JET_EVENT_CHAN_MASK = 0x0003c000; // mask for channel
+ private static final int JET_EVENT_TRACK_MASK = 0x00fc0000; // mask for track number
+ private static final int JET_EVENT_SEG_MASK = 0xff000000; // mask for segment ID
+ private static final int JET_EVENT_CTRL_SHIFT = 7; // shift to get controller number to bit 0
+ private static final int JET_EVENT_CHAN_SHIFT = 14; // shift to get MIDI channel to bit 0
+ private static final int JET_EVENT_TRACK_SHIFT = 18; // shift to get track ID to bit 0
+ private static final int JET_EVENT_SEG_SHIFT = 24; // shift to get segment ID to bit 0
//--------------------------------------------
@@ -56,13 +71,20 @@ public class JetPlayer
private EventHandler mNativeEventHandler = null;
/**
- * Lock to protect event listener updates against event notifications
+ * Lock to protect status listener updates against status change notifications
*/
- protected final Object mStatusListenerLock = new Object();
+ private final Object mStatusListenerLock = new Object();
- protected JetStatusUpdateListener mJetStatusUpdateListener = null;
+ /**
+ * Lock to protect the event listener updates against event notifications
+ */
+ private final Object mEventListenerLock = new Object();
+
+ private JetStatusUpdateListener mJetStatusUpdateListener = null;
- protected static JetPlayer singletonRef;
+ private JetEventListener mJetEventListener = null;
+
+ private static JetPlayer singletonRef;
//--------------------------------
@@ -136,8 +158,18 @@ public class JetPlayer
//--------------------------------------------
// Jet functionality
//------------------------
- public boolean openJetFile(String path) {
- return native_openJetFile(path);
+ public boolean loadJetFile(String path) {
+ return native_loadJetFromFile(path);
+ }
+
+
+ public boolean loadJetFile(AssetFileDescriptor afd) {
+ long len = afd.getLength();
+ if (len < 0) {
+ throw new AndroidRuntimeException("no length for fd");
+ }
+ return native_loadJetFromFileD(
+ afd.getFileDescriptor(), afd.getStartOffset(), len);
}
@@ -195,6 +227,10 @@ public class JetPlayer
}
+ public boolean clearQueue() {
+ return native_clearQueue();
+ }
+
//---------------------------------------------------------
// Internal class to handle events posted from native code
@@ -211,28 +247,44 @@ public class JetPlayer
@Override
public void handleMessage(Message msg) {
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(
+ mJet,
+ (short)((msg.arg1 & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT),
+ (byte) ((msg.arg1 & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT),
+ // JETCreator channel numbers start at 1, but the index starts at 0
+ // in the .jet files
+ (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(msg.arg1, msg.arg2);
+ mJetStatusUpdateListener.onJetUserIdUpdate(mJet, msg.arg1, msg.arg2);
}
}
return;
case JET_NUMQUEUEDSEGMENT_UPDATE:
synchronized (mStatusListenerLock) {
if (mJetStatusUpdateListener != null) {
- mJetStatusUpdateListener.onJetNumQueuedSegmentUpdate(msg.arg1);
+ mJetStatusUpdateListener.onJetNumQueuedSegmentUpdate(mJet, msg.arg1);
}
}
return;
case JET_PAUSE_UPDATE:
synchronized (mStatusListenerLock) {
if (mJetStatusUpdateListener != null)
- mJetStatusUpdateListener.onJetPauseUpdate(msg.arg1);
+ mJetStatusUpdateListener.onJetPauseUpdate(mJet, msg.arg1);
}
return;
-
default:
loge("Unknown message type " + msg.what);
return;
@@ -242,7 +294,7 @@ public class JetPlayer
//--------------------------------------------
- // Jet event listener
+ // Jet status update listener
//------------------------
public void setStatusUpdateListener(JetStatusUpdateListener listener) {
synchronized(mStatusListenerLock) {
@@ -255,31 +307,66 @@ public class JetPlayer
}
/**
- * Handles the notification when the JET segment userID is updated.
+ * Handles the notification when the JET status is updated.
*/
public interface JetStatusUpdateListener {
/**
* Callback for when JET's currently playing segment userID is updated.
*
+ * @param player the JET player the status update is coming from
* @param userId the ID of the currently playing segment
* @param repeatCount the repetition count for the segment (0 means it plays once)
*/
- void onJetUserIdUpdate(int userId, int repeatCount);
+ void onJetUserIdUpdate(JetPlayer player, int userId, int repeatCount);
/**
* Callback for when JET's number of queued segments is updated.
*
+ * @param player the JET player the status update is coming from
* @param nbSegments the number of segments in the JET queue
*/
- void onJetNumQueuedSegmentUpdate(int nbSegments);
+ void onJetNumQueuedSegmentUpdate(JetPlayer player, int nbSegments);
/**
* Callback for when JET pause state is updated.
*
+ * @param player the JET player the status update is coming from
* @param paused indicates whether JET is paused or not
*/
- void onJetPauseUpdate(int paused);
- };
+ void onJetPauseUpdate(JetPlayer player, int paused);
+ }
+
+
+ //--------------------------------------------
+ // 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);
+ }
//--------------------------------------------
@@ -289,7 +376,8 @@ public class JetPlayer
int maxTracks, int trackBufferSize);
private native final void native_finalize();
private native final void native_release();
- private native final boolean native_openJetFile(String pathToJetFile);
+ private native final boolean native_loadJetFromFile(String pathToJetFile);
+ private native final boolean native_loadJetFromFileD(FileDescriptor fd, long offset, long len);
private native final boolean native_closeJetFile();
private native final boolean native_playJet();
private native final boolean native_pauseJet();
@@ -300,7 +388,8 @@ public class JetPlayer
private native final boolean native_setMuteFlags(int muteFlags, boolean sync);
private native final boolean native_setMuteArray(boolean[]muteArray, boolean sync);
private native final boolean native_setMuteFlag(int trackId, boolean muteFlag, boolean sync);
- private native final boolean native_triggerClip(int clipId);
+ private native final boolean native_triggerClip(int clipId);
+ private native final boolean native_clearQueue();
//---------------------------------------------------------
// Called exclusively by native code
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 22361aa..f05842d 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -102,13 +102,17 @@ public class MediaFile {
addFileType("AMR", FILE_TYPE_AMR, "audio/amr");
addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb");
addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma");
- addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
+ addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
+ addFileType("OGA", FILE_TYPE_OGG, "application/ogg");
addFileType("MID", FILE_TYPE_MID, "audio/midi");
+ addFileType("MIDI", FILE_TYPE_MID, "audio/midi");
addFileType("XMF", FILE_TYPE_MID, "audio/midi");
addFileType("RTTTL", FILE_TYPE_MID, "audio/midi");
addFileType("SMF", FILE_TYPE_SMF, "audio/sp-midi");
addFileType("IMY", FILE_TYPE_IMY, "audio/imelody");
+ addFileType("RTX", FILE_TYPE_MID, "audio/midi");
+ addFileType("OTA", FILE_TYPE_MID, "audio/midi");
addFileType("MP4", FILE_TYPE_MP4, "video/mp4");
addFileType("M4V", FILE_TYPE_M4V, "video/mp4");
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index c1a0c21..3a49a5f 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -18,6 +18,7 @@ package android.media;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
@@ -137,11 +138,11 @@ public class MediaMetadataRetriever
return;
}
- ParcelFileDescriptor fd = null;
+ AssetFileDescriptor fd = null;
try {
ContentResolver resolver = context.getContentResolver();
try {
- fd = resolver.openFileDescriptor(uri, "r");
+ fd = resolver.openAssetFileDescriptor(uri, "r");
} catch(FileNotFoundException e) {
throw new IllegalArgumentException();
}
@@ -152,7 +153,14 @@ public class MediaMetadataRetriever
if (!descriptor.valid()) {
throw new IllegalArgumentException();
}
- setDataSource(descriptor);
+ // Note: using getDeclaredLength so that our behavior is the same
+ // as previous versions when the content provider is returning
+ // a full file.
+ if (fd.getDeclaredLength() < 0) {
+ setDataSource(descriptor);
+ } else {
+ setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength());
+ }
return;
} catch (SecurityException ex) {
} finally {
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 1a82654..202d0ae 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -39,11 +39,11 @@ import java.lang.ref.WeakReference;
/**
* MediaPlayer class can be used to control playback
* of audio/video files and streams. An example on how to use the methods in
- * this class can be found in <a href="../widget/VideoView.html">VideoView</a>.
- * Please see <a href="../../../toolbox/apis/media.html">Android Media APIs</a>
+ * this class can be found in {@link android.widget.VideoView}.
+ * Please see <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a>
* for additional help using MediaPlayer.
*
- * <p>Topics covered are:
+ * <p>Topics covered here are:
* <ol>
* <li><a href="#StateDiagram">State Diagram</a>
* <li><a href="#Valid_and_Invalid_States">Valid and Invalid States</a>
@@ -584,14 +584,21 @@ public class MediaPlayer
return;
}
- ParcelFileDescriptor fd = null;
+ AssetFileDescriptor fd = null;
try {
ContentResolver resolver = context.getContentResolver();
- fd = resolver.openFileDescriptor(uri, "r");
+ fd = resolver.openAssetFileDescriptor(uri, "r");
if (fd == null) {
return;
}
- setDataSource(fd.getFileDescriptor());
+ // Note: using getDeclaredLength so that our behavior is the same
+ // as previous versions when the content provider is returning
+ // a full file.
+ if (fd.getDeclaredLength() < 0) {
+ setDataSource(fd.getFileDescriptor());
+ } else {
+ setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
+ }
return;
} catch (SecurityException ex) {
} catch (IOException ex) {
@@ -825,13 +832,14 @@ public class MediaPlayer
* done using the MediaPlayer.
*/
public void release() {
- if (mWakeLock != null) mWakeLock.release();
+ stayAwake(false);
updateSurfaceScreenOn();
mOnPreparedListener = null;
mOnBufferingUpdateListener = null;
mOnCompletionListener = null;
mOnSeekCompleteListener = null;
mOnErrorListener = null;
+ mOnInfoListener = null;
mOnVideoSizeChangedListener = null;
_release();
}
@@ -844,6 +852,7 @@ public class MediaPlayer
* data source and calling prepare().
*/
public void reset() {
+ stayAwake(false);
_reset();
// make sure none of the listeners get called anymore
mEventHandler.removeCallbacksAndMessages(null);
@@ -910,18 +919,7 @@ public class MediaPlayer
private static final int MEDIA_SEEK_COMPLETE = 4;
private static final int MEDIA_SET_VIDEO_SIZE = 5;
private static final int MEDIA_ERROR = 100;
-
- // error codes from framework that indicate content issues
- // contained in arg1 of error message
-
- // Seek not supported - live stream
- private static final int ERROR_SEEK_NOT_SUPPORTED = 42;
-
- // A/V interleave exceeds the progressive streaming buffer
- private static final int ERROR_CONTENT_IS_POORLY_INTERLEAVED = 43;
-
- // video decoder is falling behind - content is too complex
- private static final int ERROR_VIDEO_TRACK_IS_FALLING_BEHIND = 44;
+ private static final int MEDIA_INFO = 200;
private class EventHandler extends Handler
{
@@ -966,6 +964,8 @@ public class MediaPlayer
return;
case MEDIA_ERROR:
+ // For PV specific error values (msg.arg2) look in
+ // opencore/pvmi/pvmf/include/pvmf_return_codes.h
Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
boolean error_was_handled = false;
if (mOnErrorListener != null) {
@@ -976,6 +976,17 @@ public class MediaPlayer
}
stayAwake(false);
return;
+
+ case MEDIA_INFO:
+ // For PV specific code values (msg.arg2) look in
+ // opencore/pvmi/pvmf/include/pvmf_return_codes.h
+ Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
+ if (mOnInfoListener != null) {
+ mOnInfoListener.onInfo(mMediaPlayer, msg.arg1, msg.arg2);
+ }
+ // No real default action so far.
+ return;
+
case MEDIA_NOP: // interface test message - ignore
break;
@@ -1157,12 +1168,19 @@ public class MediaPlayer
* @see android.media.MediaPlayer.OnErrorListener
*/
public static final int MEDIA_ERROR_UNKNOWN = 1;
+
/** Media server died. In this case, the application must release the
* MediaPlayer object and instantiate a new one.
* @see android.media.MediaPlayer.OnErrorListener
*/
public static final int MEDIA_ERROR_SERVER_DIED = 100;
+ /** The video is streamed and its container is not valid for progressive
+ * playback i.e the video's index (e.g moov atom) is not at the start of the
+ * file.
+ * @hide pending API council approval. Replace with @see tag after.
+ */
+ public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;
/**
* Interface definition of a callback to be invoked when there
@@ -1180,7 +1198,8 @@ public class MediaPlayer
* <li>{@link #MEDIA_ERROR_UNKNOWN}
* <li>{@link #MEDIA_ERROR_SERVER_DIED}
* </ul>
- * @param extra an extra code, specific to the error type
+ * @param extra an extra code, specific to the error. Typically
+ * implementation dependant.
* @return True if the method handled the error, false if it didn't.
* Returning false, or not having an OnErrorListener at all, will
* cause the OnCompletionListener to be called.
@@ -1192,12 +1211,83 @@ public class MediaPlayer
* Register a callback to be invoked when an error has happened
* during an asynchronous operation.
*
- * @param l the callback that will be run
+ * @param listener the callback that will be run
*/
- public void setOnErrorListener(OnErrorListener l)
+ public void setOnErrorListener(OnErrorListener listener)
{
- mOnErrorListener = l;
+ mOnErrorListener = listener;
}
private OnErrorListener mOnErrorListener;
+
+
+ /* Do not change these values without updating their counterparts
+ * in include/media/mediaplayer.h!
+ */
+ /** Unspecified media player info.
+ * @see android.media.MediaPlayer.OnInfoListener
+ * @hide pending API council approval.
+ */
+ public static final int MEDIA_INFO_UNKNOWN = 1;
+
+ /** The video is too complex for the decoder: it can't decode frames fast
+ * enough. Possibly only the audio plays fine at this stage.
+ * @see android.media.MediaPlayer.OnInfoListener
+ * @hide pending API council approval.
+ */
+ public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;
+
+ /** Bad interleaving means that a media has been improperly interleaved or
+ * not interleaved at all, e.g has all the video samples first then all the
+ * audio ones. Video is playing but a lot of disk seeks may be happening.
+ * @see android.media.MediaPlayer.OnInfoListener
+ * @hide pending API council approval.
+ */
+ public static final int MEDIA_INFO_BAD_INTERLEAVING = 800;
+
+ /** The media cannot be seeked (e.g live stream)
+ * @see android.media.MediaPlayer.OnInfoListener
+ * @hide pending API council approval.
+ */
+ public static final int MEDIA_INFO_NOT_SEEKABLE = 801;
+
+ /**
+ * Interface definition of a callback to be invoked to communicate some
+ * info and/or warning about the media or its playback.
+ * @hide pending API council approval.
+ */
+ public interface OnInfoListener
+ {
+ /**
+ * Called to indicate an info or a warning.
+ *
+ * @param mp the MediaPlayer the info pertains to.
+ * @param what the type of info or warning.
+ * <ul>
+ * <li>{@link #MEDIA_INFO_UNKNOWN}
+ * <li>{@link #MEDIA_INFO_VIDEO_TRACK_LAGGING}
+ * <li>{@link #MEDIA_INFO_BAD_INTERLEAVING}
+ * <li>{@link #MEDIA_INFO_NOT_SEEKABLE}
+ * </ul>
+ * @param extra an extra code, specific to the info. Typically
+ * implementation dependant.
+ * @return True if the method handled the info, false if it didn't.
+ * Returning false, or not having an OnErrorListener at all, will
+ * cause the info to be discarded.
+ */
+ boolean onInfo(MediaPlayer mp, int what, int extra);
+ }
+
+ /**
+ * Register a callback to be invoked when an info/warning is available.
+ *
+ * @param listener the callback that will be run
+ * @hide pending API council approval.
+ */
+ public void setOnInfoListener(OnInfoListener listener)
+ {
+ mOnInfoListener = listener;
+ }
+
+ private OnInfoListener mOnInfoListener;
}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 651cc41..1c08cba 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -16,19 +16,27 @@
package android.media;
-import android.view.Surface;
import android.hardware.Camera;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.Surface;
import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileDescriptor;
+import java.lang.ref.WeakReference;
/**
* Used to record audio and video. The recording control is based on a
- * simple state machine (see below).
- *
- * <p><img src="../../../images/mediarecorder_state_diagram.gif" border="0" />
+ * simple state machine (see below).
+ *
+ * <p><img src="{@docRoot}images/mediarecorder_state_diagram.gif" border="0" />
* </p>
- *
+ *
* <p>A common case of using MediaRecorder to record audio works as follows:
- *
+ *
* <pre>MediaRecorder recorder = new MediaRecorder();
* recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
* recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
@@ -41,38 +49,56 @@ import java.io.IOException;
* recorder.reset(); // You can reuse the object by going back to setAudioSource() step
* recorder.release(); // Now the object cannot be reused
* </pre>
- *
- * <p>See the <a href="../../../toolbox/apis/media.html">Android Media APIs</a>
- * page for additional help with using MediaRecorder.
+ *
+ * <p>See the <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a>
+ * documentation for additional help with using MediaRecorder.
*/
public class MediaRecorder
-{
+{
static {
System.loadLibrary("media_jni");
}
-
+ private final static String TAG = "MediaRecorder";
+
// The two fields below are accessed by native methods
@SuppressWarnings("unused")
private int mNativeContext;
-
+
@SuppressWarnings("unused")
private Surface mSurface;
-
+
+ private String mPath;
+ private FileDescriptor mFd;
+ private EventHandler mEventHandler;
+ private OnErrorListener mOnErrorListener;
+ private OnInfoListener mOnInfoListener;
+
/**
* Default constructor.
*/
public MediaRecorder() {
- native_setup();
+
+ Looper looper;
+ if ((looper = Looper.myLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else {
+ mEventHandler = null;
+ }
+
+ /* Native setup requires a weak reference to our object.
+ * It's easier to create it here than in C++.
+ */
+ native_setup(new WeakReference<MediaRecorder>(this));
}
-
+
/**
* Sets a Camera to use for recording. Use this function to switch
* quickly between preview and capture mode without a teardown of
* the camera object. Must call before prepare().
- *
+ *
* @param c the Camera to use for recording
- * FIXME: Temporarily hidden until API approval
- * @hide
*/
public native void setCamera(Camera c);
@@ -80,15 +106,15 @@ public class MediaRecorder
* Sets a Surface to show a preview of recorded media (video). Calls this
* before prepare() to make sure that the desirable preview display is
* set.
- *
+ *
* @param sv the Surface to use for the preview
*/
public void setPreviewDisplay(Surface sv) {
mSurface = sv;
}
-
+
/**
- * Defines the audio source. These constants are used with
+ * Defines the audio source. These constants are used with
* {@link MediaRecorder#setAudioSource(int)}.
*/
public final class AudioSource {
@@ -102,9 +128,8 @@ public class MediaRecorder
}
/**
- * Defines the video source. These constants are used with
+ * Defines the video source. These constants are used with
* {@link MediaRecorder#setVideoSource(int)}.
- * @hide
*/
public final class VideoSource {
/* Do not change these values without updating their counterparts
@@ -117,7 +142,7 @@ public class MediaRecorder
}
/**
- * Defines the output format. These constants are used with
+ * Defines the output format. These constants are used with
* {@link MediaRecorder#setOutputFormat(int)}.
*/
public final class OutputFormat {
@@ -135,7 +160,7 @@ public class MediaRecorder
};
/**
- * Defines the audio encoding. These constants are used with
+ * Defines the audio encoding. These constants are used with
* {@link MediaRecorder#setAudioEncoder(int)}.
*/
public final class AudioEncoder {
@@ -150,9 +175,8 @@ public class MediaRecorder
}
/**
- * Defines the video encoding. These constants are used with
+ * Defines the video encoding. These constants are used with
* {@link MediaRecorder#setVideoEncoder(int)}.
- * @hide
*/
public final class VideoEncoder {
/* Do not change these values without updating their counterparts
@@ -168,53 +192,51 @@ public class MediaRecorder
/**
* Sets the audio source to be used for recording. If this method is not
* called, the output file will not contain an audio track. The source needs
- * to be specified before setting recording-parameters or encoders. Call
+ * to be specified before setting recording-parameters or encoders. Call
* this only before setOutputFormat().
- *
+ *
* @param audio_source the audio source to use
* @throws IllegalStateException if it is called after setOutputFormat()
* @see android.media.MediaRecorder.AudioSource
- */
+ */
public native void setAudioSource(int audio_source)
throws IllegalStateException;
/**
* Sets the video source to be used for recording. If this method is not
* called, the output file will not contain an video track. The source needs
- * to be specified before setting recording-parameters or encoders. Call
+ * to be specified before setting recording-parameters or encoders. Call
* this only before setOutputFormat().
- *
+ *
* @param video_source the video source to use
* @throws IllegalStateException if it is called after setOutputFormat()
* @see android.media.MediaRecorder.VideoSource
- * @hide
- */
+ */
public native void setVideoSource(int video_source)
throws IllegalStateException;
/**
* Sets the format of the output file produced during recording. Call this
* after setAudioSource()/setVideoSource() but before prepare().
- *
- * @param output_format the output format to use. The output format
+ *
+ * @param output_format the output format to use. The output format
* needs to be specified before setting recording-parameters or encoders.
* @throws IllegalStateException if it is called after prepare() or before
* setAudioSource()/setVideoSource().
* @see android.media.MediaRecorder.OutputFormat
- */
+ */
public native void setOutputFormat(int output_format)
throws IllegalStateException;
-
+
/**
* Sets the width and height of the video to be captured. Must be called
* after setVideoSource(). Call this after setOutFormat() but before
* prepare().
- *
+ *
* @param width the width of the video to be captured
* @param height the height of the video to be captured
- * @throws IllegalStateException if it is called after
+ * @throws IllegalStateException if it is called after
* prepare() or before setOutputFormat()
- * @hide
*/
public native void setVideoSize(int width, int height)
throws IllegalStateException;
@@ -225,22 +247,34 @@ public class MediaRecorder
* prepare().
*
* @param rate the number of frames per second of video to capture
- * @throws IllegalStateException if it is called after
+ * @throws IllegalStateException if it is called after
* prepare() or before setOutputFormat().
- * @hide
+ *
+ * NOTE: On some devices that have auto-frame rate, this sets the
+ * maximum frame rate, not a constant frame rate. Actual frame rate
+ * will vary according to lighting conditions.
*/
public native void setVideoFrameRate(int rate) throws IllegalStateException;
/**
+ * Sets the maximum duration (in ms) of the recording session.
+ * Call this after setOutFormat() but before prepare().
+ *
+ * @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 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
* setOutputFormat() but before prepare().
- *
+ *
* @param audio_encoder the audio encoder to use.
* @throws IllegalStateException if it is called before
* setOutputFormat() or after prepare().
* @see android.media.MediaRecorder.AudioEncoder
- */
+ */
public native void setAudioEncoder(int audio_encoder)
throws IllegalStateException;
@@ -248,41 +282,78 @@ public class MediaRecorder
* Sets the video encoder to be used for recording. If this method is not
* called, the output file will not contain an video track. Call this after
* setOutputFormat() and before prepare().
- *
+ *
* @param video_encoder the video encoder to use.
* @throws IllegalStateException if it is called before
* setOutputFormat() or after prepare()
* @see android.media.MediaRecorder.VideoEncoder
- * @hide
- */
+ */
public native void setVideoEncoder(int video_encoder)
throws IllegalStateException;
/**
+ * Pass in the file descriptor of the file to be written. Call this after
+ * setOutputFormat() but before prepare().
+ *
+ * @param fd an open file descriptor to be written into.
+ * @throws IllegalStateException if it is called before
+ * setOutputFormat() or after prepare()
+ */
+ public void setOutputFile(FileDescriptor fd) throws IllegalStateException
+ {
+ mPath = null;
+ mFd = fd;
+ }
+
+ /**
* Sets the path of the output file to be produced. Call this after
* setOutputFormat() but before prepare().
- *
- * @param path The pathname to use()
+ *
+ * @param path The pathname to use.
* @throws IllegalStateException if it is called before
* setOutputFormat() or after prepare()
- */
- public native void setOutputFile(String path) throws IllegalStateException;
-
+ */
+ public void setOutputFile(String path) throws IllegalStateException
+ {
+ mFd = null;
+ mPath = path;
+ }
+
+ // native implementation
+ private native void _setOutputFile(FileDescriptor fd, long offset, long length)
+ throws IllegalStateException, IOException;
+ private native void _prepare() throws IllegalStateException, IOException;
+
/**
* Prepares the recorder to begin capturing and encoding data. This method
* must be called after setting up the desired audio and video sources,
* encoders, file format, etc., but before start().
- *
+ *
* @throws IllegalStateException if it is called after
* start() or before setOutputFormat().
* @throws IOException if prepare fails otherwise.
*/
- public native void prepare() throws IllegalStateException, IOException;
+ public void prepare() throws IllegalStateException, IOException
+ {
+ if (mPath != null) {
+ FileOutputStream fos = new FileOutputStream(mPath);
+ try {
+ _setOutputFile(fos.getFD(), 0, 0);
+ } finally {
+ fos.close();
+ }
+ } else if (mFd != null) {
+ _setOutputFile(mFd, 0, 0);
+ } else {
+ throw new IOException("No valid output file");
+ }
+ _prepare();
+ }
/**
- * Begins capturing and encoding data to the file specified with
+ * Begins capturing and encoding data to the file specified with
* setOutputFile(). Call this after prepare().
- *
+ *
* @throws IllegalStateException if it is called before
* prepare().
*/
@@ -291,7 +362,7 @@ public class MediaRecorder
/**
* Stops recording. Call this after start(). Once recording is stopped,
* you will have to configure it again as if it has just been constructed.
- *
+ *
* @throws IllegalStateException if it is called before start()
*/
public native void stop() throws IllegalStateException;
@@ -301,19 +372,167 @@ public class MediaRecorder
* this method, you will have to configure it again as if it had just been
* constructed.
*/
- public native void reset();
-
+ public void reset() {
+ native_reset();
+
+ // make sure none of the listeners get called anymore
+ mEventHandler.removeCallbacksAndMessages(null);
+ }
+
+ private native void native_reset();
+
/**
- * Returns the maximum absolute amplitude that was sampled since the last
+ * Returns the maximum absolute amplitude that was sampled since the last
* call to this method. Call this only after the setAudioSource().
- *
- * @return the maximum absolute amplitude measured since the last call, or
+ *
+ * @return the maximum absolute amplitude measured since the last call, or
* 0 when called for the first time
* @throws IllegalStateException if it is called before
* the audio source has been set.
*/
public native int getMaxAmplitude() throws IllegalStateException;
-
+
+ /* Do not change this value without updating its counterpart
+ * in include/media/mediarecorder.h!
+ */
+ /** Unspecified media recorder error.
+ * @see android.media.MediaRecorder.OnErrorListener
+ */
+ public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1;
+
+ /**
+ * Interface definition for a callback to be invoked when an error
+ * occurs while recording.
+ */
+ public interface OnErrorListener
+ {
+ /**
+ * Called when an error occurs while recording.
+ *
+ * @param mr the MediaRecorder that encountered the error
+ * @param what the type of error that has occurred:
+ * <ul>
+ * <li>{@link #MEDIA_RECORDER_ERROR_UNKNOWN}
+ * </ul>
+ * @param extra an extra code, specific to the error type
+ */
+ void onError(MediaRecorder mr, int what, int extra);
+ }
+
+ /**
+ * Register a callback to be invoked when an error occurs while
+ * recording.
+ *
+ * @param l the callback that will be run
+ */
+ public void setOnErrorListener(OnErrorListener l)
+ {
+ mOnErrorListener = l;
+ }
+
+ /* Do not change these values without updating their counterparts
+ * in include/media/mediarecorder.h!
+ */
+ /** Unspecified media recorder error.
+ * @see android.media.MediaRecorder.OnInfoListener
+ */
+ public static final int MEDIA_RECORDER_INFO_UNKNOWN = 1;
+ /** A maximum duration had been setup and has now been reached.
+ * @see android.media.MediaRecorder.OnInfoListener
+ */
+ public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800;
+
+ /**
+ * Interface definition for a callback to be invoked when an error
+ * occurs while recording.
+ */
+ public interface OnInfoListener
+ {
+ /**
+ * Called when an error occurs while recording.
+ *
+ * @param mr the MediaRecorder that encountered the error
+ * @param what the type of error that has occurred:
+ * <ul>
+ * <li>{@link #MEDIA_RECORDER_INFO_UNKNOWN}
+ * </ul>
+ * @param extra an extra code, specific to the error type
+ */
+ void onInfo(MediaRecorder mr, int what, int extra);
+ }
+
+ /**
+ * Register a callback to be invoked when an informational event occurs while
+ * recording.
+ *
+ * @param listener the callback that will be run
+ */
+ public void setOnInfoListener(OnInfoListener listener)
+ {
+ mOnInfoListener = listener;
+ }
+
+ private class EventHandler extends Handler
+ {
+ private MediaRecorder mMediaRecorder;
+
+ public EventHandler(MediaRecorder mr, Looper looper) {
+ super(looper);
+ mMediaRecorder = mr;
+ }
+
+ /* Do not change these values without updating their counterparts
+ * in include/media/mediarecorder.h!
+ */
+ private static final int MEDIA_RECORDER_EVENT_ERROR = 1;
+ private static final int MEDIA_RECORDER_EVENT_INFO = 2;
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mMediaRecorder.mNativeContext == 0) {
+ Log.w(TAG, "mediarecorder went away with unhandled events");
+ return;
+ }
+ switch(msg.what) {
+ case MEDIA_RECORDER_EVENT_ERROR:
+ if (mOnErrorListener != null)
+ mOnErrorListener.onError(mMediaRecorder, msg.arg1, msg.arg2);
+
+ return;
+
+ case MEDIA_RECORDER_EVENT_INFO:
+ if (mOnInfoListener != null)
+ mOnInfoListener.onInfo(mMediaRecorder, msg.arg1, msg.arg2);
+
+ return;
+
+ default:
+ Log.e(TAG, "Unknown message type " + msg.what);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Called from native code when an interesting event happens. This method
+ * just uses the EventHandler system to post the event back to the main app thread.
+ * We use a weak reference to the original MediaRecorder object so that the native
+ * code is safe from the object disappearing from underneath it. (This is
+ * the cookie passed to native_setup().)
+ */
+ private static void postEventFromNative(Object mediarecorder_ref,
+ int what, int arg1, int arg2, Object obj)
+ {
+ MediaRecorder mr = (MediaRecorder)((WeakReference)mediarecorder_ref).get();
+ if (mr == null) {
+ return;
+ }
+
+ if (mr.mEventHandler != null) {
+ Message m = mr.mEventHandler.obtainMessage(what, arg1, arg2, obj);
+ mr.mEventHandler.sendMessage(m);
+ }
+ }
/**
* Releases resources associated with this MediaRecorder object.
@@ -322,10 +541,10 @@ public class MediaRecorder
*/
public native void release();
- private native final void native_setup() throws IllegalStateException;
-
+ private native final void native_setup(Object mediarecorder_this) throws IllegalStateException;
+
private native final void native_finalize();
-
+
@Override
protected void finalize() { native_finalize(); }
}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 38203b6..fc8476d 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -118,6 +118,7 @@ public class MediaScanner
private static final String NOTIFICATIONS_DIR = "/notifications/";
private static final String ALARMS_DIR = "/alarms/";
private static final String MUSIC_DIR = "/music/";
+ private static final String PODCAST_DIR = "/podcasts/";
private static final String[] ID3_GENRES = {
// ID3v1 Genres
@@ -455,8 +456,9 @@ public class MediaScanner
boolean ringtones = (path.indexOf(RINGTONES_DIR) > 0);
boolean notifications = (path.indexOf(NOTIFICATIONS_DIR) > 0);
boolean alarms = (path.indexOf(ALARMS_DIR) > 0);
+ boolean podcasts = (path.indexOf(PODCAST_DIR) > 0);
boolean music = (path.indexOf(MUSIC_DIR) > 0) ||
- (!ringtones && !notifications && !alarms);
+ (!ringtones && !notifications && !alarms && !podcasts);
if (mFileType == MediaFile.FILE_TYPE_MP3 ||
mFileType == MediaFile.FILE_TYPE_MP4 ||
@@ -473,7 +475,7 @@ public class MediaScanner
// we used to compute the width and height but it's not worth it
}
- result = endFile(entry, ringtones, notifications, alarms, music);
+ result = endFile(entry, ringtones, notifications, alarms, music, podcasts);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
@@ -586,7 +588,8 @@ public class MediaScanner
return map;
}
- public Uri endFile(FileCacheEntry entry, boolean ringtones, boolean notifications, boolean alarms, boolean music)
+ private Uri endFile(FileCacheEntry entry, boolean ringtones, boolean notifications,
+ boolean alarms, boolean music, boolean podcasts)
throws RemoteException {
// update database
Uri tableUri;
@@ -634,6 +637,7 @@ public class MediaScanner
values.put(Audio.Media.IS_NOTIFICATION, notifications);
values.put(Audio.Media.IS_ALARM, alarms);
values.put(Audio.Media.IS_MUSIC, music);
+ values.put(Audio.Media.IS_PODCAST, podcasts);
} else if (isImage) {
// nothing right now
}
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index cfcb5eb..e80d8aa 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -164,9 +164,16 @@ public class Ringtone {
} else if (mFileDescriptor != null) {
mAudio.setDataSource(mFileDescriptor);
} else if (mAssetFileDescriptor != null) {
- mAudio.setDataSource(mAssetFileDescriptor.getFileDescriptor(),
- mAssetFileDescriptor.getStartOffset(),
- mAssetFileDescriptor.getLength());
+ // Note: using getDeclaredLength so that our behavior is the same
+ // as previous versions when the content provider is returning
+ // a full file.
+ if (mAssetFileDescriptor.getDeclaredLength() < 0) {
+ mAudio.setDataSource(mAssetFileDescriptor.getFileDescriptor());
+ } else {
+ mAudio.setDataSource(mAssetFileDescriptor.getFileDescriptor(),
+ mAssetFileDescriptor.getStartOffset(),
+ mAssetFileDescriptor.getDeclaredLength());
+ }
} else {
throw new IOException("No data source set.");
}
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 427f173..000430f 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -16,6 +16,7 @@
package android.media;
+import android.util.AndroidRuntimeException;
import android.util.Log;
import java.io.File;
import java.io.FileDescriptor;
@@ -79,7 +80,11 @@ public class SoundPool
public int load(AssetFileDescriptor afd, int priority) {
if (afd != null) {
- return _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority);
+ long len = afd.getLength();
+ if (len < 0) {
+ throw new AndroidRuntimeException("no length for fd");
+ }
+ return _load(afd.getFileDescriptor(), afd.getStartOffset(), len, priority);
} else {
return 0;
}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 5562254..707db02 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -29,6 +29,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include "utils/Errors.h" // for status_t
// ----------------------------------------------------------------------------
@@ -171,6 +172,7 @@ android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
return;
}
+ LOGV("setDataSource: path %s", pathStr);
status_t opStatus = mp->setDataSource(pathStr);
// Make sure that local ref is released before a potential exception
@@ -192,6 +194,7 @@ android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fil
return;
}
int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+ LOGV("setDataSourceFD: fd %d", fd);
process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
}
@@ -207,8 +210,8 @@ android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
jobject surface = env->GetObjectField(thiz, fields.surface);
if (surface != NULL) {
const sp<Surface>& native_surface = get_surface(env, surface);
- //LOGI("prepare: surface=%p (id=%d)",
- // native_surface.get(), native_surface->ID());
+ LOGV("prepare: surface=%p (id=%d)",
+ native_surface.get(), native_surface->ID());
mp->setVideoSurface(native_surface);
}
process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
@@ -225,8 +228,8 @@ android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
jobject surface = env->GetObjectField(thiz, fields.surface);
if (surface != NULL) {
const sp<Surface>& native_surface = get_surface(env, surface);
- LOGI("prepareAsync: surface=%p (id=%d)",
- native_surface.get(), native_surface->ID());
+ LOGV("prepareAsync: surface=%p (id=%d)",
+ native_surface.get(), native_surface->ID());
mp->setVideoSurface(native_surface);
}
process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
@@ -235,6 +238,7 @@ android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
static void
android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{
+ LOGV("start");
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -246,6 +250,7 @@ android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
static void
android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz)
{
+ LOGV("stop");
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -257,6 +262,7 @@ android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz)
static void
android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz)
{
+ LOGV("pause");
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -273,7 +279,10 @@ android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz)
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return false;
}
- return mp->isPlaying();
+ const jboolean is_playing = mp->isPlaying();
+
+ LOGV("isPlaying: %d", is_playing);
+ return is_playing;
}
static void
@@ -284,6 +293,7 @@ android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec)
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
+ LOGV("seekTo: %d(msec)", msec);
process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL );
}
@@ -296,9 +306,12 @@ android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz)
return 0;
}
int w;
- if (0 == mp->getVideoWidth(&w))
- return w;
- return 0;
+ if (0 != mp->getVideoWidth(&w)) {
+ LOGE("getVideoWidth failed");
+ w = 0;
+ }
+ LOGV("getVideoWidth: %d", w);
+ return w;
}
static int
@@ -310,9 +323,12 @@ android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz)
return 0;
}
int h;
- if (0 == mp->getVideoHeight(&h))
- return h;
- return 0;
+ if (0 != mp->getVideoHeight(&h)) {
+ LOGE("getVideoHeight failed");
+ h = 0;
+ }
+ LOGV("getVideoHeight: %d", h);
+ return h;
}
@@ -326,6 +342,7 @@ android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
}
int msec;
process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL );
+ LOGV("getCurrentPosition: %d (msec)", msec);
return msec;
}
@@ -339,12 +356,14 @@ android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz)
}
int msec;
process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL );
+ LOGV("getDuration: %d (msec)", msec);
return msec;
}
static void
android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
{
+ LOGV("reset");
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -356,6 +375,7 @@ android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
static void
android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype)
{
+ LOGV("setAudioStreamType: %d", streamtype);
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -367,6 +387,7 @@ android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int stre
static void
android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
{
+ LOGV("setLooping: %d", looping);
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -378,6 +399,7 @@ android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping
static jboolean
android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
{
+ LOGV("isLooping");
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -389,6 +411,7 @@ android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
static void
android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume)
{
+ LOGV("setVolume: left %f right %f", leftVolume, rightVolume);
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -570,4 +593,3 @@ bail:
}
// KTHXBYE
-
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 2810a9c..1e508d2 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -41,16 +41,68 @@ using namespace android;
// ----------------------------------------------------------------------------
// helper function to extract a native Camera object from a Camera Java object
-extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz);
+extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct camera_context_t** context);
struct fields_t {
jfieldID context;
jfieldID surface;
/* actually in android.view.Surface XXX */
jfieldID surface_native;
+
+ jmethodID post_event;
};
static fields_t fields;
+static Mutex sLock;
+
+// ----------------------------------------------------------------------------
+// ref-counted object for callbacks
+class JNIMediaRecorderListener: public MediaRecorderListener
+{
+public:
+ JNIMediaRecorderListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
+ ~JNIMediaRecorderListener();
+ void notify(int msg, int ext1, int ext2);
+private:
+ JNIMediaRecorderListener();
+ jclass mClass; // Reference to MediaRecorder class
+ jobject mObject; // Weak ref to MediaRecorder Java object to call on
+};
+
+JNIMediaRecorderListener::JNIMediaRecorderListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
+{
+
+ // Hold onto the MediaRecorder class for use in calling the static method
+ // that posts events to the application thread.
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ LOGE("Can't find android/media/MediaRecorder");
+ jniThrowException(env, "java/lang/Exception", NULL);
+ return;
+ }
+ mClass = (jclass)env->NewGlobalRef(clazz);
+
+ // We use a weak reference so the MediaRecorder object can be garbage collected.
+ // The reference is only used as a proxy for callbacks.
+ mObject = env->NewGlobalRef(weak_thiz);
+}
+
+JNIMediaRecorderListener::~JNIMediaRecorderListener()
+{
+ // remove global references
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mObject);
+ env->DeleteGlobalRef(mClass);
+}
+
+void JNIMediaRecorderListener::notify(int msg, int ext1, int ext2)
+{
+ LOGV("JNIMediaRecorderListener::notify");
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0);
+}
+
// ----------------------------------------------------------------------------
static sp<Surface> get_surface(JNIEnv* env, jobject clazz)
@@ -60,21 +112,46 @@ static sp<Surface> get_surface(JNIEnv* env, jobject clazz)
return sp<Surface>(p);
}
-static void process_media_recorder_call(JNIEnv *env, status_t opStatus, const char* exception, const char* message)
+// Returns true if it throws an exception.
+static bool process_media_recorder_call(JNIEnv *env, status_t opStatus, const char* exception, const char* message)
{
LOGV("process_media_recorder_call");
if (opStatus == (status_t)INVALID_OPERATION) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return true;
} else if (opStatus != (status_t)OK) {
jniThrowException(env, exception, message);
+ return true;
+ }
+ return false;
+}
+
+static sp<MediaRecorder> getMediaRecorder(JNIEnv* env, jobject thiz)
+{
+ Mutex::Autolock l(sLock);
+ MediaRecorder* const p = (MediaRecorder*)env->GetIntField(thiz, fields.context);
+ return sp<MediaRecorder>(p);
+}
+
+static sp<MediaRecorder> setMediaRecorder(JNIEnv* env, jobject thiz, const sp<MediaRecorder>& recorder)
+{
+ Mutex::Autolock l(sLock);
+ sp<MediaRecorder> old = (MediaRecorder*)env->GetIntField(thiz, fields.context);
+ if (recorder.get()) {
+ recorder->incStrong(thiz);
+ }
+ if (old != 0) {
+ old->decStrong(thiz);
}
- return;
+ env->SetIntField(thiz, fields.context, (int)recorder.get());
+ return old;
}
+
static void android_media_MediaRecorder_setCamera(JNIEnv* env, jobject thiz, jobject camera)
{
- sp<Camera> c = get_native_camera(env, camera);
- MediaRecorder *mr = (MediaRecorder*)env->GetIntField(thiz, fields.context);
+ sp<Camera> c = get_native_camera(env, camera, NULL);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
process_media_recorder_call(env, mr->setCamera(c->remote()),
"java/lang/RuntimeException", "setCamera failed.");
}
@@ -87,7 +164,7 @@ android_media_MediaRecorder_setVideoSource(JNIEnv *env, jobject thiz, jint vs)
jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid video source");
return;
}
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
process_media_recorder_call(env, mr->setVideoSource(vs), "java/lang/RuntimeException", "setVideoSource failed.");
}
@@ -99,7 +176,7 @@ android_media_MediaRecorder_setAudioSource(JNIEnv *env, jobject thiz, jint as)
jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid audio source");
return;
}
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
process_media_recorder_call(env, mr->setAudioSource(as), "java/lang/RuntimeException", "setAudioSource failed.");
}
@@ -111,7 +188,7 @@ android_media_MediaRecorder_setOutputFormat(JNIEnv *env, jobject thiz, jint of)
jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid output format");
return;
}
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
process_media_recorder_call(env, mr->setOutputFormat(of), "java/lang/RuntimeException", "setOutputFormat failed.");
}
@@ -123,7 +200,7 @@ android_media_MediaRecorder_setVideoEncoder(JNIEnv *env, jobject thiz, jint ve)
jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid video encoder");
return;
}
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
process_media_recorder_call(env, mr->setVideoEncoder(ve), "java/lang/RuntimeException", "setVideoEncoder failed.");
}
@@ -135,37 +212,29 @@ android_media_MediaRecorder_setAudioEncoder(JNIEnv *env, jobject thiz, jint ae)
jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid audio encoder");
return;
}
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
process_media_recorder_call(env, mr->setAudioEncoder(ae), "java/lang/RuntimeException", "setAudioEncoder failed.");
}
static void
-android_media_MediaRecorder_setOutputFile(JNIEnv *env, jobject thiz, jstring path)
+android_media_MediaRecorder_setOutputFileFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
LOGV("setOutputFile");
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
-
- if (path == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Path is a NULL pointer");
+ if (fileDescriptor == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
- const char *pathStr = env->GetStringUTFChars(path, NULL);
- if (pathStr == NULL) { // Out of memory
- jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
- return;
- }
- status_t opStatus = mr->setOutputFile(pathStr);
-
- // Make sure that local ref is released before a potential exception
- env->ReleaseStringUTFChars(path, pathStr);
- process_media_recorder_call(env, opStatus, "java/lang/RuntimeException", "setOutputFile failed.");
+ int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+ status_t opStatus = mr->setOutputFile(fd, offset, length);
+ process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed.");
}
static void
android_media_MediaRecorder_setVideoSize(JNIEnv *env, jobject thiz, jint width, jint height)
{
LOGV("setVideoSize(%d, %d)", width, height);
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
if (width <= 0 || height <= 0) {
jniThrowException(env, "java/lang/IllegalArgumentException", "invalid video size");
@@ -182,21 +251,35 @@ android_media_MediaRecorder_setVideoFrameRate(JNIEnv *env, jobject thiz, jint ra
jniThrowException(env, "java/lang/IllegalArgumentException", "invalid frame rate");
return;
}
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
process_media_recorder_call(env, mr->setVideoFrameRate(rate), "java/lang/RuntimeException", "setVideoFrameRate failed.");
}
static void
+android_media_MediaRecorder_setMaxDuration(JNIEnv *env, jobject thiz, jint max_duration_ms)
+{
+ LOGV("setMaxDuration(%d)", max_duration_ms);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+
+ char params[64];
+ sprintf(params, "max-duration=%d", max_duration_ms);
+
+ process_media_recorder_call(env, mr->setParameters(String8(params)), "java/lang/RuntimeException", "setMaxDuration failed.");
+}
+
+static void
android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
{
LOGV("prepare");
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
jobject surface = env->GetObjectField(thiz, fields.surface);
if (surface != NULL) {
const sp<Surface>& native_surface = get_surface(env, surface);
LOGI("prepare: surface=%p (id=%d)", native_surface.get(), native_surface->ID());
- process_media_recorder_call(env, mr->setPreviewSurface(native_surface), "java/lang/RuntimeException", "setPreviewSurface failed.");
+ if (process_media_recorder_call(env, mr->setPreviewSurface(native_surface), "java/lang/RuntimeException", "setPreviewSurface failed.")) {
+ return;
+ }
}
process_media_recorder_call(env, mr->prepare(), "java/io/IOException", "prepare failed.");
}
@@ -205,7 +288,7 @@ static int
android_media_MediaRecorder_native_getMaxAmplitude(JNIEnv *env, jobject thiz)
{
LOGV("getMaxAmplitude");
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
int result = 0;
process_media_recorder_call(env, mr->getMaxAmplitude(&result), "java/lang/RuntimeException", "getMaxAmplitude failed.");
return result;
@@ -215,7 +298,7 @@ static void
android_media_MediaRecorder_start(JNIEnv *env, jobject thiz)
{
LOGV("start");
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
process_media_recorder_call(env, mr->start(), "java/lang/RuntimeException", "start failed.");
}
@@ -223,68 +306,78 @@ static void
android_media_MediaRecorder_stop(JNIEnv *env, jobject thiz)
{
LOGV("stop");
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
process_media_recorder_call(env, mr->stop(), "java/lang/RuntimeException", "stop failed.");
}
static void
-android_media_MediaRecorder_reset(JNIEnv *env, jobject thiz)
+android_media_MediaRecorder_native_reset(JNIEnv *env, jobject thiz)
{
- LOGV("reset");
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
- process_media_recorder_call(env, mr->reset(), "java/lang/RuntimeException", "reset failed.");
+ LOGV("native_reset");
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+ process_media_recorder_call(env, mr->reset(), "java/lang/RuntimeException", "native_reset failed.");
}
static void
android_media_MediaRecorder_release(JNIEnv *env, jobject thiz)
{
LOGV("release");
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
- env->SetIntField(thiz, fields.context, 0);
- delete mr;
+ sp<MediaRecorder> mr = setMediaRecorder(env, thiz, 0);
+ if (mr != NULL) {
+ mr->setListener(NULL);
+ mr->release();
+ }
}
static void
-android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz)
+android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
LOGV("setup");
- MediaRecorder *mr = new MediaRecorder();
- if (mr->initCheck() == NO_ERROR) {
- env->SetIntField(thiz, fields.context, (int)mr);
- } else {
- delete mr;
+ sp<MediaRecorder> mr = new MediaRecorder();
+ if (mr == NULL) {
+ jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ return;
+ }
+ if (mr->initCheck() != NO_ERROR) {
jniThrowException(env, "java/lang/IOException", "Unable to initialize camera");
+ return;
}
+
+ // create new listener and give it to MediaRecorder
+ sp<JNIMediaRecorderListener> listener = new JNIMediaRecorderListener(env, thiz, weak_this);
+ mr->setListener(listener);
+
+ setMediaRecorder(env, thiz, mr);
}
static void
android_media_MediaRecorder_native_finalize(JNIEnv *env, jobject thiz)
{
LOGV("finalize");
- MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
- delete mr;
+ android_media_MediaRecorder_release(env, thiz);
}
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- {"setCamera", "(Landroid/hardware/Camera;)V",(void *)android_media_MediaRecorder_setCamera},
- {"setVideoSource", "(I)V", (void *)android_media_MediaRecorder_setVideoSource},
- {"setAudioSource", "(I)V", (void *)android_media_MediaRecorder_setAudioSource},
- {"setOutputFormat", "(I)V", (void *)android_media_MediaRecorder_setOutputFormat},
- {"setVideoEncoder", "(I)V", (void *)android_media_MediaRecorder_setVideoEncoder},
- {"setAudioEncoder", "(I)V", (void *)android_media_MediaRecorder_setAudioEncoder},
- {"setOutputFile", "(Ljava/lang/String;)V", (void *)android_media_MediaRecorder_setOutputFile},
- {"setVideoSize", "(II)V", (void *)android_media_MediaRecorder_setVideoSize},
- {"setVideoFrameRate", "(I)V", (void *)android_media_MediaRecorder_setVideoFrameRate},
- {"prepare", "()V", (void *)android_media_MediaRecorder_prepare},
- {"getMaxAmplitude", "()I", (void *)android_media_MediaRecorder_native_getMaxAmplitude},
- {"start", "()V", (void *)android_media_MediaRecorder_start},
- {"stop", "()V", (void *)android_media_MediaRecorder_stop},
- {"reset", "()V", (void *)android_media_MediaRecorder_reset},
- {"release", "()V", (void *)android_media_MediaRecorder_release},
- {"native_setup", "()V", (void *)android_media_MediaRecorder_native_setup},
- {"native_finalize", "()V", (void *)android_media_MediaRecorder_native_finalize},
+ {"setCamera", "(Landroid/hardware/Camera;)V", (void *)android_media_MediaRecorder_setCamera},
+ {"setVideoSource", "(I)V", (void *)android_media_MediaRecorder_setVideoSource},
+ {"setAudioSource", "(I)V", (void *)android_media_MediaRecorder_setAudioSource},
+ {"setOutputFormat", "(I)V", (void *)android_media_MediaRecorder_setOutputFormat},
+ {"setVideoEncoder", "(I)V", (void *)android_media_MediaRecorder_setVideoEncoder},
+ {"setAudioEncoder", "(I)V", (void *)android_media_MediaRecorder_setAudioEncoder},
+ {"_setOutputFile", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaRecorder_setOutputFileFD},
+ {"setVideoSize", "(II)V", (void *)android_media_MediaRecorder_setVideoSize},
+ {"setVideoFrameRate", "(I)V", (void *)android_media_MediaRecorder_setVideoFrameRate},
+ {"setMaxDuration", "(I)V", (void *)android_media_MediaRecorder_setMaxDuration},
+ {"_prepare", "()V", (void *)android_media_MediaRecorder_prepare},
+ {"getMaxAmplitude", "()I", (void *)android_media_MediaRecorder_native_getMaxAmplitude},
+ {"start", "()V", (void *)android_media_MediaRecorder_start},
+ {"stop", "()V", (void *)android_media_MediaRecorder_stop},
+ {"native_reset", "()V", (void *)android_media_MediaRecorder_native_reset},
+ {"release", "()V", (void *)android_media_MediaRecorder_release},
+ {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaRecorder_native_setup},
+ {"native_finalize", "()V", (void *)android_media_MediaRecorder_native_finalize},
};
static const char* const kClassPathName = "android/media/MediaRecorder";
@@ -323,6 +416,13 @@ int register_android_media_MediaRecorder(JNIEnv *env)
return -1;
}
+ fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
+ "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ if (fields.post_event == NULL) {
+ LOGE("Can't find MediaRecorder.postEventFromNative");
+ return -1;
+ }
+
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaRecorder", gMethods, NELEM(gMethods));
}
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 7872a8d..02731825 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -64,13 +64,6 @@ SoundPool::SoundPool(jobject soundPoolRef, int maxChannels, int streamType, int
mChannels.push_back(&mChannelPool[i]);
}
- if (AudioSystem::getOutputFrameCount(&mFrameCount) != NO_ERROR) {
- mFrameCount = kDefaultFrameCount;
- }
- if (AudioSystem::getOutputSamplingRate(&mSampleRate) != NO_ERROR) {
- mSampleRate = kDefaultSampleRate;
- }
-
// start decode thread
startThreads();
}
@@ -481,8 +474,8 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV
{
AudioTrack* oldTrack;
- LOGV("play: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
- sample->sampleID(), nextChannelID, leftVolume, rightVolume, priority, loop, rate);
+ LOGV("play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
+ this, sample->sampleID(), nextChannelID, leftVolume, rightVolume, priority, loop, rate);
// if not idle, this voice is being stolen
if (mState != IDLE) {
@@ -496,9 +489,18 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV
}
// initialize track
+ int afFrameCount;
+ int afSampleRate;
+ int streamType = mSoundPool->streamType();
+ if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
+ afFrameCount = kDefaultFrameCount;
+ }
+ if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
+ afSampleRate = kDefaultSampleRate;
+ }
int numChannels = sample->numChannels();
uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
- uint32_t bufferFrames = (mSoundPool->mFrameCount * sampleRate) / mSoundPool->mSampleRate;
+ uint32_t bufferFrames = (afFrameCount * sampleRate) / afSampleRate;
uint32_t frameCount = 0;
if (loop) {
@@ -511,12 +513,21 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV
}
AudioTrack* newTrack;
+
+ // mToggle toggles each time a track is started on a given channel.
+ // The toggle is concatenated with the SoundChannel address and passed to AudioTrack
+ // as callback user data. This enables the detection of callbacks received from the old
+ // audio track while the new one is being started and avoids processing them with
+ // wrong audio audio buffer size (mAudioBufferSize)
+ unsigned long toggle = mToggle ^ 1;
+ void *userData = (void *)((unsigned long)this | toggle);
+
#ifdef USE_SHARED_MEM_BUFFER
- newTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, sample->format(),
- numChannels, sample->getIMemory(), 0, callback, this);
+ newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
+ numChannels, sample->getIMemory(), 0, callback, userData);
#else
- newTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, sample->format(),
- numChannels, frameCount, 0, callback, this, bufferFrames);
+ newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
+ numChannels, frameCount, 0, callback, userData, bufferFrames);
#endif
if (newTrack->initCheck() != NO_ERROR) {
LOGE("Error creating AudioTrack");
@@ -529,6 +540,8 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV
{
Mutex::Autolock lock(&mLock);
+ // From now on, AudioTrack callbacks recevieved with previous toggle value will be ignored.
+ mToggle = toggle;
oldTrack = mAudioTrack;
mAudioTrack = newTrack;
mPos = 0;
@@ -583,7 +596,13 @@ void SoundChannel::nextEvent()
void SoundChannel::callback(int event, void* user, void *info)
{
- SoundChannel* channel = static_cast<SoundChannel*>(user);
+ unsigned long toggle = (unsigned long)user & 1;
+ SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1));
+
+ if (channel->mToggle != toggle) {
+ LOGV("callback with wrong toggle");
+ return;
+ }
channel->process(event, info);
}
@@ -592,7 +611,7 @@ void SoundChannel::process(int event, void *info)
//LOGV("process(%d)", mChannelID);
sp<Sample> sample = mSample;
- LOGV("SoundChannel::process event %d", event);
+// LOGV("SoundChannel::process event %d", event);
if (event == AudioTrack::EVENT_MORE_DATA) {
AudioTrack::Buffer* b = static_cast<AudioTrack::Buffer *>(info);
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index d02ae8b..7802781 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -118,7 +118,7 @@ protected:
class SoundChannel : public SoundEvent {
public:
enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
- SoundChannel() : mAudioTrack(0), mState(IDLE), mNumChannels(1), mPos(0) {}
+ SoundChannel() : mAudioTrack(0), mState(IDLE), mNumChannels(1), mPos(0), mToggle(0) {}
~SoundChannel();
void init(SoundPool* soundPool);
void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume,
@@ -151,6 +151,7 @@ private:
int mNumChannels;
int mPos;
int mAudioBufferSize;
+ unsigned long mToggle;
};
// application object for managing a pool of sounds
@@ -215,8 +216,6 @@ private:
int mAllocated;
int mNextSampleID;
int mNextChannelID;
- int mFrameCount;
- int mSampleRate;
bool mQuit;
};
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 2a697b9..8020da2 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -4,6 +4,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
AudioTrack.cpp \
IAudioFlinger.cpp \
+ IAudioFlingerClient.cpp \
IAudioTrack.cpp \
IAudioRecord.cpp \
AudioRecord.cpp \
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index e833c85..7594ff0 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -128,8 +128,23 @@ status_t AudioRecord::set(
return BAD_VALUE;
}
- // TODO: Get input frame count from hardware.
- int minFrameCount = 1024*2;
+ // validate framecount
+ size_t inputBuffSizeInBytes = -1;
+ if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes)
+ != NO_ERROR) {
+ LOGE("AudioSystem could not query the input buffer size.");
+ return NO_INIT;
+ }
+ if (inputBuffSizeInBytes == 0) {
+ LOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d",
+ sampleRate, channelCount, format);
+ return BAD_VALUE;
+ }
+ int frameSizeInBytes = channelCount * (format == AudioSystem::PCM_16_BIT ? 2 : 1);
+
+ // We use 2* size of input buffer for ping pong use of record buffer.
+ int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes;
+ LOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
if (frameCount == 0) {
frameCount = minFrameCount;
@@ -144,7 +159,11 @@ status_t AudioRecord::set(
// open record channel
status_t status;
sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), streamType,
- sampleRate, format, channelCount, frameCount, flags, &status);
+ sampleRate, format,
+ channelCount,
+ frameCount,
+ ((uint16_t)flags) << 16,
+ &status);
if (record == 0) {
LOGE("AudioFlinger could not create record track, status: %d", status);
return status;
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index a375b55..63dfc3b 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -15,10 +15,11 @@
*/
#define LOG_TAG "AudioSystem"
+//#define LOG_NDEBUG 0
+
#include <utils/Log.h>
#include <utils/IServiceManager.h>
#include <media/AudioSystem.h>
-#include <media/AudioTrack.h>
#include <math.h>
namespace android {
@@ -26,12 +27,18 @@ namespace android {
// client singleton for AudioFlinger binder interface
Mutex AudioSystem::gLock;
sp<IAudioFlinger> AudioSystem::gAudioFlinger;
-sp<AudioSystem::DeathNotifier> AudioSystem::gDeathNotifier;
+sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
// Cached values
-int AudioSystem::gOutSamplingRate = 0;
-int AudioSystem::gOutFrameCount = 0;
-uint32_t AudioSystem::gOutLatency = 0;
+int AudioSystem::gOutSamplingRate[NUM_AUDIO_OUTPUT_TYPES];
+int AudioSystem::gOutFrameCount[NUM_AUDIO_OUTPUT_TYPES];
+uint32_t AudioSystem::gOutLatency[NUM_AUDIO_OUTPUT_TYPES];
+bool AudioSystem::gA2dpEnabled;
+// Cached values for recording queries
+uint32_t AudioSystem::gPrevInSamplingRate = 16000;
+int AudioSystem::gPrevInFormat = AudioSystem::PCM_16_BIT;
+int AudioSystem::gPrevInChannelCount = 1;
+size_t AudioSystem::gInBuffSize = 0;
// establish binder interface to AudioFlinger service
@@ -48,19 +55,23 @@ const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
LOGW("AudioFlinger not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
- if (gDeathNotifier == NULL) {
- gDeathNotifier = new DeathNotifier();
+ if (gAudioFlingerClient == NULL) {
+ gAudioFlingerClient = new AudioFlingerClient();
} else {
if (gAudioErrorCallback) {
gAudioErrorCallback(NO_ERROR);
}
}
- binder->linkToDeath(gDeathNotifier);
+ binder->linkToDeath(gAudioFlingerClient);
gAudioFlinger = interface_cast<IAudioFlinger>(binder);
+ gAudioFlinger->registerClient(gAudioFlingerClient);
// Cache frequently accessed parameters
- gOutFrameCount = (int)gAudioFlinger->frameCount();
- gOutSamplingRate = (int)gAudioFlinger->sampleRate();
- gOutLatency = gAudioFlinger->latency();
+ for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
+ gOutFrameCount[output] = (int)gAudioFlinger->frameCount(output);
+ gOutSamplingRate[output] = (int)gAudioFlinger->sampleRate(output);
+ gOutLatency[output] = gAudioFlinger->latency(output);
+ }
+ gA2dpEnabled = gAudioFlinger->isA2dpEnabled();
}
LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");
return gAudioFlinger;
@@ -139,7 +150,7 @@ status_t AudioSystem::getMasterMute(bool* mute)
status_t AudioSystem::setStreamVolume(int stream, float value)
{
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+ if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
af->setStreamVolume(stream, value);
@@ -148,7 +159,7 @@ status_t AudioSystem::setStreamVolume(int stream, float value)
status_t AudioSystem::setStreamMute(int stream, bool mute)
{
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+ if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
af->setStreamMute(stream, mute);
@@ -157,7 +168,7 @@ status_t AudioSystem::setStreamMute(int stream, bool mute)
status_t AudioSystem::getStreamVolume(int stream, float* volume)
{
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+ if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
*volume = af->streamVolume(stream);
@@ -166,7 +177,7 @@ status_t AudioSystem::getStreamVolume(int stream, float* volume)
status_t AudioSystem::getStreamMute(int stream, bool* mute)
{
- if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+ if (uint32_t(stream) >= NUM_STREAM_TYPES) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
*mute = af->streamMute(stream);
@@ -244,60 +255,129 @@ int AudioSystem::logToLinear(float volume)
return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0;
}
-status_t AudioSystem::getOutputSamplingRate(int* samplingRate)
+status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
{
- if (gOutSamplingRate == 0) {
+ int output = getOutput(streamType);
+
+ if (gOutSamplingRate[output] == 0) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
// gOutSamplingRate is updated by get_audio_flinger()
- }
- *samplingRate = gOutSamplingRate;
+ }
+ LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, gOutSamplingRate[output]);
+ *samplingRate = gOutSamplingRate[output];
return NO_ERROR;
}
-status_t AudioSystem::getOutputFrameCount(int* frameCount)
+status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType)
{
- if (gOutFrameCount == 0) {
+ int output = getOutput(streamType);
+
+ if (gOutFrameCount[output] == 0) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
- // gOutSamplingRate is updated by get_audio_flinger()
+ // gOutFrameCount is updated by get_audio_flinger()
}
- *frameCount = gOutFrameCount;
+ LOGV("getOutputFrameCount() streamType %d, output %d, frame count %d", streamType, output, gOutFrameCount[output]);
+
+ *frameCount = gOutFrameCount[output];
return NO_ERROR;
}
-status_t AudioSystem::getOutputLatency(uint32_t* latency)
+status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType)
{
- if (gOutLatency == 0) {
+ int output = getOutput(streamType);
+
+ if (gOutLatency[output] == 0) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
// gOutLatency is updated by get_audio_flinger()
- }
- *latency = gOutLatency;
+ }
+ LOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, gOutLatency[output]);
+
+ *latency = gOutLatency[output];
+
+ return NO_ERROR;
+}
+
+status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount,
+ size_t* buffSize)
+{
+ // Do we have a stale gInBufferSize or are we requesting the input buffer size for new values
+ if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat)
+ || (channelCount != gPrevInChannelCount)) {
+ // save the request params
+ gPrevInSamplingRate = sampleRate;
+ gPrevInFormat = format;
+ gPrevInChannelCount = channelCount;
+
+ gInBuffSize = 0;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ return PERMISSION_DENIED;
+ }
+ gInBuffSize = af->getInputBufferSize(sampleRate, format, channelCount);
+ }
+ *buffSize = gInBuffSize;
return NO_ERROR;
}
// ---------------------------------------------------------------------------
-void AudioSystem::DeathNotifier::binderDied(const wp<IBinder>& who) {
+void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
Mutex::Autolock _l(AudioSystem::gLock);
AudioSystem::gAudioFlinger.clear();
- AudioSystem::gOutSamplingRate = 0;
- AudioSystem::gOutFrameCount = 0;
- AudioSystem::gOutLatency = 0;
-
+
+ for (int output = 0; output < NUM_AUDIO_OUTPUT_TYPES; output++) {
+ gOutFrameCount[output] = 0;
+ gOutSamplingRate[output] = 0;
+ gOutLatency[output] = 0;
+ }
+ AudioSystem::gInBuffSize = 0;
+
if (gAudioErrorCallback) {
gAudioErrorCallback(DEAD_OBJECT);
}
LOGW("AudioFlinger server died!");
}
+void AudioSystem::AudioFlingerClient::a2dpEnabledChanged(bool enabled) {
+ gA2dpEnabled = enabled;
+ LOGV("AudioFlinger A2DP enabled status changed! %d", enabled);
+}
+
void AudioSystem::setErrorCallback(audio_error_callback cb) {
Mutex::Autolock _l(AudioSystem::gLock);
gAudioErrorCallback = cb;
}
+int AudioSystem::getOutput(int streamType)
+{
+ if (streamType == DEFAULT) {
+ streamType = MUSIC;
+ }
+ if (gA2dpEnabled && routedToA2dpOutput(streamType)) {
+ return AUDIO_OUTPUT_A2DP;
+ } else {
+ return AUDIO_OUTPUT_HARDWARE;
+ }
+}
+
+bool AudioSystem::routedToA2dpOutput(int streamType) {
+ switch(streamType) {
+ case MUSIC:
+ case VOICE_CALL:
+ case BLUETOOTH_SCO:
+ case SYSTEM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+
}; // namespace android
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index f9f8568..d26b0c5 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -128,22 +128,21 @@ status_t AudioTrack::set(
return NO_INIT;
}
int afSampleRate;
- if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+ if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
return NO_INIT;
}
int afFrameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+ if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
return NO_INIT;
}
uint32_t afLatency;
- if (AudioSystem::getOutputLatency(&afLatency) != NO_ERROR) {
+ if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
return NO_INIT;
}
-
// handle default values first.
- if (streamType == DEFAULT) {
- streamType = MUSIC;
+ if (streamType == AudioSystem::DEFAULT) {
+ streamType = AudioSystem::MUSIC;
}
if (sampleRate == 0) {
sampleRate = afSampleRate;
@@ -157,7 +156,7 @@ status_t AudioTrack::set(
}
// validate parameters
- if (((format != AudioSystem::PCM_8_BIT) || mSharedBuffer != 0) &&
+ if (((format != AudioSystem::PCM_8_BIT) || sharedBuffer != 0) &&
(format != AudioSystem::PCM_16_BIT)) {
LOGE("Invalid format");
return BAD_VALUE;
@@ -169,6 +168,8 @@ status_t AudioTrack::set(
// Ensure that buffer depth covers at least audio hardware latency
uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
+ if (minBufCount < 2) minBufCount = 2;
+
// When playing from shared buffer, playback will start even if last audioflinger
// block is partly filled.
if (sharedBuffer != 0 && minBufCount > 1) {
@@ -260,7 +261,7 @@ status_t AudioTrack::set(
mMarkerPosition = 0;
mNewPosition = 0;
mUpdatePeriod = 0;
-
+
return NO_ERROR;
}
@@ -317,7 +318,7 @@ void AudioTrack::start()
{
sp<AudioTrackThread> t = mAudioTrackThread;
- LOGV("start");
+ LOGV("start %p", this);
if (t != 0) {
if (t->exitPending()) {
if (t->requestExitAndWait() == WOULD_BLOCK) {
@@ -349,7 +350,7 @@ void AudioTrack::stop()
{
sp<AudioTrackThread> t = mAudioTrackThread;
- LOGV("stop");
+ LOGV("stop %p", this);
if (t != 0) {
t->mLock.lock();
}
@@ -434,12 +435,12 @@ void AudioTrack::setSampleRate(int rate)
{
int afSamplingRate;
- if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {
+ if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
return;
}
// Resampler implementation limits input sampling rate to 2 x output sampling rate.
+ if (rate <= 0) rate = 1;
if (rate > afSamplingRate*2) rate = afSamplingRate*2;
-
if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE;
mCblk->sampleRate = rate;
@@ -467,10 +468,15 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount
if (loopStart >= loopEnd ||
loopEnd - loopStart > mFrameCount) {
- LOGW("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user);
+ LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user);
return BAD_VALUE;
}
- // TODO handle shared buffer here: limit loop end to framecount
+
+ if ((mSharedBuffer != 0) && (loopEnd > mFrameCount)) {
+ LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
+ loopStart, loopEnd, mFrameCount);
+ return BAD_VALUE;
+ }
cblk->loopStart = loopStart;
cblk->loopEnd = loopEnd;
@@ -603,13 +609,20 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
if (__builtin_expect(result!=NO_ERROR, false)) {
cblk->waitTimeMs += WAIT_PERIOD_MS;
if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
- LOGW( "obtainBuffer timed out (is the CPU pegged?) "
- "user=%08x, server=%08x", cblk->user, cblk->server);
- mAudioTrack->start(); // FIXME: Wake up audioflinger
- timeout = 1;
+ // timing out when a loop has been set and we have already written upto loop end
+ // is a normal condition: no need to wake AudioFlinger up.
+ if (cblk->user < cblk->loopEnd) {
+ LOGW( "obtainBuffer timed out (is the CPU pegged?) %p "
+ "user=%08x, server=%08x", this, cblk->user, cblk->server);
+ //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
+ cblk->lock.unlock();
+ mAudioTrack->start();
+ cblk->lock.lock();
+ timeout = 1;
+ }
cblk->waitTimeMs = 0;
}
- ;
+
if (--waitCount == 0) {
return TIMED_OUT;
}
@@ -668,7 +681,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
return BAD_VALUE;
}
- LOGV("write %d bytes, mActive=%d", userSize, mActive);
+ LOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive);
ssize_t written = 0;
const int8_t *src = (const int8_t *)buffer;
@@ -795,7 +808,14 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
writtenSize = audioBuffer.size;
// Sanity check on returned size
- if (ssize_t(writtenSize) <= 0) break;
+ if (ssize_t(writtenSize) <= 0) {
+ // The callback is done filling buffers
+ // Keep this thread going to handle timed events and
+ // still try to get more data in intervals of WAIT_PERIOD_MS
+ // but don't just loop and block the CPU, so wait
+ usleep(WAIT_PERIOD_MS*1000);
+ break;
+ }
if (writtenSize > reqSize) writtenSize = reqSize;
if (mFormat == AudioSystem::PCM_8_BIT) {
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 018ea6c..5cbb25c 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -51,6 +51,10 @@ enum {
GET_MIC_MUTE,
IS_MUSIC_ACTIVE,
SET_PARAMETER,
+ REGISTER_CLIENT,
+ GET_INPUTBUFFERSIZE,
+ WAKE_UP,
+ IS_A2DP_ENABLED
};
class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -120,42 +124,47 @@ public:
return interface_cast<IAudioRecord>(reply.readStrongBinder());
}
- virtual uint32_t sampleRate() const
+ virtual uint32_t sampleRate(int output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(output);
remote()->transact(SAMPLE_RATE, data, &reply);
return reply.readInt32();
}
- virtual int channelCount() const
+ virtual int channelCount(int output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(output);
remote()->transact(CHANNEL_COUNT, data, &reply);
return reply.readInt32();
}
- virtual int format() const
+ virtual int format(int output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(output);
remote()->transact(FORMAT, data, &reply);
return reply.readInt32();
}
- virtual size_t frameCount() const
+ virtual size_t frameCount(int output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(output);
remote()->transact(FRAME_COUNT, data, &reply);
return reply.readInt32();
}
- virtual uint32_t latency() const
+ virtual uint32_t latency(int output) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(output);
remote()->transact(LATENCY, data, &reply);
return reply.readInt32();
}
@@ -303,6 +312,41 @@ public:
remote()->transact(SET_PARAMETER, data, &reply);
return reply.readInt32();
}
+
+ virtual void registerClient(const sp<IAudioFlingerClient>& client)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeStrongBinder(client->asBinder());
+ remote()->transact(REGISTER_CLIENT, data, &reply);
+ }
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(sampleRate);
+ data.writeInt32(format);
+ data.writeInt32(channelCount);
+ remote()->transact(GET_INPUTBUFFERSIZE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual void wakeUp()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(WAKE_UP, data, &reply);
+ return;
+ }
+
+ virtual bool isA2dpEnabled() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(IS_A2DP_ENABLED, data, &reply);
+ return (bool)reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -355,27 +399,32 @@ status_t BnAudioFlinger::onTransact(
} break;
case SAMPLE_RATE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( sampleRate() );
+ int output = data.readInt32();
+ reply->writeInt32( sampleRate(output) );
return NO_ERROR;
} break;
case CHANNEL_COUNT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( channelCount() );
+ int output = data.readInt32();
+ reply->writeInt32( channelCount(output) );
return NO_ERROR;
} break;
case FORMAT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( format() );
+ int output = data.readInt32();
+ reply->writeInt32( format(output) );
return NO_ERROR;
} break;
case FRAME_COUNT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( frameCount() );
+ int output = data.readInt32();
+ reply->writeInt32( frameCount(output) );
return NO_ERROR;
} break;
case LATENCY: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- reply->writeInt32( latency() );
+ int output = data.readInt32();
+ reply->writeInt32( latency(output) );
return NO_ERROR;
} break;
case SET_MASTER_VOLUME: {
@@ -470,6 +519,30 @@ status_t BnAudioFlinger::onTransact(
reply->writeInt32( setParameter(key, value) );
return NO_ERROR;
} break;
+ case REGISTER_CLIENT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient>(data.readStrongBinder());
+ registerClient(client);
+ return NO_ERROR;
+ } break;
+ case GET_INPUTBUFFERSIZE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ uint32_t sampleRate = data.readInt32();
+ int format = data.readInt32();
+ int channelCount = data.readInt32();
+ reply->writeInt32( getInputBufferSize(sampleRate, format, channelCount) );
+ return NO_ERROR;
+ } break;
+ case WAKE_UP: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ wakeUp();
+ return NO_ERROR;
+ } break;
+ case IS_A2DP_ENABLED: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( (int)isA2dpEnabled() );
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
new file mode 100644
index 0000000..5feb11f
--- /dev/null
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IAudioFlingerClient"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioFlingerClient.h>
+
+namespace android {
+
+enum {
+ AUDIO_OUTPUT_CHANGED = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpAudioFlingerClient : public BpInterface<IAudioFlingerClient>
+{
+public:
+ BpAudioFlingerClient(const sp<IBinder>& impl)
+ : BpInterface<IAudioFlingerClient>(impl)
+ {
+ }
+
+ void a2dpEnabledChanged(bool enabled)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
+ data.writeInt32((int)enabled);
+ remote()->transact(AUDIO_OUTPUT_CHANGED, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(AudioFlingerClient, "android.media.IAudioFlingerClient");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnAudioFlingerClient::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case AUDIO_OUTPUT_CHANGED: {
+ CHECK_INTERFACE(IAudioFlingerClient, data, reply);
+ bool enabled = (bool)data.readInt32();
+ a2dpEnabledChanged(enabled);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 1f6d599..84d08c4 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -21,6 +21,7 @@
#include <utils/Parcel.h>
#include <ui/ISurface.h>
#include <ui/ICamera.h>
+#include <media/IMediaPlayerClient.h>
#include <media/IMediaRecorder.h>
namespace android {
@@ -39,11 +40,14 @@ enum {
SET_OUTPUT_FORMAT,
SET_VIDEO_ENCODER,
SET_AUDIO_ENCODER,
- SET_OUTPUT_FILE,
+ SET_OUTPUT_FILE_PATH,
+ SET_OUTPUT_FILE_FD,
SET_VIDEO_SIZE,
SET_VIDEO_FRAMERATE,
+ SET_PARAMETERS,
SET_PREVIEW_SURFACE,
- SET_CAMERA
+ SET_CAMERA,
+ SET_LISTENER
};
class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -139,7 +143,18 @@ public:
Parcel data, reply;
data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
data.writeCString(path);
- remote()->transact(SET_OUTPUT_FILE, data, &reply);
+ remote()->transact(SET_OUTPUT_FILE_PATH, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setOutputFile(int fd, int64_t offset, int64_t length) {
+ LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeFileDescriptor(fd);
+ data.writeInt64(offset);
+ data.writeInt64(length);
+ remote()->transact(SET_OUTPUT_FILE_FD, data, &reply);
return reply.readInt32();
}
@@ -164,6 +179,26 @@ public:
return reply.readInt32();
}
+ status_t setParameters(const String8& params)
+ {
+ LOGV("setParameter(%s)", params.string());
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeString8(params);
+ remote()->transact(SET_PARAMETERS, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setListener(const sp<IMediaPlayerClient>& listener)
+ {
+ LOGV("setListener(%p)", listener.get());
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeStrongBinder(listener->asBinder());
+ remote()->transact(SET_LISTENER, data, &reply);
+ return reply.readInt32();
+ }
+
status_t prepare()
{
LOGV("prepare");
@@ -330,13 +365,22 @@ status_t BnMediaRecorder::onTransact(
return NO_ERROR;
} break;
- case SET_OUTPUT_FILE: {
- LOGV("SET_OUTPUT_FILE");
+ case SET_OUTPUT_FILE_PATH: {
+ LOGV("SET_OUTPUT_FILE_PATH");
CHECK_INTERFACE(IMediaRecorder, data, reply);
const char* path = data.readCString();
reply->writeInt32(setOutputFile(path));
return NO_ERROR;
} break;
+ case SET_OUTPUT_FILE_FD: {
+ LOGV("SET_OUTPUT_FILE_FD");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ int fd = dup(data.readFileDescriptor());
+ int64_t offset = data.readInt64();
+ int64_t length = data.readInt64();
+ reply->writeInt32(setOutputFile(fd, offset, length));
+ return NO_ERROR;
+ } break;
case SET_VIDEO_SIZE: {
LOGV("SET_VIDEO_SIZE");
CHECK_INTERFACE(IMediaRecorder, data, reply);
@@ -352,6 +396,20 @@ status_t BnMediaRecorder::onTransact(
reply->writeInt32(setVideoFrameRate(frames_per_second));
return NO_ERROR;
} break;
+ case SET_PARAMETERS: {
+ LOGV("SET_PARAMETER");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(setParameters(data.readString8()));
+ return NO_ERROR;
+ } break;
+ case SET_LISTENER: {
+ LOGV("SET_LISTENER");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ sp<IMediaPlayerClient> listener =
+ interface_cast<IMediaPlayerClient>(data.readStrongBinder());
+ reply->writeInt32(setListener(listener));
+ return NO_ERROR;
+ } break;
case SET_PREVIEW_SURFACE: {
LOGV("SET_PREVIEW_SURFACE");
CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index f0edf88..2c62104 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -86,8 +86,8 @@ int JetPlayer::init()
mState = EAS_STATE_ERROR;
return result;
}
- // init the JET library
- result = JET_Init(mEasData, NULL, 0);
+ // init the JET library with the default app event controller range
+ result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG));
if( result != EAS_SUCCESS) {
LOGE("JetPlayer::init(): Error initializing JET library, aborting.");
mState = EAS_STATE_ERROR;
@@ -96,7 +96,7 @@ int JetPlayer::init()
// create the output AudioTrack
mAudioTrack = new AudioTrack();
- mAudioTrack->set(AudioTrack::MUSIC, //TODO parametrize this
+ mAudioTrack->set(AudioSystem::MUSIC, //TODO parametrize this
pLibConfig->sampleRate,
1, // format = PCM 16bits per sample,
pLibConfig->numChannels,
@@ -200,6 +200,11 @@ int JetPlayer::render() {
while (!mRender)
{
LOGV("JetPlayer::render(): signal wait");
+ if (audioStarted) {
+ mAudioTrack->pause();
+ // we have to restart the playback once we start rendering again
+ audioStarted = false;
+ }
mCondition.wait(mMutex);
LOGV("JetPlayer::render(): signal rx'd");
}
@@ -214,12 +219,15 @@ int JetPlayer::render() {
}
p += count * pLibConfig->numChannels;
num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
+
+ // send events that were generated (if any) to the event callback
+ fireEventsFromJetQueue();
}
// update playback state
//LOGV("JetPlayer::render(): updating state");
JET_Status(mEasData, &mJetStatus);
- fireEventOnStatusChange();
+ fireUpdateOnStatusChange();
mPaused = mJetStatus.paused;
mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
@@ -261,9 +269,9 @@ threadExit:
//-------------------------------------------------------------------------------------------------
-// fire up an event if any of the status fields has changed
+// fire up an update if any of the status fields has changed
// precondition: mMutex locked
-void JetPlayer::fireEventOnStatusChange()
+void JetPlayer::fireUpdateOnStatusChange()
{
if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
@@ -303,9 +311,31 @@ void JetPlayer::fireEventOnStatusChange()
//-------------------------------------------------------------------------------------------------
-int JetPlayer::openFile(const char* path)
+// fire up all the JET events in the JET engine queue (until the queue is empty)
+// precondition: mMutex locked
+void JetPlayer::fireEventsFromJetQueue()
+{
+ if(!mEventCallback) {
+ // no callback, just empty the event queue
+ while (JET_GetEvent(mEasData, NULL, NULL)) { }
+ return;
+ }
+
+ EAS_U32 rawEvent;
+ while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
+ mEventCallback(
+ JetPlayer::JET_EVENT,
+ rawEvent,
+ -1,
+ mJavaJetPlayerRef);
+ }
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::loadFromFile(const char* path)
{
- LOGV("JetPlayer::openFile(): path=%s", path);
+ LOGV("JetPlayer::loadFromFile(): path=%s", path);
Mutex::Autolock lock(mMutex);
@@ -326,6 +356,29 @@ int JetPlayer::openFile(const char* path)
return( result );
}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
+{
+ LOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
+
+ Mutex::Autolock lock(mMutex);
+
+ mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
+ mEasJetFileLoc->fd = fd;
+ mEasJetFileLoc->offset = offset;
+ mEasJetFileLoc->length = length;
+ mEasJetFileLoc->path = NULL;
+
+ EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
+ if(result != EAS_SUCCESS)
+ mState = EAS_STATE_ERROR;
+ else
+ mState = EAS_STATE_OPEN;
+ return( result );
+}
+
+
//-------------------------------------------------------------------------------------------------
int JetPlayer::closeFile()
{
@@ -348,7 +401,7 @@ int JetPlayer::play()
JET_Status(mEasData, &mJetStatus);
this->dumpJetStatus(&mJetStatus);
- fireEventOnStatusChange();
+ fireUpdateOnStatusChange();
// wake up render thread
LOGV("JetPlayer::play(): wakeup render thread");
@@ -368,7 +421,7 @@ int JetPlayer::pause()
JET_Status(mEasData, &mJetStatus);
this->dumpJetStatus(&mJetStatus);
- fireEventOnStatusChange();
+ fireUpdateOnStatusChange();
return result;
@@ -408,6 +461,14 @@ int JetPlayer::triggerClip(int clipId)
}
//-------------------------------------------------------------------------------------------------
+int JetPlayer::clearQueue()
+{
+ LOGV("JetPlayer::clearQueue");
+ Mutex::Autolock lock(mMutex);
+ return JET_Clear_Queue(mEasData);
+}
+
+//-------------------------------------------------------------------------------------------------
void JetPlayer::dump()
{
LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path);
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 584d135..8560593 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -93,11 +93,7 @@ ToneGenerator::ToneGenerator(int streamType, float volume) {
mState = TONE_IDLE;
- if (AudioSystem::getOutputSamplingRate(&mSamplingRate) != NO_ERROR) {
- LOGE("Unable to marshal AudioFlinger");
- return;
- }
- if (AudioSystem::getOutputFrameCount(&mBufferSize) != NO_ERROR) {
+ if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) {
LOGE("Unable to marshal AudioFlinger");
return;
}
@@ -179,38 +175,42 @@ bool ToneGenerator::startTone(int toneType) {
if (mState == TONE_INIT) {
if (prepareWave()) {
LOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000));
-
+ lResult = true;
mState = TONE_STARTING;
mLock.unlock();
mpAudioTrack->start();
mLock.lock();
if (mState == TONE_STARTING) {
- if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR) {
- LOGE("--- timed out");
+ LOGV("Wait for start callback");
+ status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(1));
+ if (lStatus != NO_ERROR) {
+ LOGE("--- Immediate start timed out, status %d", lStatus);
mState = TONE_IDLE;
+ lResult = false;
}
}
-
- if (mState == TONE_PLAYING)
- lResult = true;
+ } else {
+ mState == TONE_IDLE;
}
} else {
LOGV("Delayed start\n");
mState = TONE_RESTARTING;
- if (mWaitCbkCond.waitRelative(mLock, seconds(1)) == NO_ERROR) {
- if (mState != TONE_INIT) {
+ status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(1));
+ if (lStatus == NO_ERROR) {
+ if (mState != TONE_IDLE) {
lResult = true;
}
LOGV("cond received");
} else {
- LOGE("--- timed out");
+ LOGE("--- Delayed start timed out, status %d", lStatus);
mState = TONE_IDLE;
}
}
mLock.unlock();
- LOGV("Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
+ LOGV_IF(lResult, "Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
+ LOGW_IF(!lResult, "Tone start failed!!!, time %d\n", (unsigned int)(systemTime()/1000000));
return lResult;
}
@@ -239,7 +239,7 @@ void ToneGenerator::stopTone() {
if (lStatus == NO_ERROR) {
LOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000));
} else {
- LOGE("--- timed out");
+ LOGE("--- Stop timed out");
mState = TONE_IDLE;
mpAudioTrack->stop();
}
@@ -275,9 +275,9 @@ bool ToneGenerator::initAudioTrack() {
mpAudioTrack = 0;
}
- // Open audio track in mono, PCM 16bit, default sampling rate, 2 buffers of
+ // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
mpAudioTrack
- = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, NUM_PCM_BUFFERS*mBufferSize, 0, audioCallback, this, mBufferSize);
+ = new AudioTrack(mStreamType, 0, AudioSystem::PCM_16_BIT, 1, 0, 0, audioCallback, this, 0);
if (mpAudioTrack == 0) {
LOGE("AudioTrack allocation failed");
@@ -370,6 +370,8 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
break;
default:
LOGV("Extra Cbk");
+ // Force loop exit
+ lNumSmp = 0;
goto audioCallback_EndLoop;
}
@@ -461,8 +463,11 @@ audioCallback_EndLoop:
if (lpToneGen->prepareWave()) {
lpToneGen->mState = TONE_STARTING;
} else {
- lpToneGen->mState = TONE_INIT;
+ LOGW("Cbk restarting prepareWave() failed\n");
+ lpToneGen->mState = TONE_IDLE;
lpToneGen->mpAudioTrack->stop();
+ // Force loop exit
+ lNumSmp = 0;
}
lSignal = true;
break;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index ebdbda8..6b40412 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -82,7 +82,7 @@ MediaPlayer::MediaPlayer()
mListener = NULL;
mCookie = NULL;
mDuration = -1;
- mStreamType = AudioTrack::MUSIC;
+ mStreamType = AudioSystem::MUSIC;
mCurrentPosition = -1;
mSeekPosition = -1;
mCurrentState = MEDIA_PLAYER_IDLE;
@@ -172,7 +172,7 @@ status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
status_t MediaPlayer::setDataSource(const char *url)
{
LOGV("setDataSource(%s)", url);
- status_t err = UNKNOWN_ERROR;
+ status_t err = BAD_VALUE;
if (url != NULL) {
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
@@ -199,7 +199,7 @@ status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
{
LOGV("setVideoSurface");
Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return UNKNOWN_ERROR;
+ if (mPlayer == 0) return NO_INIT;
return mPlayer->setVideoSurface(surface->getISurface());
}
@@ -215,11 +215,15 @@ status_t MediaPlayer::prepareAsync_l()
return INVALID_OPERATION;
}
+// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
+// one defined in the Android framework and one provided by the implementation
+// that generated the error. The sync version of prepare returns only 1 error
+// code.
status_t MediaPlayer::prepare()
{
LOGV("prepare");
Mutex::Autolock _l(mLock);
- if (mPrepareSync) return UNKNOWN_ERROR;
+ if (mPrepareSync) return -EALREADY;
mPrepareSync = true;
status_t ret = prepareAsync_l();
if (ret != NO_ERROR) return ret;
@@ -253,7 +257,6 @@ status_t MediaPlayer::start()
status_t ret = mPlayer->start();
if (ret != NO_ERROR) {
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
- ret = UNKNOWN_ERROR;
} else {
if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
LOGV("playback completed immediately following start()");
@@ -275,7 +278,6 @@ status_t MediaPlayer::stop()
status_t ret = mPlayer->stop();
if (ret != NO_ERROR) {
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
- ret = UNKNOWN_ERROR;
} else {
mCurrentState = MEDIA_PLAYER_STOPPED;
}
@@ -295,7 +297,6 @@ status_t MediaPlayer::pause()
status_t ret = mPlayer->pause();
if (ret != NO_ERROR) {
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
- ret = UNKNOWN_ERROR;
} else {
mCurrentState = MEDIA_PLAYER_PAUSED;
}
@@ -422,7 +423,6 @@ status_t MediaPlayer::reset()
if (ret != NO_ERROR) {
LOGE("reset() failed with return code (%d)", ret);
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
- ret = UNKNOWN_ERROR;
} else {
mCurrentState = MEDIA_PLAYER_IDLE;
}
@@ -516,7 +516,9 @@ void MediaPlayer::notify(int msg, int ext1, int ext2)
}
break;
case MEDIA_ERROR:
- // Always log errors
+ // Always log errors.
+ // ext1: Media framework error code.
+ // ext2: Implementation dependant error code.
LOGE("error (%d, %d)", ext1, ext2);
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
if (mPrepareSync)
@@ -528,6 +530,11 @@ void MediaPlayer::notify(int msg, int ext1, int ext2)
send = false;
}
break;
+ case MEDIA_INFO:
+ // ext1: Media framework error code.
+ // ext2: Implementation dependant error code.
+ LOGW("info/warning (%d, %d)", ext1, ext2);
+ break;
case MEDIA_SEEK_COMPLETE:
LOGV("Received seek complete");
if (mSeekPosition != mCurrentPosition) {
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 6ee4c0d..23b3b9d 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -21,6 +21,7 @@
#include <ui/Surface.h>
#include <media/mediarecorder.h>
#include <utils/IServiceManager.h>
+#include <utils/String8.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
@@ -42,7 +43,7 @@ status_t MediaRecorder::setCamera(const sp<ICamera>& camera)
if (OK != ret) {
LOGV("setCamera failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
return ret;
}
@@ -58,12 +59,16 @@ status_t MediaRecorder::setPreviewSurface(const sp<Surface>& surface)
LOGE("setPreviewSurface called in an invalid state(%d)", mCurrentState);
return INVALID_OPERATION;
}
+ if (!mIsVideoSourceSet) {
+ LOGE("try to set preview surface without setting the video source first");
+ return INVALID_OPERATION;
+ }
status_t ret = mMediaRecorder->setPreviewSurface(surface->getISurface());
if (OK != ret) {
LOGV("setPreviewSurface failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
return ret;
}
@@ -84,8 +89,16 @@ status_t MediaRecorder::init()
if (OK != ret) {
LOGV("init failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
+
+ ret = mMediaRecorder->setListener(this);
+ if (OK != ret) {
+ LOGV("setListener failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return ret;
+ }
+
mCurrentState = MEDIA_RECORDER_INITIALIZED;
return ret;
}
@@ -117,7 +130,7 @@ status_t MediaRecorder::setVideoSource(int vs)
if (OK != ret) {
LOGV("setVideoSource failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mIsVideoSourceSet = true;
return ret;
@@ -150,7 +163,7 @@ status_t MediaRecorder::setAudioSource(int as)
if (OK != ret) {
LOGV("setAudioSource failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mIsAudioSourceSet = true;
return ret;
@@ -167,12 +180,16 @@ status_t MediaRecorder::setOutputFormat(int of)
LOGE("setOutputFormat called in an invalid state: %d", mCurrentState);
return INVALID_OPERATION;
}
+ if (mIsVideoSourceSet && of >= OUTPUT_FORMAT_RAW_AMR) {
+ LOGE("output format (%d) is meant for audio recording only and incompatible with video recording", of);
+ return INVALID_OPERATION;
+ }
status_t ret = mMediaRecorder->setOutputFormat(of);
if (OK != ret) {
LOGE("setOutputFormat failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mCurrentState = MEDIA_RECORDER_DATASOURCE_CONFIGURED;
return ret;
@@ -185,6 +202,10 @@ status_t MediaRecorder::setVideoEncoder(int ve)
LOGE("media recorder is not initialized yet");
return INVALID_OPERATION;
}
+ if (!mIsVideoSourceSet) {
+ LOGE("try to set the video encoder without setting the video source first");
+ return INVALID_OPERATION;
+ }
if (mIsVideoEncoderSet) {
LOGE("video encoder has already been set");
return INVALID_OPERATION;
@@ -198,7 +219,7 @@ status_t MediaRecorder::setVideoEncoder(int ve)
if (OK != ret) {
LOGV("setVideoEncoder failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mIsVideoEncoderSet = true;
return ret;
@@ -211,6 +232,10 @@ status_t MediaRecorder::setAudioEncoder(int ae)
LOGE("media recorder is not initialized yet");
return INVALID_OPERATION;
}
+ if (!mIsAudioSourceSet) {
+ LOGE("try to set the audio encoder without setting the audio source first");
+ return INVALID_OPERATION;
+ }
if (mIsAudioEncoderSet) {
LOGE("audio encoder has already been set");
return INVALID_OPERATION;
@@ -224,7 +249,7 @@ status_t MediaRecorder::setAudioEncoder(int ae)
if (OK != ret) {
LOGV("setAudioEncoder failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mIsAudioEncoderSet = true;
return ret;
@@ -248,9 +273,35 @@ status_t MediaRecorder::setOutputFile(const char* path)
status_t ret = mMediaRecorder->setOutputFile(path);
if (OK != ret) {
- LOGV("setAudioEncoder failed: %d", ret);
+ LOGV("setOutputFile failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
+ }
+ mIsOutputFileSet = true;
+ return ret;
+}
+
+status_t MediaRecorder::setOutputFile(int fd, int64_t offset, int64_t length)
+{
+ LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (mIsOutputFileSet) {
+ LOGE("output file has already been set");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
+ LOGE("setOutputFile called in an invalid state(%d)", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setOutputFile(fd, offset, length);
+ if (OK != ret) {
+ LOGV("setOutputFile failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return ret;
}
mIsOutputFileSet = true;
return ret;
@@ -267,12 +318,16 @@ status_t MediaRecorder::setVideoSize(int width, int height)
LOGE("setVideoSize called in an invalid state: %d", mCurrentState);
return INVALID_OPERATION;
}
+ if (!mIsVideoSourceSet) {
+ LOGE("try to set video size without setting video source first");
+ return INVALID_OPERATION;
+ }
status_t ret = mMediaRecorder->setVideoSize(width, height);
if (OK != ret) {
LOGE("setVideoSize failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
return ret;
}
@@ -288,16 +343,37 @@ status_t MediaRecorder::setVideoFrameRate(int frames_per_second)
LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
return INVALID_OPERATION;
}
+ if (!mIsVideoSourceSet) {
+ LOGE("try to set video frame rate without setting video source first");
+ return INVALID_OPERATION;
+ }
status_t ret = mMediaRecorder->setVideoFrameRate(frames_per_second);
if (OK != ret) {
LOGE("setVideoFrameRate failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
return ret;
}
+status_t MediaRecorder::setParameters(const String8& params) {
+ LOGV("setParameters(%s)", params.string());
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setParameters(params);
+ if (OK != ret) {
+ LOGE("setParameters(%s) failed: %d", params.string(), ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return ret;
+ }
+
+ return ret;
+}
+
status_t MediaRecorder::prepare()
{
LOGV("prepare");
@@ -306,7 +382,24 @@ status_t MediaRecorder::prepare()
return INVALID_OPERATION;
}
if (!(mCurrentState & MEDIA_RECORDER_DATASOURCE_CONFIGURED)) {
- LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
+ LOGE("prepare called in an invalid state: %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+ if (mIsAudioSourceSet != mIsAudioEncoderSet) {
+ if (mIsAudioSourceSet) {
+ LOGE("audio source is set, but audio encoder is not set");
+ } else { // must not happen, since setAudioEncoder checks this already
+ LOGE("audio encoder is set, but audio source is not set");
+ }
+ return INVALID_OPERATION;
+ }
+
+ if (mIsVideoSourceSet != mIsVideoEncoderSet) {
+ if (mIsVideoSourceSet) {
+ LOGE("video source is set, but video encoder is not set");
+ } else { // must not happen, since setVideoEncoder checks this already
+ LOGE("video encoder is set, but video source is not set");
+ }
return INVALID_OPERATION;
}
@@ -314,7 +407,7 @@ status_t MediaRecorder::prepare()
if (OK != ret) {
LOGE("prepare failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mCurrentState = MEDIA_RECORDER_PREPARED;
return ret;
@@ -328,7 +421,7 @@ status_t MediaRecorder::getMaxAmplitude(int* max)
return INVALID_OPERATION;
}
if (mCurrentState & MEDIA_RECORDER_ERROR) {
- LOGE("setVideoFrameRate called in an invalid state: %d", mCurrentState);
+ LOGE("getMaxAmplitude called in an invalid state: %d", mCurrentState);
return INVALID_OPERATION;
}
@@ -336,7 +429,7 @@ status_t MediaRecorder::getMaxAmplitude(int* max)
if (OK != ret) {
LOGE("getMaxAmplitude failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
return ret;
}
@@ -357,7 +450,7 @@ status_t MediaRecorder::start()
if (OK != ret) {
LOGE("start failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
mCurrentState = MEDIA_RECORDER_RECORDING;
return ret;
@@ -379,8 +472,13 @@ status_t MediaRecorder::stop()
if (OK != ret) {
LOGE("stop failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
}
+
+ // FIXME:
+ // stop and reset are semantically different.
+ // We treat them the same for now, and will change this in the future.
+ doCleanUp();
mCurrentState = MEDIA_RECORDER_IDLE;
return ret;
}
@@ -447,7 +545,7 @@ status_t MediaRecorder::doReset()
if (OK != ret) {
LOGE("doReset failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
- return UNKNOWN_ERROR;
+ return ret;
} else {
mCurrentState = MEDIA_RECORDER_INITIALIZED;
}
@@ -512,5 +610,31 @@ MediaRecorder::~MediaRecorder()
}
}
+status_t MediaRecorder::setListener(const sp<MediaRecorderListener>& listener)
+{
+ LOGV("setListener");
+ Mutex::Autolock _l(mLock);
+ mListener = listener;
+
+ return NO_ERROR;
+}
+
+void MediaRecorder::notify(int msg, int ext1, int ext2)
+{
+ LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+
+ sp<MediaRecorderListener> listener;
+ mLock.lock();
+ listener = mListener;
+ mLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock _l(mNotifyLock);
+ LOGV("callback application");
+ listener->notify(msg, ext1, ext2);
+ LOGV("back from callback");
+ }
+}
+
}; // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 53831717..40705c6 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -61,113 +61,32 @@ pid_t gettid() { return syscall(__NR_gettid);}
#undef __KERNEL__
#endif
-/*
- When USE_SIGBUS_HANDLER is set to 1, a handler for SIGBUS will be
- installed, which allows us to recover when there is a read error
- when accessing an mmap'ed file. However, since the kernel folks
- don't seem to like it when non kernel folks install signal handlers
- in their own process, this is currently disabled.
- Without the handler, the process hosting this service will die and
- then be restarted. This is mostly OK right now because the process is
- not being shared with any other services, and clients of the service
- will be notified of its death in their MediaPlayer.onErrorListener
- callback, assuming they have installed one, and can then attempt to
- do their own recovery.
- It does open us up to a DOS attack against the media server, where
- a malicious application can trivially force the media server to
- restart continuously.
-*/
-#define USE_SIGBUS_HANDLER 0
+
+namespace android {
// TODO: Temp hack until we can register players
-static const char* MIDI_FILE_EXTS[] =
-{
- ".mid",
- ".smf",
- ".xmf",
- ".imy",
- ".rtttl",
- ".rtx",
- ".ota"
+typedef struct {
+ const char *extension;
+ const player_type playertype;
+} extmap;
+extmap FILE_EXTS [] = {
+ {".mid", SONIVOX_PLAYER},
+ {".midi", SONIVOX_PLAYER},
+ {".smf", SONIVOX_PLAYER},
+ {".xmf", SONIVOX_PLAYER},
+ {".imy", SONIVOX_PLAYER},
+ {".rtttl", SONIVOX_PLAYER},
+ {".rtx", SONIVOX_PLAYER},
+ {".ota", SONIVOX_PLAYER},
+ {".ogg", VORBIS_PLAYER},
+ {".oga", VORBIS_PLAYER},
};
-namespace android {
-
// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
/* static */ const uint32_t MediaPlayerService::AudioOutput::kAudioVideoDelayMs = 96;
/* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4;
/* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false;
-static struct sigaction oldact;
-static pthread_key_t sigbuskey;
-
-static void sigbushandler(int signal, siginfo_t *info, void *context)
-{
- char *faultaddr = (char*) info->si_addr;
- LOGE("SIGBUS at %p\n", faultaddr);
-
- struct mediasigbushandler* h = (struct mediasigbushandler*) pthread_getspecific(sigbuskey);
-
- if (h) {
- if (h->len) {
- if (faultaddr < h->base || faultaddr >= h->base + h->len) {
- // outside specified range, call old handler
- if (oldact.sa_flags & SA_SIGINFO) {
- oldact.sa_sigaction(signal, info, context);
- } else {
- oldact.sa_handler(signal);
- }
- return;
- }
- }
-
- // no range specified or address was in range
-
- if (h->handlesigbus) {
- if (h->handlesigbus(info, h)) {
- // thread's handler didn't handle the signal
- if (oldact.sa_flags & SA_SIGINFO) {
- oldact.sa_sigaction(signal, info, context);
- } else {
- oldact.sa_handler(signal);
- }
- }
- return;
- }
-
- if (h->sigbusvar) {
- // map in a zeroed out page so the operation can succeed
- long pagesize = sysconf(_SC_PAGE_SIZE);
- long pagemask = ~(pagesize - 1);
- void * pageaddr = (void*) (((long)(faultaddr)) & pagemask);
-
- void * bar = mmap( pageaddr, pagesize, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
- if (bar == MAP_FAILED) {
- LOGE("couldn't map zero page at %p: %s", pageaddr, strerror(errno));
- if (oldact.sa_flags & SA_SIGINFO) {
- oldact.sa_sigaction(signal, info, context);
- } else {
- oldact.sa_handler(signal);
- }
- return;
- }
-
- LOGE("setting sigbusvar at %p", h->sigbusvar);
- *(h->sigbusvar) = 1;
- return;
- }
- }
-
- LOGE("SIGBUS: no handler, or improperly configured handler (%p)", h);
-
- if (oldact.sa_flags & SA_SIGINFO) {
- oldact.sa_sigaction(signal, info, context);
- } else {
- oldact.sa_handler(signal);
- }
- return;
-}
-
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
@@ -177,25 +96,10 @@ MediaPlayerService::MediaPlayerService()
{
LOGV("MediaPlayerService created");
mNextConnId = 1;
-
- pthread_key_create(&sigbuskey, NULL);
-
-
-#if USE_SIGBUS_HANDLER
- struct sigaction act;
- memset(&act,0, sizeof act);
- act.sa_sigaction = sigbushandler;
- act.sa_flags = SA_SIGINFO;
- sigaction(SIGBUS, &act, &oldact);
-#endif
}
MediaPlayerService::~MediaPlayerService()
{
-#if USE_SIGBUS_HANDLER
- sigaction(SIGBUS, &oldact, NULL);
-#endif
- pthread_key_delete(sigbuskey);
LOGV("MediaPlayerService destroyed");
}
@@ -314,6 +218,104 @@ static int myTid() {
#endif
}
+#if defined(__arm__)
+extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
+ size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
+extern "C" void free_malloc_leak_info(uint8_t* info);
+
+void memStatus(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ typedef struct {
+ size_t size;
+ size_t dups;
+ intptr_t * backtrace;
+ } AllocEntry;
+
+ uint8_t *info = NULL;
+ size_t overallSize = 0;
+ size_t infoSize = 0;
+ size_t totalMemory = 0;
+ size_t backtraceSize = 0;
+
+ get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, &backtraceSize);
+ if (info) {
+ uint8_t *ptr = info;
+ size_t count = overallSize / infoSize;
+
+ snprintf(buffer, SIZE, " Allocation count %i\n", count);
+ result.append(buffer);
+
+ AllocEntry * entries = new AllocEntry[count];
+
+ for (size_t i = 0; i < count; i++) {
+ // Each entry should be size_t, size_t, intptr_t[backtraceSize]
+ AllocEntry *e = &entries[i];
+
+ e->size = *reinterpret_cast<size_t *>(ptr);
+ ptr += sizeof(size_t);
+
+ e->dups = *reinterpret_cast<size_t *>(ptr);
+ ptr += sizeof(size_t);
+
+ e->backtrace = reinterpret_cast<intptr_t *>(ptr);
+ ptr += sizeof(intptr_t) * backtraceSize;
+ }
+
+ // Now we need to sort the entries. They come sorted by size but
+ // not by stack trace which causes problems using diff.
+ bool moved;
+ do {
+ moved = false;
+ for (size_t i = 0; i < (count - 1); i++) {
+ AllocEntry *e1 = &entries[i];
+ AllocEntry *e2 = &entries[i+1];
+
+ bool swap = e1->size < e2->size;
+ if (e1->size == e2->size) {
+ for(size_t j = 0; j < backtraceSize; j++) {
+ if (e1->backtrace[j] == e2->backtrace[j]) {
+ continue;
+ }
+ swap = e1->backtrace[j] < e2->backtrace[j];
+ break;
+ }
+ }
+ if (swap) {
+ AllocEntry t = entries[i];
+ entries[i] = entries[i+1];
+ entries[i+1] = t;
+ moved = true;
+ }
+ }
+ } while (moved);
+
+ for (size_t i = 0; i < count; i++) {
+ AllocEntry *e = &entries[i];
+
+ snprintf(buffer, SIZE, "size %8i, dup %4i", e->size, e->dups);
+ result.append(buffer);
+ for (size_t ct = 0; (ct < backtraceSize) && e->backtrace[ct]; ct++) {
+ if (ct) {
+ result.append(", ");
+ }
+ snprintf(buffer, SIZE, "0x%08x", e->backtrace[ct]);
+ result.append(buffer);
+ }
+ result.append("\n");
+ }
+
+ delete[] entries;
+ free_malloc_leak_info(info);
+ }
+
+ write(fd, result.string(), result.size());
+}
+#endif
+
status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
@@ -396,6 +398,18 @@ status_t MediaPlayerService::dump(int fd, const Vector<String16>& args)
result.append(buffer);
result.append("\n");
}
+
+#if defined(__arm__)
+ bool dumpMem = false;
+ for (size_t i = 0; i < args.size(); i++) {
+ if (args[i] == String16("-m")) {
+ dumpMem = true;
+ }
+ }
+ if (dumpMem) {
+ memStatus(fd, args);
+ }
+#endif
}
write(fd, result.string(), result.size());
return NO_ERROR;
@@ -481,7 +495,7 @@ static player_type getPlayerType(int fd, int64_t offset, int64_t length)
locator.offset = offset;
locator.length = length;
EAS_HANDLE eashandle;
- if (EAS_OpenFile(easdata, &locator, &eashandle, NULL) == EAS_SUCCESS) {
+ if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
EAS_CloseFile(easdata, eashandle);
EAS_Shutdown(easdata);
return SONIVOX_PLAYER;
@@ -498,22 +512,16 @@ static player_type getPlayerType(const char* url)
// use MidiFile for MIDI extensions
int lenURL = strlen(url);
- for (int i = 0; i < NELEM(MIDI_FILE_EXTS); ++i) {
- int len = strlen(MIDI_FILE_EXTS[i]);
+ for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
+ int len = strlen(FILE_EXTS[i].extension);
int start = lenURL - len;
if (start > 0) {
- if (!strncmp(url + start, MIDI_FILE_EXTS[i], len)) {
- LOGV("Type is MIDI");
- return SONIVOX_PLAYER;
+ if (!strncmp(url + start, FILE_EXTS[i].extension, len)) {
+ return FILE_EXTS[i].playertype;
}
}
}
- if (strcmp(url + strlen(url) - 4, ".ogg") == 0) {
- LOGV("Type is Vorbis");
- return VORBIS_PLAYER;
- }
-
// Fall through to PV
return PV_PLAYER;
}
@@ -539,7 +547,6 @@ static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
if (p != NULL) {
if (p->initCheck() == NO_ERROR) {
p->setNotifyCallback(cookie, notifyFunc);
- p->setSigBusHandlerStructTLSKey(sigbuskey);
} else {
p.clear();
}
@@ -921,7 +928,7 @@ Exit:
MediaPlayerService::AudioOutput::AudioOutput()
{
mTrack = 0;
- mStreamType = AudioTrack::MUSIC;
+ mStreamType = AudioSystem::MUSIC;
mLeftVolume = 1.0;
mRightVolume = 1.0;
mLatency = 0;
@@ -1003,15 +1010,15 @@ status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelC
int afFrameCount;
int frameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {
+ if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
return NO_INIT;
}
- if (AudioSystem::getOutputSamplingRate(&afSampleRate) != NO_ERROR) {
+ if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
return NO_INIT;
}
- frameCount = (sampleRate*afFrameCount)/afSampleRate;
- AudioTrack *t = new AudioTrack(mStreamType, sampleRate, format, channelCount, frameCount*bufferCount);
+ frameCount = (sampleRate*afFrameCount*bufferCount)/afSampleRate;
+ AudioTrack *t = new AudioTrack(mStreamType, sampleRate, format, channelCount, frameCount);
if ((t == 0) || (t->initCheck() != NO_ERROR)) {
LOGE("Unable to create audio track");
delete t;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index f326a0e..5d1887d 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -121,6 +121,17 @@ status_t MediaRecorderClient::setOutputFile(const char* path)
return mRecorder->setOutputFile(path);
}
+status_t MediaRecorderClient::setOutputFile(int fd, int64_t offset, int64_t length)
+{
+ LOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setOutputFile(fd, offset, length);
+}
+
status_t MediaRecorderClient::setVideoSize(int width, int height)
{
LOGV("setVideoSize(%dx%d)", width, height);
@@ -143,6 +154,16 @@ status_t MediaRecorderClient::setVideoFrameRate(int frames_per_second)
return mRecorder->setVideoFrameRate(frames_per_second);
}
+status_t MediaRecorderClient::setParameters(const String8& params) {
+ LOGV("setParameters(%s)", params.string());
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setParameters(params);
+}
+
status_t MediaRecorderClient::prepare()
{
LOGV("prepare");
@@ -247,5 +268,16 @@ MediaRecorderClient::~MediaRecorderClient()
release();
}
+status_t MediaRecorderClient::setListener(const sp<IMediaPlayerClient>& listener)
+{
+ LOGV("setListener");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setListener(listener);
+}
+
}; // namespace android
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 3158017..6a1c2d5 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -36,8 +36,11 @@ public:
virtual status_t setVideoEncoder(int ve);
virtual status_t setAudioEncoder(int ae);
virtual status_t setOutputFile(const char* path);
+ virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
virtual status_t setVideoSize(int width, int height);
virtual status_t setVideoFrameRate(int frames_per_second);
+ virtual status_t setParameters(const String8& params);
+ virtual status_t setListener(const sp<IMediaPlayerClient>& listener);
virtual status_t prepare();
virtual status_t getMaxAmplitude(int* max);
virtual status_t start();
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
index cfad66c..d03caa5 100644
--- a/media/libmediaplayerservice/MidiFile.cpp
+++ b/media/libmediaplayerservice/MidiFile.cpp
@@ -40,8 +40,6 @@ static pid_t myTid() { return getpid(); }
// ----------------------------------------------------------------------------
-extern pthread_key_t EAS_sigbuskey;
-
namespace android {
// ----------------------------------------------------------------------------
@@ -60,7 +58,7 @@ static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
MidiFile::MidiFile() :
mEasData(NULL), mEasHandle(NULL), mAudioBuffer(NULL),
mPlayTime(-1), mDuration(-1), mState(EAS_STATE_ERROR),
- mStreamType(AudioTrack::MUSIC), mLoop(false), mExit(false),
+ mStreamType(AudioSystem::MUSIC), mLoop(false), mExit(false),
mPaused(false), mRender(false), mTid(-1)
{
LOGV("constructor");
@@ -132,7 +130,7 @@ status_t MidiFile::setDataSource(const char* path)
mFileLocator.fd = -1;
mFileLocator.offset = 0;
mFileLocator.length = 0;
- EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle, &mMemFailedVar);
+ EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle);
if (result == EAS_SUCCESS) {
updateState();
}
@@ -148,12 +146,6 @@ status_t MidiFile::setDataSource(const char* path)
return NO_ERROR;
}
-status_t MidiFile::setSigBusHandlerStructTLSKey(pthread_key_t key)
-{
- EAS_sigbuskey = key;
- return 0;
-}
-
status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length)
{
LOGV("MidiFile::setDataSource fd=%d", fd);
@@ -168,7 +160,7 @@ status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length)
mFileLocator.fd = dup(fd);
mFileLocator.offset = offset;
mFileLocator.length = length;
- EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle, &mMemFailedVar);
+ EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle);
updateState();
if (result != EAS_SUCCESS) {
@@ -332,7 +324,7 @@ status_t MidiFile::getDuration(int* duration)
EAS_HANDLE easHandle = NULL;
EAS_RESULT result = EAS_Init(&easData);
if (result == EAS_SUCCESS) {
- result = EAS_OpenFile(easData, &mFileLocator, &easHandle, NULL);
+ result = EAS_OpenFile(easData, &mFileLocator, &easHandle);
}
if (result == EAS_SUCCESS) {
result = EAS_Prepare(easData, easHandle);
@@ -451,8 +443,6 @@ int MidiFile::render() {
LOGV("MidiFile::render");
- struct mediasigbushandler sigbushandler;
-
// allocate render buffer
mAudioBuffer = new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * NUM_BUFFERS];
if (!mAudioBuffer) {
@@ -468,10 +458,6 @@ int MidiFile::render() {
mCondition.signal();
}
- sigbushandler.handlesigbus = NULL;
- sigbushandler.sigbusvar = mMemFailedVar;
- pthread_setspecific(EAS_sigbuskey, &sigbushandler);
-
while (1) {
mMutex.lock();
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
index 9d2dfdd..302f1cf 100644
--- a/media/libmediaplayerservice/MidiFile.h
+++ b/media/libmediaplayerservice/MidiFile.h
@@ -30,7 +30,6 @@ public:
~MidiFile();
virtual status_t initCheck();
- virtual status_t setSigBusHandlerStructTLSKey(pthread_key_t key);
virtual status_t setDataSource(const char* path);
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
virtual status_t setVideoSurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; }
@@ -57,7 +56,6 @@ private:
Mutex mMutex;
Condition mCondition;
- int* mMemFailedVar;
EAS_DATA_HANDLE mEasData;
EAS_HANDLE mEasHandle;
EAS_PCM* mAudioBuffer;
diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp
index 9a64403..0ad335f 100644
--- a/media/libmediaplayerservice/VorbisPlayer.cpp
+++ b/media/libmediaplayerservice/VorbisPlayer.cpp
@@ -55,7 +55,7 @@ static status_t STATE_OPEN = 2;
VorbisPlayer::VorbisPlayer() :
mAudioBuffer(NULL), mPlayTime(-1), mDuration(-1), mState(STATE_ERROR),
- mStreamType(AudioTrack::MUSIC), mLoop(false), mAndroidLoop(false),
+ mStreamType(AudioSystem::MUSIC), mLoop(false), mAndroidLoop(false),
mExit(false), mPaused(false), mRender(false), mRenderTid(-1)
{
LOGV("constructor\n");
@@ -455,13 +455,15 @@ int VorbisPlayer::render() {
current_section = 0;
numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, &current_section);
} else {
- sendEvent(MEDIA_PLAYBACK_COMPLETE);
mAudioSink->stop();
audioStarted = false;
mRender = false;
mPaused = true;
int endpos = ov_time_tell(&mVorbisFile);
+ LOGV("send MEDIA_PLAYBACK_COMPLETE");
+ sendEvent(MEDIA_PLAYBACK_COMPLETE);
+
// wait until we're started again
LOGV("playback complete - wait for signal");
mCondition.wait(mMutex);
diff --git a/media/sdutils/sdutil.cpp b/media/sdutils/sdutil.cpp
index 0daa523..a9aabf0 100644
--- a/media/sdutils/sdutil.cpp
+++ b/media/sdutils/sdutil.cpp
@@ -114,6 +114,16 @@ static int unmount(const char* path) {
return -1;
}
+static int format(const char* path) {
+ String16 string(path);
+
+ if (isMounted(path))
+ return -EBUSY;
+ gMountService->formatMedia(string);
+
+ return 0;
+}
+
static int umsEnable(bool enable) {
gMountService->setMassStorageEnabled(enable);
return 0;
@@ -129,6 +139,9 @@ int main(int argc, char **argv)
if (strcmp(command, "mount") == 0) {
android::init();
return android::mount(argument);
+ } else if (strcmp(command, "format") == 0) {
+ android::init();
+ return android::format(argument);
} else if (strcmp(command, "unmount") == 0) {
android::init();
return android::unmount(argument);
@@ -145,6 +158,7 @@ int main(int argc, char **argv)
fprintf(stderr, "usage:\n"
" sdutil mount <mount path> - mounts the SD card at the given mount point\n"
" sdutil unmount <mount path> - unmounts the SD card at the given mount point\n"
+ " sdutil format <mount path> - formats the SD card at the given mount point\n"
" sdutil ums enable - enables USB mass storage\n"
" sdutil ums disable - disnables USB mass storage\n"
);
diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index 16e658a..a32f590 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -42,5 +42,10 @@
android:targetPackage="com.android.mediaframeworktest"
android:label="MediaFramework unit tests InstrumentationRunner">
</instrumentation>
+
+ <instrumentation android:name=".MediaRecorderStressTestRunner"
+ android:targetPackage="com.android.mediaframeworktest"
+ android:label="MediaRecorder stress tests InstrumentationRunner">
+ </instrumentation>
</manifest>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
index 3d3878e..3c449c9 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
@@ -21,6 +21,7 @@ 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 junit.framework.TestSuite;
@@ -48,6 +49,7 @@ public class MediaFrameworkTestRunner extends InstrumentationTestRunner {
suite.addTestSuite(MediaMetadataTest.class);
suite.addTestSuite(CameraTest.class);
suite.addTestSuite(MediaRecorderTest.class);
+ suite.addTestSuite(MediaAudioTrackTest.class);
return suite;
}
@@ -57,3 +59,4 @@ public class MediaFrameworkTestRunner extends InstrumentationTestRunner {
}
}
+
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index 5843007..07b43bb 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -25,16 +25,16 @@ package com.android.mediaframeworktest;
public class MediaNames {
//Audio files
- public static final String MP3CBR = "/sdcard/music/MP3CBR.mp3";
- public static final String MP3VBR = "/sdcard/music/MP3VBR.mp3";
- public static final String SHORTMP3 = "/sdcard/music/SHORTMP3.mp3";
- public static final String MIDI = "/sdcard/music/MIDI.mid";
- public static final String WMA9 = "/sdcard/music/WMA9.wma";
- public static final String WMA10 = "/sdcard/music/WMA10.wma";
- public static final String WAV = "/sdcard/music/complicated_wav.wav";
- public static final String AMR = "/sdcard/music/AMRNB.amr";
- public static final String OGG = "/sdcard/music/Mists_of_Time-4T.ogg";
- public static final String OGGSHORT = "/sdcard/music/Skippy.ogg";
+ public static final String MP3CBR = "/sdcard/media_api/music/MP3CBR.mp3";
+ public static final String MP3VBR = "/sdcard/media_api/music/MP3VBR.mp3";
+ public static final String SHORTMP3 = "/sdcard/media_api/music/SHORTMP3.mp3";
+ public static final String MIDI = "/sdcard/media_api/music/MIDI.mid";
+ public static final String WMA9 = "/sdcard/media_api/music/WMA9.wma";
+ public static final String WMA10 = "/sdcard/media_api/music/WMA10.wma";
+ public static final String WAV = "/sdcard/media_api/music/complicated_wav.wav";
+ public static final String AMR = "/sdcard/media_api/music/AMRNB.amr";
+ public static final String OGG = "/sdcard/media_api/music/Mists_of_Time-4T.ogg";
+ public static final String OGGSHORT = "/sdcard/media_api/music/Skippy.ogg";
public static final int MP3CBR_LENGTH = 231116;
public static final int MP3VBR_LENGTH = 126407;
@@ -60,20 +60,20 @@ public class MediaNames {
//public static final String VIDEO_RTSP3GP = "rtsp://193.159.241.21/sp/alizee05.3gp";
//local video
- public static final String VIDEO_MP4 = "/sdcard/video/gingerkids.MP4";
- public static final String VIDEO_LONG_3GP = "/sdcard/video/radiohead.3gp";
- public static final String VIDEO_SHORT_3GP = "/sdcard/video/short.3gp";
- public static final String VIDEO_LARGE_SIZE_3GP = "/sdcard/video/border_large.3gp";
- public static final String VIDEO_H263_AAC = "/sdcard/video/H263_AAC.3gp";
- public static final String VIDEO_H263_AMR = "/sdcard/video/H263_AMR.3gp";
- public static final String VIDEO_H264_AAC = "/sdcard/video/H264_AAC.3gp";
- public static final String VIDEO_H264_AMR = "/sdcard/video/H264_AMR.3gp";
- public static final String VIDEO_WMV = "/sdcard/video/bugs.wmv";
- public static final String VIDEO_HIGHRES_H263 = "/sdcard/video/h263_qcif_30fps.3gp";
- public static final String VIDEO_HIGHRES_MP4 = "/sdcard/video/mpeg4_qvga_24fps.3gp";
+ public static final String VIDEO_MP4 = "/sdcard/media_api/video/gingerkids.MP4";
+ public static final String VIDEO_LONG_3GP = "/sdcard/media_api/video/radiohead.3gp";
+ public static final String VIDEO_SHORT_3GP = "/sdcard/media_api/video/short.3gp";
+ public static final String VIDEO_LARGE_SIZE_3GP = "/sdcard/media_api/video/border_large.3gp";
+ public static final String VIDEO_H263_AAC = "/sdcard/media_api/video/H263_AAC.3gp";
+ public static final String VIDEO_H263_AMR = "/sdcard/media_api/video/H263_AMR.3gp";
+ public static final String VIDEO_H264_AAC = "/sdcard/media_api/video/H264_AAC.3gp";
+ public static final String VIDEO_H264_AMR = "/sdcard/media_api/video/H264_AMR.3gp";
+ public static final String VIDEO_WMV = "/sdcard/media_api/video/bugs.wmv";
+ public static final String VIDEO_HIGHRES_H263 = "/sdcard/media_api/video/h263_qcif_30fps.3gp";
+ public static final String VIDEO_HIGHRES_MP4 = "/sdcard/media_api/video/mpeg4_qvga_24fps.3gp";
//ringtone
- public static final String ringtone = "/sdcard/ringtones/F1_NewVoicemail.mp3";
+ public static final String ringtone = "/sdcard/media_api/ringtones/F1_NewVoicemail.mp3";
//streaming mp3
public static final String STREAM_LARGE_MP3 =
@@ -110,264 +110,266 @@ public class MediaNames {
"http://wms.pv.com:7070/MediaDownloadContent/UserUploads/beefcake.mp3";
//Sonivox
- public static String MIDIFILES[] = { "/sdcard/music/Leadsol.mxmf",
- "/sdcard/music/abba.imy", "/sdcard/music/ants.mid",
- "/sdcard/music/greensleeves.rtttl", "/sdcard/music/test.ota"};
+ public static String MIDIFILES[] = {
+ "/sdcard/media_api/music/Leadsol.mxmf",
+ "/sdcard/media_api/music/abba.imy", "/sdcard/media_api/music/ants.mid",
+ "/sdcard/media_api/music/greensleeves.rtttl", "/sdcard/media_api/music/test.ota"};
//Performance measurement
- public static String[] WAVFILES = { "/sdcard/music_perf/WAV/M1F1-AlawWE-AFsp.wav",
- "/sdcard/music_perf/WAV/M1F1-float64-AFsp.wav",
- "/sdcard/music_perf/WAV/song.wav",
- "/sdcard/music_perf/WAV/WAVEtest.wav",
- "/sdcard/music_perf/WAV/WAVEtest_out.wav",
- "/sdcard/music_perf/WAV/test_out.wav"};
-
+ public static String[] WAVFILES = {
+ "/sdcard/media_api/music_perf/WAV/M1F1-AlawWE-AFsp.wav",
+ "/sdcard/media_api/music_perf/WAV/M1F1-float64-AFsp.wav",
+ "/sdcard/media_api/music_perf/WAV/song.wav",
+ "/sdcard/media_api/music_perf/WAV/WAVEtest.wav",
+ "/sdcard/media_api/music_perf/WAV/WAVEtest_out.wav",
+ "/sdcard/media_api/music_perf/WAV/test_out.wav"};
+
public static String[] AMRNBFILES = {
- "/sdcard/music_perf/AMR/AI_AMR-NB_5.9kbps_6.24kbps_8khz_mono_NMC.amr",
- "/sdcard/music_perf/AMR/AI_AMR-NB_5.15kbps_5.46kbps_8khz_mono_NMC.amr",
- "/sdcard/music_perf/AMR/AI_AMR-NB_7.4kbps_7.80kbps_8khz_mono_NMC.amr",
- "/sdcard/music_perf/AMR/AI_AMR-NB_7.95kbps_9.6kbps_8khz_mono_NMC.amr",
- "/sdcard/music_perf/AMR/AI_AMR-NB_10.2kbps_10.48kbps_8khz_mono_NMC.amr"};
+ "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_5.9kbps_6.24kbps_8khz_mono_NMC.amr",
+ "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_5.15kbps_5.46kbps_8khz_mono_NMC.amr",
+ "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_7.4kbps_7.80kbps_8khz_mono_NMC.amr",
+ "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_7.95kbps_9.6kbps_8khz_mono_NMC.amr",
+ "/sdcard/media_api/music_perf/AMR/AI_AMR-NB_10.2kbps_10.48kbps_8khz_mono_NMC.amr"};
public static String[] AMRWBFILES = {
- "/sdcard/music_perf/AMRWB/NIN_AMR-WB_15.85kbps_16kbps.amr",
- "/sdcard/music_perf/AMRWB/NIN_AMR-WB_18.25kbps_18kbps.amr",
- "/sdcard/music_perf/AMRWB/NIN_AMR-WB_19.85kbps_20kbps.amr",
- "/sdcard/music_perf/AMRWB/NIN_AMR-WB_23.05kbps_23kbps.amr",
- "/sdcard/music_perf/AMRWB/NIN_AMR-WB_23.85kbps_24kbps.amr",
- "/sdcard/music_perf/AMRWB/PD_AMR-WB_19.85kbps_20kbps.amr",
- "/sdcard/music_perf/AMRWB/PD_AMR-WB_23.05kbps_23kbps.amr",
- "/sdcard/music_perf/AMRWB/PD_AMR-WB_23.85kbps_24kbps.amr",
- "/sdcard/music_perf/AMRWB/WC_AMR-WB_23.05kbps_23kbps.amr",
- "/sdcard/music_perf/AMRWB/WC_AMR-WB_23.85kbps_24kbps.amr", };
+ "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_15.85kbps_16kbps.amr",
+ "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_18.25kbps_18kbps.amr",
+ "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_19.85kbps_20kbps.amr",
+ "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_23.05kbps_23kbps.amr",
+ "/sdcard/media_api/music_perf/AMRWB/NIN_AMR-WB_23.85kbps_24kbps.amr",
+ "/sdcard/media_api/music_perf/AMRWB/PD_AMR-WB_19.85kbps_20kbps.amr",
+ "/sdcard/media_api/music_perf/AMRWB/PD_AMR-WB_23.05kbps_23kbps.amr",
+ "/sdcard/media_api/music_perf/AMRWB/PD_AMR-WB_23.85kbps_24kbps.amr",
+ "/sdcard/media_api/music_perf/AMRWB/WC_AMR-WB_23.05kbps_23kbps.amr",
+ "/sdcard/media_api/music_perf/AMRWB/WC_AMR-WB_23.85kbps_24kbps.amr", };
public static String[] MP3FILES = {
- "/sdcard/music_perf/MP3/NIN_56kbps_32khz_stereo_VBR_MCA.MP3",
- "/sdcard/music_perf/MP3/NIN_80kbps_32khz_stereo_VBR_MCA.mp3",
- "/sdcard/music_perf/MP3/NIN_80kbps_44.1khz_stereo_VBR_MCA.mp3",
- "/sdcard/music_perf/MP3/NIN_80kbps_48khz_stereo_VBR_MCA.mp3",
- "/sdcard/music_perf/MP3/NIN_112kbps_32khz_stereo_VBR_MCA.mp3",
- "/sdcard/music_perf/MP3/NIN_112kbps_44.1khz_stereo_VBR_MCA.mp3",
- "/sdcard/music_perf/MP3/NIN_112kbps_48khz_stereo_VBR_MCA.mp3",
- "/sdcard/music_perf/MP3/NIN_192kbps_32khz_mono_CBR_MCA.mp3",
- "/sdcard/music_perf/MP3/NIN_192kbps_44.1khz_mono_CBR_MCA.mp3",
- "/sdcard/music_perf/MP3/NIN_192kbps_48khz_mono_CBR_MCA.mp3",
- "/sdcard/music_perf/MP3/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3",
- "/sdcard/music_perf/MP3/NIN_256kbps_48khz_mono_CBR_MCA.mp3",
- "/sdcard/music_perf/MP3/PD_112kbps_32khz_stereo_VBR_MCA.mp3",
- "/sdcard/music_perf/MP3/PD_112kbps_44.1khz_stereo_VBR_MCA.mp3",
- "/sdcard/music_perf/MP3/PD_112kbps_48khz_stereo_VBR_MCA.mp3",
- "/sdcard/music_perf/MP3/PD_192kbps_32khz_mono_CBR_DPA.mp3",
- "/sdcard/music_perf/MP3/PD_256kbps_44.1khz_mono_CBR_DPA.mp3",
- "/sdcard/music_perf/MP3/PD_256kbps_48khz_mono_CBR_MCA.mp3",
- "/sdcard/music_perf/MP3/WC_256kbps_44.1khz_mono_CBR_DPA.mp3",
- "/sdcard/music_perf/MP3/WC_256kbps_48khz_mono_CBR_DPA.mp3",
- "/sdcard/music_perf/regular_album_photo/Apologize.mp3",
- "/sdcard/music_perf/regular_album_photo/Because_Of_You.mp3",
- "/sdcard/music_perf/regular_album_photo/Complicated.mp3",
- "/sdcard/music_perf/regular_album_photo/Glamorous.mp3",
- "/sdcard/music_perf/regular_album_photo/Im_With_You.mp3",
- "/sdcard/music_perf/regular_album_photo/Smile.mp3",
- "/sdcard/music_perf/regular_album_photo/Suddenly_I_See.mp3",
- "/sdcard/music_perf/regular_album_photo/When You Say Nothing At All.mp3",
- "/sdcard/music_perf/regular_album_photo/my_happy_ending.mp3"};
+ "/sdcard/media_api/music_perf/MP3/NIN_56kbps_32khz_stereo_VBR_MCA.MP3",
+ "/sdcard/media_api/music_perf/MP3/NIN_80kbps_32khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/NIN_80kbps_44.1khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/NIN_80kbps_48khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/NIN_112kbps_32khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/NIN_112kbps_44.1khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/NIN_112kbps_48khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/NIN_192kbps_32khz_mono_CBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/NIN_192kbps_44.1khz_mono_CBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/NIN_192kbps_48khz_mono_CBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/NIN_256kbps_48khz_mono_CBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/PD_112kbps_32khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/PD_112kbps_44.1khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/PD_112kbps_48khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/PD_192kbps_32khz_mono_CBR_DPA.mp3",
+ "/sdcard/media_api/music_perf/MP3/PD_256kbps_44.1khz_mono_CBR_DPA.mp3",
+ "/sdcard/media_api/music_perf/MP3/PD_256kbps_48khz_mono_CBR_MCA.mp3",
+ "/sdcard/media_api/music_perf/MP3/WC_256kbps_44.1khz_mono_CBR_DPA.mp3",
+ "/sdcard/media_api/music_perf/MP3/WC_256kbps_48khz_mono_CBR_DPA.mp3",
+ "/sdcard/media_api/music_perf/regular_album_photo/Apologize.mp3",
+ "/sdcard/media_api/music_perf/regular_album_photo/Because_Of_You.mp3",
+ "/sdcard/media_api/music_perf/regular_album_photo/Complicated.mp3",
+ "/sdcard/media_api/music_perf/regular_album_photo/Glamorous.mp3",
+ "/sdcard/media_api/music_perf/regular_album_photo/Im_With_You.mp3",
+ "/sdcard/media_api/music_perf/regular_album_photo/Smile.mp3",
+ "/sdcard/media_api/music_perf/regular_album_photo/Suddenly_I_See.mp3",
+ "/sdcard/media_api/music_perf/regular_album_photo/When You Say Nothing At All.mp3",
+ "/sdcard/media_api/music_perf/regular_album_photo/my_happy_ending.mp3"};
public static String[] AACFILES = {
- "/sdcard/music_perf/AAC/AI_AAC_24kbps_12khz_Mono_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/AI_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/AI_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/music_perf/AAC/AI_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/music_perf/AAC/NIN_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/NIN_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/music_perf/AAC/NIN_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/music_perf/AAC/PD_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/PD_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/music_perf/AAC/PD_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/music_perf/AAC/PV_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/PV_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/music_perf/AAC/PV_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/music_perf/AAC/WC_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/WC_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
- "/sdcard/music_perf/AAC/WC_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
- "/sdcard/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/AI_AAC_24kbps_12khz_Mono_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/AI_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/AI_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/AI_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/AI_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/NIN_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/NIN_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/NIN_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/NIN_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/PD_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/PD_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/PD_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/PD_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/PV_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/PV_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/PV_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/PV_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/WC_AAC_56kbps_22.05khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/WC_AAC_56kbps_32khz_Stereo_CBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/WC_AAC_56kbps_44.1khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_1pCBR_SSE.mp4",
+ "/sdcard/media_api/music_perf/AAC/WC_AAC_80kbps_32khz_Stereo_CBR_SSE.mp4",
};
- public static String[] VIDEOFILES = { "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_10fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
- "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_12fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
- "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_15fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
- "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
- "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_SSE.mp4",
- "/sdcard/video_perf/AI_CTO_Mpeg4_32kbps_7.5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
- "/sdcard/video_perf/AI_WMV_1024kbps_20fps_QCIF_176x144_noaudio_SSE.wmv",
- "/sdcard/video_perf/AI_WMV_1024kbps_25fps_QCIF_176x144_noaudio_SSE.wmv",
- "/sdcard/video_perf/Chicken.wmv",
- "/sdcard/video_perf/MP_qcif_15fps_100kbps_48kHz_192kbps_30secs.wmv",
- "/sdcard/video_perf/NIN_CTO_H264_123kbps_5fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
- "/sdcard/video_perf/NIN_CTO_H264_96kbps_10.2fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
- "/sdcard/video_perf/NIN_CTO_H264_96kbps_12fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
- "/sdcard/video_perf/NIN_CTO_H264_96kbps_15fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
- "/sdcard/video_perf/NIN_CTO_Mpeg4_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_mono_SSE.3gp",
- "/sdcard/video_perf/NIN_CTO_Mpeg4_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp",
- "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_10fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
- "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_12fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
- "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_15fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
- "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
- "/sdcard/video_perf/NIN_CTO_Mpeg4_128kbps_7.5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
- "/sdcard/video_perf/NIN_H263_128kbps_10fps_QCIF_174x144_noaudio_SSE.mp4",
- "/sdcard/video_perf/NIN_H263_128kbps_15fps_QCIF_174x144_noaudio_SSE.mp4",
- "/sdcard/video_perf/NIN_H263_48kbps_10fps_QCIF_174x144_noaudio_SSE.3gp",
- "/sdcard/video_perf/NIN_H263_48kbps_12fps_QCIF_174x144_noaudio_SSE.3gp",
- "/sdcard/video_perf/NIN_H264_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp",
- "/sdcard/video_perf/NIN_H264_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp",
- "/sdcard/video_perf/PV_H264_2000kbps_20fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4",
- "/sdcard/video_perf/PV_H264_2000kbps_25fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4",
- "/sdcard/video_perf/PV_H264_2000kbps_30fps_CIF_352x288+AAC_128kbps_48khz_stereo_SSE.mp4",
- "/sdcard/video_perf/Stevie-1.wmv",
- "/sdcard/video_perf/WC_H264_1600kbps_20fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4",
- "/sdcard/video_perf/WC_H264_1600kbps_25fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4",
- "/sdcard/video_perf/WC_H264_1600kbps_30fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4",
- "/sdcard/video_perf/bugs.wmv",
- "/sdcard/video_perf/niceday.wmv",
- "/sdcard/video_perf/eaglesatopnflpe.wmv",
+ public static String[] VIDEOFILES = { "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_10fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
+ "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_12fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
+ "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_15fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
+ "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
+ "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_SSE.mp4",
+ "/sdcard/media_api/video_perf/AI_CTO_Mpeg4_32kbps_7.5fps_SQCIF_128x96+AAC_8kbps_8khz_mono_QTE.mp4",
+ "/sdcard/media_api/video_perf/AI_WMV_1024kbps_20fps_QCIF_176x144_noaudio_SSE.wmv",
+ "/sdcard/media_api/video_perf/AI_WMV_1024kbps_25fps_QCIF_176x144_noaudio_SSE.wmv",
+ "/sdcard/media_api/video_perf/Chicken.wmv",
+ "/sdcard/media_api/video_perf/MP_qcif_15fps_100kbps_48kHz_192kbps_30secs.wmv",
+ "/sdcard/media_api/video_perf/NIN_CTO_H264_123kbps_5fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
+ "/sdcard/media_api/video_perf/NIN_CTO_H264_96kbps_10.2fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
+ "/sdcard/media_api/video_perf/NIN_CTO_H264_96kbps_12fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
+ "/sdcard/media_api/video_perf/NIN_CTO_H264_96kbps_15fps_QCIF_176x144+AMR_12.2kbps_8khz_mono_QTE.3gp",
+ "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_mono_SSE.3gp",
+ "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp",
+ "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_10fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
+ "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_12fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
+ "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_15fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
+ "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
+ "/sdcard/media_api/video_perf/NIN_CTO_Mpeg4_128kbps_7.5fps_QCIF_176x144+AAC+_32kbps_48khz_stereo_SSE.3gp",
+ "/sdcard/media_api/video_perf/NIN_H263_128kbps_10fps_QCIF_174x144_noaudio_SSE.mp4",
+ "/sdcard/media_api/video_perf/NIN_H263_128kbps_15fps_QCIF_174x144_noaudio_SSE.mp4",
+ "/sdcard/media_api/video_perf/NIN_H263_48kbps_10fps_QCIF_174x144_noaudio_SSE.3gp",
+ "/sdcard/media_api/video_perf/NIN_H263_48kbps_12fps_QCIF_174x144_noaudio_SSE.3gp",
+ "/sdcard/media_api/video_perf/NIN_H264_123kbps_15fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp",
+ "/sdcard/media_api/video_perf/NIN_H264_123kbps_7.5fps_QCIF_176x144+AAC_32kbps_22khz_stereo_SSE.3gp",
+ "/sdcard/media_api/video_perf/PV_H264_2000kbps_20fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4",
+ "/sdcard/media_api/video_perf/PV_H264_2000kbps_25fps_CIF_352x288+AAC_96kbps_48khz_stereo_SSE.mp4",
+ "/sdcard/media_api/video_perf/PV_H264_2000kbps_30fps_CIF_352x288+AAC_128kbps_48khz_stereo_SSE.mp4",
+ "/sdcard/media_api/video_perf/Stevie-1.wmv",
+ "/sdcard/media_api/video_perf/WC_H264_1600kbps_20fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4",
+ "/sdcard/media_api/video_perf/WC_H264_1600kbps_25fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4",
+ "/sdcard/media_api/video_perf/WC_H264_1600kbps_30fps_QCIF_176x144+AAC_96kbps_48khz_mono_SSE.mp4",
+ "/sdcard/media_api/video_perf/bugs.wmv",
+ "/sdcard/media_api/video_perf/niceday.wmv",
+ "/sdcard/media_api/video_perf/eaglesatopnflpe.wmv",
};
//wma - only support up to wma 9
public static String[] WMASUPPORTED = {
- "/sdcard/music_perf/WMASUPPORTED/AI_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/music_perf/WMASUPPORTED/AI_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/music_perf/WMASUPPORTED/NIN_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/music_perf/WMASUPPORTED/NIN_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/music_perf/WMASUPPORTED/PD_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/music_perf/WMASUPPORTED/PD_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/music_perf/WMASUPPORTED/PV_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/music_perf/WMASUPPORTED/PV_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/music_perf/WMASUPPORTED/WC_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
- "/sdcard/music_perf/WMASUPPORTED/WC_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma"
+ "/sdcard/media_api/music_perf/WMASUPPORTED/AI_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMASUPPORTED/AI_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMASUPPORTED/NIN_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMASUPPORTED/NIN_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMASUPPORTED/PD_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMASUPPORTED/PD_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMASUPPORTED/PV_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMASUPPORTED/PV_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMASUPPORTED/WC_WMA9.2_32kbps_44.1khz_mono_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMASUPPORTED/WC_WMA9.2_48kbps_44.1khz_mono_CBR_DPA.wma"
};
public static String[] WMAUNSUPPORTED = {
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_127kbps_48khz_stereo_CBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_44.1khz_stereo_2pVBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_48khz_stereo_2pVBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_88khz_stereo_CBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_96khz_stereo_CBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_44.1khz_stereo_2pVBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_88khz_stereo_CBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_96khz_stereo_CBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_44khz_stereo_CBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_48khz_stereo_CBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_88khz_stereo_CBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_96khz_stereo_CBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_44khz_stereo_CBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_48khz_stereo_CBR_DPA.wma",
- "/sdcard/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_88khz_stereo_CBR_DPA.wma"
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_127kbps_48khz_stereo_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_44.1khz_stereo_2pVBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_48khz_stereo_2pVBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_88khz_stereo_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_128kbps_96khz_stereo_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_44.1khz_stereo_2pVBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_88khz_stereo_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_192kbps_96khz_stereo_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_44khz_stereo_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_48khz_stereo_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_88khz_stereo_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_256kbps_96khz_stereo_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_44khz_stereo_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_48khz_stereo_CBR_DPA.wma",
+ "/sdcard/media_api/music_perf/WMAUNSUPPORTED/AI_WMA10_384kbps_88khz_stereo_CBR_DPA.wma"
};
//Media Recorder
- public static final String RECORDER_OUTPUT = "/sdcard/recorderOutput.amr";
+ public static final String RECORDER_OUTPUT = "/sdcard/media_api/recorderOutput.amr";
//video thumbnail
- public static final String THUMBNAIL_OUTPUT = "/sdcard/videoThumbnail.png";
- public static final String GOLDEN_THUMBNAIL_OUTPUT = "/sdcard/goldenThumbnail.png";
+ public static final String THUMBNAIL_OUTPUT = "/sdcard/media_api/videoThumbnail.png";
+ public static final String GOLDEN_THUMBNAIL_OUTPUT = "/sdcard/media_api/goldenThumbnail.png";
//Metadata Utility
public static final String[] THUMBNAIL_CAPTURE_TEST_FILES = {
- "/sdcard/metadata/test.mp4",
- "/sdcard/metadata/test1.3gp",
- "/sdcard/metadata/test2.3gp",
- "/sdcard/metadata/test3.3gp",
- "/sdcard/metadata/test4.3gp",
- "/sdcard/metadata/test5.3gp",
- "/sdcard/metadata/test6.3gp",
- "/sdcard/metadata/test7.3gp",
- "/sdcard/metadata/test8.3gp",
- "/sdcard/metadata/test9.3gp",
- "/sdcard/metadata/test10.3gp",
- "/sdcard/metadata/test11.3gp",
- "/sdcard/metadata/test12.3gp",
- "/sdcard/metadata/test13.3gp",
- "/sdcard/metadata/test14.3gp",
- "/sdcard/metadata/test15.3gp",
- "/sdcard/metadata/test16.3gp",
- "/sdcard/metadata/test17.3gp",
- "/sdcard/metadata/test18.3gp",
- "/sdcard/metadata/test19.3gp",
- "/sdcard/metadata/test20.3gp",
- "/sdcard/metadata/test21.3gp",
- "/sdcard/metadata/test22.3gp",
- "/sdcard/metadata/test23.3gp",
- "/sdcard/metadata/test24.3gp",
- "/sdcard/metadata/test25.3gp",
- "/sdcard/metadata/test26.3gp",
- "/sdcard/metadata/test27.3gp",
- "/sdcard/metadata/test28.3gp",
- "/sdcard/metadata/test29.3gp",
- "/sdcard/metadata/test30.3gp",
- "/sdcard/metadata/test31.3gp",
- "/sdcard/metadata/test32.3gp",
- "/sdcard/metadata/test33.3gp",
- "/sdcard/metadata/test35.mp4",
- "/sdcard/metadata/test36.m4v",
- "/sdcard/metadata/test34.wmv",
- "/sdcard/metadata/test_metadata.mp4",
+ "/sdcard/media_api/metadata/test.mp4",
+ "/sdcard/media_api/metadata/test1.3gp",
+ "/sdcard/media_api/metadata/test2.3gp",
+ "/sdcard/media_api/metadata/test3.3gp",
+ "/sdcard/media_api/metadata/test4.3gp",
+ "/sdcard/media_api/metadata/test5.3gp",
+ "/sdcard/media_api/metadata/test6.3gp",
+ "/sdcard/media_api/metadata/test7.3gp",
+ "/sdcard/media_api/metadata/test8.3gp",
+ "/sdcard/media_api/metadata/test9.3gp",
+ "/sdcard/media_api/metadata/test10.3gp",
+ "/sdcard/media_api/metadata/test11.3gp",
+ "/sdcard/media_api/metadata/test12.3gp",
+ "/sdcard/media_api/metadata/test13.3gp",
+ "/sdcard/media_api/metadata/test14.3gp",
+ "/sdcard/media_api/metadata/test15.3gp",
+ "/sdcard/media_api/metadata/test16.3gp",
+ "/sdcard/media_api/metadata/test17.3gp",
+ "/sdcard/media_api/metadata/test18.3gp",
+ "/sdcard/media_api/metadata/test19.3gp",
+ "/sdcard/media_api/metadata/test20.3gp",
+ "/sdcard/media_api/metadata/test21.3gp",
+ "/sdcard/media_api/metadata/test22.3gp",
+ "/sdcard/media_api/metadata/test23.3gp",
+ "/sdcard/media_api/metadata/test24.3gp",
+ "/sdcard/media_api/metadata/test25.3gp",
+ "/sdcard/media_api/metadata/test26.3gp",
+ "/sdcard/media_api/metadata/test27.3gp",
+ "/sdcard/media_api/metadata/test28.3gp",
+ "/sdcard/media_api/metadata/test29.3gp",
+ "/sdcard/media_api/metadata/test30.3gp",
+ "/sdcard/media_api/metadata/test31.3gp",
+ "/sdcard/media_api/metadata/test32.3gp",
+ "/sdcard/media_api/metadata/test33.3gp",
+ "/sdcard/media_api/metadata/test35.mp4",
+ "/sdcard/media_api/metadata/test36.m4v",
+ "/sdcard/media_api/metadata/test34.wmv",
+ "/sdcard/media_api/metadata/test_metadata.mp4",
};
public static final String[] METADATA_RETRIEVAL_TEST_FILES = {
// Raw AAC is not supported
- // "/sdcard/test_raw.aac",
- // "/sdcard/test_adts.aac",
- // "/sdcard/test_adif.aac",
- "/sdcard/metadata/test_metadata.mp4",
- "/sdcard/metadata/WMA10.wma",
- "/sdcard/metadata/Leadsol_out.wav",
- "/sdcard/metadata/test_aac.mp4",
- "/sdcard/metadata/test_amr.mp4",
- "/sdcard/metadata/test_avc_amr.mp4",
- "/sdcard/metadata/test_metadata.mp4",
- "/sdcard/metadata/test_vbr.mp3",
- "/sdcard/metadata/test_cbr.mp3",
- "/sdcard/metadata/metadata_test1.mp3",
- "/sdcard/metadata/test33.3gp",
- "/sdcard/metadata/test35.mp4",
- "/sdcard/metadata/test36.m4v",
- "/sdcard/metadata/test_m4v_amr.mp4",
- "/sdcard/metadata/test_h263_amr.mp4",
- "/sdcard/metadata/test34.wmv",
+ // "/sdcard/media_api/test_raw.aac",
+ // "/sdcard/media_api/test_adts.aac",
+ // "/sdcard/media_api/test_adif.aac",
+ "/sdcard/media_api/metadata/test_metadata.mp4",
+ "/sdcard/media_api/metadata/WMA10.wma",
+ "/sdcard/media_api/metadata/Leadsol_out.wav",
+ "/sdcard/media_api/metadata/test_aac.mp4",
+ "/sdcard/media_api/metadata/test_amr.mp4",
+ "/sdcard/media_api/metadata/test_avc_amr.mp4",
+ "/sdcard/media_api/metadata/test_metadata.mp4",
+ "/sdcard/media_api/metadata/test_vbr.mp3",
+ "/sdcard/media_api/metadata/test_cbr.mp3",
+ "/sdcard/media_api/metadata/metadata_test1.mp3",
+ "/sdcard/media_api/metadata/test33.3gp",
+ "/sdcard/media_api/metadata/test35.mp4",
+ "/sdcard/media_api/metadata/test36.m4v",
+ "/sdcard/media_api/metadata/test_m4v_amr.mp4",
+ "/sdcard/media_api/metadata/test_h263_amr.mp4",
+ "/sdcard/media_api/metadata/test34.wmv",
};
public static final String[] ALBUMART_TEST_FILES = {
- "/sdcard/album_photo/test_22_16_mp3.mp3",
- "/sdcard/album_photo/PD_256kbps_48khz_mono_CBR_MCA.mp3",
- "/sdcard/album_photo/PD_256kbps_44.1khz_mono_CBR_DPA.mp3",
- "/sdcard/album_photo/PD_192kbps_32khz_mono_CBR_DPA.mp3",
- "/sdcard/album_photo/NIN_256kbps_48khz_mono_CBR_MCA.mp3",
- "/sdcard/album_photo/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3",
- "/sdcard/album_photo/NIN_112kbps(96kbps)_48khz_stereo_VBR_MCA.mp3",
- "/sdcard/album_photo/NIN_112kbps(96kbps)_44.1khz_stereo_VBR_MCA.mp3",
- "/sdcard/album_photo/lightGreen1.mp3",
- "/sdcard/album_photo/babyBlue2 1.mp3",
- "/sdcard/album_photo/2-01 01 NIN_56kbps(64kbps)_32khz_stereo_VBR_MCA.mp3",
- "/sdcard/album_photo/02_NIN_112kbps(80kbps)_32khz_stereo_VBR_MCA.mp3",
- "/sdcard/album_photo/No_Woman_No_Cry_128K.wma",
- "/sdcard/album_photo/Beethoven_2.wma",
+ "/sdcard/media_api/album_photo/test_22_16_mp3.mp3",
+ "/sdcard/media_api/album_photo/PD_256kbps_48khz_mono_CBR_MCA.mp3",
+ "/sdcard/media_api/album_photo/PD_256kbps_44.1khz_mono_CBR_DPA.mp3",
+ "/sdcard/media_api/album_photo/PD_192kbps_32khz_mono_CBR_DPA.mp3",
+ "/sdcard/media_api/album_photo/NIN_256kbps_48khz_mono_CBR_MCA.mp3",
+ "/sdcard/media_api/album_photo/NIN_256kbps_44.1khz_mono_CBR_MCA.mp3",
+ "/sdcard/media_api/album_photo/NIN_112kbps(96kbps)_48khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/album_photo/NIN_112kbps(96kbps)_44.1khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/album_photo/lightGreen1.mp3",
+ "/sdcard/media_api/album_photo/babyBlue2 1.mp3",
+ "/sdcard/media_api/album_photo/2-01 01 NIN_56kbps(64kbps)_32khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/album_photo/02_NIN_112kbps(80kbps)_32khz_stereo_VBR_MCA.mp3",
+ "/sdcard/media_api/album_photo/No_Woman_No_Cry_128K.wma",
+ "/sdcard/media_api/album_photo/Beethoven_2.wma",
};
//TEST_PATH_1: is a video and contains metadata for key "num-tracks"
// TEST_PATH_2: any valid media file.
// TEST_PATH_3: invalid media file
- public static final String TEST_PATH_1 = "/sdcard/metadata/test.mp4";
- public static final String TEST_PATH_3 = "/sdcard/data.txt";
+ public static final String TEST_PATH_1 = "/sdcard/media_api/metadata/test.mp4";
+ public static final String TEST_PATH_3 = "/sdcard/media_api/data.txt";
public static final String TEST_PATH_4 = "somenonexistingpathname";
public static final String TEST_PATH_5 = "mem://012345";
@@ -376,81 +378,81 @@ public class MediaNames {
//cd_track_number, album, artist, author, composer, date, genre
//title, years, duration
public static final String META_DATA_MP3 [][] = {
- {"/sdcard/metaDataTestMedias/MP3/ID3V1_ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist",
+ {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1_ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist",
"ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues",
"ID3V2.3 Title", "1234", "321", "1"},
- {"/sdcard/metaDataTestMedias/MP3/ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist",
+ {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V2.mp3", "1/10", "ID3V2.3 Album", "ID3V2.3 Artist",
"ID3V2.3 Lyricist", "ID3V2.3 Composer", null, "Blues",
"ID3V2.3 Title", "1234", "313", "1"},
- {"/sdcard/metaDataTestMedias/MP3/ID3V1.mp3", null, "test ID3V1 Album", "test ID3V1 Artist",
+ {"/sdcard/media_api/metaDataTestMedias/MP3/ID3V1.mp3", null, "test ID3V1 Album", "test ID3V1 Artist",
null, null, null, null, "test ID3V1 Title", "1234", "231332", "1"},
- {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V1.mp3" , null, null, null,
+ {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V1.mp3" , null, null, null,
null, null, null, null, null, null, "231330", "1"},
//The corrupted TALB field in id3v2 would not switch to id3v1 tag automatically
- {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TALB.mp3", "01", null, "ID3V2.3 Artist",
+ {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TALB.mp3", "01", null, "ID3V2.3 Artist",
"ID3V2.3 Lyricist", "ID3V2.3 Composer", null,
"Blues", "ID3V2.3 Title", "1234", "321", "1"},
- {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM.mp3", "01", "ID3V2.3 Album",
+ {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM.mp3", "01", "ID3V2.3 Album",
"ID3V2.3 Artist", "ID3V2.3 Lyricist", null, null,
"Blues", "ID3V2.3 Title", "1234", "321", "1"},
- {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM_2.mp3", "01", "ID3V2.3 Album",
+ {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TCOM_2.mp3", "01", "ID3V2.3 Album",
"ID3V2.3 Artist", null, null, null, "Blues", "ID3V2.3 Title", "1234", "321", "1"},
- {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK.mp3", "dd", "ID3V2.3 Album",
+ {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK.mp3", "dd", "ID3V2.3 Album",
"ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null,
"Blues", "ID3V2.3 Title", "1234", "321", "1"},
- {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK_2.mp3", "01", "ID3V2.3 Album",
+ {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK_2.mp3", "01", "ID3V2.3 Album",
"ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", null, "321", "1"},
- {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER.mp3", "01", "ID3V2.3 Album",
+ {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER.mp3", "01", "ID3V2.3 Album",
"ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "321", "1"},
- {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER_2.mp3", "01", "ID3V2.3 Album",
+ {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER_2.mp3", "01", "ID3V2.3 Album",
"ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null,
"Blues", "ID3V2.3 Title", null, "321", "1"},
- {"/sdcard/metaDataTestMedias/MP3/Corrupted_ID3V2_TIT.mp3", null, null, null,
+ {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TIT.mp3", null, null, null,
null, null, null, null, null, null, "577", "1"}
};
public static final String META_DATA_OTHERS [][] = {
- {"/sdcard/metaDataTestMedias/3GP/cat.3gp", null, null, null,
+ {"/sdcard/media_api/metaDataTestMedias/3GP/cat.3gp", null, null, null,
null, null, "20080309T002415.000Z", null,
null, null, "1404928", "2"},
- {"/sdcard/metaDataTestMedias/AMR/AMR_NB.amr", null, null, null,
+ {"/sdcard/media_api/metaDataTestMedias/AMR/AMR_NB.amr", null, null, null,
null, null, null, null,
null, null, "126540", "1"},
- {"/sdcard/metaDataTestMedias/AMRWB/AMR_WB.amr", null, null, null,
+ {"/sdcard/media_api/metaDataTestMedias/AMRWB/AMR_WB.amr", null, null, null,
null, null, null, null,
null, null, "231180", "1"},
- {"/sdcard/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", null, "Suspended Animation",
+ {"/sdcard/media_api/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", null, "Suspended Animation",
"John Petrucci", null, null, "20070510T125223.000Z",
null, null, "2005", "231180", "1"},
- {"/sdcard/metaDataTestMedias/M4V/sample_iPod.m4v", null, null,
+ {"/sdcard/media_api/metaDataTestMedias/M4V/sample_iPod.m4v", null, null,
null, null, null, "20051220T202015.000Z",
null, null, null, "3771392", "2"},
- {"/sdcard/metaDataTestMedias/MIDI/MIDI.mid", null, "Suspended Animation",
+ {"/sdcard/media_api/metaDataTestMedias/MIDI/MIDI.mid", null, "Suspended Animation",
"John Petrucci", null, null, "20070510T125223.000Z",
null, null, "2005", "231180", "1"},
- {"/sdcard/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", null, "mp4 album Kung Fu Panda",
+ {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", null, "mp4 album Kung Fu Panda",
"mp4 artist Kung Fu Panda", null, null, "20080517T091451.000Z",
"Kung Fu Panda", "Kung Fu Panda", "2008", "5667840", "2"},
- {"/sdcard/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation",
+ {"/sdcard/media_api/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation",
"John Petrucci", null, null, "20070510T125223.000Z",
null, null, "2005", "231180", "1"},
- {"/sdcard/metaDataTestMedias/OGG/When You Say Nothing At All.ogg",
+ {"/sdcard/media_api/metaDataTestMedias/OGG/When You Say Nothing At All.ogg",
null, "Suspended Animation", "John Petrucci",
null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1"},
- {"/sdcard/metaDataTestMedias/WAV/Im With You.wav", null, null,
+ {"/sdcard/media_api/metaDataTestMedias/WAV/Im With You.wav", null, null,
null, null, null, null,
null, null, null, "224000", "1"},
- {"/sdcard/metaDataTestMedias/WMA/WMA9.wma", "6", "Ten Songs in the Key of Betrayal",
+ {"/sdcard/media_api/metaDataTestMedias/WMA/WMA9.wma", "6", "Ten Songs in the Key of Betrayal",
"Alien Crime Syndicate", "Alien Crime Syndicate",
"wma 9 Composer", "20040521T175729.483Z",
"Rock", "Run for the Money", "2004", "134479", "1"},
- {"/sdcard/metaDataTestMedias/WMA/WMA10.wma", "09", "wma 10 Album",
+ {"/sdcard/media_api/metaDataTestMedias/WMA/WMA10.wma", "09", "wma 10 Album",
"wma 10 Album Artist", "wma 10 Artist", "wma 10 Composer", "20070705T063625.097Z",
"Acid Jazz", "wma 10 Title", "2010", "126574", "1"},
- {"/sdcard/metaDataTestMedias/WMV/bugs.wmv", "8", "wmv 9 Album",
+ {"/sdcard/media_api/metaDataTestMedias/WMV/bugs.wmv", "8", "wmv 9 Album",
null, "wmv 9 Artist ", null, "20051122T155247.540Z",
null, "Looney Tunes - Hare-Breadth Hurry", "2005", "193482", "2"},
- {"/sdcard/metaDataTestMedias/WMV/clips_ver7.wmv", "50", "wmv 7 Album",
+ {"/sdcard/media_api/metaDataTestMedias/WMV/clips_ver7.wmv", "50", "wmv 7 Album",
null, "Hallau Shoots & Company", null, "20020226T170045.891Z",
null, "CODEC Shootout", "1986", "43709", "2"}
};
@@ -471,9 +473,39 @@ public class MediaNames {
public static final String RECORDED_VIDEO_3GP = "/sdcard/temp.3gp";
+ public static final String INVALD_VIDEO_PATH = "/sdcard/media_api/filepathdoesnotexist" +
+ "/filepathdoesnotexist/temp.3gp";
+
- public static final long RECORDED_TIME = 3000;
+ public static final long RECORDED_TIME = 5000;
public static final long VALID_VIDEO_DURATION = 2000;
-
+ //Videos for the mediaplayer stress test
+ public static String[] H263_STRESS = {
+ "/sdcard/media_api/video_stress/h263/H263_CIF.3gp",
+ "/sdcard/media_api/video_stress/h263/H263_QCIF.3gp",
+ "/sdcard/media_api/video_stress/h263/H263_QVGA.3gp",
+ "/sdcard/media_api/video_stress/h263/H263_SQVGA.3gp"
+ };
+
+ public static String[] MPEG4_STRESS = {
+ "/sdcard/media_api/video_stress/h263/mpeg4_CIF.mp4",
+ "/sdcard/media_api/video_stress/h263/mpeg4_QCIF.3gp",
+ "/sdcard/media_api/video_stress/h263/mpeg4_QVGA.3gp",
+ "/sdcard/media_api/video_stress/h263/mpeg4_SQVGA.mp4"
+ };
+
+ //Streaming test files
+ public static final String STREAM_H264_480_360_1411k =
+ "http://sridharg.googlejunta.com/yslau/stress_media/h264_regular.mp4";
+ public static final String STREAM_WMV =
+ "http://sridharg.googlejunta.com/yslau/stress_media/bugs.wmv";
+ public static final String STREAM_H263_176x144_325k =
+ "http://sridharg.googlejunta.com/yslau/stress_media/h263_regular.3gp";
+ public static final String STREAM_H264_352x288_1536k =
+ "http://sridharg.googlejunta.com/yslau/stress_media/h264_highBitRate.mp4";
+ public static final String STREAM_MP3=
+ "http://sridharg.googlejunta.com/yslau/stress_media/mp3_regular.mp3";
+ public static final String STREAM_MPEG4_QVGA_128k =
+ "http://sridharg.googlejunta.com/yslau/stress_media/mpeg4_qvga_24fps.3gp";
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaRecorderStressTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaRecorderStressTestRunner.java
new file mode 100755
index 0000000..12eacd3
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaRecorderStressTestRunner.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+import com.android.mediaframeworktest.stress.MediaRecorderStressTest;
+
+import junit.framework.TestSuite;
+
+public class MediaRecorderStressTestRunner extends InstrumentationTestRunner {
+
+ @Override
+ public TestSuite getAllTests() {
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(MediaRecorderStressTest.class);
+ return suite;
+ }
+
+ @Override
+ public ClassLoader getLoader() {
+ return MediaRecorderStressTestRunner.class.getClassLoader();
+ }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
index 5981a13..c30db38 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CameraTest.java
@@ -100,6 +100,12 @@ public class CameraTest extends ActivityInstrumentationTestCase<MediaFrameworkTe
*/
private void terminateMessageLooper() {
mLooper.quit();
+ //TODO yslau : take out the sleep until bug#1693519 fix
+ try {
+ Thread.sleep(1000);
+ } catch (Exception e){
+ Log.v(TAG, e.toString());
+ }
mCamera.release();
}
@@ -136,11 +142,13 @@ public class CameraTest extends ActivityInstrumentationTestCase<MediaFrameworkTe
//Implement the RawPictureCallback
private final class RawPictureCallback implements PictureCallback {
public void onPictureTaken(byte [] rawData, Camera camera) {
- if (rawData != null) {
- rawPictureCallbackResult = true;
- } else {
- rawPictureCallbackResult = false;
- }
+ // no support for raw data - success if we get the callback
+ rawPictureCallbackResult = true;
+ //if (rawData != null) {
+ // rawPictureCallbackResult = true;
+ //} else {
+ // rawPictureCallbackResult = false;
+ //}
Log.v(TAG, "RawPictureCallback callback");
}
};
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
index 0e88719..caba47c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
@@ -28,6 +28,7 @@ import android.graphics.BitmapFactory;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
+import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
@@ -39,6 +40,16 @@ import java.io.InputStream;
*/
public class CodecTest {
private static String TAG = "MediaPlayerApiTest";
+ private static MediaPlayer mMediaPlayer;
+ private MediaPlayer.OnPreparedListener mOnPreparedListener;
+
+ private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000; //10 seconds max.
+ private static boolean mInitialized = false;
+ private static Looper mLooper = null;
+ private static final Object lock = new Object();
+ private static final Object prepareDone = new Object();
+ private static boolean onPrepareSuccess = false;
+
public static String printCpuInfo(){
String cm = "dumpsys cpuinfo";
@@ -573,5 +584,89 @@ public class CodecTest {
return true;
}
+
+ /*
+ * Initializes the message looper so that the mediaPlayer object can
+ * receive the callback messages.
+ */
+ private static void initializeMessageLooper() {
+ Log.v(TAG, "start looper");
+ new Thread() {
+ @Override
+ public void run() {
+ // Set up a looper to be used by camera.
+ Looper.prepare();
+ Log.v(TAG, "start loopRun");
+ // Save the looper so that we can terminate this thread
+ // after we are done with it.
+ mLooper = Looper.myLooper();
+ mMediaPlayer = new MediaPlayer();
+ synchronized (lock) {
+ mInitialized = true;
+ lock.notify();
+ }
+ Looper.loop(); // Blocks forever until Looper.quit() is called.
+ Log.v(TAG, "initializeMessageLooper: quit.");
+ }
+ }.start();
+ }
+
+ /*
+ * Terminates the message looper thread.
+ */
+ private static void terminateMessageLooper() {
+ mLooper.quit();
+ mMediaPlayer.release();
+ }
+
+ static MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
+ public void onPrepared(MediaPlayer mp) {
+ synchronized (prepareDone) {
+ Log.v(TAG, "notify the prepare callback");
+ prepareDone.notify();
+ onPrepareSuccess = true;
+ }
+ }
+ };
+
+ public static boolean prepareAsyncCallback(String filePath) throws Exception {
+ int videoWidth = 0;
+ int videoHeight = 0;
+ boolean checkVideoDimension = false;
+
+ initializeMessageLooper();
+ synchronized (lock) {
+ try {
+ lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+ } catch(Exception e) {
+ Log.v(TAG, "looper was interrupted.");
+ return false;
+ }
+ }
+ try{
+ mMediaPlayer.setOnPreparedListener(mPreparedListener);
+ mMediaPlayer.setDataSource(filePath);
+ mMediaPlayer.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder());
+ mMediaPlayer.prepareAsync();
+ synchronized (prepareDone) {
+ try {
+ prepareDone.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+ Log.v(TAG, "setPreview done");
+ } catch (Exception e) {
+ Log.v(TAG, "wait was interrupted.");
+ }
+ }
+ videoWidth = mMediaPlayer.getVideoWidth();
+ videoHeight = mMediaPlayer.getVideoHeight();
+
+ terminateMessageLooper();
+ }catch (Exception e){
+ Log.v(TAG,e.getMessage());
+ }
+ return onPrepareSuccess;
+ }
+
+
+
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
new file mode 100644
index 0000000..05ac408
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
@@ -0,0 +1,1215 @@
+/*
+ * 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 com.android.mediaframeworktest.MediaFrameworkTest;
+import com.android.mediaframeworktest.MediaNames;
+
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+/**
+ * Junit / Instrumentation test case for the media AudioTrack api
+
+ */
+public class MediaAudioTrackTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
+ private String TAG = "MediaAudioTrackTest";
+
+ public MediaAudioTrackTest() {
+ super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ private static void assumeTrue(String message, boolean cond) {
+ assertTrue("(assume)"+message, cond);
+ }
+
+ private void log(String testName, String message) {
+ Log.v(TAG, "["+testName+"] "+message);
+ }
+
+ private void loge(String testName, String message) {
+ Log.e(TAG, "["+testName+"] "+message);
+ }
+
+ //-----------------------------------------------------------------
+ // private class to hold test reslts
+ public class TestResults {
+ public boolean mResult = false;
+ public String mResultLog = "";
+ public TestResults(boolean b, String s) { mResult = b; mResultLog = s; }
+ }
+
+ //-----------------------------------------------------------------
+ // generic test methods
+ public TestResults constructorTestMultiSampleRate(
+ // parameters tested by this method
+ int _inTest_streamType, int _inTest_mode,
+ int _inTest_config, int _inTest_format,
+ // parameter-dependent expected results
+ int _expected_stateForMode) {
+
+ int[] testSampleRates = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000};
+ String failedRates = "Failure for rate(s): ";
+ boolean localRes, finalRes = true;
+
+ for (int i = 0 ; i < testSampleRates.length ; i++) {
+ //Log.v("MediaAudioTrackTest", "[ constructorTestMultiSampleRate ] testing "+ testSampleRates[i]);
+ AudioTrack track = null;
+ try {
+ track = new AudioTrack(
+ _inTest_streamType,
+ testSampleRates[i],
+ _inTest_config,
+ _inTest_format,
+ AudioTrack.getMinBufferSize(testSampleRates[i],
+ _inTest_config, _inTest_format),
+ _inTest_mode);
+ } catch(IllegalArgumentException iae) {
+ Log.e("MediaAudioTrackTest", "[ constructorTestMultiSampleRate ] exception at SR "
+ + testSampleRates[i]+": \n" + iae);
+ localRes = false;
+ }
+ if (track != null) {
+ localRes = (track.getState() == _expected_stateForMode);
+ track.release();
+ }
+ else {
+ localRes = false;
+ }
+
+ if (!localRes) {
+ //log the error for the test runner
+ failedRates += Integer.toString(testSampleRates[i]) + "Hz ";
+ //log the error for logcat
+ log("constructorTestMultiSampleRate", "failed to construct "
+ +"AudioTrack(streamType="+_inTest_streamType
+ +", sampleRateInHz=" + testSampleRates[i]
+ +", channelConfig=" + _inTest_config
+ +", audioFormat=" + _inTest_format
+ +", bufferSizeInBytes=" + AudioTrack.getMinBufferSize(testSampleRates[i],
+ _inTest_config, AudioFormat.ENCODING_PCM_16BIT)
+ +", mode="+ _inTest_mode );
+ //mark test as failed
+ finalRes = false;
+ }
+ }
+ return new TestResults(finalRes, failedRates);
+ }
+
+ //-----------------------------------------------------------------
+ // AUDIOTRACK TESTS:
+ //----------------------------------
+
+ //-----------------------------------------------------------------
+ // AudioTrack constructor and AudioTrack.getMinBufferSize(...) for 16bit PCM
+ //----------------------------------
+
+ //Test case 1: constructor for streaming AudioTrack, mono, 16bit at misc valid sample rates
+ @LargeTest
+ public void testConstructorMono16MusicStream() throws Exception {
+
+ TestResults res = constructorTestMultiSampleRate(
+ AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
+ AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioTrack.STATE_INITIALIZED);
+
+ assertTrue("testConstructorMono16MusicStream: " + res.mResultLog, res.mResult);
+ }
+
+
+ //Test case 2: constructor for streaming AudioTrack, stereo, 16bit at misc valid sample rates
+ @LargeTest
+ public void testConstructorStereo16MusicStream() throws Exception {
+
+ TestResults res = constructorTestMultiSampleRate(
+ AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
+ AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioTrack.STATE_INITIALIZED);
+
+ assertTrue("testConstructorStereo16MusicStream: " + res.mResultLog, res.mResult);
+ }
+
+
+ //Test case 3: constructor for static AudioTrack, mono, 16bit at misc valid sample rates
+ @LargeTest
+ public void testConstructorMono16MusicStatic() throws Exception {
+
+ TestResults res = constructorTestMultiSampleRate(
+ AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
+ AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioTrack.STATE_NO_STATIC_DATA);
+
+ assertTrue("testConstructorMono16MusicStatic: " + res.mResultLog, res.mResult);
+ }
+
+
+ //Test case 4: constructor for static AudioTrack, stereo, 16bit at misc valid sample rates
+ @LargeTest
+ public void testConstructorStereo16MusicStatic() throws Exception {
+
+ TestResults res = constructorTestMultiSampleRate(
+ AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
+ AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioTrack.STATE_NO_STATIC_DATA);
+
+ assertTrue("testConstructorStereo16MusicStatic: " + res.mResultLog, res.mResult);
+ }
+
+
+ //-----------------------------------------------------------------
+ // AudioTrack constructor and AudioTrack.getMinBufferSize(...) for 8bit PCM
+ //----------------------------------
+
+ //Test case 1: constructor for streaming AudioTrack, mono, 8bit at misc valid sample rates
+ @LargeTest
+ public void testConstructorMono8MusicStream() throws Exception {
+
+ TestResults res = constructorTestMultiSampleRate(
+ AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
+ AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioTrack.STATE_INITIALIZED);
+
+ assertTrue("testConstructorMono8MusicStream: " + res.mResultLog, res.mResult);
+ }
+
+ //Test case 2: constructor for streaming AudioTrack, stereo, 8bit at misc valid sample rates
+ @LargeTest
+ public void testConstructorStereo8MusicStream() throws Exception {
+
+ TestResults res = constructorTestMultiSampleRate(
+ AudioManager.STREAM_MUSIC, AudioTrack.MODE_STREAM,
+ AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioTrack.STATE_INITIALIZED);
+
+ assertTrue("testConstructorStereo8MusicStream: " + res.mResultLog, res.mResult);
+ }
+
+ //Test case 3: constructor for static AudioTrack, mono, 8bit at misc valid sample rates
+ @LargeTest
+ public void testConstructorMono8MusicStatic() throws Exception {
+
+ TestResults res = constructorTestMultiSampleRate(
+ AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
+ AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioTrack.STATE_NO_STATIC_DATA);
+
+ assertTrue("testConstructorMono8MusicStatic: " + res.mResultLog, res.mResult);
+ }
+
+ //Test case 4: constructor for static AudioTrack, stereo, 8bit at misc valid sample rates
+ @LargeTest
+ public void testConstructorStereo8MusicStatic() throws Exception {
+
+ TestResults res = constructorTestMultiSampleRate(
+ AudioManager.STREAM_MUSIC, AudioTrack.MODE_STATIC,
+ AudioFormat.CHANNEL_CONFIGURATION_STEREO, AudioFormat.ENCODING_PCM_8BIT,
+ AudioTrack.STATE_NO_STATIC_DATA);
+
+ assertTrue("testConstructorStereo8MusicStatic: " + res.mResultLog, res.mResult);
+ }
+
+
+ //-----------------------------------------------------------------
+ // AudioTrack constructor for all stream types
+ //----------------------------------
+
+ //Test case 1: constructor for all stream types
+ @LargeTest
+ public void testConstructorStreamType() throws Exception {
+ // constants for test
+ final int TYPE_TEST_SR = 22050;
+ final int TYPE_TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TYPE_TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TYPE_TEST_MODE = AudioTrack.MODE_STREAM;
+ final int[] STREAM_TYPES = { AudioManager.STREAM_ALARM, AudioManager.STREAM_BLUETOOTH_SCO,
+ AudioManager.STREAM_MUSIC, AudioManager.STREAM_NOTIFICATION,
+ AudioManager.STREAM_RING, AudioManager.STREAM_SYSTEM,
+ AudioManager.STREAM_VOICE_CALL };
+ final String[] STREAM_NAMES = { "STREAM_ALARM", "STREAM_BLUETOOTH_SCO", "STREAM_MUSIC",
+ "STREAM_NOTIFICATION", "STREAM_RING", "STREAM_SYSTEM", "STREAM_VOICE_CALL" };
+
+ boolean localTestRes = true;
+ AudioTrack track = null;
+ // test: loop constructor on all stream types
+ for (int i = 0 ; i < STREAM_TYPES.length ; i++)
+ {
+ try {
+ //-------- initialization --------------
+ track = new AudioTrack(STREAM_TYPES[i],
+ TYPE_TEST_SR, TYPE_TEST_CONF, TYPE_TEST_FORMAT,
+ AudioTrack.getMinBufferSize(TYPE_TEST_SR, TYPE_TEST_CONF, TYPE_TEST_FORMAT),
+ TYPE_TEST_MODE);
+ } catch (IllegalArgumentException iae) {
+ loge("testConstructorStreamType", "exception for stream type "
+ + STREAM_NAMES[i] + ": "+ iae);
+ localTestRes = false;
+ }
+ //-------- test --------------
+ if (track != null) {
+ if (track.getState() != AudioTrack.STATE_INITIALIZED) {
+ localTestRes = false;
+ Log.e("MediaAudioTrackTest",
+ "[ testConstructorStreamType ] failed for stream type "+STREAM_NAMES[i]);
+ }
+ //-------- tear down --------------
+ track.release();
+ }
+ else {
+ localTestRes = false;
+ }
+ }
+
+ assertTrue("testConstructorStreamType", localTestRes);
+ }
+
+
+ //-----------------------------------------------------------------
+ // Playback head position
+ //----------------------------------
+
+ //Test case 1: getPlaybackHeadPosition() at 0 after initialization
+ @LargeTest
+ public void testPlaybackHeadPositionAfterInit() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testPlaybackHeadPositionAfterInit";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT), TEST_MODE);
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME, track.getPlaybackHeadPosition() == 0);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 2: getPlaybackHeadPosition() increases after play()
+ @LargeTest
+ public void testPlaybackHeadPositionIncrease() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testPlaybackHeadPositionIncrease";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ track.play();
+ Thread.sleep(100);
+ log(TEST_NAME, "position ="+ track.getPlaybackHeadPosition());
+ assertTrue(TEST_NAME, track.getPlaybackHeadPosition() > 0);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 3: getPlaybackHeadPosition() is 0 after flush();
+ @LargeTest
+ public void testPlaybackHeadPositionAfterFlush() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testPlaybackHeadPositionAfterFlush";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ track.play();
+ Thread.sleep(100);
+ track.stop();
+ track.flush();
+ log(TEST_NAME, "position ="+ track.getPlaybackHeadPosition());
+ assertTrue(TEST_NAME, track.getPlaybackHeadPosition() == 0);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 3: getPlaybackHeadPosition() is 0 after stop();
+ @LargeTest
+ public void testPlaybackHeadPositionAfterStop() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testPlaybackHeadPositionAfterStop";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ track.play();
+ Thread.sleep(100);
+ track.stop();
+ Thread.sleep(100); // TODO: what is a sensible value?
+ int pos = track.getPlaybackHeadPosition();
+ log(TEST_NAME, "position ="+ pos);
+ assertTrue(TEST_NAME, pos == 0);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 4: getPlaybackHeadPosition() is > 0 after play(); pause();
+ @LargeTest
+ public void testPlaybackHeadPositionAfterPause() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testPlaybackHeadPositionAfterPause";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ track.play();
+ Thread.sleep(100);
+ track.pause();
+ int pos = track.getPlaybackHeadPosition();
+ log(TEST_NAME, "position ="+ pos);
+ assertTrue(TEST_NAME, pos > 0);
+ //-------- tear down --------------
+ track.release();
+ }
+
+
+ //-----------------------------------------------------------------
+ // Playback properties
+ //----------------------------------
+
+ //Test case 1: setStereoVolume() with max volume returns SUCCESS
+ @LargeTest
+ public void testSetStereoVolumeMax() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetStereoVolumeMax";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize/2];
+ //-------- test --------------
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ track.play();
+ float maxVol = AudioTrack.getMaxVolume();
+ assertTrue(TEST_NAME, track.setStereoVolume(maxVol, maxVol) == AudioTrack.SUCCESS);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 2: setStereoVolume() with min volume returns SUCCESS
+ @LargeTest
+ public void testSetStereoVolumeMin() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetStereoVolumeMin";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize/2];
+ //-------- test --------------
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ track.play();
+ float minVol = AudioTrack.getMinVolume();
+ assertTrue(TEST_NAME, track.setStereoVolume(minVol, minVol) == AudioTrack.SUCCESS);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 3: setStereoVolume() with mid volume returns SUCCESS
+ @LargeTest
+ public void testSetStereoVolumeMid() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetStereoVolumeMid";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize/2];
+ //-------- test --------------
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ track.play();
+ float midVol = (AudioTrack.getMaxVolume() - AudioTrack.getMinVolume()) / 2;
+ assertTrue(TEST_NAME, track.setStereoVolume(midVol, midVol) == AudioTrack.SUCCESS);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 4: setPlaybackRate() with half the content rate returns SUCCESS
+ @LargeTest
+ public void testSetPlaybackRate() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetPlaybackRate";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize/2];
+ //-------- test --------------
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ track.play();
+ assertTrue(TEST_NAME, track.setPlaybackRate((int)(TEST_SR/2)) == AudioTrack.SUCCESS);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 5: setPlaybackRate(0) returns bad value error
+ @LargeTest
+ public void testSetPlaybackRateZero() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetPlaybackRateZero";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME, track.setPlaybackRate(0) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 6: setPlaybackRate() accepts values twice the output sample rate
+ @LargeTest
+ public void testSetPlaybackRateTwiceOutputSR() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetPlaybackRateTwiceOutputSR";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize/2];
+ int outputSR = AudioTrack.getNativeOutputSampleRate(TEST_STREAM_TYPE);
+ //-------- test --------------
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ track.play();
+ assertTrue(TEST_NAME, track.setPlaybackRate(2*outputSR) == AudioTrack.SUCCESS);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 7: setPlaybackRate() and retrieve value, should be the same for half the content SR
+ @LargeTest
+ public void testSetGetPlaybackRate() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetGetPlaybackRate";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize/2];
+ //-------- test --------------
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ track.play();
+ track.setPlaybackRate((int)(TEST_SR/2));
+ assertTrue(TEST_NAME, track.getPlaybackRate() == (int)(TEST_SR/2));
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 8: setPlaybackRate() invalid operation if track not initialized
+ @LargeTest
+ public void testSetPlaybackRateUninit() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetPlaybackRateUninit";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STATIC;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_NO_STATIC_DATA);
+ assertTrue(TEST_NAME,
+ track.setPlaybackRate(TEST_SR/2) == AudioTrack.ERROR_INVALID_OPERATION);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //-----------------------------------------------------------------
+ // Playback progress
+ //----------------------------------
+
+ //Test case 1: setPlaybackHeadPosition() on playing track
+ @LargeTest
+ public void testSetPlaybackHeadPositionPlaying() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetPlaybackHeadPositionPlaying";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ track.play();
+ assertTrue(TEST_NAME,
+ track.setPlaybackHeadPosition(10) == AudioTrack.ERROR_INVALID_OPERATION);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 2: setPlaybackHeadPosition() on stopped track
+ @LargeTest
+ public void testSetPlaybackHeadPositionStopped() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetPlaybackHeadPositionStopped";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ track.play();
+ track.stop();
+ assumeTrue(TEST_NAME, track.getPlayState() == AudioTrack.PLAYSTATE_STOPPED);
+ assertTrue(TEST_NAME, track.setPlaybackHeadPosition(10) == AudioTrack.SUCCESS);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 3: setPlaybackHeadPosition() on paused track
+ @LargeTest
+ public void testSetPlaybackHeadPositionPaused() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetPlaybackHeadPositionPaused";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ track.play();
+ track.pause();
+ assumeTrue(TEST_NAME, track.getPlayState() == AudioTrack.PLAYSTATE_PAUSED);
+ assertTrue(TEST_NAME, track.setPlaybackHeadPosition(10) == AudioTrack.SUCCESS);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 4: setPlaybackHeadPosition() beyond what has been written
+ @LargeTest
+ public void testSetPlaybackHeadPositionTooFar() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetPlaybackHeadPositionTooFar";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ // make up a frame index that's beyond what has been written: go from buffer size to frame
+ // count (given the audio track properties), and add 77.
+ int frameIndexTooFar = (2*minBuffSize/2) + 77;
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ track.write(data, 0, data.length);
+ track.write(data, 0, data.length);
+ track.play();
+ track.stop();
+ assumeTrue(TEST_NAME, track.getPlayState() == AudioTrack.PLAYSTATE_STOPPED);
+ assertTrue(TEST_NAME, track.setPlaybackHeadPosition(frameIndexTooFar) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+
+ //Test case 5: setLoopPoints() fails for MODE_STREAM
+ @LargeTest
+ public void testSetLoopPointsStream() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetLoopPointsStream";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ track.write(data, 0, data.length);
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME, track.setLoopPoints(2, 50, 2) == AudioTrack.ERROR_INVALID_OPERATION);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 6: setLoopPoints() fails start > end
+ @LargeTest
+ public void testSetLoopPointsStartAfterEnd() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetLoopPointsStartAfterEnd";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STATIC;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ track.write(data, 0, data.length);
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME, track.setLoopPoints(50, 0, 2) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 6: setLoopPoints() success
+ @LargeTest
+ public void testSetLoopPointsSuccess() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetLoopPointsSuccess";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STATIC;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ track.write(data, 0, data.length);
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME, track.setLoopPoints(0, 50, 2) == AudioTrack.SUCCESS);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 7: setLoopPoints() fails with loop length bigger than content
+ @LargeTest
+ public void testSetLoopPointsLoopTooLong() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetLoopPointsLoopTooLong";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STATIC;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ int dataSizeInFrames = minBuffSize/2;
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_NO_STATIC_DATA);
+ track.write(data, 0, data.length);
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.setLoopPoints(10, dataSizeInFrames+20, 2) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+ //Test case 8: setLoopPoints() fails with start beyond what can be written for the track
+ @LargeTest
+ public void testSetLoopPointsStartTooFar() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetLoopPointsStartTooFar";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STATIC;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ int dataSizeInFrames = minBuffSize/2;//16bit data
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_NO_STATIC_DATA);
+ track.write(data, 0, data.length);
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.setLoopPoints(dataSizeInFrames+20, dataSizeInFrames+50, 2)
+ == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 9: setLoopPoints() fails with end beyond what can be written for the track
+ @LargeTest
+ public void testSetLoopPointsEndTooFar() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetLoopPointsEndTooFar";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STATIC;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ int dataSizeInFrames = minBuffSize/2;//16bit data
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_NO_STATIC_DATA);
+ track.write(data, 0, data.length);
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.setLoopPoints(dataSizeInFrames-10, dataSizeInFrames+50, 2)
+ == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+
+ //-----------------------------------------------------------------
+ // Audio data supply
+ //----------------------------------
+
+ //Test case 1: write() fails when supplying less data (bytes) than declared
+ @LargeTest
+ public void testWriteByteOffsetTooBig() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByteOffsetTooBig";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 10, data.length) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 2: write() fails when supplying less data (shorts) than declared
+ @LargeTest
+ public void testWriteShortOffsetTooBig() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShortOffsetTooBig";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 10, data.length) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 3: write() fails when supplying less data (bytes) than declared
+ @LargeTest
+ public void testWriteByteSizeTooBig() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByteSizeTooBig";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length + 10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 4: write() fails when supplying less data (shorts) than declared
+ @LargeTest
+ public void testWriteShortSizeTooBig() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShortSizeTooBig";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length + 10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 5: write() fails with negative offset
+ @LargeTest
+ public void testWriteByteNegativeOffset() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByteNegativeOffset";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, -10, data.length - 10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 6: write() fails with negative offset
+ @LargeTest
+ public void testWriteShortNegativeOffset() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShortNegativeOffset";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, -10, data.length - 10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 7: write() fails with negative size
+ @LargeTest
+ public void testWriteByteNegativeSize() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByteNegativeSize";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, -10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 8: write() fails with negative size
+ @LargeTest
+ public void testWriteShortNegativeSize() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShortNegativeSize";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, -10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 9: write() succeeds and returns the size that was written for 16bit
+ @LargeTest
+ public void testWriteByte() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByte";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length) == data.length);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 10: write() succeeds and returns the size that was written for 16bit
+ @LargeTest
+ public void testWriteShort() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShort";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length) == data.length);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 11: write() succeeds and returns the size that was written for 8bit
+ @LargeTest
+ public void testWriteByte8bit() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByte8bit";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length) == data.length);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 12: write() succeeds and returns the size that was written for 8bit
+ @LargeTest
+ public void testWriteShort8bit() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShort8bit";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length) == data.length);
+ //-------- tear down --------------
+ track.release();
+ }
+
+}
+
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
index 20f213e..ee6a727 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
@@ -52,7 +52,8 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFra
return true;
}
-
+
+
//Audio
//Wait for PV bugs for MP3 duration
@MediumTest
@@ -385,9 +386,6 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFra
assertTrue("WMV SeekTo", isSeek);
}
- //TODO(elaurent)
- //reactivate the test until bug#1495237 fix
- @Suppress
@LargeTest
public void testSoundRecord() throws Exception {
boolean isRecordered = CodecTest.mediaRecorderRecord(MediaNames.RECORDER_OUTPUT);
@@ -413,8 +411,6 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFra
assertTrue("Play mp3 from resources", mp3Resources);
}
- //Bug# 1422662
- @Suppress
@MediumTest
public void testPrepareAsyncReset() throws Exception {
boolean isReset = CodecTest.prepareAsyncReset(MediaNames.STREAM_LARGE_MP3);
@@ -432,5 +428,19 @@ public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFra
boolean isLooping = CodecTest.isLoopingAfterReset(MediaNames.AMR);
assertTrue("isLooping after reset", isLooping);
}
+
+ @LargeTest
+ public void testLocalMp3PrepareAsyncCallback() throws Exception {
+ boolean onPrepareSuccess =
+ CodecTest.prepareAsyncCallback(MediaNames.VIDEO_H263_AMR);
+ assertTrue("LocalMp3prepareAsyncCallback", onPrepareSuccess);
+ }
+
+ @LargeTest
+ public void testStreamPrepareAsyncCallback() throws Exception {
+ boolean onPrepareSuccess =
+ CodecTest.prepareAsyncCallback(MediaNames.STREAM_H264_480_360_1411k);
+ assertTrue("StreamH264PrepareAsyncCallback", onPrepareSuccess);
+ }
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
index d970f5e..65451c5 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
@@ -35,8 +35,7 @@ import android.test.suitebuilder.annotation.Suppress;
/**
- * Junit / Instrumentation test case for the media recorder api
-
+ * Junit / Instrumentation test case for the media recorder api
*/
public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFrameworkTest> {
private String TAG = "MediaRecorderTest";
@@ -60,12 +59,48 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
}
private void recordVideo(int frameRate, int width, int height,
- int videoFormat, int outFormat, String outFile, boolean videoOnly){
+ int videoFormat, int outFormat, String outFile, boolean videoOnly) {
Log.v(TAG,"startPreviewAndPrepareRecording");
- try{
- if (!videoOnly){
+ try {
+ if (!videoOnly) {
+ Log.v(TAG, "setAudioSource");
+ mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ }
+ mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+ mRecorder.setOutputFormat(outFormat);
+ Log.v(TAG, "output format " + outFormat);
+ mRecorder.setOutputFile(outFile);
+ mRecorder.setVideoFrameRate(frameRate);
+ mRecorder.setVideoSize(width, height);
+ Log.v(TAG, "setEncoder");
+ mRecorder.setVideoEncoder(videoFormat);
+ if (!videoOnly) {
+ mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+ }
+ mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+ Log.v(TAG, "setPreview");
+ mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
+ Log.v(TAG, "prepare");
+ mRecorder.prepare();
+ Log.v(TAG, "start");
+ mRecorder.start();
+ Thread.sleep(MediaNames.RECORDED_TIME);
+ Log.v(TAG, "stop");
+ mRecorder.stop();
+ mRecorder.release();
+ } catch (Exception e) {
+ Log.v("record video failed ", e.toString());
+ mRecorder.release();
+ }
+ }
+
+
+ private boolean invalidRecordSetting(int frameRate, int width, int height,
+ int videoFormat, int outFormat, String outFile, boolean videoOnly) {
+ try {
+ if (!videoOnly) {
Log.v(TAG, "setAudioSource");
- //mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
}
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mRecorder.setOutputFormat(outFormat);
@@ -75,8 +110,8 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
mRecorder.setVideoSize(width, height);
Log.v(TAG, "setEncoder");
mRecorder.setVideoEncoder(videoFormat);
- if (!videoOnly){
- // mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+ if (!videoOnly) {
+ mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
}
mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
Log.v(TAG, "setPreview");
@@ -88,16 +123,21 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
Thread.sleep(MediaNames.RECORDED_TIME);
Log.v(TAG, "stop");
mRecorder.stop();
- mRecorder.reset();
mRecorder.release();
- } catch (Exception e){
+ } catch (Exception e) {
Log.v("record video failed ", e.toString());
+ mRecorder.release();
+ Log.v(TAG, "reset and release");
+ return true;
}
+ return false;
}
- private void getOutputVideoProperty(String outputFilePath){
+
+
+ private void getOutputVideoProperty(String outputFilePath) {
MediaPlayer mediaPlayer = new MediaPlayer();
- try{
+ try {
mediaPlayer.setDataSource(outputFilePath);
Log.v(TAG, "file Path = " + outputFilePath);
mediaPlayer.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder());
@@ -111,19 +151,20 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
mediaPlayer.release();
} catch (Exception e) {
Log.v(TAG, e.toString());
+ mediaPlayer.release();
}
}
- private void removeFile(String filePath){
+ private void removeFile(String filePath) {
File fileRemove = new File(filePath);
fileRemove.delete();
}
- private boolean validateVideo(String filePath, int width, int height){
+ private boolean validateVideo(String filePath, int width, int height) {
boolean validVideo = false;
getOutputVideoProperty(filePath);
if (mOutputVideoWidth == width && mOutputVideoHeight == height &&
- mOutputDuration > MediaNames.VALID_VIDEO_DURATION ){
+ mOutputDuration > MediaNames.VALID_VIDEO_DURATION ) {
validVideo = true;
}
Log.v(TAG, "width = " + mOutputVideoWidth + " height = " + mOutputVideoHeight + " Duration = " + mOutputDuration);
@@ -143,7 +184,7 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
}
//Format: QVGA h263
- @Suppress
+ @LargeTest
public void testQVGAH263() throws Exception {
boolean videoRecordedResult = false;
recordVideo(15, 320, 240, MediaRecorder.VideoEncoder.H263,
@@ -153,7 +194,7 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
}
//Format: SQVGA h263
- @Suppress
+ @LargeTest
public void testSQVGAH263() throws Exception {
boolean videoRecordedResult = false;
recordVideo(15, 240, 160, MediaRecorder.VideoEncoder.H263,
@@ -184,14 +225,12 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
- @Suppress
+ @LargeTest
public void testVideoOnly() throws Exception {
boolean videoRecordedResult = false;
- for (int i=0; i< 10; i++){
recordVideo(15, 176, 144, MediaRecorder.VideoEncoder.H263,
MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true);
videoRecordedResult = validateVideo(MediaNames.RECORDED_VIDEO_3GP, 176, 144);
- }
assertTrue("QCIFH263 Video Only", videoRecordedResult);
}
@@ -204,7 +243,7 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
assertTrue("PortraitH263", videoRecordedResult);
}
- @LargeTest
+ @Suppress
public void testHVGAMP4() throws Exception {
boolean videoRecordedResult = false;
recordVideo(15, 480, 320, MediaRecorder.VideoEncoder.MPEG_4_SP,
@@ -242,7 +281,7 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
}
- //Format: CIF h263
+ //Format: CIF MP4
@LargeTest
public void testCIFMP4() throws Exception {
boolean videoRecordedResult = false;
@@ -253,14 +292,14 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
}
- //Format: CIF h263 outputforma 3gpp
+ //Format: CIF MP4 output format 3gpp
@LargeTest
public void testCIFMP43GPP() throws Exception {
boolean videoRecordedResult = false;
recordVideo(15, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP,
MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false);
videoRecordedResult = validateVideo(MediaNames.RECORDED_VIDEO_3GP, 352, 288);
- assertTrue("CIFH263", videoRecordedResult);
+ assertTrue("CIFMP4 3GPP", videoRecordedResult);
}
@LargeTest
@@ -272,5 +311,29 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
assertTrue("QCIFH263 3GPP", videoRecordedResult);
}
+ @LargeTest
+ public void testInvalidVideoPath() throws Exception {
+ boolean isTestInvalidVideoPathSuccessful = false;
+ isTestInvalidVideoPathSuccessful = invalidRecordSetting(15, 176, 144, MediaRecorder.VideoEncoder.H263,
+ MediaRecorder.OutputFormat.THREE_GPP, MediaNames.INVALD_VIDEO_PATH, false);
+ assertTrue("Invalid outputFile Path", isTestInvalidVideoPathSuccessful);
+ }
+
+ @Suppress
+ public void testInvalidVideoSize() throws Exception {
+ boolean isTestInvalidVideoSizeSuccessful = false;
+ isTestInvalidVideoSizeSuccessful = invalidRecordSetting(15, 800, 600, MediaRecorder.VideoEncoder.H263,
+ MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false);
+ assertTrue("Invalid video Size", isTestInvalidVideoSizeSuccessful);
+ }
+
+ @LargeTest
+ public void testInvalidFrameRate() throws Exception {
+ boolean isTestInvalidFrameRateSuccessful = false;
+ isTestInvalidFrameRateSuccessful = invalidRecordSetting(50, 176, 144, MediaRecorder.VideoEncoder.H263,
+ MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false);
+ assertTrue("Invalid FrameRate", isTestInvalidFrameRateSuccessful);
+ }
+
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java
index 0209305..da18e74 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java
@@ -88,7 +88,7 @@ import android.media.AudioManager;
toneGen = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
- for (type = ToneGenerator.TONE_PROP_BEEP; type <= ToneGenerator.TONE_PROP_PROMPT; type++) {
+ for (type = ToneGenerator.TONE_PROP_BEEP; type <= ToneGenerator.TONE_PROP_BEEP2; type++) {
if (toneGen.startTone(type)) {
Thread.sleep(1000);
toneGen.stopTone();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index b606f25..2f0173d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -1,17 +1,17 @@
/*
* 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
- *
+ *
+ * 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.
+ * 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.performance;
@@ -19,141 +19,358 @@ package com.android.mediaframeworktest.performance;
import com.android.mediaframeworktest.MediaFrameworkTest;
import com.android.mediaframeworktest.MediaNames;
-import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.media.MediaPlayer;
+import android.media.MediaRecorder;
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
+import android.view.SurfaceHolder;
import java.io.FileDescriptor;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.BufferedWriter;
+
import android.media.MediaMetadataRetriever;
/**
- * Junit / Instrumentation test case for the media player api
-
- */
-public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<MediaFrameworkTest> {
-
-
- private boolean mIsPlaying = true;
- private String TAG = "MediaPlayerApiTest";
- Context mContext;
- private SQLiteDatabase mDB;
-
-
- public MediaPlayerPerformance() {
- super("com.android.mediaframeworktest", MediaFrameworkTest.class);
- }
+ * Junit / Instrumentation - performance measurement for media player and
+ * recorder
+ */
+public class MediaPlayerPerformance extends ActivityInstrumentationTestCase<MediaFrameworkTest> {
+
+ private String TAG = "MediaFrameworkPerformance";
+
+ private SQLiteDatabase mDB;
+ private SurfaceHolder mSurfaceHolder = null;
+ private static final int NUM_STRESS_LOOP = 10;
+ private static final int NUM_PLAYBACk_IN_EACH_LOOP = 20;
+ private static final long MEDIA_STRESS_WAIT_TIME = 5000; //5 seconds
+ private static final String H263_VIDEO_PLAYBACK_MEMOUT =
+ "/sdcard/h263VideoPlaybackMemOut.txt";
+ private static final String H264_VIDEO_PLAYBACK_MEMOUT =
+ "/sdcard/h264VideoPlaybackMemOut.txt";
+ private static final String WMV_VIDEO_PLAYBACK_MEMOUT =
+ "/sdcard/WmvVideoPlaybackMemOut.txt";
+ private static final String H263_VIDEO_ONLY_RECORD_MEMOUT =
+ "/sdcard/recordH263VideoOnlyMemOut.txt";
+ private static final String MP4_VIDEO_ONLY_RECORD_MEMOUT =
+ "/sdcard/recordMPEG4VideoOnlyMemOut.txt";
+ private static final String H263_VIDEO_AUDIO_RECORD_MEMOUT =
+ "/sdcard/recordVideoH263AudioMemOut.txt";
+ private static final String AUDIO_ONLY_RECORD_MEMOUT =
+ "/sdcard/recordAudioOnlyMemOut.txt";
+
+
+ public MediaPlayerPerformance() {
+ super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+ }
protected void setUp() throws Exception {
-
- super.setUp();
- }
-
- public void createDB(){
- mDB = SQLiteDatabase.openOrCreateDatabase("/sdcard/perf.db",null);
- mDB.execSQL("CREATE TABLE perfdata (_id INTEGER PRIMARY KEY,"
- + "file TEXT," + "setdatatime LONG," +"preparetime LONG," +"playtime LONG" + ");");
- }
-
- public void audioPlaybackStartupTime(String[] testFile){
- long t1 = 0;
- long t2 = 0;
- long t3 = 0;
- long t4 =0;
-
- long setDataSourceDuration = 0;
- long prepareDuration = 0;
- long startDuration=0;
-
- long totalSetDataTime=0;
- long totalPrepareTime=0;
- long totalStartDuration=0;
-
- int numberOfFiles = testFile.length;
- Log.v(TAG, "File lenght " + numberOfFiles);
- for (int k=0; k<numberOfFiles; k++){
- MediaPlayer mp = new MediaPlayer();
- try{
- t1 = SystemClock.uptimeMillis();
- FileInputStream fis = new FileInputStream(testFile[k]);
- FileDescriptor fd = fis.getFD();
- mp.setDataSource(fd);
- fis.close();
- t2 = SystemClock.uptimeMillis();
- mp.prepare();
- t3 = SystemClock.uptimeMillis();
- mp.start();
- t4 = SystemClock.uptimeMillis();
- Thread.sleep(10000);
- mp.pause();
- }catch (Exception e){}
- setDataSourceDuration = t2 -t1;
- prepareDuration = t3 - t2;
- startDuration = t4 - t3;
- totalSetDataTime = totalSetDataTime + setDataSourceDuration;
- totalPrepareTime = totalPrepareTime + prepareDuration;
- totalStartDuration = totalStartDuration + startDuration;
- mDB.execSQL("INSERT INTO perfdata (file, setdatatime, preparetime, playtime) VALUES (" + '"' + testFile[k] + '"' +','
- +setDataSourceDuration+ ',' + prepareDuration + ',' + startDuration +");");
- Log.v(TAG,"File name " + testFile[k]);
- mp.stop();
- mp.release();
- }
- Log.v (TAG, "setDataSource average " + totalSetDataTime/numberOfFiles);
- Log.v (TAG, "prepare average " + totalPrepareTime/numberOfFiles);
- Log.v (TAG, "start average " + totalStartDuration/numberOfFiles);
-
- }
-
- //Test cases for GetCurrentPosition
- @LargeTest
+ super.setUp();
+ }
+
+ public void createDB() {
+ mDB = SQLiteDatabase.openOrCreateDatabase("/sdcard/perf.db", null);
+ mDB.execSQL("CREATE TABLE perfdata (_id INTEGER PRIMARY KEY," +
+ "file TEXT," + "setdatatime LONG," + "preparetime LONG," +
+ "playtime LONG" + ");");
+ }
+
+ public void audioPlaybackStartupTime(String[] testFile) {
+ long t1 = 0;
+ long t2 = 0;
+ long t3 = 0;
+ long t4 = 0;
+ long setDataSourceDuration = 0;
+ long prepareDuration = 0;
+ long startDuration = 0;
+ long totalSetDataTime = 0;
+ long totalPrepareTime = 0;
+ long totalStartDuration = 0;
+
+ int numberOfFiles = testFile.length;
+ Log.v(TAG, "File length " + numberOfFiles);
+ for (int k = 0; k < numberOfFiles; k++) {
+ MediaPlayer mp = new MediaPlayer();
+ try {
+ t1 = SystemClock.uptimeMillis();
+ FileInputStream fis = new FileInputStream(testFile[k]);
+ FileDescriptor fd = fis.getFD();
+ mp.setDataSource(fd);
+ fis.close();
+ t2 = SystemClock.uptimeMillis();
+ mp.prepare();
+ t3 = SystemClock.uptimeMillis();
+ mp.start();
+ t4 = SystemClock.uptimeMillis();
+ } catch (Exception e) {
+ Log.v(TAG, e.toString());
+ }
+ setDataSourceDuration = t2 - t1;
+ prepareDuration = t3 - t2;
+ startDuration = t4 - t3;
+ totalSetDataTime = totalSetDataTime + setDataSourceDuration;
+ totalPrepareTime = totalPrepareTime + prepareDuration;
+ totalStartDuration = totalStartDuration + startDuration;
+ mDB.execSQL("INSERT INTO perfdata (file, setdatatime, preparetime," +
+ " playtime) VALUES (" + '"' + testFile[k] + '"' + ',' +
+ setDataSourceDuration + ',' + prepareDuration +
+ ',' + startDuration + ");");
+ Log.v(TAG, "File name " + testFile[k]);
+ mp.stop();
+ mp.release();
+ }
+ Log.v(TAG, "setDataSource average " + totalSetDataTime / numberOfFiles);
+ Log.v(TAG, "prepare average " + totalPrepareTime / numberOfFiles);
+ Log.v(TAG, "start average " + totalStartDuration / numberOfFiles);
+
+ }
+
+ @Suppress
public void testStartUpTime() throws Exception {
- createDB();
- audioPlaybackStartupTime(MediaNames.MP3FILES);
- audioPlaybackStartupTime(MediaNames.AACFILES);
-
- }
-
- public void wmametadatautility(String[] testFile){
- long t1 = 0;
- long t2 = 0;
- long sum = 0;
- long duration = 0;
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- String value;
- for(int i = 0, n = testFile.length; i < n; ++i) {
- try {
- t1 = SystemClock.uptimeMillis();
- retriever.setDataSource(testFile[i]);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COMPOSER);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR);
- value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER);
- t2 = SystemClock.uptimeMillis();
- duration = t2 - t1;
- Log.v(TAG, "Time taken = " + duration);
- sum=sum+duration;
- }
- catch (Exception e){Log.v(TAG, e.getMessage());}
-
- }
- Log.v(TAG, "Average duration = " + sum/testFile.length);
- }
-
+ createDB();
+ audioPlaybackStartupTime(MediaNames.MP3FILES);
+ audioPlaybackStartupTime(MediaNames.AACFILES);
+
+ }
+
+ public void wmametadatautility(String[] testFile) {
+ long t1 = 0;
+ long t2 = 0;
+ long sum = 0;
+ long duration = 0;
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ String value;
+ for (int i = 0, n = testFile.length; i < n; ++i) {
+ try {
+ t1 = SystemClock.uptimeMillis();
+ retriever.setDataSource(testFile[i]);
+ value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
+ value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
+ value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COMPOSER);
+ value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE);
+ value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
+ value = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR);
+ value =
+ retriever
+ .extractMetadata(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER);
+ t2 = SystemClock.uptimeMillis();
+ duration = t2 - t1;
+ Log.v(TAG, "Time taken = " + duration);
+ sum = sum + duration;
+ } catch (Exception e) {
+ Log.v(TAG, e.getMessage());
+ }
+
+ }
+ Log.v(TAG, "Average duration = " + sum / testFile.length);
+ }
+
+
+ // Note: This test is to assume the mediaserver's pid is 34
+ public void mediaStressPlayback(String testFilePath) {
+ for (int i = 0; i < NUM_PLAYBACk_IN_EACH_LOOP; i++) {
+ MediaPlayer mp = new MediaPlayer();
+ try {
+ mp.setDataSource(testFilePath);
+ mp.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder());
+ mp.prepare();
+ mp.start();
+ Thread.sleep(MEDIA_STRESS_WAIT_TIME);
+ mp.release();
+ } catch (Exception e) {
+ mp.release();
+ Log.v(TAG, e.toString());
+ }
+ }
+ }
+
+ // Note: This test is to assume the mediaserver's pid is 34
+ private void stressVideoRecord(int frameRate, int width, int height, int videoFormat,
+ int outFormat, String outFile, boolean videoOnly) {
+ // Video recording
+ for (int i = 0; i < NUM_PLAYBACk_IN_EACH_LOOP; i++) {
+ MediaRecorder mRecorder = new MediaRecorder();
+ try {
+ if (!videoOnly) {
+ Log.v(TAG, "setAudioSource");
+ mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ }
+ mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+ mRecorder.setOutputFormat(outFormat);
+ Log.v(TAG, "output format " + outFormat);
+ mRecorder.setOutputFile(outFile);
+ mRecorder.setVideoFrameRate(frameRate);
+ mRecorder.setVideoSize(width, height);
+ Log.v(TAG, "setEncoder");
+ mRecorder.setVideoEncoder(videoFormat);
+ if (!videoOnly) {
+ mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+ }
+ mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+ mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
+ mRecorder.prepare();
+ mRecorder.start();
+ Thread.sleep(MEDIA_STRESS_WAIT_TIME);
+ mRecorder.stop();
+ mRecorder.release();
+ } catch (Exception e) {
+ Log.v("record video failed ", e.toString());
+ mRecorder.release();
+ }
+ }
+ }
+
+ public void stressAudioRecord(String filePath) {
+ // This test is only for the short media file
+ for (int i = 0; i < NUM_PLAYBACk_IN_EACH_LOOP; i++) {
+ MediaRecorder mRecorder = new MediaRecorder();
+ try {
+ mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+ mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+ mRecorder.setOutputFile(filePath);
+ mRecorder.prepare();
+ mRecorder.start();
+ Thread.sleep(MEDIA_STRESS_WAIT_TIME);
+ mRecorder.stop();
+ mRecorder.release();
+ } catch (Exception e) {
+ Log.v(TAG, e.toString());
+ mRecorder.release();
+ }
+ }
+ }
+
+ //Write the ps output to the file
+ public void getMemoryWriteToLog(Writer output) {
+ String cm = "ps mediaserver";
+ String memoryUsage = null;
+ int ch;
+ try {
+ Process p = Runtime.getRuntime().exec(cm);
+ InputStream in = p.getInputStream();
+ StringBuffer sb = new StringBuffer(512);
+ while ((ch = in.read()) != -1) {
+ sb.append((char) ch);
+ }
+ memoryUsage = sb.toString();
+ } catch (IOException e) {
+ Log.v(TAG, e.toString());
+ }
+
+ String[] poList = memoryUsage.split("\r|\n|\r\n");
+ String memusage = poList[1].concat("\n");
+ Log.v(TAG, memusage);
+ try {
+ //Write to file output
+ output.write(memusage);
+ } catch (Exception e) {
+ e.toString();
+ }
+ }
+
+
@Suppress
public void testWmaParseTime() throws Exception {
- // createDB();
- wmametadatautility(MediaNames.WMASUPPORTED);
+ // createDB();
+ wmametadatautility(MediaNames.WMASUPPORTED);
+ }
+
+
+ // Test case 1: Capture the memory usage after every 20 h263 playback
+ @LargeTest
+ public void testH263VideoPlaybackMemoryUsage() throws Exception {
+ File h263MemoryOut = new File(H263_VIDEO_PLAYBACK_MEMOUT);
+ Writer output = new BufferedWriter(new FileWriter(h263MemoryOut));
+ for (int i = 0; i < NUM_STRESS_LOOP; i++) {
+ mediaStressPlayback(MediaNames.VIDEO_HIGHRES_H263);
+ getMemoryWriteToLog(output);
+ }
+ output.close();
+ }
+
+ // Test case 2: Capture the memory usage after every 20 h264 playback
+ @LargeTest
+ public void testH264VideoPlaybackMemoryUsage() throws Exception {
+ File h264MemoryOut = new File(H264_VIDEO_PLAYBACK_MEMOUT);
+ Writer output = new BufferedWriter(new FileWriter(h264MemoryOut));
+ for (int i = 0; i < NUM_STRESS_LOOP; i++) {
+ mediaStressPlayback(MediaNames.VIDEO_H264_AMR);
+ getMemoryWriteToLog(output);
+ }
+ output.close();
+ }
+
+ // Test case 3: Capture the memory usage after each 20 WMV playback
+ @LargeTest
+ public void testWMVVideoPlaybackMemoryUsage() throws Exception {
+ File wmvMemoryOut = new File(WMV_VIDEO_PLAYBACK_MEMOUT);
+ Writer output = new BufferedWriter(new FileWriter(wmvMemoryOut));
+ for (int i = 0; i < NUM_STRESS_LOOP; i++) {
+ mediaStressPlayback(MediaNames.VIDEO_WMV);
+ getMemoryWriteToLog(output);
+ }
+ output.close();
+ }
+
+ // Test case 4: Capture the memory usage after every 20 video only recorded
+ @LargeTest
+ public void testH263RecordVideoOnlyMemoryUsage() throws Exception {
+ File videoH263RecordOnlyMemoryOut = new File(H263_VIDEO_ONLY_RECORD_MEMOUT);
+ Writer output = new BufferedWriter(new FileWriter(videoH263RecordOnlyMemoryOut));
+ for (int i = 0; i < NUM_STRESS_LOOP; i++) {
+ stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263,
+ MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true);
+ getMemoryWriteToLog(output);
+ }
+ output.close();
+ }
+
+ // Test case 5: Capture the memory usage after every 20 video only recorded
+ @LargeTest
+ public void testMpeg4RecordVideoOnlyMemoryUsage() throws Exception {
+ File videoMp4RecordOnlyMemoryOut = new File(MP4_VIDEO_ONLY_RECORD_MEMOUT);
+ Writer output = new BufferedWriter(new FileWriter(videoMp4RecordOnlyMemoryOut));
+ for (int i = 0; i < NUM_STRESS_LOOP; i++) {
+ stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP,
+ MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true);
+ getMemoryWriteToLog(output);
+ }
+ output.close();
+ }
+
+ // Test case 6: Capture the memory usage after every 20 video and audio recorded
+ @LargeTest
+ public void testRecordVidedAudioMemoryUsage() throws Exception {
+ File videoRecordAudioMemoryOut = new File(H263_VIDEO_AUDIO_RECORD_MEMOUT);
+ Writer output = new BufferedWriter(new FileWriter(videoRecordAudioMemoryOut));
+ for (int i = 0; i < NUM_STRESS_LOOP; i++) {
+ stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263,
+ MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false);
+ getMemoryWriteToLog(output);
+ }
+ output.close();
}
-
-
-}
+ // Test case 7: Capture the memory usage after every 20 audio only recorded
+ @LargeTest
+ public void testRecordAudioOnlyMemoryUsage() throws Exception {
+ File audioOnlyMemoryOut = new File(AUDIO_ONLY_RECORD_MEMOUT);
+ Writer output = new BufferedWriter(new FileWriter(audioOnlyMemoryOut));
+ for (int i = 0; i < NUM_STRESS_LOOP; i++) {
+ stressAudioRecord(MediaNames.RECORDER_OUTPUT);
+ getMemoryWriteToLog(output);
+ }
+ output.close();
+ }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
new file mode 100644
index 0000000..dbf937c
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
@@ -0,0 +1,198 @@
+/*
+ * 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.stress;
+
+import com.android.mediaframeworktest.MediaFrameworkTest;
+
+import android.hardware.Camera;
+import android.media.MediaPlayer;
+import android.media.MediaRecorder;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+/**
+ * Junit / Instrumentation test case for the media player api
+
+ */
+public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
+
+
+ private String TAG = "MediaRecorderStressTest";
+ private MediaRecorder mRecorder;
+ private Camera mCamera;
+
+ private static final int NUMBER_OF_CAMERA_STRESS_LOOPS = 100;
+ private static final int NUMBER_OF_RECORDER_STRESS_LOOPS = 100;
+ private static final int NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS = 50;
+ private static final int NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER = 200;
+ private static final long WAIT_TIME_CAMERA_TEST = 3000; // 3 second
+ private static final long WAIT_TIME_RECORDER_TEST = 60000; // 6 second
+ private static final long WAIT_TIME_RECORD = 100000; // 10 seconds
+ private static final long WAIT_TIME_PLAYBACK = 60000; // 6 second
+ private static final String OUTPUT_FILE = "/sdcard/temp";
+ private static final String OUTPUT_FILE_EXT = ".3gp";
+
+ public MediaRecorderStressTest() {
+ super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+ }
+
+ protected void setUp() throws Exception {
+ getActivity();
+ super.setUp();
+ }
+
+ //Test case for stressing the camera preview.
+ @LargeTest
+ public void testStressCamera() throws Exception {
+ SurfaceHolder mSurfaceHolder;
+ mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+ try {
+ Log.v(TAG, "Start preview");
+ for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++){
+ mCamera = Camera.open();
+ mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.startPreview();
+ Thread.sleep(WAIT_TIME_CAMERA_TEST);
+ mCamera.stopPreview();
+ mCamera.release();
+ }
+ } catch (Exception e) {
+ Log.v(TAG, e.toString());
+ }
+ }
+
+ //Test case for stressing the camera preview.
+ @LargeTest
+ public void testStressRecorder() throws Exception {
+ String filename;
+ SurfaceHolder mSurfaceHolder;
+ mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+ try {
+ Log.v(TAG, "Start preview");
+ for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++){
+ Log.v(TAG, "counter = " + i);
+ filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
+ Log.v(TAG, filename);
+ mRecorder = new MediaRecorder();
+ mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+ mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+ mRecorder.setOutputFile(filename);
+ mRecorder.setVideoFrameRate(20);
+ mRecorder.setVideoSize(176,144);
+ Log.v(TAG, "setEncoder");
+ mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
+ mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+ Log.v(TAG, "setPreview");
+ mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
+ Log.v(TAG, "prepare");
+ mRecorder.prepare();
+ Log.v(TAG, "before release");
+ Thread.sleep(WAIT_TIME_RECORDER_TEST);
+ mRecorder.reset();
+ mRecorder.release();
+ }
+ } catch (Exception e) {
+ Log.v(TAG, e.toString());
+ }
+ }
+
+
+ //Stress test case for switching camera and video recorder preview.
+ @LargeTest
+ public void testStressCameraSwitchRecorder() throws Exception {
+ String filename;
+ SurfaceHolder mSurfaceHolder;
+ mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+ try {
+ Log.v(TAG, "Start preview");
+ for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++){
+ mCamera = Camera.open();
+ mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.startPreview();
+ Thread.sleep(WAIT_TIME_CAMERA_TEST);
+ mCamera.stopPreview();
+ mCamera.release();
+ mCamera = null;
+ Log.v(TAG, "release camera");
+ filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
+ Log.v(TAG, filename);
+ mRecorder = new MediaRecorder();
+ mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+ mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+ mRecorder.setOutputFile(filename);
+ mRecorder.setVideoFrameRate(20);
+ mRecorder.setVideoSize(176,144);
+ Log.v(TAG, "Media recorder setEncoder");
+ mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
+ Log.v(TAG, "mediaRecorder setPreview");
+ mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
+ Log.v(TAG, "prepare");
+ mRecorder.prepare();
+ Log.v(TAG, "before release");
+ Thread.sleep(WAIT_TIME_CAMERA_TEST);
+ mRecorder.release();
+ Log.v(TAG, "release video recorder");
+ }
+ } catch (Exception e) {
+ Log.v(TAG, e.toString());
+ }
+ }
+
+ //Stress test case for record a video and play right away.
+ @LargeTest
+ public void testStressRecordVideoAndPlayback() throws Exception {
+ String filename;
+ SurfaceHolder mSurfaceHolder;
+ mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+ try {
+ for (int i = 0; i < NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS; i++){
+ filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
+ Log.v(TAG, filename);
+ mRecorder = new MediaRecorder();
+ mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+ mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+ mRecorder.setOutputFile(filename);
+ mRecorder.setVideoFrameRate(20);
+ mRecorder.setVideoSize(352,288);
+ mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
+ mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+ Log.v(TAG, "mediaRecorder setPreview");
+ mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
+ mRecorder.prepare();
+ mRecorder.start();
+ Thread.sleep(WAIT_TIME_RECORD);
+ Log.v(TAG, "Before stop");
+ mRecorder.stop();
+ mRecorder.release();
+ //start the playback
+ MediaPlayer mp = new MediaPlayer();
+ mp.setDataSource(filename);
+ mp.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder());
+ mp.prepare();
+ mp.start();
+ Thread.sleep(WAIT_TIME_PLAYBACK);
+ mp.release();
+ }
+ } catch (Exception e) {
+ Log.v(TAG, e.toString());
+ }
+ }
+}
+
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
index 61a8a29..4fa6735 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
@@ -22,7 +22,8 @@ import android.graphics.Bitmap;
import java.io.FileOutputStream;
import android.test.AndroidTestCase;
import com.android.mediaframeworktest.MediaNames;
-import android.test.suitebuilder.annotation.*;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
/**
* WARNING:
@@ -34,7 +35,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
private static final String TAG = "MediaMetadataRetrieverTest";
// Test album art extraction.
- @MediumTest
+ @LargeTest
public static void testAlbumArt() throws Exception {
Log.v(TAG, "testAlbumArt starts.");
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
@@ -108,7 +109,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
// If the specified call order and valid media file is used, no exception
// should be thrown.
- @MediumTest
+ @LargeTest
public static void testBasicNormalMethodCallSequence() throws Exception {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
@@ -135,7 +136,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
// If setDataSource() has not been called, both captureFrame() and extractMetadata() must
// return null.
- @MediumTest
+ @LargeTest
public static void testBasicAbnormalMethodCallSequence() {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
@@ -144,7 +145,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
}
// Test setDataSource()
- @MediumTest
+ @LargeTest
public static void testSetDataSource() {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
@@ -189,7 +190,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
// Due to the lack of permission to access hardware decoder, any calls
// attempting to capture a frame will fail. These are commented out for now
// until we find a solution to this access permission problem.
- @MediumTest
+ @LargeTest
public static void testIntendedUsage() {
// By default, capture frame and retrieve metadata
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java
index 366b6ff..bde000b 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderPrepareStateUnitTest.java
@@ -18,7 +18,7 @@ package com.android.mediaframeworktest.unit;
import android.media.MediaRecorder;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
import java.io.IOException;
@@ -55,14 +55,11 @@ public class MediaRecorderPrepareStateUnitTest extends AndroidTestCase implement
try {
recorder.prepare();
} catch (IOException exception) {
- fail("recorder.prepare() failed");
+ throw new RuntimeException();
}
}
- //TODO(elaurent)
- //reactivate the test until bug#1495237 fix
- @Suppress
- @MediumTest
+ @LargeTest
public void testPrepare() {
mTestTemplate.runTestOnMethod(this);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java
index a45f7ba..80532c3 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderResetStateUnitTest.java
@@ -18,7 +18,7 @@ package com.android.mediaframeworktest.unit;
import android.media.MediaRecorder;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
/**
@@ -54,10 +54,7 @@ public class MediaRecorderResetStateUnitTest extends AndroidTestCase implements
recorder.reset();
}
- //TODO(elaurent)
- //reactivate the test until bug#1495237 fix
- @Suppress
- @MediumTest
+ @LargeTest
public void testReset() {
mTestTemplate.runTestOnMethod(this);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java
index f17d017..e387a77 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioEncoderStateUnitTest.java
@@ -18,7 +18,7 @@ package com.android.mediaframeworktest.unit;
import android.media.MediaRecorder;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
/**
@@ -54,10 +54,7 @@ public class MediaRecorderSetAudioEncoderStateUnitTest extends AndroidTestCase i
recorder.setAudioEncoder(MediaRecorderStateUnitTestTemplate.AUDIO_ENCODER);
}
- //TODO(elaurent)
- //reactivate the test until bug#1495237 fix
- @Suppress
- @MediumTest
+ @LargeTest
public void testSetAudioEncoder() {
mTestTemplate.runTestOnMethod(this);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java
index a972dae..60af54c 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetAudioSourceStateUnitTest.java
@@ -18,7 +18,7 @@ package com.android.mediaframeworktest.unit;
import android.media.MediaRecorder;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
/**
@@ -54,10 +54,7 @@ public class MediaRecorderSetAudioSourceStateUnitTest extends AndroidTestCase im
recorder.setAudioSource(MediaRecorderStateUnitTestTemplate.AUDIO_SOURCE);
}
- //TODO(elaurent)
- //reactivate the test until bug#1495237 fix
- @Suppress
- @MediumTest
+ @LargeTest
public void testSetAudioSource() {
mTestTemplate.runTestOnMethod(this);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java
index b5e7bb7..37d97e9 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFileStateUnitTest.java
@@ -18,7 +18,7 @@ package com.android.mediaframeworktest.unit;
import android.media.MediaRecorder;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
/**
@@ -29,34 +29,29 @@ public class MediaRecorderSetOutputFileStateUnitTest extends AndroidTestCase imp
private MediaRecorderStateUnitTestTemplate mTestTemplate = new MediaRecorderStateUnitTestTemplate();
/**
* 1. It is valid to call setOutputFile() in the following states:
- * {DataSourceConfigured}.
+ * {DataSourceConfigured, Initial, Initialized, Prepared, Recording, Error}.
* 2. It is invalid to call setOutputFile() in the following states:
- * {Initial, Initialized, Prepared, Recording, Error}
+ * {}
*
* @param stateErrors the MediaRecorderStateErrors to check against.
*/
public void checkStateErrors(MediaRecorderStateErrors stateErrors) {
// Valid states.
assertTrue(!stateErrors.errorInDataSourceConfiguredState);
-
- // Invalid states.
- assertTrue(stateErrors.errorInPreparedState);
- assertTrue(stateErrors.errorInRecordingState);
- assertTrue(stateErrors.errorInErrorState);
- assertTrue(stateErrors.errorInInitialState);
- assertTrue(stateErrors.errorInInitialStateAfterReset);
- assertTrue(stateErrors.errorInInitialStateAfterStop);
- assertTrue(stateErrors.errorInInitializedState);
+ assertTrue(!stateErrors.errorInPreparedState);
+ assertTrue(!stateErrors.errorInRecordingState);
+ assertTrue(!stateErrors.errorInErrorState);
+ assertTrue(!stateErrors.errorInInitialState);
+ assertTrue(!stateErrors.errorInInitialStateAfterReset);
+ assertTrue(!stateErrors.errorInInitialStateAfterStop);
+ assertTrue(!stateErrors.errorInInitializedState);
}
public void invokeMethodUnderTest(MediaRecorder recorder) {
recorder.setOutputFile(MediaRecorderStateUnitTestTemplate.RECORD_OUTPUT_PATH);
}
- //TODO(elaurent)
- //reactivate the test until bug#1495237 fix
- @Suppress
- @MediumTest
+ @LargeTest
public void testSetOutputFile() {
mTestTemplate.runTestOnMethod(this);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java
index 3d6f87f..a7ee2d4 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderSetOutputFormatStateUnitTest.java
@@ -18,7 +18,7 @@ package com.android.mediaframeworktest.unit;
import android.media.MediaRecorder;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
/**
@@ -54,10 +54,7 @@ public class MediaRecorderSetOutputFormatStateUnitTest extends AndroidTestCase i
recorder.setOutputFormat(MediaRecorderStateUnitTestTemplate.OUTPUT_FORMAT);
}
- //TODO(elaurent)
- //reactivate the test until bug#1495237 fix
- @Suppress
- @MediumTest
+ @LargeTest
public void testSetOutputFormat() {
mTestTemplate.runTestOnMethod(this);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java
index 03180d5..4af5967 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStartStateUnitTest.java
@@ -18,7 +18,7 @@ package com.android.mediaframeworktest.unit;
import android.media.MediaRecorder;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
/**
@@ -54,10 +54,7 @@ public class MediaRecorderStartStateUnitTest extends AndroidTestCase implements
recorder.start();
}
- //TODO(elaurent)
- //reactivate the test until bug#1495237 fix
- @Suppress
- @MediumTest
+ @LargeTest
public void testStart() {
mTestTemplate.runTestOnMethod(this);
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStateUnitTestTemplate.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStateUnitTestTemplate.java
index f350467..9edc9aa 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStateUnitTestTemplate.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStateUnitTestTemplate.java
@@ -90,9 +90,15 @@ class MediaRecorderStateUnitTestTemplate extends AndroidTestCase {
}
}
+ // FIXME:
+ // In the past, stop() == reset().
+ // However, this is no longer true. The plan is to have a STOPPED state.
+ // and from STOPPED state, start can be called without the need to
+ // do the recording configuration again.
private void setMediaRecorderToInitialStateAfterStop() {
try {
mMediaRecorder.reset();
+/*
mMediaRecorder.setAudioSource(AUDIO_SOURCE);
mMediaRecorder.setOutputFormat(OUTPUT_FORMAT);
mMediaRecorder.setAudioEncoder(AUDIO_ENCODER);
@@ -100,6 +106,7 @@ class MediaRecorderStateUnitTestTemplate extends AndroidTestCase {
mMediaRecorder.prepare();
mMediaRecorder.start();
mMediaRecorder.stop();
+*/
} catch(Exception e) {
fail("setMediaRecorderToInitialStateAfterReset: Exception " + e.getClass().getName() + " was thrown.");
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java
index 330e8ab..5475900 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaRecorderStopStateUnitTest.java
@@ -18,7 +18,7 @@ package com.android.mediaframeworktest.unit;
import android.media.MediaRecorder;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
/**
@@ -54,10 +54,7 @@ public class MediaRecorderStopStateUnitTest extends AndroidTestCase implements M
recorder.stop();
}
- //TODO(elaurent)
- //reactivate the test until bug#1495237 fix
- @Suppress
- @MediumTest
+ @LargeTest
public void testStop() {
mTestTemplate.runTestOnMethod(this);
}
diff --git a/opengl/include/EGL/egl.h b/opengl/include/EGL/egl.h
new file mode 100644
index 0000000..c269976
--- /dev/null
+++ b/opengl/include/EGL/egl.h
@@ -0,0 +1,330 @@
+/* -*- mode: c; tab-width: 8; -*- */
+/* vi: set sw=4 ts=8: */
+/* Reference version of egl.h for EGL 1.4.
+ * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $
+ */
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#ifndef __egl_h_
+#define __egl_h_
+
+/* All platform-dependent types and macro boilerplate (such as EGLAPI
+ * and EGLAPIENTRY) should go in eglplatform.h.
+ */
+#include <EGL/eglplatform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* EGL Types */
+/* EGLint is defined in eglplatform.h */
+typedef unsigned int EGLBoolean;
+typedef unsigned int EGLenum;
+typedef void *EGLConfig;
+typedef void *EGLContext;
+typedef void *EGLDisplay;
+typedef void *EGLSurface;
+typedef void *EGLClientBuffer;
+
+/* EGL Versioning */
+#define EGL_VERSION_1_0 1
+#define EGL_VERSION_1_1 1
+#define EGL_VERSION_1_2 1
+#define EGL_VERSION_1_3 1
+#define EGL_VERSION_1_4 1
+
+/* EGL Enumerants. Bitmasks and other exceptional cases aside, most
+ * enums are assigned unique values starting at 0x3000.
+ */
+
+/* EGL aliases */
+#define EGL_FALSE 0
+#define EGL_TRUE 1
+
+/* Out-of-band handle values */
+#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
+#define EGL_NO_CONTEXT ((EGLContext)0)
+#define EGL_NO_DISPLAY ((EGLDisplay)0)
+#define EGL_NO_SURFACE ((EGLSurface)0)
+
+/* Out-of-band attribute value */
+#define EGL_DONT_CARE ((EGLint)-1)
+
+/* Errors / GetError return values */
+#define EGL_SUCCESS 0x3000
+#define EGL_NOT_INITIALIZED 0x3001
+#define EGL_BAD_ACCESS 0x3002
+#define EGL_BAD_ALLOC 0x3003
+#define EGL_BAD_ATTRIBUTE 0x3004
+#define EGL_BAD_CONFIG 0x3005
+#define EGL_BAD_CONTEXT 0x3006
+#define EGL_BAD_CURRENT_SURFACE 0x3007
+#define EGL_BAD_DISPLAY 0x3008
+#define EGL_BAD_MATCH 0x3009
+#define EGL_BAD_NATIVE_PIXMAP 0x300A
+#define EGL_BAD_NATIVE_WINDOW 0x300B
+#define EGL_BAD_PARAMETER 0x300C
+#define EGL_BAD_SURFACE 0x300D
+#define EGL_CONTEXT_LOST 0x300E /* EGL 1.1 - IMG_power_management */
+
+/* Reserved 0x300F-0x301F for additional errors */
+
+/* Config attributes */
+#define EGL_BUFFER_SIZE 0x3020
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_RED_SIZE 0x3024
+#define EGL_DEPTH_SIZE 0x3025
+#define EGL_STENCIL_SIZE 0x3026
+#define EGL_CONFIG_CAVEAT 0x3027
+#define EGL_CONFIG_ID 0x3028
+#define EGL_LEVEL 0x3029
+#define EGL_MAX_PBUFFER_HEIGHT 0x302A
+#define EGL_MAX_PBUFFER_PIXELS 0x302B
+#define EGL_MAX_PBUFFER_WIDTH 0x302C
+#define EGL_NATIVE_RENDERABLE 0x302D
+#define EGL_NATIVE_VISUAL_ID 0x302E
+#define EGL_NATIVE_VISUAL_TYPE 0x302F
+#define EGL_PRESERVED_RESOURCES 0x3030
+#define EGL_SAMPLES 0x3031
+#define EGL_SAMPLE_BUFFERS 0x3032
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_TRANSPARENT_TYPE 0x3034
+#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
+#define EGL_TRANSPARENT_RED_VALUE 0x3037
+#define EGL_NONE 0x3038 /* Attrib list terminator */
+#define EGL_BIND_TO_TEXTURE_RGB 0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
+#define EGL_MIN_SWAP_INTERVAL 0x303B
+#define EGL_MAX_SWAP_INTERVAL 0x303C
+#define EGL_LUMINANCE_SIZE 0x303D
+#define EGL_ALPHA_MASK_SIZE 0x303E
+#define EGL_COLOR_BUFFER_TYPE 0x303F
+#define EGL_RENDERABLE_TYPE 0x3040
+#define EGL_MATCH_NATIVE_PIXMAP 0x3041 /* Pseudo-attribute (not queryable) */
+#define EGL_CONFORMANT 0x3042
+
+/* Reserved 0x3041-0x304F for additional config attributes */
+
+/* Config attribute values */
+#define EGL_SLOW_CONFIG 0x3050 /* EGL_CONFIG_CAVEAT value */
+#define EGL_NON_CONFORMANT_CONFIG 0x3051 /* EGL_CONFIG_CAVEAT value */
+#define EGL_TRANSPARENT_RGB 0x3052 /* EGL_TRANSPARENT_TYPE value */
+#define EGL_RGB_BUFFER 0x308E /* EGL_COLOR_BUFFER_TYPE value */
+#define EGL_LUMINANCE_BUFFER 0x308F /* EGL_COLOR_BUFFER_TYPE value */
+
+/* More config attribute values, for EGL_TEXTURE_FORMAT */
+#define EGL_NO_TEXTURE 0x305C
+#define EGL_TEXTURE_RGB 0x305D
+#define EGL_TEXTURE_RGBA 0x305E
+#define EGL_TEXTURE_2D 0x305F
+
+/* Config attribute mask bits */
+#define EGL_PBUFFER_BIT 0x0001 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_PIXMAP_BIT 0x0002 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_WINDOW_BIT 0x0004 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 /* EGL_SURFACE_TYPE mask bits */
+
+#define EGL_OPENGL_ES_BIT 0x0001 /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENVG_BIT 0x0002 /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENGL_ES2_BIT 0x0004 /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENGL_BIT 0x0008 /* EGL_RENDERABLE_TYPE mask bits */
+
+/* QueryString targets */
+#define EGL_VENDOR 0x3053
+#define EGL_VERSION 0x3054
+#define EGL_EXTENSIONS 0x3055
+#define EGL_CLIENT_APIS 0x308D
+
+/* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */
+#define EGL_HEIGHT 0x3056
+#define EGL_WIDTH 0x3057
+#define EGL_LARGEST_PBUFFER 0x3058
+#define EGL_TEXTURE_FORMAT 0x3080
+#define EGL_TEXTURE_TARGET 0x3081
+#define EGL_MIPMAP_TEXTURE 0x3082
+#define EGL_MIPMAP_LEVEL 0x3083
+#define EGL_RENDER_BUFFER 0x3086
+#define EGL_VG_COLORSPACE 0x3087
+#define EGL_VG_ALPHA_FORMAT 0x3088
+#define EGL_HORIZONTAL_RESOLUTION 0x3090
+#define EGL_VERTICAL_RESOLUTION 0x3091
+#define EGL_PIXEL_ASPECT_RATIO 0x3092
+#define EGL_SWAP_BEHAVIOR 0x3093
+#define EGL_MULTISAMPLE_RESOLVE 0x3099
+
+/* EGL_RENDER_BUFFER values / BindTexImage / ReleaseTexImage buffer targets */
+#define EGL_BACK_BUFFER 0x3084
+#define EGL_SINGLE_BUFFER 0x3085
+
+/* OpenVG color spaces */
+#define EGL_VG_COLORSPACE_sRGB 0x3089 /* EGL_VG_COLORSPACE value */
+#define EGL_VG_COLORSPACE_LINEAR 0x308A /* EGL_VG_COLORSPACE value */
+
+/* OpenVG alpha formats */
+#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B /* EGL_ALPHA_FORMAT value */
+#define EGL_VG_ALPHA_FORMAT_PRE 0x308C /* EGL_ALPHA_FORMAT value */
+
+/* Constant scale factor by which fractional display resolutions &
+ * aspect ratio are scaled when queried as integer values.
+ */
+#define EGL_DISPLAY_SCALING 10000
+
+/* Unknown display resolution/aspect ratio */
+#define EGL_UNKNOWN ((EGLint)-1)
+
+/* Back buffer swap behaviors */
+#define EGL_BUFFER_PRESERVED 0x3094 /* EGL_SWAP_BEHAVIOR value */
+#define EGL_BUFFER_DESTROYED 0x3095 /* EGL_SWAP_BEHAVIOR value */
+
+/* CreatePbufferFromClientBuffer buffer types */
+#define EGL_OPENVG_IMAGE 0x3096
+
+/* QueryContext targets */
+#define EGL_CONTEXT_CLIENT_TYPE 0x3097
+
+/* CreateContext attributes */
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+
+/* Multisample resolution behaviors */
+#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A /* EGL_MULTISAMPLE_RESOLVE value */
+#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B /* EGL_MULTISAMPLE_RESOLVE value */
+
+/* BindAPI/QueryAPI targets */
+#define EGL_OPENGL_ES_API 0x30A0
+#define EGL_OPENVG_API 0x30A1
+#define EGL_OPENGL_API 0x30A2
+
+/* GetCurrentSurface targets */
+#define EGL_DRAW 0x3059
+#define EGL_READ 0x305A
+
+/* WaitNative engines */
+#define EGL_CORE_NATIVE_ENGINE 0x305B
+
+/* EGL 1.2 tokens renamed for consistency in EGL 1.3 */
+#define EGL_COLORSPACE EGL_VG_COLORSPACE
+#define EGL_ALPHA_FORMAT EGL_VG_ALPHA_FORMAT
+#define EGL_COLORSPACE_sRGB EGL_VG_COLORSPACE_sRGB
+#define EGL_COLORSPACE_LINEAR EGL_VG_COLORSPACE_LINEAR
+#define EGL_ALPHA_FORMAT_NONPRE EGL_VG_ALPHA_FORMAT_NONPRE
+#define EGL_ALPHA_FORMAT_PRE EGL_VG_ALPHA_FORMAT_PRE
+
+/* EGL extensions must request enum blocks from the Khronos
+ * API Registrar, who maintains the enumerant registry. Submit
+ * a bug in Khronos Bugzilla against task "Registry".
+ */
+
+
+
+/* EGL Functions */
+
+EGLAPI EGLint EGLAPIENTRY eglGetError(void);
+
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy);
+
+EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs,
+ EGLint config_size, EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value);
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
+ EGLNativeWindowType win,
+ const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
+ EGLNativePixmapType pixmap,
+ const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint *value);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api);
+EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void);
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(
+ EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+ EGLConfig config, const EGLint *attrib_list);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval);
+
+
+EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_context,
+ const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext ctx);
+
+EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void);
+EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx,
+ EGLint attribute, EGLint *value);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface,
+ EGLNativePixmapType target);
+
+/* This is a generic function pointer type, whose name indicates it must
+ * be cast to the proper type *and calling convention* before use.
+ */
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+
+/* Now, define eglGetProcAddress using the generic function ptr. type */
+EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY
+ eglGetProcAddress(const char *procname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __egl_h_ */
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
new file mode 100644
index 0000000..25cfcb8
--- /dev/null
+++ b/opengl/include/EGL/eglext.h
@@ -0,0 +1,138 @@
+#ifndef __eglext_h_
+#define __eglext_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#include <EGL/eglplatform.h>
+
+/*************************************************************/
+
+/* Header file version number */
+/* Current version at http://www.khronos.org/registry/egl/ */
+/* $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ */
+#define EGL_EGLEXT_VERSION 3
+
+#ifndef EGL_KHR_config_attribs
+#define EGL_KHR_config_attribs 1
+#define EGL_CONFORMANT_KHR 0x3042 /* EGLConfig attribute */
+#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 /* EGL_SURFACE_TYPE bitfield */
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 /* EGL_SURFACE_TYPE bitfield */
+#endif
+
+#ifndef EGL_KHR_lock_surface
+#define EGL_KHR_lock_surface 1
+#define EGL_READ_SURFACE_BIT_KHR 0x0001 /* EGL_LOCK_USAGE_HINT_KHR bitfield */
+#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 /* EGL_LOCK_USAGE_HINT_KHR bitfield */
+#define EGL_LOCK_SURFACE_BIT_KHR 0x0080 /* EGL_SURFACE_TYPE bitfield */
+#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 /* EGL_SURFACE_TYPE bitfield */
+#define EGL_MATCH_FORMAT_KHR 0x3043 /* EGLConfig attribute */
+#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGB_565_KHR 0x30C1 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGBA_8888_KHR 0x30C3 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 /* eglLockSurfaceKHR attribute */
+#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 /* eglLockSurfaceKHR attribute */
+#define EGL_BITMAP_POINTER_KHR 0x30C6 /* eglQuerySurface attribute */
+#define EGL_BITMAP_PITCH_KHR 0x30C7 /* eglQuerySurface attribute */
+#define EGL_BITMAP_ORIGIN_KHR 0x30C8 /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD /* eglQuerySurface attribute */
+#define EGL_LOWER_LEFT_KHR 0x30CE /* EGL_BITMAP_ORIGIN_KHR value */
+#define EGL_UPPER_LEFT_KHR 0x30CF /* EGL_BITMAP_ORIGIN_KHR value */
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface);
+#endif
+
+#ifndef EGL_KHR_image
+#define EGL_KHR_image 1
+#define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */
+typedef void *EGLImageKHR;
+#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0)
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
+#endif
+
+#ifndef EGL_KHR_vg_parent_image
+#define EGL_KHR_vg_parent_image 1
+#define EGL_VG_PARENT_IMAGE_KHR 0x30BA /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_gl_texture_2D_image
+#define EGL_KHR_gl_texture_2D_image 1
+#define EGL_GL_TEXTURE_2D_KHR 0x30B1 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_gl_texture_cubemap_image
+#define EGL_KHR_gl_texture_cubemap_image 1
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_gl_texture_3D_image
+#define EGL_KHR_gl_texture_3D_image 1
+#define EGL_GL_TEXTURE_3D_KHR 0x30B2 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_gl_renderbuffer_image
+#define EGL_KHR_gl_renderbuffer_image 1
+#define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_image_base
+#define EGL_KHR_image_base 1
+/* Most interfaces defined by EGL_KHR_image_pixmap above */
+#define EGL_IMAGE_PRESERVED_KHR 0x30D2 /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_image_pixmap
+#define EGL_KHR_image_pixmap 1
+/* Interfaces defined by EGL_KHR_image above */
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/GLES/eglnatives.h b/opengl/include/EGL/eglnatives.h
index 1cd57d0..21622dc 100644
--- a/include/GLES/eglnatives.h
+++ b/opengl/include/EGL/eglnatives.h
@@ -22,23 +22,8 @@
#ifdef __cplusplus
extern "C" {
#endif
-/*****************************************************************************/
-
-struct egl_native_window_t;
-struct egl_native_pixmap_t;
-
-
-typedef struct egl_native_window_t* NativeWindowType;
-typedef struct egl_native_pixmap_t* NativePixmapType;
-typedef void* NativeDisplayType;
-
-/*
- * This a convenience function to create a NativeWindowType surface
- * that maps to the whole screen
- * This function is actually implemented in libui.so
- */
-NativeWindowType android_createDisplaySurface();
+/*****************************************************************************/
/* flags returned from swapBuffer */
#define EGL_NATIVES_FLAG_SIZE_CHANGED 0x00000001
@@ -151,48 +136,46 @@ struct egl_native_window_t
/*
* Hook called by EGL to hold a reference on this structure
*/
- void (*incRef)(NativeWindowType window);
+ void (*incRef)(struct egl_native_window_t* window);
/*
* Hook called by EGL to release a reference on this structure
*/
- void (*decRef)(NativeWindowType window);
+ void (*decRef)(struct egl_native_window_t* window);
/*
* Hook called by EGL to perform a page flip. This function
* may update the size attributes above, in which case it returns
* the EGL_NATIVES_FLAG_SIZE_CHANGED bit set.
*/
- uint32_t (*swapBuffers)(NativeWindowType window);
+ uint32_t (*swapBuffers)(struct egl_native_window_t* window);
/*
- * Hook called by EGL to set the swap rectangle. this hook can be
- * null (operation not supported)
+ * Reserved for future use. MUST BE ZERO.
*/
- void (*setSwapRectangle)(NativeWindowType window, int l, int t, int w, int h);
+ void (*reserved_proc_0)(void);
/*
* Reserved for future use. MUST BE ZERO.
*/
- void (*reserved_proc_0)(void);
-
+ void (*reserved_proc_1)(void);
/*
- * Hook called by EGL to retrieve the next buffer to render into.
- * This call updates this structure.
+ * Reserved for future use. MUST BE ZERO.
*/
- uint32_t (*nextBuffer)(NativeWindowType window);
+ void (*reserved_proc_2)(void);
+
/*
* Hook called by EGL when the native surface is associated to EGL
* (eglCreateWindowSurface). Can be NULL.
*/
- void (*connect)(NativeWindowType window);
+ void (*connect)(struct egl_native_window_t* window);
/*
* Hook called by EGL when eglDestroySurface is called. Can be NULL.
*/
- void (*disconnect)(NativeWindowType window);
+ void (*disconnect)(struct egl_native_window_t* window);
/*
* Reserved for future use. MUST BE ZERO.
@@ -224,6 +207,17 @@ struct egl_native_pixmap_t
/*****************************************************************************/
+/*
+ * This a convenience function to create a NativeWindowType surface
+ * that maps to the whole screen
+ * This function is actually implemented in libui.so
+ */
+
+struct egl_native_window_t* android_createDisplaySurface();
+
+/*****************************************************************************/
+
+
/*
* OEM's egl's library (libhgl.so) must imlement these hooks to allocate
* the GPU memory they need
diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h
new file mode 100644
index 0000000..ac00901
--- /dev/null
+++ b/opengl/include/EGL/eglplatform.h
@@ -0,0 +1,117 @@
+#ifndef __eglplatform_h_
+#define __eglplatform_h_
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Platform-specific types and definitions for egl.h
+ * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "EGL" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+/* Macros used in EGL function prototype declarations.
+ *
+ * EGL functions should be prototyped as:
+ *
+ * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
+ * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
+ *
+ * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
+ */
+
+#ifndef EGLAPI
+#define EGLAPI KHRONOS_APICALL
+#endif
+
+#define EGLAPIENTRY KHRONOS_APIENTRY
+#define EGLAPIENTRYP KHRONOS_APIENTRY*
+
+/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
+ * are aliases of window-system-dependent types, such as X Display * or
+ * Windows Device Context. They must be defined in platform-specific
+ * code below. The EGL-prefixed versions of Native*Type are the same
+ * types, renamed in EGL 1.3 so all types in the API start with "EGL".
+ */
+
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+
+typedef HDC EGLNativeDisplayType;
+typedef HBITMAP EGLNativePixmapType;
+typedef HWND EGLNativeWindowType;
+
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
+
+typedef int EGLNativeDisplayType;
+typedef void *EGLNativeWindowType;
+typedef void *EGLNativePixmapType;
+
+#elif defined(__unix__) && !defined(ANDROID)
+
+/* X11 (tentative) */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef Display *EGLNativeDisplayType;
+typedef Pixmap EGLNativePixmapType;
+typedef Window EGLNativeWindowType;
+
+
+#elif defined(ANDROID)
+
+#include <EGL/eglnatives.h>
+
+typedef struct egl_native_window_t* EGLNativeWindowType;
+typedef struct egl_native_pixmap_t* EGLNativePixmapType;
+typedef void* EGLNativeDisplayType;
+
+#else
+#error "Platform not recognized"
+#endif
+
+/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
+typedef EGLNativeDisplayType NativeDisplayType;
+typedef EGLNativePixmapType NativePixmapType;
+typedef EGLNativeWindowType NativeWindowType;
+
+
+/* Define EGLint. This must be a signed integral type large enough to contain
+ * all legal attribute names and values passed into and out of EGL, whether
+ * their type is boolean, bitmask, enumerant (symbolic constant), integer,
+ * handle, or other. While in general a 32-bit integer will suffice, if
+ * handles are 64 bit types, then EGLint should be defined as a signed 64-bit
+ * integer type.
+ */
+typedef khronos_int32_t EGLint;
+
+#endif /* __eglplatform_h */
diff --git a/opengl/include/GLES/egl.h b/opengl/include/GLES/egl.h
new file mode 100644
index 0000000..5778e00
--- /dev/null
+++ b/opengl/include/GLES/egl.h
@@ -0,0 +1,15 @@
+/*
+ * Skeleton egl.h to provide compatibility for early GLES 1.0
+ * applications. Several early implementations included gl.h
+ * in egl.h leading applications to include only egl.h
+ *
+ * $Revision: 6252 $ on $Date:: 2008-08-06 16:35:08 -0700 #$
+ */
+
+#ifndef __legacy_egl_h_
+#define __legacy_egl_h_
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+
+#endif /* __legacy_egl_h_ */
diff --git a/opengl/include/GLES/gl.h b/opengl/include/GLES/gl.h
new file mode 100644
index 0000000..2e8b971
--- /dev/null
+++ b/opengl/include/GLES/gl.h
@@ -0,0 +1,769 @@
+#ifndef __gl_h_
+#define __gl_h_
+
+/* $Revision: 7172 $ on $Date:: 2009-01-09 11:17:41 -0800 #$ */
+
+#include <GLES/glplatform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+typedef void GLvoid;
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef khronos_int8_t GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef khronos_uint8_t GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef khronos_int32_t GLfixed;
+typedef khronos_int32_t GLclampx;
+
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t GLsizeiptr;
+
+
+/*************************************************************/
+
+/* OpenGL ES core versions */
+#define GL_VERSION_ES_CM_1_0 1
+#define GL_VERSION_ES_CL_1_0 1
+#define GL_VERSION_ES_CM_1_1 1
+#define GL_VERSION_ES_CL_1_1 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Boolean */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* AlphaFunction */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* ClipPlaneName */
+#define GL_CLIP_PLANE0 0x3000
+#define GL_CLIP_PLANE1 0x3001
+#define GL_CLIP_PLANE2 0x3002
+#define GL_CLIP_PLANE3 0x3003
+#define GL_CLIP_PLANE4 0x3004
+#define GL_CLIP_PLANE5 0x3005
+
+/* ColorMaterialFace */
+/* GL_FRONT_AND_BACK */
+
+/* ColorMaterialParameter */
+/* GL_AMBIENT_AND_DIFFUSE */
+
+/* ColorPointerType */
+/* GL_UNSIGNED_BYTE */
+/* GL_FLOAT */
+/* GL_FIXED */
+
+/* CullFaceMode */
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* DepthFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* EnableCap */
+#define GL_FOG 0x0B60
+#define GL_LIGHTING 0x0B50
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_ALPHA_TEST 0x0BC0
+#define GL_BLEND 0x0BE2
+#define GL_COLOR_LOGIC_OP 0x0BF2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+/* GL_LIGHT0 */
+/* GL_LIGHT1 */
+/* GL_LIGHT2 */
+/* GL_LIGHT3 */
+/* GL_LIGHT4 */
+/* GL_LIGHT5 */
+/* GL_LIGHT6 */
+/* GL_LIGHT7 */
+#define GL_POINT_SMOOTH 0x0B10
+#define GL_LINE_SMOOTH 0x0B20
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_COLOR_MATERIAL 0x0B57
+#define GL_NORMALIZE 0x0BA1
+#define GL_RESCALE_NORMAL 0x803A
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_VERTEX_ARRAY 0x8074
+#define GL_NORMAL_ARRAY 0x8075
+#define GL_COLOR_ARRAY 0x8076
+#define GL_TEXTURE_COORD_ARRAY 0x8078
+#define GL_MULTISAMPLE 0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_STACK_OVERFLOW 0x0503
+#define GL_STACK_UNDERFLOW 0x0504
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* FogMode */
+/* GL_LINEAR */
+#define GL_EXP 0x0800
+#define GL_EXP2 0x0801
+
+/* FogParameter */
+#define GL_FOG_DENSITY 0x0B62
+#define GL_FOG_START 0x0B63
+#define GL_FOG_END 0x0B64
+#define GL_FOG_MODE 0x0B65
+#define GL_FOG_COLOR 0x0B66
+
+/* FrontFaceDirection */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+/* GetPName */
+#define GL_CURRENT_COLOR 0x0B00
+#define GL_CURRENT_NORMAL 0x0B02
+#define GL_CURRENT_TEXTURE_COORDS 0x0B03
+#define GL_POINT_SIZE 0x0B11
+#define GL_POINT_SIZE_MIN 0x8126
+#define GL_POINT_SIZE_MAX 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128
+#define GL_POINT_DISTANCE_ATTENUATION 0x8129
+#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
+#define GL_LINE_WIDTH 0x0B21
+#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_SHADE_MODEL 0x0B54
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_MATRIX_MODE 0x0BA0
+#define GL_VIEWPORT 0x0BA2
+#define GL_MODELVIEW_STACK_DEPTH 0x0BA3
+#define GL_PROJECTION_STACK_DEPTH 0x0BA4
+#define GL_TEXTURE_STACK_DEPTH 0x0BA5
+#define GL_MODELVIEW_MATRIX 0x0BA6
+#define GL_PROJECTION_MATRIX 0x0BA7
+#define GL_TEXTURE_MATRIX 0x0BA8
+#define GL_ALPHA_TEST_FUNC 0x0BC1
+#define GL_ALPHA_TEST_REF 0x0BC2
+#define GL_BLEND_DST 0x0BE0
+#define GL_BLEND_SRC 0x0BE1
+#define GL_LOGIC_OP_MODE 0x0BF0
+#define GL_SCISSOR_BOX 0x0C10
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_LIGHTS 0x0D31
+#define GL_MAX_CLIP_PLANES 0x0D32
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36
+#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38
+#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_MAX_TEXTURE_UNITS 0x84E2
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_VERTEX_ARRAY_SIZE 0x807A
+#define GL_VERTEX_ARRAY_TYPE 0x807B
+#define GL_VERTEX_ARRAY_STRIDE 0x807C
+#define GL_NORMAL_ARRAY_TYPE 0x807E
+#define GL_NORMAL_ARRAY_STRIDE 0x807F
+#define GL_COLOR_ARRAY_SIZE 0x8081
+#define GL_COLOR_ARRAY_TYPE 0x8082
+#define GL_COLOR_ARRAY_STRIDE 0x8083
+#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A
+#define GL_VERTEX_ARRAY_POINTER 0x808E
+#define GL_NORMAL_ARRAY_POINTER 0x808F
+#define GL_COLOR_ARRAY_POINTER 0x8090
+#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+
+/* GetTextureParameter */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50
+#define GL_POINT_SMOOTH_HINT 0x0C51
+#define GL_LINE_SMOOTH_HINT 0x0C52
+#define GL_FOG_HINT 0x0C54
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* LightModelParameter */
+#define GL_LIGHT_MODEL_AMBIENT 0x0B53
+#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52
+
+/* LightParameter */
+#define GL_AMBIENT 0x1200
+#define GL_DIFFUSE 0x1201
+#define GL_SPECULAR 0x1202
+#define GL_POSITION 0x1203
+#define GL_SPOT_DIRECTION 0x1204
+#define GL_SPOT_EXPONENT 0x1205
+#define GL_SPOT_CUTOFF 0x1206
+#define GL_CONSTANT_ATTENUATION 0x1207
+#define GL_LINEAR_ATTENUATION 0x1208
+#define GL_QUADRATIC_ATTENUATION 0x1209
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* LogicOp */
+#define GL_CLEAR 0x1500
+#define GL_AND 0x1501
+#define GL_AND_REVERSE 0x1502
+#define GL_COPY 0x1503
+#define GL_AND_INVERTED 0x1504
+#define GL_NOOP 0x1505
+#define GL_XOR 0x1506
+#define GL_OR 0x1507
+#define GL_NOR 0x1508
+#define GL_EQUIV 0x1509
+#define GL_INVERT 0x150A
+#define GL_OR_REVERSE 0x150B
+#define GL_COPY_INVERTED 0x150C
+#define GL_OR_INVERTED 0x150D
+#define GL_NAND 0x150E
+#define GL_SET 0x150F
+
+/* MaterialFace */
+/* GL_FRONT_AND_BACK */
+
+/* MaterialParameter */
+#define GL_EMISSION 0x1600
+#define GL_SHININESS 0x1601
+#define GL_AMBIENT_AND_DIFFUSE 0x1602
+/* GL_AMBIENT */
+/* GL_DIFFUSE */
+/* GL_SPECULAR */
+
+/* MatrixMode */
+#define GL_MODELVIEW 0x1700
+#define GL_PROJECTION 0x1701
+#define GL_TEXTURE 0x1702
+
+/* NormalPointerType */
+/* GL_BYTE */
+/* GL_SHORT */
+/* GL_FLOAT */
+/* GL_FIXED */
+
+/* PixelFormat */
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* PixelStoreParameter */
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* ShadingModel */
+#define GL_FLAT 0x1D00
+#define GL_SMOOTH 0x1D01
+
+/* StencilFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* StencilOp */
+/* GL_ZERO */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+/* GL_INVERT */
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* TexCoordPointerType */
+/* GL_SHORT */
+/* GL_FLOAT */
+/* GL_FIXED */
+/* GL_BYTE */
+
+/* TextureEnvMode */
+#define GL_MODULATE 0x2100
+#define GL_DECAL 0x2101
+/* GL_BLEND */
+#define GL_ADD 0x0104
+/* GL_REPLACE */
+
+/* TextureEnvParameter */
+#define GL_TEXTURE_ENV_MODE 0x2200
+#define GL_TEXTURE_ENV_COLOR 0x2201
+
+/* TextureEnvTarget */
+#define GL_TEXTURE_ENV 0x2300
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureMinFilter */
+/* GL_NEAREST */
+/* GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_GENERATE_MIPMAP 0x8191
+
+/* TextureTarget */
+/* GL_TEXTURE_2D */
+
+/* TextureUnit */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+
+/* VertexPointerType */
+/* GL_SHORT */
+/* GL_FLOAT */
+/* GL_FIXED */
+/* GL_BYTE */
+
+/* LightName */
+#define GL_LIGHT0 0x4000
+#define GL_LIGHT1 0x4001
+#define GL_LIGHT2 0x4002
+#define GL_LIGHT3 0x4003
+#define GL_LIGHT4 0x4004
+#define GL_LIGHT5 0x4005
+#define GL_LIGHT6 0x4006
+#define GL_LIGHT7 0x4007
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
+
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+/* Texture combine + dot3 */
+#define GL_SUBTRACT 0x84E7
+#define GL_COMBINE 0x8570
+#define GL_COMBINE_RGB 0x8571
+#define GL_COMBINE_ALPHA 0x8572
+#define GL_RGB_SCALE 0x8573
+#define GL_ADD_SIGNED 0x8574
+#define GL_INTERPOLATE 0x8575
+#define GL_CONSTANT 0x8576
+#define GL_PRIMARY_COLOR 0x8577
+#define GL_PREVIOUS 0x8578
+#define GL_OPERAND0_RGB 0x8590
+#define GL_OPERAND1_RGB 0x8591
+#define GL_OPERAND2_RGB 0x8592
+#define GL_OPERAND0_ALPHA 0x8598
+#define GL_OPERAND1_ALPHA 0x8599
+#define GL_OPERAND2_ALPHA 0x859A
+
+#define GL_ALPHA_SCALE 0x0D1C
+
+#define GL_SRC0_RGB 0x8580
+#define GL_SRC1_RGB 0x8581
+#define GL_SRC2_RGB 0x8582
+#define GL_SRC0_ALPHA 0x8588
+#define GL_SRC1_ALPHA 0x8589
+#define GL_SRC2_ALPHA 0x858A
+
+#define GL_DOT3_RGB 0x86AE
+#define GL_DOT3_RGBA 0x86AF
+
+/*------------------------------------------------------------------------*
+ * required OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* OES_read_format */
+#ifndef GL_OES_read_format
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+#endif
+
+/* OES_point_size_array */
+#ifndef GL_OES_point_size_array
+#define GL_POINT_SIZE_ARRAY_OES 0x8B9C
+#define GL_POINT_SIZE_ARRAY_TYPE_OES 0x898A
+#define GL_POINT_SIZE_ARRAY_STRIDE_OES 0x898B
+#define GL_POINT_SIZE_ARRAY_POINTER_OES 0x898C
+#define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES 0x8B9F
+#endif
+
+/* GL_OES_point_sprite */
+#ifndef GL_OES_point_sprite
+#define GL_POINT_SPRITE_OES 0x8861
+#define GL_COORD_REPLACE_OES 0x8862
+#endif
+
+/*************************************************************/
+
+/* Available only in Common profile */
+GL_API void GL_APIENTRY glAlphaFunc (GLenum func, GLclampf ref);
+GL_API void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_API void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_API void GL_APIENTRY glClipPlanef (GLenum plane, const GLfloat *equation);
+GL_API void GL_APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GL_API void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_API void GL_APIENTRY glFogf (GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glFogfv (GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glFrustumf (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glGetClipPlanef (GLenum pname, GLfloat eqn[4]);
+GL_API void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetLightfv (GLenum light, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetMaterialfv (GLenum face, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetTexEnvfv (GLenum env, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glLightModelf (GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glLightModelfv (GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glLightf (GLenum light, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glLightfv (GLenum light, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glLineWidth (GLfloat width);
+GL_API void GL_APIENTRY glLoadMatrixf (const GLfloat *m);
+GL_API void GL_APIENTRY glMaterialf (GLenum face, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glMultMatrixf (const GLfloat *m);
+GL_API void GL_APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+GL_API void GL_APIENTRY glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);
+GL_API void GL_APIENTRY glOrthof (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glPointParameterf (GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glPointSize (GLfloat size);
+GL_API void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_API void GL_APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+GL_API void GL_APIENTRY glScalef (GLfloat x, GLfloat y, GLfloat z);
+GL_API void GL_APIENTRY glTexEnvf (GLenum target, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z);
+
+/* Available in both Common and Common-Lite profiles */
+GL_API void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_API void GL_APIENTRY glAlphaFuncx (GLenum func, GLclampx ref);
+GL_API void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_API void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_API void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_API void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+GL_API void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
+GL_API void GL_APIENTRY glClear (GLbitfield mask);
+GL_API void GL_APIENTRY glClearColorx (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+GL_API void GL_APIENTRY glClearDepthx (GLclampx depth);
+GL_API void GL_APIENTRY glClearStencil (GLint s);
+GL_API void GL_APIENTRY glClientActiveTexture (GLenum texture);
+GL_API void GL_APIENTRY glClipPlanex (GLenum plane, const GLfixed *equation);
+GL_API void GL_APIENTRY glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+GL_API void GL_APIENTRY glColor4x (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GL_API void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_API void GL_APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+GL_API void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+GL_API void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_API void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glCullFace (GLenum mode);
+GL_API void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
+GL_API void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
+GL_API void GL_APIENTRY glDepthFunc (GLenum func);
+GL_API void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_API void GL_APIENTRY glDepthRangex (GLclampx zNear, GLclampx zFar);
+GL_API void GL_APIENTRY glDisable (GLenum cap);
+GL_API void GL_APIENTRY glDisableClientState (GLenum array);
+GL_API void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_API void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+GL_API void GL_APIENTRY glEnable (GLenum cap);
+GL_API void GL_APIENTRY glEnableClientState (GLenum array);
+GL_API void GL_APIENTRY glFinish (void);
+GL_API void GL_APIENTRY glFlush (void);
+GL_API void GL_APIENTRY glFogx (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glFogxv (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glFrontFace (GLenum mode);
+GL_API void GL_APIENTRY glFrustumx (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *params);
+GL_API void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetClipPlanex (GLenum pname, GLfixed eqn[4]);
+GL_API void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
+GL_API void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures);
+GL_API GLenum GL_APIENTRY glGetError (void);
+GL_API void GL_APIENTRY glGetFixedv (GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetLightxv (GLenum light, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetMaterialxv (GLenum face, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetPointerv (GLenum pname, void **params);
+GL_API const GLubyte * GL_APIENTRY glGetString (GLenum name);
+GL_API void GL_APIENTRY glGetTexEnviv (GLenum env, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetTexEnvxv (GLenum env, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetTexParameterxv (GLenum target, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_API GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_API GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_API GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_API void GL_APIENTRY glLightModelx (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightModelxv (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLightx (GLenum light, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightxv (GLenum light, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLineWidthx (GLfixed width);
+GL_API void GL_APIENTRY glLoadIdentity (void);
+GL_API void GL_APIENTRY glLoadMatrixx (const GLfixed *m);
+GL_API void GL_APIENTRY glLogicOp (GLenum opcode);
+GL_API void GL_APIENTRY glMaterialx (GLenum face, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glMaterialxv (GLenum face, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glMatrixMode (GLenum mode);
+GL_API void GL_APIENTRY glMultMatrixx (const GLfixed *m);
+GL_API void GL_APIENTRY glMultiTexCoord4x (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GL_API void GL_APIENTRY glNormal3x (GLfixed nx, GLfixed ny, GLfixed nz);
+GL_API void GL_APIENTRY glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_API void GL_APIENTRY glPointParameterx (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glPointParameterxv (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glPointSizex (GLfixed size);
+GL_API void GL_APIENTRY glPolygonOffsetx (GLfixed factor, GLfixed units);
+GL_API void GL_APIENTRY glPopMatrix (void);
+GL_API void GL_APIENTRY glPushMatrix (void);
+GL_API void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+GL_API void GL_APIENTRY glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_API void GL_APIENTRY glSampleCoveragex (GLclampx value, GLboolean invert);
+GL_API void GL_APIENTRY glScalex (GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glShadeModel (GLenum mode);
+GL_API void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_API void GL_APIENTRY glStencilMask (GLuint mask);
+GL_API void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_API void GL_APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glTexEnvi (GLenum target, GLenum pname, GLint param);
+GL_API void GL_APIENTRY glTexEnvx (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexEnviv (GLenum target, GLenum pname, const GLint *params);
+GL_API void GL_APIENTRY glTexEnvxv (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+GL_API void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_API void GL_APIENTRY glTexParameterx (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params);
+GL_API void GL_APIENTRY glTexParameterxv (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+GL_API void GL_APIENTRY glTranslatex (GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+/*------------------------------------------------------------------------*
+ * Required OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_read_format */
+#ifndef GL_OES_read_format
+#define GL_OES_read_format 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_point_size_array */
+#ifndef GL_OES_point_size_array
+#define GL_OES_point_size_array 1
+GL_API void GL_APIENTRY glPointSizePointerOES (GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+/* GL_OES_point_sprite */
+#ifndef GL_OES_point_sprite
+#define GL_OES_point_sprite 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl_h_ */
+
diff --git a/opengl/include/GLES/glext.h b/opengl/include/GLES/glext.h
new file mode 100644
index 0000000..4c01871
--- /dev/null
+++ b/opengl/include/GLES/glext.h
@@ -0,0 +1,622 @@
+#ifndef __glext_h_
+#define __glext_h_
+
+/* $Revision: 7172 $ on $Date:: 2009-01-09 11:17:41 -0800 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+# define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_blend_equation_separate */
+#ifndef GL_OES_blend_equation_separate
+/* BLEND_EQUATION_RGB_OES same as BLEND_EQUATION_OES */
+#define GL_BLEND_EQUATION_RGB_OES 0x8009
+#define GL_BLEND_EQUATION_ALPHA_OES 0x883D
+#endif
+
+/* GL_OES_blend_func_separate */
+#ifndef GL_OES_blend_func_separate
+#define GL_BLEND_DST_RGB_OES 0x80C8
+#define GL_BLEND_SRC_RGB_OES 0x80C9
+#define GL_BLEND_DST_ALPHA_OES 0x80CA
+#define GL_BLEND_SRC_ALPHA_OES 0x80CB
+#endif
+
+/* GL_OES_blend_subtract */
+#ifndef GL_OES_blend_subtract
+#define GL_BLEND_EQUATION_OES 0x8009
+#define GL_FUNC_ADD_OES 0x8006
+#define GL_FUNC_SUBTRACT_OES 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT_OES 0x800B
+#endif
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES 0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#endif
+
+/* GL_OES_draw_texture */
+#ifndef GL_OES_draw_texture
+#define GL_TEXTURE_CROP_RECT_OES 0x8B9D
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_fixed_point */
+#ifndef GL_OES_fixed_point
+#define GL_FIXED_OES 0x140C
+#endif
+
+/* GL_OES_framebuffer_object */
+#ifndef GL_OES_framebuffer_object
+#define GL_NONE_OES 0
+#define GL_FRAMEBUFFER_OES 0x8D40
+#define GL_RENDERBUFFER_OES 0x8D41
+#define GL_RGBA4_OES 0x8056
+#define GL_RGB5_A1_OES 0x8057
+#define GL_RGB565_OES 0x8D62
+#define GL_DEPTH_COMPONENT16_OES 0x81A5
+#define GL_RENDERBUFFER_WIDTH_OES 0x8D42
+#define GL_RENDERBUFFER_HEIGHT_OES 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_OES 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE_OES 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE_OES 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE_OES 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE_OES 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE_OES 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE_OES 0x8D55
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES 0x8CD3
+#define GL_COLOR_ATTACHMENT0_OES 0x8CE0
+#define GL_DEPTH_ATTACHMENT_OES 0x8D00
+#define GL_STENCIL_ATTACHMENT_OES 0x8D20
+#define GL_FRAMEBUFFER_COMPLETE_OES 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES 0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES 0x8CDA
+#define GL_FRAMEBUFFER_UNSUPPORTED_OES 0x8CDD
+#define GL_FRAMEBUFFER_BINDING_OES 0x8CA6
+#define GL_RENDERBUFFER_BINDING_OES 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE_OES 0x84E8
+#define GL_INVALID_FRAMEBUFFER_OPERATION_OES 0x0506
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES 0x88B9
+#define GL_BUFFER_ACCESS_OES 0x88BB
+#define GL_BUFFER_MAPPED_OES 0x88BC
+#define GL_BUFFER_MAP_POINTER_OES 0x88BD
+#endif
+
+/* GL_OES_matrix_get */
+#ifndef GL_OES_matrix_get
+#define GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES 0x898D
+#define GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES 0x898E
+#define GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES 0x898F
+#endif
+
+/* GL_OES_matrix_palette */
+#ifndef GL_OES_matrix_palette
+#define GL_MAX_VERTEX_UNITS_OES 0x86A4
+#define GL_MAX_PALETTE_MATRICES_OES 0x8842
+#define GL_MATRIX_PALETTE_OES 0x8840
+#define GL_MATRIX_INDEX_ARRAY_OES 0x8844
+#define GL_WEIGHT_ARRAY_OES 0x86AD
+#define GL_CURRENT_PALETTE_MATRIX_OES 0x8843
+#define GL_MATRIX_INDEX_ARRAY_SIZE_OES 0x8846
+#define GL_MATRIX_INDEX_ARRAY_TYPE_OES 0x8847
+#define GL_MATRIX_INDEX_ARRAY_STRIDE_OES 0x8848
+#define GL_MATRIX_INDEX_ARRAY_POINTER_OES 0x8849
+#define GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES 0x8B9E
+#define GL_WEIGHT_ARRAY_SIZE_OES 0x86AB
+#define GL_WEIGHT_ARRAY_TYPE_OES 0x86A9
+#define GL_WEIGHT_ARRAY_STRIDE_OES 0x86AA
+#define GL_WEIGHT_ARRAY_POINTER_OES 0x86AC
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_OES 0x889E
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES 0x8051
+#define GL_RGBA8_OES 0x8058
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES 0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES 0x8D47
+#endif
+
+/* GL_OES_stencil8 */
+#ifndef GL_OES_stencil8
+#define GL_STENCIL_INDEX8_OES 0x8D48
+#endif
+
+/* GL_OES_stencil_wrap */
+#ifndef GL_OES_stencil_wrap
+#define GL_INCR_WRAP_OES 0x8507
+#define GL_DECR_WRAP_OES 0x8508
+#endif
+
+/* GL_OES_texture_cube_map */
+#ifndef GL_OES_texture_cube_map
+#define GL_NORMAL_MAP_OES 0x8511
+#define GL_REFLECTION_MAP_OES 0x8512
+#define GL_TEXTURE_CUBE_MAP_OES 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_OES 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES 0x851C
+#define GL_TEXTURE_GEN_MODE_OES 0x2500
+#define GL_TEXTURE_GEN_STR_OES 0x8D60
+#endif
+
+/* GL_OES_texture_mirrored_repeat */
+#ifndef GL_OES_texture_mirrored_repeat
+#define GL_MIRRORED_REPEAT_OES 0x8370
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD 0x87F9
+#define GL_3DC_XY_AMD 0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD 0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_blend_equation_separate */
+#ifndef GL_OES_blend_equation_separate
+#define GL_OES_blend_equation_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glBlendEquationSeparateOES (GLenum modeRGB, GLenum modeAlpha);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEOESPROC) (GLenum modeRGB, GLenum modeAlpha);
+#endif
+
+/* GL_OES_blend_func_separate */
+#ifndef GL_OES_blend_func_separate
+#define GL_OES_blend_func_separate 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glBlendFuncSeparateOES (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEOESPROC) (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+#endif
+
+/* GL_OES_blend_subtract */
+#ifndef GL_OES_blend_subtract
+#define GL_OES_blend_subtract 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glBlendEquationOES (GLenum mode);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONOESPROC) (GLenum mode);
+#endif
+
+/* GL_OES_byte_coordinates */
+#ifndef GL_OES_byte_coordinates
+#define GL_OES_byte_coordinates 1
+#endif
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 1
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 1
+#endif
+
+/* GL_OES_draw_texture */
+#ifndef GL_OES_draw_texture
+#define GL_OES_draw_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glDrawTexsOES (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height);
+GL_API void GL_APIENTRY glDrawTexiOES (GLint x, GLint y, GLint z, GLint width, GLint height);
+GL_API void GL_APIENTRY glDrawTexxOES (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height);
+GL_API void GL_APIENTRY glDrawTexsvOES (const GLshort *coords);
+GL_API void GL_APIENTRY glDrawTexivOES (const GLint *coords);
+GL_API void GL_APIENTRY glDrawTexxvOES (const GLfixed *coords);
+GL_API void GL_APIENTRY glDrawTexfOES (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
+GL_API void GL_APIENTRY glDrawTexfvOES (const GLfloat *coords);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWTEXSOESPROC) (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXIOESPROC) (GLint x, GLint y, GLint z, GLint width, GLint height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXXOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXSVOESPROC) (const GLshort *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXIVOESPROC) (const GLint *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXXVOESPROC) (const GLfixed *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXFOESPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXFVOESPROC) (const GLfloat *coords);
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_API void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 1
+#endif
+
+/* GL_OES_extended_matrix_palette */
+#ifndef GL_OES_extended_matrix_palette
+#define GL_OES_extended_matrix_palette 1
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 1
+#endif
+
+/* GL_OES_fixed_point */
+#ifndef GL_OES_fixed_point
+#define GL_OES_fixed_point 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glAlphaFuncxOES (GLenum func, GLclampx ref);
+GL_API void GL_APIENTRY glClearColorxOES (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+GL_API void GL_APIENTRY glClearDepthxOES (GLclampx depth);
+GL_API void GL_APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation);
+GL_API void GL_APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GL_API void GL_APIENTRY glDepthRangexOES (GLclampx zNear, GLclampx zFar);
+GL_API void GL_APIENTRY glFogxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glFogxvOES (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glFrustumxOES (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glGetClipPlanexOES (GLenum pname, GLfixed eqn[4]);
+GL_API void GL_APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetLightxvOES (GLenum light, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetMaterialxvOES (GLenum face, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetTexEnvxvOES (GLenum env, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glLightModelxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLineWidthxOES (GLfixed width);
+GL_API void GL_APIENTRY glLoadMatrixxOES (const GLfixed *m);
+GL_API void GL_APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glMultMatrixxOES (const GLfixed *m);
+GL_API void GL_APIENTRY glMultiTexCoord4xOES (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GL_API void GL_APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz);
+GL_API void GL_APIENTRY glOrthoxOES (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glPointParameterxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glPointSizexOES (GLfixed size);
+GL_API void GL_APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units);
+GL_API void GL_APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glSampleCoveragexOES (GLclampx value, GLboolean invert);
+GL_API void GL_APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z);
+#endif
+typedef void (GL_APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLclampx ref);
+typedef void (GL_APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+typedef void (GL_APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLclampx depth);
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation);
+typedef void (GL_APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (GL_APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLclampx zNear, GLclampx zFar);
+typedef void (GL_APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum pname, GLfixed eqn[4]);
+typedef void (GL_APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETLIGHTXVOESPROC) (GLenum light, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETMATERIALXVOESPROC) (GLenum face, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum env, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width);
+typedef void (GL_APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m);
+typedef void (GL_APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m);
+typedef void (GL_APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+typedef void (GL_APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz);
+typedef void (GL_APIENTRYP PFNGLORTHOXOESPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+typedef void (GL_APIENTRYP PFNGLPOINTPARAMETERXOESPROC) (GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size);
+typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units);
+typedef void (GL_APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+typedef void (GL_APIENTRYP PFNGLSAMPLECOVERAGEXOESPROC) (GLclampx value, GLboolean invert);
+typedef void (GL_APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (GL_APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+#endif
+
+/* GL_OES_framebuffer_object */
+#ifndef GL_OES_framebuffer_object
+#define GL_OES_framebuffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API GLboolean GL_APIENTRY glIsRenderbufferOES (GLuint renderbuffer);
+GL_API void GL_APIENTRY glBindRenderbufferOES (GLenum target, GLuint renderbuffer);
+GL_API void GL_APIENTRY glDeleteRenderbuffersOES (GLsizei n, const GLuint* renderbuffers);
+GL_API void GL_APIENTRY glGenRenderbuffersOES (GLsizei n, GLuint* renderbuffers);
+GL_API void GL_APIENTRY glRenderbufferStorageOES (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glGetRenderbufferParameterivOES (GLenum target, GLenum pname, GLint* params);
+GL_API GLboolean GL_APIENTRY glIsFramebufferOES (GLuint framebuffer);
+GL_API void GL_APIENTRY glBindFramebufferOES (GLenum target, GLuint framebuffer);
+GL_API void GL_APIENTRY glDeleteFramebuffersOES (GLsizei n, const GLuint* framebuffers);
+GL_API void GL_APIENTRY glGenFramebuffersOES (GLsizei n, GLuint* framebuffers);
+GL_API GLenum GL_APIENTRY glCheckFramebufferStatusOES (GLenum target);
+GL_API void GL_APIENTRY glFramebufferRenderbufferOES (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_API void GL_APIENTRY glFramebufferTexture2DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_API void GL_APIENTRY glGetFramebufferAttachmentParameterivOES (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_API void GL_APIENTRY glGenerateMipmapOES (GLenum target);
+#endif
+typedef GLboolean (GL_APIENTRYP PFNGLISRENDERBUFFEROESPROC) (GLuint renderbuffer);
+typedef void (GL_APIENTRYP PFNGLBINDRENDERBUFFEROESPROC) (GLenum target, GLuint renderbuffer);
+typedef void (GL_APIENTRYP PFNGLDELETERENDERBUFFERSOESPROC) (GLsizei n, const GLuint* renderbuffers);
+typedef void (GL_APIENTRYP PFNGLGENRENDERBUFFERSOESPROC) (GLsizei n, GLuint* renderbuffers);
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVOESPROC) (GLenum target, GLenum pname, GLint* params);
+typedef GLboolean (GL_APIENTRYP PFNGLISFRAMEBUFFEROESPROC) (GLuint framebuffer);
+typedef void (GL_APIENTRYP PFNGLBINDFRAMEBUFFEROESPROC) (GLenum target, GLuint framebuffer);
+typedef void (GL_APIENTRYP PFNGLDELETEFRAMEBUFFERSOESPROC) (GLsizei n, const GLuint* framebuffers);
+typedef void (GL_APIENTRYP PFNGLGENFRAMEBUFFERSOESPROC) (GLsizei n, GLuint* framebuffers);
+typedef GLenum (GL_APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSOESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEROESPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVOESPROC) (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+typedef void (GL_APIENTRYP PFNGLGENERATEMIPMAPOESPROC) (GLenum target);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_API GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_API void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, void** params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void** params);
+#endif
+
+/* GL_OES_matrix_get */
+#ifndef GL_OES_matrix_get
+#define GL_OES_matrix_get 1
+#endif
+
+/* GL_OES_matrix_palette */
+#ifndef GL_OES_matrix_palette
+#define GL_OES_matrix_palette 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glCurrentPaletteMatrixOES (GLuint matrixpaletteindex);
+GL_API void GL_APIENTRY glLoadPaletteFromModelViewMatrixOES (void);
+GL_API void GL_APIENTRY glMatrixIndexPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glWeightPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+typedef void (GL_APIENTRYP PFNGLCURRENTPALETTEMATRIXOESPROC) (GLuint matrixpaletteindex);
+typedef void (GL_APIENTRYP PFNGLLOADPALETTEFROMMODELVIEWMATRIXOESPROC) (void);
+typedef void (GL_APIENTRYP PFNGLMATRIXINDEXPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GL_APIENTRYP PFNGLWEIGHTPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 1
+#endif
+
+/* GL_OES_query_matrix */
+#ifndef GL_OES_query_matrix
+#define GL_OES_query_matrix 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API GLbitfield GL_APIENTRY glQueryMatrixxOES (GLfixed mantissa[16], GLint exponent[16]);
+#endif
+typedef GLbitfield (GL_APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed mantissa[16], GLint exponent[16]);
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 1
+#endif
+
+/* GL_OES_single_precision */
+#ifndef GL_OES_single_precision
+#define GL_OES_single_precision 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glDepthRangefOES (GLclampf zNear, GLclampf zFar);
+GL_API void GL_APIENTRY glFrustumfOES (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glOrthofOES (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation);
+GL_API void GL_APIENTRY glGetClipPlanefOES (GLenum pname, GLfloat eqn[4]);
+GL_API void GL_APIENTRY glClearDepthfOES (GLclampf depth);
+#endif
+typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf zNear, GLclampf zFar);
+typedef void (GL_APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+typedef void (GL_APIENTRYP PFNGLORTHOFOESPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);
+typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum pname, GLfloat eqn[4]);
+typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth);
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 1
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 1
+#endif
+
+/* GL_OES_stencil8 */
+#ifndef GL_OES_stencil8
+#define GL_OES_stencil8 1
+#endif
+
+/* GL_OES_stencil_wrap */
+#ifndef GL_OES_stencil_wrap
+#define GL_OES_stencil_wrap 1
+#endif
+
+/* GL_OES_texture_cube_map */
+#ifndef GL_OES_texture_cube_map
+#define GL_OES_texture_cube_map 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glTexGenfOES (GLenum coord, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glTexGenfvOES (GLenum coord, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glTexGeniOES (GLenum coord, GLenum pname, GLint param);
+GL_API void GL_APIENTRY glTexGenivOES (GLenum coord, GLenum pname, const GLint *params);
+GL_API void GL_APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glGetTexGenfvOES (GLenum coord, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetTexGenivOES (GLenum coord, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXGENFOESPROC) (GLenum coord, GLenum pname, GLfloat param);
+typedef void (GL_APIENTRYP PFNGLTEXGENFVOESPROC) (GLenum coord, GLenum pname, const GLfloat *params);
+typedef void (GL_APIENTRYP PFNGLTEXGENIOESPROC) (GLenum coord, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLTEXGENIVOESPROC) (GLenum coord, GLenum pname, const GLint *params);
+typedef void (GL_APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENFVOESPROC) (GLenum coord, GLenum pname, GLfloat *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENIVOESPROC) (GLenum coord, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);
+#endif
+
+/* GL_OES_texture_env_crossbar */
+#ifndef GL_OES_texture_env_crossbar
+#define GL_OES_texture_env_crossbar 1
+#endif
+
+/* GL_OES_texture_mirrored_repeat */
+#ifndef GL_OES_texture_mirrored_repeat
+#define GL_OES_texture_mirrored_repeat 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 1
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * dalvik extension functions
+ *------------------------------------------------------------------------*/
+#ifdef ANDROID
+void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+ const GLvoid *ptr, GLsizei count);
+void glNormalPointerBounds(GLenum type, GLsizei stride,
+ const GLvoid *pointer, GLsizei count);
+void glTexCoordPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+void glVertexPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __glext_h_ */
+
diff --git a/opengl/include/GLES/glplatform.h b/opengl/include/GLES/glplatform.h
new file mode 100644
index 0000000..0924cae
--- /dev/null
+++ b/opengl/include/GLES/glplatform.h
@@ -0,0 +1,39 @@
+#ifndef __glplatform_h_
+#define __glplatform_h_
+
+/* $Revision: 7172 $ on $Date:: 2009-01-09 11:17:41 -0800 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 1.X gl.h
+ * Last modified on 2008/12/19
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+#ifndef GL_API
+#define GL_API KHRONOS_APICALL
+#endif
+
+#if defined(ANDROID)
+
+#define GL_APIENTRY KHRONOS_APIENTRY
+
+// XXX: this should probably not be here
+#define GL_DIRECT_TEXTURE_2D_QUALCOMM 0x7E80
+
+// XXX: not sure how this is intended to be used
+#define GL_GLEXT_PROTOTYPES
+
+#endif
+
+#endif /* __glplatform_h_ */
diff --git a/opengl/include/KHR/khrplatform.h b/opengl/include/KHR/khrplatform.h
new file mode 100644
index 0000000..4cc27c5
--- /dev/null
+++ b/opengl/include/KHR/khrplatform.h
@@ -0,0 +1,241 @@
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Platform-specific types and definitions.
+ * $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $
+ *
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by sending them to the public Khronos Bugzilla
+ * (http://khronos.org/bugzilla) by filing a bug against product
+ * "Khronos (general)" component "Registry".
+ *
+ * A predefined template which fills in some of the bug fields can be
+ * reached using http://tinyurl.com/khrplatform-h-bugreport, but you
+ * must create a Bugzilla login first.
+ *
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system.
+ * http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ *
+ * This file should be included as
+ * #include <KHR/khrplatform.h>
+ * by the Khronos API header file that uses its types and defines.
+ *
+ * The types in this file should only be used to define API-specific types.
+ * Types defined in this file:
+ * khronos_int8_t signed 8 bit
+ * khronos_uint8_t unsigned 8 bit
+ * khronos_int16_t signed 16 bit
+ * khronos_uint16_t unsigned 16 bit
+ * khronos_int32_t signed 32 bit
+ * khronos_uint32_t unsigned 32 bit
+ * khronos_int64_t signed 64 bit
+ * khronos_uint64_t unsigned 64 bit
+ * khronos_intptr_t signed same number of bits as a pointer
+ * khronos_uintptr_t unsigned same number of bits as a pointer
+ * khronos_ssize_t signed size
+ * khronos_usize_t unsigned size
+ * khronos_float_t signed 32 bit floating point
+ * khronos_time_ns_t unsigned 64 bit time in nanoseconds
+ * khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ * nanoseconds
+ * khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ *
+ * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ *
+ *
+ * Macros defined in this file:
+ * KHRONOS_APICALL
+ * KHRONOS_APIENTRY
+ * KHRONOS_APIATTRIBUTES
+ * These may be used in function prototypes as:
+ * KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+ * int arg1,
+ * int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
+# define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+# define KHRONOS_APICALL IMPORT_C
+#else
+# define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIENTRY
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
+ /* Win32 but not WinCE */
+# define KHRONOS_APIENTRY __stdcall
+#else
+# define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32 khronos_int32_t;
+typedef unsigned __int32 khronos_uint32_t;
+typedef __int64 khronos_int64_t;
+typedef unsigned __int64 khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int khronos_int64_t;
+typedef unsigned long int khronos_uint64_t;
+#else
+typedef long long int khronos_int64_t;
+typedef unsigned long long int khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64 0
+#define KHRONOS_SUPPORT_FLOAT 0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed char khronos_int8_t;
+typedef unsigned char khronos_uint8_t;
+typedef signed short int khronos_int16_t;
+typedef unsigned short int khronos_uint16_t;
+typedef signed long int khronos_intptr_t;
+typedef unsigned long int khronos_uintptr_t;
+typedef signed long int khronos_ssize_t;
+typedef unsigned long int khronos_usize_t;
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef float khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or
+ * an absolute Unadjusted System Time. Unadjusted System Time is the number
+ * of nanoseconds since some arbitrary system event (e.g. since the last
+ * time the system booted). The Unadjusted System Time is an unsigned
+ * 64 bit value that wraps back to 0 every 584 years. Time intervals
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t khronos_utime_nanoseconds_t;
+typedef khronos_int64_t khronos_stime_nanoseconds_t;
+#endif
+
+
+#endif /* __khrplatform_h_ */
diff --git a/opengl/java/android/opengl/Matrix.java b/opengl/java/android/opengl/Matrix.java
index 38be6be..13ba36e 100644
--- a/opengl/java/android/opengl/Matrix.java
+++ b/opengl/java/android/opengl/Matrix.java
@@ -19,7 +19,7 @@ package android.opengl;
/**
* Matrix math utilities. These methods operate on OpenGL ES format
* matrices and vectors stored in float arrays.
- *
+ *
* Matrices are 4 x 4 column-vector matrices stored in column-major
* order:
* <pre>
@@ -28,7 +28,7 @@ package android.opengl;
* m[offset + 2] m[offset + 6] m[offset + 10] m[offset + 14]
* m[offset + 3] m[offset + 7] m[offset + 11] m[offset + 15]
* </pre>
- *
+ *
* Vectors are 4 row x 1 column column-vectors stored in order:
* <pre>
* v[offset + 0]
@@ -45,11 +45,11 @@ public class Matrix {
* matrix multiplication works, the result matrix will have the same
* effect as first multiplying by the rhs matrix, then multiplying by
* the lhs matrix. This is the opposite of what you might expect.
- *
+ *
* The same float array may be passed for result, lhs, and/or rhs. However,
* the result element values are undefined if the result elements overlap
* either the lhs or rhs elements.
- *
+ *
* @param result The float array that holds the result.
* @param resultOffset The offset into the result array where the result is
* stored.
@@ -57,7 +57,7 @@ public class Matrix {
* @param lhsOffset The offset into the lhs array where the lhs is stored
* @param rhs The float array that holds the right-hand-side matrix.
* @param rhsOffset The offset into the rhs array where the rhs is stored.
- *
+ *
* @throws IllegalArgumentException if result, lhs, or rhs are null, or if
* resultOffset + 16 > result.length or lhsOffset + 16 > lhs.length or
* rhsOffset + 16 > rhs.length.
@@ -68,11 +68,11 @@ public class Matrix {
/**
* Multiply a 4 element vector by a 4x4 matrix and store the result in a 4
* element column vector. In matrix notation: result = lhs x rhs
- *
+ *
* The same float array may be passed for resultVec, lhsMat, and/or rhsVec.
* However, the resultVec element values are undefined if the resultVec
* elements overlap either the lhsMat or rhsVec elements.
- *
+ *
* @param resultVec The float array that holds the result vector.
* @param resultVecOffset The offset into the result array where the result
* vector is stored.
@@ -90,10 +90,10 @@ public class Matrix {
public static native void multiplyMV(float[] resultVec,
int resultVecOffset, float[] lhsMat, int lhsMatOffset,
float[] rhsVec, int rhsVecOffset);
-
+
/**
* Transposes a 4 x 4 matrix.
- *
+ *
* @param mTrans the array that holds the output inverted matrix
* @param mTransOffset an offset into mInv where the inverted matrix is
* stored.
@@ -113,7 +113,7 @@ public class Matrix {
/**
* Inverts a 4 x 4 matrix.
- *
+ *
* @param mInv the array that holds the output inverted matrix
* @param mInvOffset an offset into mInv where the inverted matrix is
* stored.
@@ -220,7 +220,7 @@ public class Matrix {
/**
* Computes an orthographic projection matrix.
- *
+ *
* @param m returns the result
* @param mOffset
* @param left
@@ -269,8 +269,8 @@ public class Matrix {
m[mOffset + 9] = 0.0f;
m[mOffset + 11] = 0.0f;
}
-
-
+
+
/**
* Define a projection matrix in terms of six clip planes
* @param m the float array that holds the perspective matrix
@@ -283,7 +283,7 @@ public class Matrix {
* @param near
* @param far
*/
-
+
public static void frustumM(float[] m, int offset,
float left, float right, float bottom, float top,
float near, float far) {
@@ -331,7 +331,7 @@ public class Matrix {
/**
* Computes the length of a vector
- *
+ *
* @param x x coordinate of a vector
* @param y y coordinate of a vector
* @param z z coordinate of a vector
@@ -340,7 +340,7 @@ public class Matrix {
public static float length(float x, float y, float z) {
return (float) Math.sqrt(x * x + y * y + z * z);
}
-
+
/**
* Sets matrix m to the identity matrix.
* @param sm returns the result
@@ -356,7 +356,7 @@ public class Matrix {
}
/**
- * Scales matrix m by sx, sy, and sz, putting the result in sm
+ * Scales matrix m by x, y, and z, putting the result in sm
* @param sm returns the result
* @param smOffset index into sm where the result matrix starts
* @param m source matrix
@@ -395,9 +395,9 @@ public class Matrix {
m[ 8 + mi] *= z;
}
}
-
+
/**
- * Translates matrix m by sx, sy, and sz, putting the result in tm
+ * Translates matrix m by x, y, and z, putting the result in tm
* @param tm returns the result
* @param tmOffset index into sm where the result matrix starts
* @param m source matrix
@@ -409,6 +409,9 @@ public class Matrix {
public static void translateM(float[] tm, int tmOffset,
float[] m, int mOffset,
float x, float y, float z) {
+ for (int i=0 ; i<12 ; i++) {
+ tm[tmOffset + i] = m[mOffset + i];
+ }
for (int i=0 ; i<4 ; i++) {
int tmi = tmOffset + i;
int mi = mOffset + i;
@@ -416,9 +419,9 @@ public class Matrix {
m[12 + mi];
}
}
-
+
/**
- * Translates matrix m by sx, sy, and sz in place.
+ * Translates matrix m by x, y, and z in place.
* @param m matrix
* @param mOffset index into m where the matrix starts
* @param x translation factor x
@@ -433,7 +436,7 @@ public class Matrix {
m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z;
}
}
-
+
/**
* Rotates matrix m by angle a (in degrees) around the axis (x, y, z)
* @param rm returns the result
@@ -452,7 +455,7 @@ public class Matrix {
setRotateM(r, 0, a, x, y, z);
multiplyMM(rm, rmOffset, m, mOffset, r, 0);
}
-
+
/**
* Rotates matrix m in place by angle a (in degrees)
* around the axis (x, y, z)
@@ -470,7 +473,7 @@ public class Matrix {
multiplyMM(temp, 16, m, mOffset, temp, 0);
System.arraycopy(temp, 16, m, mOffset, 16);
}
-
+
/**
* Rotates matrix m by angle a (in degrees) around the axis (x, y, z)
* @param rm returns the result
@@ -524,7 +527,7 @@ public class Matrix {
float zx = z * x;
float xs = x * s;
float ys = y * s;
- float zs = z * s;
+ float zs = z * s;
rm[rmOffset + 0] = x*x*nc + c;
rm[rmOffset + 4] = xy*nc - zs;
rm[rmOffset + 8] = zx*nc + ys;
@@ -536,7 +539,7 @@ public class Matrix {
rm[rmOffset + 10] = z*z*nc + c;
}
}
-
+
/**
* Converts Euler angles to a rotation matrix
* @param rm returns the result
@@ -558,7 +561,7 @@ public class Matrix {
float sz = (float) Math.sin(z);
float cxsy = cx * sy;
float sxsy = sx * sy;
-
+
rm[rmOffset + 0] = cy * cz;
rm[rmOffset + 1] = -cy * sz;
rm[rmOffset + 2] = sy;
diff --git a/opengl/java/android/opengl/Visibility.java b/opengl/java/android/opengl/Visibility.java
index b802160..40e446f 100644
--- a/opengl/java/android/opengl/Visibility.java
+++ b/opengl/java/android/opengl/Visibility.java
@@ -17,7 +17,6 @@
package android.opengl;
/**
- * {@hide}
* A collection of utility methods for computing the visibility of triangle
* meshes.
*
diff --git a/opengl/libGLES_CM/Android.mk b/opengl/libGLES_CM/Android.mk
deleted file mode 100644
index e350e02..0000000
--- a/opengl/libGLES_CM/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#
-# Build the wrapper OpenGL ES library
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= gl_wrapper.cpp.arm gl_logger.cpp
-
-LOCAL_SHARED_LIBRARIES += libcutils libutils libui
-LOCAL_LDLIBS := -lpthread -ldl
-LOCAL_MODULE:= libGLES_CM
-
-# needed on sim build because of weird logging issues
-ifeq ($(TARGET_SIMULATOR),true)
-else
- LOCAL_SHARED_LIBRARIES += libdl
- # we need to access the Bionic private header <bionic_tls.h>
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
-endif
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 3e8dca9..5b90bf0 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -33,7 +33,10 @@
#include <utils/threads.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
#include <pixelflinger/format.h>
#include <pixelflinger/pixelflinger.h>
@@ -149,7 +152,6 @@ struct egl_surface_t
virtual EGLint getRefreshRate() const;
virtual EGLint getSwapBehavior() const;
virtual EGLBoolean swapBuffers();
- virtual EGLBoolean swapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
protected:
GGLSurface depth;
};
@@ -171,10 +173,6 @@ egl_surface_t::~egl_surface_t()
EGLBoolean egl_surface_t::swapBuffers() {
return EGL_FALSE;
}
-EGLBoolean egl_surface_t::swapRectangle(
- EGLint l, EGLint t, EGLint w, EGLint h) {
- return EGL_FALSE;
-}
EGLint egl_surface_t::getHorizontalResolution() const {
return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
}
@@ -201,7 +199,6 @@ struct egl_window_surface_t : public egl_surface_t
virtual bool isValid() const { return nativeWindow->magic == 0x600913; }
virtual EGLBoolean swapBuffers();
- virtual EGLBoolean swapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
virtual EGLint getWidth() const { return nativeWindow->width; }
@@ -243,7 +240,6 @@ EGLBoolean egl_window_surface_t::swapBuffers()
if (flags & EGL_NATIVES_FLAG_SIZE_CHANGED) {
// TODO: we probably should reset the swap rect here
// if the window size has changed
- // window->setSwapRectangle(Rect(info.w, info.h));
if (depth.data) {
free(depth.data);
depth.width = nativeWindow->width;
@@ -259,12 +255,6 @@ EGLBoolean egl_window_surface_t::swapBuffers()
return EGL_TRUE;
}
-EGLBoolean egl_window_surface_t::swapRectangle(
- EGLint l, EGLint t, EGLint w, EGLint h)
-{
- nativeWindow->setSwapRectangle(nativeWindow, l, t, w, h);
- return EGL_TRUE;
-}
EGLBoolean egl_window_surface_t::bindDrawSurface(ogles_context_t* gl)
{
GGLSurface buffer;
@@ -473,24 +463,21 @@ struct config_management_t {
// ----------------------------------------------------------------------------
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 2
static char const * const gVendorString = "Google Inc.";
static char const * const gVersionString = "1.2 Android Driver";
static char const * const gClientApiString = "OpenGL ES";
-static char const * const gExtensionsString =
- "EGL_ANDROID_swap_rectangle" " "
- "EGL_ANDROID_copy_front_to_back" " "
- "EGL_ANDROID_get_render_buffer_address"
- ;
+static char const * const gExtensionsString = "";
// ----------------------------------------------------------------------------
struct extention_map_t {
const char * const name;
- void (*address)(void);
+ __eglMustCastToProperFunctionPointerType address;
};
static const extention_map_t gExtentionMap[] = {
- { "eglSwapRectangleANDROID", (void(*)())&eglSwapRectangleANDROID },
{ "glDrawTexsOES", (void(*)())&glDrawTexsOES },
{ "glDrawTexiOES", (void(*)())&glDrawTexiOES },
{ "glDrawTexfOES", (void(*)())&glDrawTexfOES },
@@ -1017,8 +1004,8 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
}
if (res == EGL_TRUE) {
- if (major != NULL) *major = 1;
- if (minor != NULL) *minor = 2;
+ if (major != NULL) *major = VERSION_MAJOR;
+ if (minor != NULL) *minor = VERSION_MINOR;
}
return res;
}
@@ -1554,15 +1541,3 @@ void (*eglGetProcAddress (const char *procname))()
}
return NULL;
}
-
-EGLBoolean eglSwapRectangleANDROID(
- EGLDisplay dpy, EGLSurface draw,
- EGLint l, EGLint t, EGLint w, EGLint h)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- egl_surface_t* surface = (egl_surface_t*)draw;
- if (surface->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- return surface->swapRectangle(l, t, w, h);
-}
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
index c2f9f12..5cbabea 100644
--- a/opengl/libagl/state.cpp
+++ b/opengl/libagl/state.cpp
@@ -403,12 +403,6 @@ void glGetIntegerv(GLenum pname, GLint *params)
case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
params[0] = GL_UNSIGNED_SHORT_5_6_5;
break;
- case GL_MAX_ELEMENTS_INDICES:
- params[0] = 65536;
- break;
- case GL_MAX_ELEMENTS_VERTICES:
- params[0] = 0x7FFFFFFF;
- break;
case GL_MAX_LIGHTS:
params[0] = OGLES_MAX_LIGHTS;
break;
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 6b2640a..b6f534b 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -526,7 +526,7 @@ void generateMipmap(ogles_context_t* c, GLint level)
static void texParameterx(
GLenum target, GLenum pname, GLfixed param, ogles_context_t* c)
{
- if (target != GGL_TEXTURE_2D) {
+ if (target != GL_TEXTURE_2D) {
ogles_error(c, GL_INVALID_ENUM);
return;
}
@@ -534,8 +534,7 @@ static void texParameterx(
EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
switch (pname) {
case GL_TEXTURE_WRAP_S:
- if ((param == GL_CLAMP) ||
- (param == GL_REPEAT) ||
+ if ((param == GL_REPEAT) ||
(param == GL_CLAMP_TO_EDGE)) {
textureObject->wraps = param;
} else {
@@ -543,9 +542,8 @@ static void texParameterx(
}
break;
case GL_TEXTURE_WRAP_T:
- if ((param == GGL_CLAMP) ||
- (param == GGL_REPEAT) ||
- (param == GGL_CLAMP_TO_EDGE)) {
+ if ((param == GL_REPEAT) ||
+ (param == GL_CLAMP_TO_EDGE)) {
textureObject->wrapt = param;
} else {
goto invalid_enum;
@@ -1006,7 +1004,7 @@ void glCompressedTexImage2D(
void glTexImage2D(
- GLenum target, GLint level, GLenum internalformat,
+ GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLint border,
GLenum format, GLenum type, const GLvoid *pixels)
{
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
new file mode 100644
index 0000000..2ecc776
--- /dev/null
+++ b/opengl/libs/Android.mk
@@ -0,0 +1,53 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# Build META EGL library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ EGL/egl.cpp \
+ EGL/gpu.cpp \
+#
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libui
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libEGL
+
+# needed on sim build because of weird logging issues
+ifeq ($(TARGET_SIMULATOR),true)
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+ # we need to access the Bionic private header <bionic_tls.h>
+ LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+
+#
+# Build the wrapper OpenGL ES library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ GLES_CM/gl.cpp.arm \
+ GLES_CM/gl_logger.cpp \
+#
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libui libEGL
+LOCAL_LDLIBS := -lpthread -ldl
+LOCAL_MODULE:= libGLESv1_CM
+
+# needed on sim build because of weird logging issues
+ifeq ($(TARGET_SIMULATOR),true)
+else
+ LOCAL_SHARED_LIBRARIES += libdl
+ # we need to access the Bionic private header <bionic_tls.h>
+ LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libGLES_CM/gl_wrapper.cpp b/opengl/libs/EGL/egl.cpp
index 3197535..687c8bc 100644
--- a/opengl/libGLES_CM/gl_wrapper.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -27,31 +27,22 @@
#include <linux/android_pmem.h>
#endif
-#include <GLES/egl.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <cutils/memory.h>
-#include <utils/IMemory.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-#include <utils/IServiceManager.h>
-#include <utils/IPCThreadState.h>
-#include <utils/Parcel.h>
+#include <utils/RefBase.h>
-#include <ui/EGLDisplaySurface.h>
-#include <ui/ISurfaceComposer.h>
+#include "hooks.h"
+#include "egl_impl.h"
-#include "gl_logger.h"
-#undef NELEM
-
-#define GL_LOGGER 0
-#define USE_SLOW_BINDING 0
-#define NELEM(x) (sizeof(x)/sizeof(*(x)))
-#define MAX_NUMBER_OF_GL_EXTENSIONS 32
#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
@@ -59,26 +50,12 @@
namespace android {
// ----------------------------------------------------------------------------
-// EGLDisplay are global, not attached to a given thread
-static const unsigned int NUM_DISPLAYS = 1;
-static const unsigned int IMPL_HARDWARE = 0;
-static const unsigned int IMPL_SOFTWARE = 1;
-static const unsigned int IMPL_HARDWARE_CONTEXT_LOST = 2;
-static const unsigned int IMPL_SOFTWARE_CONTEXT_LOST = 3;
-static const unsigned int IMPL_NO_CONTEXT = 4;
-
-// ----------------------------------------------------------------------------
-
-struct gl_hooks_t;
-
-struct egl_connection_t
-{
- void volatile * dso;
- gl_hooks_t * hooks;
- EGLint major;
- EGLint minor;
- int unavailable;
-};
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 4
+static char const * const gVendorString = "Android";
+static char const * const gVersionString = "1.31 Android META-EGL";
+static char const * const gClientApiString = "OpenGL ES";
+static char const * const gExtensionString = "";
template <int MAGIC>
struct egl_object_t
@@ -103,7 +80,6 @@ struct egl_display_t : public egl_object_t<'_dpy'>
char const * version;
char const * clientApi;
char const * extensions;
- char const * extensions_config;
};
strings_t queryString[2];
};
@@ -152,82 +128,45 @@ struct tls_t
EGLContext ctx;
};
+static void gl_unimplemented() {
+ LOGE("called unimplemented OpenGL ES API");
+}
+// ----------------------------------------------------------------------------
// GL / EGL hooks
+// ----------------------------------------------------------------------------
-typedef void(*proc_t)();
-
-struct gl_hooks_t {
- struct gl_t {
- #define GL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
- #include "gl_entries.cpp"
- #undef GL_ENTRY
- } gl;
- struct egl_t {
- #define EGL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
- #include "egl_entries.cpp"
- #undef EGL_ENTRY
- } egl;
- struct gl_ext_t {
- void (*extensions[MAX_NUMBER_OF_GL_EXTENSIONS])(void);
- } ext;
-};
+#undef GL_ENTRY
+#undef EGL_ENTRY
+#define GL_ENTRY(_r, _api, ...) #_api,
+#define EGL_ENTRY(_r, _api, ...) #_api,
static char const * const gl_names[] = {
- #define GL_ENTRY(_r, _api, ...) #_api,
- #include "gl_entries.cpp"
- #undef GL_ENTRY
+ #include "gl_entries.in"
NULL
};
static char const * const egl_names[] = {
- #define EGL_ENTRY(_r, _api, ...) #_api,
- #include "egl_entries.cpp"
- #undef EGL_ENTRY
+ #include "egl_entries.in"
NULL
};
-static void gl_unimplemented() {
- LOGE("called unimplemented OpenGL ES API");
-}
+#undef GL_ENTRY
+#undef EGL_ENTRY
// ----------------------------------------------------------------------------
-static egl_connection_t gEGLImpl[2];
+egl_connection_t gEGLImpl[2];
static egl_display_t gDisplay[NUM_DISPLAYS];
-static gl_hooks_t gHooks[5];
static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t gEGLThreadLocalStorageKey = -1;
// ----------------------------------------------------------------------------
-#if defined(HAVE_ANDROID_OS) && !USE_SLOW_BINDING && !GL_LOGGER
+gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
+pthread_key_t gGLWrapperKey = -1;
-/* special private C library header */
-#include <bionic_tls.h>
-// We have a dedicated TLS slot in bionic
-static inline void setGlThreadSpecific(gl_hooks_t const *value) {
- ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL_API] = (uint32_t)value;
-}
-static gl_hooks_t const* getGlThreadSpecific() {
- gl_hooks_t const* hooks = (gl_hooks_t const *)(((unsigned const *)__get_tls())[TLS_SLOT_OPENGL_API]);
- if (hooks) return hooks;
- return &gHooks[IMPL_NO_CONTEXT];
-}
-
-#else
-
-static pthread_key_t gGLWrapperKey = -1;
-static inline void setGlThreadSpecific(gl_hooks_t const *value) {
- pthread_setspecific(gGLWrapperKey, value);
-}
-static gl_hooks_t const* getGlThreadSpecific() {
- gl_hooks_t const* hooks = static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
- if (hooks) return hooks;
- return &gHooks[IMPL_NO_CONTEXT];
-}
-
-#endif
+// ----------------------------------------------------------------------------
static __attribute__((noinline))
const char *egl_strerror(EGLint err)
@@ -322,170 +261,14 @@ EGLContext getContext() {
return tls->ctx;
}
-/*****************************************************************************/
-
-/*
- * we provide our own allocators for the GPU regions, these
- * allocators go through surfaceflinger
- */
-
-static Mutex gRegionsLock;
-static request_gpu_t gRegions;
-static sp<ISurfaceComposer> gSurfaceManager;
-ISurfaceComposer* GLES_localSurfaceManager = 0;
-
-const sp<ISurfaceComposer>& getSurfaceFlinger()
-{
- Mutex::Autolock _l(gRegionsLock);
-
- /*
- * There is a little bit of voodoo magic here. We want to access
- * surfaceflinger for allocating GPU regions, however, when we are
- * running as part of surfaceflinger, we want to bypass the
- * service manager because surfaceflinger might not be registered yet.
- * SurfaceFlinger will populate "GLES_localSurfaceManager" with its
- * own address, so we can just use that.
- */
- if (gSurfaceManager == 0) {
- if (GLES_localSurfaceManager) {
- // we're running in SurfaceFlinger's context
- gSurfaceManager = GLES_localSurfaceManager;
- } else {
- // we're a remote process or not part of surfaceflinger,
- // go through the service manager
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm != NULL) {
- sp<IBinder> binder = sm->getService(String16("SurfaceFlinger"));
- gSurfaceManager = interface_cast<ISurfaceComposer>(binder);
- }
- }
- }
- return gSurfaceManager;
-}
-
-class GPURevokeRequester : public BnGPUCallback
-{
-public:
- virtual void gpuLost() {
- LOGD("CONTEXT_LOST: Releasing GPU upon request from SurfaceFlinger.");
- gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_HARDWARE_CONTEXT_LOST];
- }
-};
-
-static sp<GPURevokeRequester> gRevokerCallback;
-
-
-static request_gpu_t* gpu_acquire(void* user)
-{
- sp<ISurfaceComposer> server( getSurfaceFlinger() );
-
- Mutex::Autolock _l(gRegionsLock);
- if (server == NULL) {
- return 0;
- }
-
- ISurfaceComposer::gpu_info_t info;
-
- if (gRevokerCallback == 0)
- gRevokerCallback = new GPURevokeRequester();
-
- status_t err = server->requestGPU(gRevokerCallback, &info);
- if (err != NO_ERROR) {
- LOGD("requestGPU returned %d", err);
- return 0;
- }
-
- bool failed = false;
- request_gpu_t* gpu = &gRegions;
- memset(gpu, 0, sizeof(*gpu));
-
- if (info.regs != 0) {
- sp<IMemoryHeap> heap(info.regs->getMemory());
- if (heap != 0) {
- int fd = heap->heapID();
- gpu->regs.fd = fd;
- gpu->regs.base = info.regs->pointer();
- gpu->regs.size = info.regs->size();
- gpu->regs.user = info.regs.get();
-#if HAVE_ANDROID_OS
- struct pmem_region region;
- if (ioctl(fd, PMEM_GET_PHYS, &region) >= 0)
- gpu->regs.phys = (void*)region.offset;
-#endif
- info.regs->incStrong(gpu);
- } else {
- LOGE("GPU register handle %p is invalid!", info.regs.get());
- failed = true;
- }
- }
-
- for (size_t i=0 ; i<info.count && !failed ; i++) {
- sp<IMemory>& region(info.regions[i].region);
- if (region != 0) {
- sp<IMemoryHeap> heap(region->getMemory());
- if (heap != 0) {
- const int fd = heap->heapID();
- gpu->gpu[i].fd = fd;
- gpu->gpu[i].base = region->pointer();
- gpu->gpu[i].size = region->size();
- gpu->gpu[i].user = region.get();
- gpu->gpu[i].offset = info.regions[i].reserved;
-#if HAVE_ANDROID_OS
- struct pmem_region reg;
- if (ioctl(fd, PMEM_GET_PHYS, &reg) >= 0)
- gpu->gpu[i].phys = (void*)reg.offset;
-#endif
- region->incStrong(gpu);
- } else {
- LOGE("GPU region handle [%d, %p] is invalid!", i, region.get());
- failed = true;
- }
- }
- }
-
- if (failed) {
- // something went wrong, clean up everything!
- if (gpu->regs.user) {
- static_cast<IMemory*>(gpu->regs.user)->decStrong(gpu);
- for (size_t i=0 ; i<info.count ; i++) {
- if (gpu->gpu[i].user) {
- static_cast<IMemory*>(gpu->gpu[i].user)->decStrong(gpu);
- }
- }
- }
- }
-
- gpu->count = info.count;
- return gpu;
-}
-
-static int gpu_release(void*, request_gpu_t* gpu)
-{
- sp<IMemory> regs;
-
- { // scope for lock
- Mutex::Autolock _l(gRegionsLock);
- regs = static_cast<IMemory*>(gpu->regs.user);
- gpu->regs.user = 0;
- if (regs != 0) regs->decStrong(gpu);
-
- for (int i=0 ; i<gpu->count ; i++) {
- sp<IMemory> r(static_cast<IMemory*>(gpu->gpu[i].user));
- gpu->gpu[i].user = 0;
- if (r != 0) r->decStrong(gpu);
- }
- }
-
- // there is a special transaction to relinquish the GPU
- // (it will happen automatically anyway if we don't do this)
- Parcel data, reply;
- // NOTE: this transaction does not require an interface token
- regs->asBinder()->transact(1000, data, &reply);
- return 1;
-}
/*****************************************************************************/
+class ISurfaceComposer;
+const sp<ISurfaceComposer>& getSurfaceFlinger();
+request_gpu_t* gpu_acquire(void* user);
+int gpu_release(void*, request_gpu_t* gpu);
+
static __attribute__((noinline))
void *load_driver(const char* driver, gl_hooks_t* hooks)
{
@@ -576,18 +359,12 @@ static int cmp_configs(const void* a, const void *b)
return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
}
-static char const * const gVendorString = "Android";
-static char const * const gVersionString = "1.3 Android META-EGL";
-static char const * const gClientApiString = "OpenGL ES";
-
struct extention_map_t {
const char* name;
- void (*address)(void);
+ __eglMustCastToProperFunctionPointerType address;
};
static const extention_map_t gExtentionMap[] = {
- { "eglSwapRectangleANDROID", (void(*)())&eglSwapRectangleANDROID },
- { "eglQueryStringConfigANDROID", (void(*)())&eglQueryStringConfigANDROID },
};
static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
@@ -604,109 +381,18 @@ static void(*findProcAddress(const char* name,
}
// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
-using namespace android;
-
-
-// ----------------------------------------------------------------------------
-// extensions for the framework
-// ----------------------------------------------------------------------------
-
-void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
- const GLvoid *ptr, GLsizei count) {
- glColorPointer(size, type, stride, ptr);
-}
-void glNormalPointerBounds(GLenum type, GLsizei stride,
- const GLvoid *pointer, GLsizei count) {
- glNormalPointer(type, stride, pointer);
-}
-void glTexCoordPointerBounds(GLint size, GLenum type,
- GLsizei stride, const GLvoid *pointer, GLsizei count) {
- glTexCoordPointer(size, type, stride, pointer);
-}
-void glVertexPointerBounds(GLint size, GLenum type,
- GLsizei stride, const GLvoid *pointer, GLsizei count) {
- glVertexPointer(size, type, stride, pointer);
-}
-
-
-// ----------------------------------------------------------------------------
-// Actual GL wrappers
-// ----------------------------------------------------------------------------
-
-#if __OPTIMIZE__ && defined(__arm__) && !defined(__thumb__) && !USE_SLOW_BINDING && !GL_LOGGER
-
- #define API_ENTRY(_api) __attribute__((naked)) _api
- #define CALL_GL_API(_api, ...) \
- asm volatile( \
- "mov r12, #0xFFFF0FFF \n" \
- "ldr r12, [r12, #-15] \n" \
- "ldr r12, [r12, %[tls]] \n" \
- "cmp r12, #0 \n" \
- "ldrne pc, [r12, %[api]] \n" \
- "bx lr \n" \
- : \
- : [tls] "J"(TLS_SLOT_OPENGL_API*4), \
- [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
- : \
- );
-
- #define CALL_GL_API_RETURN(_api, ...) \
- CALL_GL_API(_api, __VA_ARGS__) \
- return 0; // placate gcc's warnings. never reached.
-
-#else
-
- #define API_ENTRY(_api) _api
- #if GL_LOGGER
-
- #define CALL_GL_API(_api, ...) \
- gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
- log_##_api(__VA_ARGS__); \
- _c->_api(__VA_ARGS__);
-
- #define CALL_GL_API_RETURN(_api, ...) \
- gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
- log_##_api(__VA_ARGS__); \
- return _c->_api(__VA_ARGS__)
-
- #else
-
- #define CALL_GL_API(_api, ...) \
- gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
- _c->_api(__VA_ARGS__);
-
- #define CALL_GL_API_RETURN(_api, ...) \
- gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
- return _c->_api(__VA_ARGS__)
-
- #endif
-
-#endif
-
-#include "gl_api.cpp"
-
-#undef API_ENTRY
-#undef CALL_GL_API
-#undef CALL_GL_API_RETURN
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
static int gl_context_lost() {
- setGlThreadSpecific(&gHooks[IMPL_HARDWARE_CONTEXT_LOST]);
+ setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
return 0;
}
static int egl_context_lost() {
- setGlThreadSpecific(&gHooks[IMPL_HARDWARE_CONTEXT_LOST]);
+ setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
return EGL_FALSE;
}
static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
usleep(100000); // don't use all the CPU
- setGlThreadSpecific(&gHooks[IMPL_HARDWARE_CONTEXT_LOST]);
+ setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
return EGL_FALSE;
}
static GLint egl_context_lost_get_error() {
@@ -721,11 +407,14 @@ static void gl_no_context() {
}
static void early_egl_init(void)
{
-#if !defined(HAVE_ANDROID_OS) || USE_SLOW_BINDING || GL_LOGGER
+#if !USE_FAST_TLS_KEY
pthread_key_create(&gGLWrapperKey, NULL);
#endif
uint32_t addr = (uint32_t)((void*)gl_no_context);
- android_memset32((uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT], addr, sizeof(gHooks[IMPL_NO_CONTEXT]));
+ android_memset32(
+ (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
+ addr,
+ sizeof(gHooks[IMPL_NO_CONTEXT]));
setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
}
@@ -802,25 +491,12 @@ static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
return EGL_TRUE;
}
-static void add_extension(egl_display_t* dp, char const*& p, const char* ext)
-{
- if (!strstr(p, ext)) {
- p = (char const*)realloc((void*)p, strlen(p) + 1 + strlen(ext) + 1);
- strcat((char*)p, " ");
- strcat((char*)p, ext);
- }
- if (!strstr(dp->extensionsString, ext)) {
- char const*& es = dp->extensionsString;
- es = (char const*)realloc((void*)es, strlen(es) + 1 + strlen(ext) + 1);
- strcat((char*)es, " ");
- strcat((char*)es, ext);
- }
-}
-
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
+using namespace android;
+
EGLDisplay eglGetDisplay(NativeDisplayType display)
{
if (sEarlyInitState) {
@@ -854,38 +530,32 @@ EGLDisplay eglGetDisplay(NativeDisplayType display)
property_get("debug.egl.hw", value, "1");
if (atoi(value) != 0) {
cnx->hooks = &gHooks[IMPL_HARDWARE];
- property_get("debug.egl.profiler", value, "0");
- if (atoi(value) == 0) {
- cnx->dso = load_driver("libhgl.so", cnx->hooks);
- } else {
- LOGW("Using instrumented h/w OpenGL ES library");
- cnx->dso = load_driver("libhgld.so", cnx->hooks);
- }
+ cnx->dso = load_driver("libhgl.so", cnx->hooks);
} else {
LOGD("3D hardware acceleration is disabled");
}
}
if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_HARDWARE_CONTEXT_LOST].gl,
+ (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
(uint32_t)((void*)gl_context_lost),
- sizeof(gHooks[IMPL_HARDWARE_CONTEXT_LOST].gl));
+ sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl,
+ (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
(uint32_t)((void*)egl_context_lost),
- sizeof(gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl));
+ sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
android_memset32(
- (uint32_t*)(void*)&gHooks[IMPL_HARDWARE_CONTEXT_LOST].ext,
+ (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
(uint32_t)((void*)ext_context_lost),
- sizeof(gHooks[IMPL_HARDWARE_CONTEXT_LOST].ext));
+ sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
- gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl.eglSwapBuffers =
+ gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
egl_context_lost_swap_buffers;
- gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl.eglGetError =
+ gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
egl_context_lost_get_error;
- gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl.eglTerminate =
+ gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
gHooks[IMPL_HARDWARE].egl.eglTerminate;
d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
@@ -913,8 +583,8 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
if (android_atomic_inc(&dp->refs) > 0) {
- if (major != NULL) *major = 1;
- if (minor != NULL) *minor = 2;
+ if (major != NULL) *major = VERSION_MAJOR;
+ if (minor != NULL) *minor = VERSION_MINOR;
return EGL_TRUE;
}
@@ -923,7 +593,7 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
// initialize each EGL and
// build our own extension string first, based on the extension we know
// and the extension supported by our client implementation
- dp->extensionsString = strdup("EGL_ANDROID_query_string_config");
+ dp->extensionsString = strdup(gExtensionString);
for (int i=0 ; i<2 ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
cnx->major = -1;
@@ -947,54 +617,16 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
dp->queryString[i].clientApi =
cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
- // Dynamically insert extensions we know about
- if (cnx->hooks->egl.eglSwapRectangleANDROID)
- add_extension(dp, dp->queryString[i].extensions,
- "EGL_ANDROID_swap_rectangle");
-
- if (cnx->hooks->egl.eglQueryStringConfigANDROID)
- add_extension(dp, dp->queryString[i].extensions,
- "EGL_ANDROID_query_string_config");
} else {
LOGD("%d: eglInitialize() failed (%s)",
i, egl_strerror(cnx->hooks->egl.eglGetError()));
}
}
- // Build the extension list that depends on the current config.
- // It is the intersection of our extension list and the
- // underlying EGL's extensions list
EGLBoolean res = EGL_FALSE;
for (int i=0 ; i<2 ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
- char const* const their_extensions = dp->queryString[i].extensions;
- char* our_extensions = strdup(dp->extensionsString);
- char* const our_extensions_org = our_extensions;
- char* extensions_config = (char*)calloc(strlen(our_extensions)+2, 1);
- char* p;
- do {
- p = strchr(our_extensions, ' ');
- if (p) *p++ = 0;
- else p = strchr(our_extensions, 0);
- if (strstr(their_extensions, our_extensions)) {
- strcat(extensions_config, our_extensions);
- strcat(extensions_config, " ");
- }
- our_extensions = p;
- } while (*p);
- free((void*)our_extensions_org);
-
- // remove the trailing white space
- if (extensions_config[0] != 0) {
- size_t l = strlen(extensions_config) - 1; // new size
- extensions_config[l] = 0; // remove the trailing white space
- extensions_config = (char*)realloc(extensions_config, l+1);
- } else {
- extensions_config = (char*)realloc(extensions_config, 1);
- }
- dp->queryString[i].extensions_config = extensions_config;
-
EGLint n;
if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
@@ -1016,8 +648,8 @@ EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
}
if (res == EGL_TRUE) {
- if (major != NULL) *major = 1;
- if (minor != NULL) *minor = 2;
+ if (major != NULL) *major = VERSION_MAJOR;
+ if (minor != NULL) *minor = VERSION_MINOR;
return EGL_TRUE;
}
return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
@@ -1042,7 +674,6 @@ EGLBoolean eglTerminate(EGLDisplay dpy)
* threads around). */
free(dp->configs[i]);
- free((void*)dp->queryString[i].extensions_config);
free((void*)dp->queryString[i].extensions);
dp->numConfigs[i] = 0;
dp->dpys[i] = EGL_NO_DISPLAY;
@@ -1486,7 +1117,7 @@ EGLint eglGetError(void)
void (*eglGetProcAddress(const char *procname))()
{
- void (*addr)();
+ __eglMustCastToProperFunctionPointerType addr;
addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
if (addr) return addr;
@@ -1570,7 +1201,7 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name)
case EGL_VERSION:
return gVersionString;
case EGL_EXTENSIONS:
- return dp->extensionsString;
+ return gExtensionString;
case EGL_CLIENT_APIS:
return gClientApiString;
}
@@ -1730,34 +1361,3 @@ EGLSurface eglCreatePbufferFromClientBuffer(
}
return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
}
-
-// ----------------------------------------------------------------------------
-// Android extentions
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglSwapRectangleANDROID(
- EGLDisplay dpy, EGLSurface draw,
- EGLint l, EGLint t, EGLint w, EGLint h)
-{
- if (!validate_display_surface(dpy, draw))
- return EGL_FALSE;
- egl_display_t const * const dp = get_display(dpy);
- egl_surface_t const * const s = get_surface(draw);
- if (s->cnx->hooks->egl.eglSwapRectangleANDROID) {
- return s->cnx->hooks->egl.eglSwapRectangleANDROID(
- dp->dpys[s->impl], s->surface, l, t, w, h);
- }
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
-}
-
-const char* eglQueryStringConfigANDROID(
- EGLDisplay dpy, EGLConfig config, EGLint name)
-{
- egl_display_t const* dp = 0;
- int i=0, index=0;
- egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
- if (cnx) {
- return dp->queryString[i].extensions_config;
- }
- return setError(EGL_BAD_PARAMETER, (const char *)0);
-}
diff --git a/opengl/libs/EGL/gpu.cpp b/opengl/libs/EGL/gpu.cpp
new file mode 100644
index 0000000..3f9fd63
--- /dev/null
+++ b/opengl/libs/EGL/gpu.cpp
@@ -0,0 +1,212 @@
+/*
+ ** Copyright 2007, 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.
+ */
+
+#define LOG_TAG "EGL"
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <utils/IMemory.h>
+#include <utils/threads.h>
+#include <utils/IServiceManager.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Parcel.h>
+
+#include <ui/EGLDisplaySurface.h>
+#include <ui/ISurfaceComposer.h>
+
+#include "hooks.h"
+#include "egl_impl.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+/*
+ * we provide our own allocators for the GPU regions, these
+ * allocators go through surfaceflinger
+ */
+
+static Mutex gRegionsLock;
+static request_gpu_t gRegions;
+static sp<ISurfaceComposer> gSurfaceManager;
+ISurfaceComposer* GLES_localSurfaceManager = 0;
+
+extern egl_connection_t gEGLImpl[2];
+
+const sp<ISurfaceComposer>& getSurfaceFlinger()
+{
+ Mutex::Autolock _l(gRegionsLock);
+
+ /*
+ * There is a little bit of voodoo magic here. We want to access
+ * surfaceflinger for allocating GPU regions, however, when we are
+ * running as part of surfaceflinger, we want to bypass the
+ * service manager because surfaceflinger might not be registered yet.
+ * SurfaceFlinger will populate "GLES_localSurfaceManager" with its
+ * own address, so we can just use that.
+ */
+ if (gSurfaceManager == 0) {
+ if (GLES_localSurfaceManager) {
+ // we're running in SurfaceFlinger's context
+ gSurfaceManager = GLES_localSurfaceManager;
+ } else {
+ // we're a remote process or not part of surfaceflinger,
+ // go through the service manager
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm != NULL) {
+ sp<IBinder> binder = sm->getService(String16("SurfaceFlinger"));
+ gSurfaceManager = interface_cast<ISurfaceComposer>(binder);
+ }
+ }
+ }
+ return gSurfaceManager;
+}
+
+class GPURevokeRequester : public BnGPUCallback
+{
+public:
+ virtual void gpuLost() {
+ LOGD("CONTEXT_LOST: Releasing GPU upon request from SurfaceFlinger.");
+ gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
+ }
+};
+
+static sp<GPURevokeRequester> gRevokerCallback;
+
+
+request_gpu_t* gpu_acquire(void* user)
+{
+ sp<ISurfaceComposer> server( getSurfaceFlinger() );
+
+ Mutex::Autolock _l(gRegionsLock);
+ if (server == NULL) {
+ return 0;
+ }
+
+ ISurfaceComposer::gpu_info_t info;
+
+ if (gRevokerCallback == 0)
+ gRevokerCallback = new GPURevokeRequester();
+
+ status_t err = server->requestGPU(gRevokerCallback, &info);
+ if (err != NO_ERROR) {
+ LOGD("requestGPU returned %d", err);
+ return 0;
+ }
+
+ bool failed = false;
+ request_gpu_t* gpu = &gRegions;
+ memset(gpu, 0, sizeof(*gpu));
+
+ if (info.regs != 0) {
+ sp<IMemoryHeap> heap(info.regs->getMemory());
+ if (heap != 0) {
+ int fd = heap->heapID();
+ gpu->regs.fd = fd;
+ gpu->regs.base = info.regs->pointer();
+ gpu->regs.size = info.regs->size();
+ gpu->regs.user = info.regs.get();
+#if HAVE_ANDROID_OS
+ struct pmem_region region;
+ if (ioctl(fd, PMEM_GET_PHYS, &region) >= 0)
+ gpu->regs.phys = (void*)region.offset;
+#endif
+ info.regs->incStrong(gpu);
+ } else {
+ LOGE("GPU register handle %p is invalid!", info.regs.get());
+ failed = true;
+ }
+ }
+
+ for (size_t i=0 ; i<info.count && !failed ; i++) {
+ sp<IMemory>& region(info.regions[i].region);
+ if (region != 0) {
+ sp<IMemoryHeap> heap(region->getMemory());
+ if (heap != 0) {
+ const int fd = heap->heapID();
+ gpu->gpu[i].fd = fd;
+ gpu->gpu[i].base = region->pointer();
+ gpu->gpu[i].size = region->size();
+ gpu->gpu[i].user = region.get();
+ gpu->gpu[i].offset = info.regions[i].reserved;
+#if HAVE_ANDROID_OS
+ struct pmem_region reg;
+ if (ioctl(fd, PMEM_GET_PHYS, &reg) >= 0)
+ gpu->gpu[i].phys = (void*)reg.offset;
+#endif
+ region->incStrong(gpu);
+ } else {
+ LOGE("GPU region handle [%d, %p] is invalid!", i, region.get());
+ failed = true;
+ }
+ }
+ }
+
+ if (failed) {
+ // something went wrong, clean up everything!
+ if (gpu->regs.user) {
+ static_cast<IMemory*>(gpu->regs.user)->decStrong(gpu);
+ for (size_t i=0 ; i<info.count ; i++) {
+ if (gpu->gpu[i].user) {
+ static_cast<IMemory*>(gpu->gpu[i].user)->decStrong(gpu);
+ }
+ }
+ }
+ }
+
+ gpu->count = info.count;
+ return gpu;
+}
+
+int gpu_release(void*, request_gpu_t* gpu)
+{
+ sp<IMemory> regs;
+
+ { // scope for lock
+ Mutex::Autolock _l(gRegionsLock);
+ regs = static_cast<IMemory*>(gpu->regs.user);
+ gpu->regs.user = 0;
+ if (regs != 0) regs->decStrong(gpu);
+
+ for (int i=0 ; i<gpu->count ; i++) {
+ sp<IMemory> r(static_cast<IMemory*>(gpu->gpu[i].user));
+ gpu->gpu[i].user = 0;
+ if (r != 0) r->decStrong(gpu);
+ }
+ }
+
+ // there is a special transaction to relinquish the GPU
+ // (it will happen automatically anyway if we don't do this)
+ Parcel data, reply;
+ // NOTE: this transaction does not require an interface token
+ regs->asBinder()->transact(1000, data, &reply);
+ return 1;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
new file mode 100644
index 0000000..865cf44
--- /dev/null
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -0,0 +1,116 @@
+/*
+ ** Copyright 2007, 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.
+ */
+
+#define LOG_TAG "GLES_CM"
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "hooks.h"
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// extensions for the framework
+// ----------------------------------------------------------------------------
+
+void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+ const GLvoid *ptr, GLsizei count) {
+ glColorPointer(size, type, stride, ptr);
+}
+void glNormalPointerBounds(GLenum type, GLsizei stride,
+ const GLvoid *pointer, GLsizei count) {
+ glNormalPointer(type, stride, pointer);
+}
+void glTexCoordPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count) {
+ glTexCoordPointer(size, type, stride, pointer);
+}
+void glVertexPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count) {
+ glVertexPointer(size, type, stride, pointer);
+}
+
+// ----------------------------------------------------------------------------
+// Actual GL entry-points
+// ----------------------------------------------------------------------------
+
+#if GL_LOGGER
+# include "gl_logger.h"
+# define GL_LOGGER_IMPL(_x) _x
+#else
+# define GL_LOGGER_IMPL(_x)
+#endif
+
+#undef API_ENTRY
+#undef CALL_GL_API
+#undef CALL_GL_API_RETURN
+
+#if USE_FAST_TLS_KEY
+
+ #define API_ENTRY(_api) __attribute__((naked)) _api
+
+ #define CALL_GL_API(_api, ...) \
+ asm volatile( \
+ "mov r12, #0xFFFF0FFF \n" \
+ "ldr r12, [r12, #-15] \n" \
+ "ldr r12, [r12, %[tls]] \n" \
+ "cmp r12, #0 \n" \
+ "ldrne pc, [r12, %[api]] \n" \
+ "bx lr \n" \
+ : \
+ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \
+ [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
+ : \
+ );
+
+ #define CALL_GL_API_RETURN(_api, ...) \
+ CALL_GL_API(_api, __VA_ARGS__) \
+ return 0; // placate gcc's warnings. never reached.
+
+#else
+
+ #define API_ENTRY(_api) _api
+
+ #define CALL_GL_API(_api, ...) \
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+ GL_LOGGER_IMPL( log_##_api(__VA_ARGS__); ) \
+ _c->_api(__VA_ARGS__)
+
+ #define CALL_GL_API_RETURN(_api, ...) \
+ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
+ GL_LOGGER_IMPL( log_##_api(__VA_ARGS__); ) \
+ return _c->_api(__VA_ARGS__)
+
+#endif
+
+extern "C" {
+#include "gl_api.in"
+}
+
+#undef API_ENTRY
+#undef CALL_GL_API
+#undef CALL_GL_API_RETURN
+
diff --git a/opengl/libGLES_CM/gl_api.cpp b/opengl/libs/GLES_CM/gl_api.in
index ed3bdaa..9234ef2 100644
--- a/opengl/libGLES_CM/gl_api.cpp
+++ b/opengl/libs/GLES_CM/gl_api.in
@@ -415,7 +415,7 @@ void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) {
CALL_GL_API(glTexEnvxv, target, pname, params);
}
-void API_ENTRY(glTexImage2D)( GLenum target, GLint level, GLenum internalformat,
+void API_ENTRY(glTexImage2D)( GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLint border, GLenum format,
GLenum type, const GLvoid *pixels) {
CALL_GL_API(glTexImage2D, target, level, internalformat, width, height,
diff --git a/opengl/libGLES_CM/gl_logger.cpp b/opengl/libs/GLES_CM/gl_logger.cpp
index 14b5a39..27be5c9 100644
--- a/opengl/libGLES_CM/gl_logger.cpp
+++ b/opengl/libs/GLES_CM/gl_logger.cpp
@@ -23,7 +23,10 @@
#include <sys/ioctl.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
@@ -33,13 +36,13 @@
#include "gl_logger.h"
+#undef NELEM
+#define NELEM(x) (sizeof(x)/sizeof(*(x)))
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
-#undef NELEM
-#define NELEM(x) (sizeof(x)/sizeof(*(x)))
-
template<typename T>
static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
{
@@ -226,12 +229,6 @@ private:
int mNumParams;
};
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
-using namespace android;
-
#define API_ENTRY(api) log_##api
#define CALL_GL_API(_x, ...)
#define CALL_GL_API_RETURN(_x, ...) return(0);
@@ -785,7 +782,7 @@ void API_ENTRY(glTexEnvxv)(GLenum target, GLenum pname, const GLfixed *params) {
GLLog("glTexEnvxv") << GLLogEnum(target) << GLLogEnum(pname) << GLLogBuffer<GLfixed>(params);
}
-void API_ENTRY(glTexImage2D)( GLenum target, GLint level, GLenum internalformat,
+void API_ENTRY(glTexImage2D)( GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLint border, GLenum format,
GLenum type, const GLvoid *pixels) {
CALL_GL_API(glTexImage2D, target, level, internalformat, width, height,
@@ -1057,3 +1054,7 @@ GLbitfield API_ENTRY(glQueryMatrixxOES)(GLfixed* mantissa, GLint* exponent) {
GLLog("glQueryMatrixxOES") << GLLogBuffer<GLfixed>(mantissa, 16) << GLLogBuffer<GLfixed>(exponent, 16);
CALL_GL_API_RETURN(glQueryMatrixxOES, mantissa, exponent);
}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/opengl/libGLES_CM/egl_entries.cpp b/opengl/libs/egl_entries.in
index ba46f40..33b4c65 100644
--- a/opengl/libGLES_CM/egl_entries.cpp
+++ b/opengl/libs/egl_entries.in
@@ -23,7 +23,7 @@ EGL_ENTRY(EGLBoolean, eglSwapBuffers, EGLDisplay, EGLSurface)
EGL_ENTRY(EGLBoolean, eglCopyBuffers, EGLDisplay, EGLSurface, NativePixmapType)
EGL_ENTRY(EGLint, eglGetError, void)
EGL_ENTRY(const char*, eglQueryString, EGLDisplay, EGLint)
-EGL_ENTRY(proc_t, eglGetProcAddress, const char *)
+EGL_ENTRY(__eglMustCastToProperFunctionPointerType, eglGetProcAddress, const char *)
/* EGL 1.1 */
@@ -40,7 +40,6 @@ EGL_ENTRY(EGLBoolean, eglWaitClient, void)
EGL_ENTRY(EGLBoolean, eglReleaseThread, void)
EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint *)
-/* Android extentions */
+/* EGL 1.3 */
-EGL_ENTRY(EGLBoolean, eglSwapRectangleANDROID, EGLDisplay, EGLSurface , EGLint, EGLint, EGLint, EGLint)
-EGL_ENTRY(const char*, eglQueryStringConfigANDROID, EGLDisplay, EGLConfig, EGLint)
+/* EGL 1.4 */
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
new file mode 100644
index 0000000..62ce3fc
--- /dev/null
+++ b/opengl/libs/egl_impl.h
@@ -0,0 +1,43 @@
+/*
+ ** Copyright 2007, 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.
+ */
+
+#ifndef ANDROID_EGL_IMPL_H
+#define ANDROID_EGL_IMPL_H
+
+#include <ctype.h>
+
+#include <EGL/egl.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+struct gl_hooks_t;
+
+struct egl_connection_t
+{
+ void volatile * dso;
+ gl_hooks_t * hooks;
+ EGLint major;
+ EGLint minor;
+ int unavailable;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_EGL_IMPL_H */
diff --git a/opengl/libGLES_CM/gl_entries.cpp b/opengl/libs/gl_entries.in
index 3279322..b97e8fe 100644
--- a/opengl/libGLES_CM/gl_entries.cpp
+++ b/opengl/libs/gl_entries.in
@@ -101,7 +101,7 @@ GL_ENTRY(void, glCompressedTexImage2D, GLenum, GLint, GLenum, GLsizei, GLsize
GL_ENTRY(void, glCompressedTexSubImage2D, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)
GL_ENTRY(void, glCopyTexImage2D, GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint)
GL_ENTRY(void, glCopyTexSubImage2D, GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)
-GL_ENTRY(void, glTexImage2D, GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)
+GL_ENTRY(void, glTexImage2D, GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)
GL_ENTRY(void, glTexSubImage2D, GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)
GL_ENTRY(void, glReadPixels, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid *)
diff --git a/opengl/libGLES_CM/gl_enums.in b/opengl/libs/gl_enums.in
index ffc2fad..ffc2fad 100644
--- a/opengl/libGLES_CM/gl_enums.in
+++ b/opengl/libs/gl_enums.in
diff --git a/opengl/libGLES_CM/gl_logger.h b/opengl/libs/gl_logger.h
index 59e31c7..ce85dd1 100644
--- a/opengl/libGLES_CM/gl_logger.h
+++ b/opengl/libs/gl_logger.h
@@ -17,10 +17,10 @@
#ifndef ANDROID_GL_LOGGER_H
#define ANDROID_GL_LOGGER_H
-extern "C" {
+namespace android {
#define GL_ENTRY(r, api, ...) r log_##api(__VA_ARGS__);
-#include "gl_entries.cpp"
+#include "gl_entries.in"
#undef GL_ENTRY
-};
+}; // namespace android
#endif /* ANDROID_GL_LOGGER_H */
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
new file mode 100644
index 0000000..63fb017
--- /dev/null
+++ b/opengl/libs/hooks.h
@@ -0,0 +1,134 @@
+/*
+ ** Copyright 2007, 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.
+ */
+
+#ifndef ANDROID_GLES_CM_HOOKS_H
+#define ANDROID_GLES_CM_HOOKS_H
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+
+#define GL_LOGGER 0
+#if !defined(__arm__)
+#define USE_SLOW_BINDING 1
+#else
+#define USE_SLOW_BINDING 0
+#endif
+#undef NELEM
+#define NELEM(x) (sizeof(x)/sizeof(*(x)))
+#define MAX_NUMBER_OF_GL_EXTENSIONS 32
+
+
+#if defined(HAVE_ANDROID_OS) && !USE_SLOW_BINDING && !GL_LOGGER && __OPTIMIZE__
+#define USE_FAST_TLS_KEY 1
+#else
+#define USE_FAST_TLS_KEY 0
+#endif
+
+#if USE_FAST_TLS_KEY
+# include <bionic_tls.h> /* special private C library header */
+#endif
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+// EGLDisplay are global, not attached to a given thread
+const unsigned int NUM_DISPLAYS = 1;
+
+enum {
+ IMPL_HARDWARE = 0,
+ IMPL_SOFTWARE,
+ IMPL_CONTEXT_LOST,
+ IMPL_NO_CONTEXT,
+
+ IMPL_NUM_IMPLEMENTATIONS
+};
+
+// ----------------------------------------------------------------------------
+
+// GL / EGL hooks
+
+#undef GL_ENTRY
+#undef EGL_ENTRY
+#define GL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
+#define EGL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
+
+struct gl_hooks_t {
+ struct gl_t {
+ #include "gl_entries.in"
+ } gl;
+ struct egl_t {
+ #include "egl_entries.in"
+ } egl;
+ struct gl_ext_t {
+ void (*extensions[MAX_NUMBER_OF_GL_EXTENSIONS])(void);
+ } ext;
+};
+#undef GL_ENTRY
+#undef EGL_ENTRY
+
+
+// ----------------------------------------------------------------------------
+
+extern gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
+extern pthread_key_t gGLWrapperKey;
+
+#if USE_FAST_TLS_KEY
+
+// We have a dedicated TLS slot in bionic
+static inline gl_hooks_t const * volatile * get_tls_hooks() {
+ volatile void *tls_base = __get_tls();
+ gl_hooks_t const * volatile * tls_hooks =
+ reinterpret_cast<gl_hooks_t const * volatile *>(tls_base);
+ return tls_hooks;
+}
+
+static inline void setGlThreadSpecific(gl_hooks_t const *value) {
+ gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
+ tls_hooks[TLS_SLOT_OPENGL_API] = value;
+}
+
+static gl_hooks_t const* getGlThreadSpecific() {
+ gl_hooks_t const * volatile * tls_hooks = get_tls_hooks();
+ gl_hooks_t const* hooks = tls_hooks[TLS_SLOT_OPENGL_API];
+ if (hooks) return hooks;
+ return &gHooks[IMPL_NO_CONTEXT];
+}
+
+#else
+
+static inline void setGlThreadSpecific(gl_hooks_t const *value) {
+ pthread_setspecific(gGLWrapperKey, value);
+}
+
+static gl_hooks_t const* getGlThreadSpecific() {
+ gl_hooks_t const* hooks = static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
+ if (hooks) return hooks;
+ return &gHooks[IMPL_NO_CONTEXT];
+}
+
+#endif
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_GLES_CM_HOOKS_H */
diff --git a/opengl/libGLES_CM/enumextract.sh b/opengl/libs/tools/enumextract.sh
index 5707302..5707302 100644
--- a/opengl/libGLES_CM/enumextract.sh
+++ b/opengl/libs/tools/enumextract.sh
diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk
index 41673cb..46958d3 100644
--- a/opengl/tests/angeles/Android.mk
+++ b/opengl/tests/angeles/Android.mk
@@ -3,7 +3,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= app-linux.c demo.c.arm
-LOCAL_SHARED_LIBRARIES := libGLES_CM libui
+LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui
LOCAL_MODULE:= angeles
LOCAL_MODULE_TAGS := tests
include $(BUILD_EXECUTABLE)
@@ -11,7 +11,7 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= gpustate.c
-LOCAL_SHARED_LIBRARIES := libGLES_CM
+LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM
LOCAL_MODULE:= gpustate
LOCAL_MODULE_TAGS := tests
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/angeles/app-linux.c b/opengl/tests/angeles/app-linux.c
index d439eb2..7d0d320 100644
--- a/opengl/tests/angeles/app-linux.c
+++ b/opengl/tests/angeles/app-linux.c
@@ -49,7 +49,8 @@
#include <stdio.h>
#include <sys/time.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
#include "app.h"
diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk
index 1c4253c..a448f0d 100644
--- a/opengl/tests/filter/Android.mk
+++ b/opengl/tests/filter/Android.mk
@@ -6,7 +6,8 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libcutils \
- libGLES_CM \
+ libEGL \
+ libGLESv1_CM \
libui
LOCAL_MODULE:= test-opengl-filter
diff --git a/opengl/tests/filter/filter.c b/opengl/tests/filter/filter.c
index c8bac06..de97119 100644
--- a/opengl/tests/filter/filter.c
+++ b/opengl/tests/filter/filter.c
@@ -1,7 +1,9 @@
#include <stdlib.h>
#include <stdio.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
int main(int argc, char** argv)
{
@@ -40,6 +42,9 @@ int main(int argc, char** argv)
printf("using pbuffer\n");
EGLint attribs[] = { EGL_WIDTH, 320, EGL_HEIGHT, 480, EGL_NONE };
surface = eglCreatePbufferSurface(dpy, config, attribs);
+ if (surface == EGL_NO_SURFACE) {
+ printf("eglCreatePbufferSurface error %x\n", eglGetError());
+ }
}
context = eglCreateContext(dpy, config, NULL, NULL);
eglMakeCurrent(dpy, surface, surface, context);
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
index f7b95ed..26836c1 100644
--- a/opengl/tests/finish/Android.mk
+++ b/opengl/tests/finish/Android.mk
@@ -6,7 +6,8 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libcutils \
- libGLES_CM \
+ libEGL \
+ libGLESv1_CM \
libui
LOCAL_MODULE:= test-opengl-finish
diff --git a/opengl/tests/finish/finish.c b/opengl/tests/finish/finish.c
index 3afe227..45fc758 100644
--- a/opengl/tests/finish/finish.c
+++ b/opengl/tests/finish/finish.c
@@ -20,7 +20,10 @@
#include <sched.h>
#include <sys/resource.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
long long systemTime()
{
diff --git a/opengl/tests/sfsim/Android.mk b/opengl/tests/sfsim/Android.mk
deleted file mode 100644
index 8a1a03c..0000000
--- a/opengl/tests/sfsim/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- egl_surface.cpp \
- sfsim.c
-
-LOCAL_SHARED_LIBRARIES := \
- libGLES_CM
-
-LOCAL_MODULE:= test-opengl-sfsim
-
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/sfsim/egl_surface.cpp b/opengl/tests/sfsim/egl_surface.cpp
deleted file mode 100644
index b0777f8..0000000
--- a/opengl/tests/sfsim/egl_surface.cpp
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- **
- ** Copyright 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.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <GLES/egl.h>
-
-#include "egl_surface.h"
-
-#define LOGI(x...) do { printf("INFO: " x); } while (0)
-#define LOGW(x...) do { printf("WARN: " x); } while (0)
-#define LOGE(x...) do { printf("ERR: " x); } while (0)
-
-// ----------------------------------------------------------------------------
-
-egl_native_window_t* android_createDisplaySurface()
-{
- egl_native_window_t* s = new android::EGLDisplaySurface();
- s->memory_type = NATIVE_MEMORY_TYPE_GPU;
- return s;
-}
-
-#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
-#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-EGLDisplaySurface::EGLDisplaySurface()
- : EGLNativeSurface<EGLDisplaySurface>()
-{
- egl_native_window_t::version = sizeof(egl_native_window_t);
- egl_native_window_t::ident = 0;
- egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
- egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
- egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
- egl_native_window_t::setSwapRectangle = &EGLDisplaySurface::hook_setSwapRectangle;
- egl_native_window_t::nextBuffer = &EGLDisplaySurface::hook_nextBuffer;
- egl_native_window_t::connect = 0;
- egl_native_window_t::disconnect = 0;
-
- mFb[0].data = 0;
- mFb[1].data = 0;
- egl_native_window_t::fd = mapFrameBuffer();
- if (egl_native_window_t::fd >= 0) {
- const float in2mm = 25.4f;
- float refreshRate = 1000000000000000LLU / (
- float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres )
- * ( mInfo.left_margin + mInfo.right_margin + mInfo.xres )
- * mInfo.pixclock);
-
- const GGLSurface& buffer = mFb[1 - mIndex];
- egl_native_window_t::width = buffer.width;
- egl_native_window_t::height = buffer.height;
- egl_native_window_t::stride = buffer.stride;
- egl_native_window_t::format = buffer.format;
- egl_native_window_t::base = intptr_t(mFb[0].data);
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
- egl_native_window_t::flags = 0;
- egl_native_window_t::xdpi = (mInfo.xres * in2mm) / mInfo.width;
- egl_native_window_t::ydpi = (mInfo.yres * in2mm) / mInfo.height;
- egl_native_window_t::fps = refreshRate;
- egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_FB;
- // no error, set the magic word
- egl_native_window_t::magic = 0x600913;
- }
- mSwapCount = -1;
- mPageFlipCount = 0;
-}
-
-EGLDisplaySurface::~EGLDisplaySurface()
-{
- magic = 0;
- close(egl_native_window_t::fd);
- munmap(mFb[0].data, mSize);
- if (!(mFlags & PAGE_FLIP))
- free((void*)mFb[1].data);
-}
-
-void EGLDisplaySurface::hook_incRef(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->incStrong(that);
-}
-void EGLDisplaySurface::hook_decRef(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->decStrong(that);
-}
-uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- return that->swapBuffers();
-}
-uint32_t EGLDisplaySurface::hook_nextBuffer(NativeWindowType window) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- return that->nextBuffer();
-}
-void EGLDisplaySurface::hook_setSwapRectangle(NativeWindowType window,
- int l, int t, int w, int h) {
- EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
- that->setSwapRectangle(l, t, w, h);
-}
-
-void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
-{
- mInfo.reserved[0] = 0x54445055; // "UPDT";
- mInfo.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
- mInfo.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
-}
-
-uint32_t EGLDisplaySurface::swapBuffers()
-{
- if (!(mFlags & PAGE_FLIP))
- return 0;
-
- // do the actual flip
- mIndex = 1 - mIndex;
- mInfo.activate = FB_ACTIVATE_VBL;
- mInfo.yoffset = mIndex ? mInfo.yres : 0;
- if (ioctl(egl_native_window_t::fd, FBIOPUT_VSCREENINFO, &mInfo) == -1) {
- LOGE("FBIOPUT_VSCREENINFO failed");
- return 0;
- }
-
- /*
- * this is a monstruous hack: Because the h/w accelerator is not able
- * to render directly into the framebuffer, we need to copy its
- * internal framebuffer out to the fb. the base address of the internal fb
- * is given in oem[0].
- * All this is needed only in standalone mode, in SurfaceFlinger mode
- * we control where the GPU renders.
- */
- if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0]) {
- // could use MDP here, but that's tricky because we need
- // /dev/pmem_gpu* filedescriptor
- const GGLSurface& buffer = mFb[mIndex];
- memcpy( buffer.data,
- (void*)(oem[0] + egl_native_window_t::offset),
- buffer.stride*buffer.height*2);
- }
-
- // update the address of the buffer to draw to next
- const GGLSurface& buffer = mFb[1 - mIndex];
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
-
- mPageFlipCount++;
-
- // We don't support screen-size changes for now
- return 0;
-}
-
-int32_t EGLDisplaySurface::getPageFlipCount() const
-{
- return mPageFlipCount;
-}
-
-uint32_t EGLDisplaySurface::nextBuffer()
-{
- // update the address of the buffer to draw to next
- const GGLSurface& buffer = mFb[mIndex];
- egl_native_window_t::offset =
- intptr_t(buffer.data) - egl_native_window_t::base;
- return 0;
-}
-
-int EGLDisplaySurface::mapFrameBuffer()
-{
- char const * const device_template[] = {
- "/dev/graphics/fb%u",
- "/dev/fb%u",
- 0 };
- int fd = -1;
- int i=0;
- char name[64];
- while ((fd==-1) && device_template[i]) {
- snprintf(name, 64, device_template[i], 0);
- fd = open(name, O_RDWR, 0);
- i++;
- }
- if (fd < 0)
- return -errno;
-
- struct fb_fix_screeninfo finfo;
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
- return -errno;
-
- struct fb_var_screeninfo info;
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- info.reserved[0] = 0;
- info.reserved[1] = 0;
- info.reserved[2] = 0;
- info.xoffset = 0;
- info.yoffset = 0;
- info.yres_virtual = info.yres * 2;
- info.bits_per_pixel = 16;
- info.activate = FB_ACTIVATE_NOW;
-
- uint32_t flags = PAGE_FLIP;
- if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
- }
-
- if (info.yres_virtual < info.yres * 2) {
- info.yres_virtual = info.yres;
- flags &= ~PAGE_FLIP;
- LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
- info.yres_virtual, info.yres*2);
- }
-
- if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
- return -errno;
-
- int refreshRate = 1000000000000000LLU /
- (
- uint64_t( info.upper_margin + info.lower_margin + info.yres )
- * ( info.left_margin + info.right_margin + info.xres )
- * info.pixclock
- );
-
- if (refreshRate == 0) {
- // bleagh, bad info from the driver
- refreshRate = 60*1000; // 60 Hz
- }
-
- if (int(info.width) <= 0 || int(info.height) <= 0) {
- // stupid driver, doesn't return that information
- // default to Sooner's screen size (160 dpi)
- info.width = 51;
- info.height = 38;
- }
-
- float xdpi = (info.xres * 25.4f) / info.width;
- float ydpi = (info.yres * 25.4f) / info.height;
- float fps = refreshRate / 1000.0f;
-
- LOGI( "using (fd=%d)\n"
- "id = %s\n"
- "xres = %d px\n"
- "yres = %d px\n"
- "xres_virtual = %d px\n"
- "yres_virtual = %d px\n"
- "bpp = %d\n"
- "r = %2u:%u\n"
- "g = %2u:%u\n"
- "b = %2u:%u\n",
- fd,
- finfo.id,
- info.xres,
- info.yres,
- info.xres_virtual,
- info.yres_virtual,
- info.bits_per_pixel,
- info.red.offset, info.red.length,
- info.green.offset, info.green.length,
- info.blue.offset, info.blue.length
- );
-
- LOGI( "width = %d mm (%f dpi)\n"
- "height = %d mm (%f dpi)\n"
- "refresh rate = %.2f Hz\n",
- info.width, xdpi,
- info.height, ydpi,
- fps
- );
-
-
- if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
- return -errno;
-
- if (finfo.smem_len <= 0)
- return -errno;
-
- /*
- * Open and map the display.
- */
-
- void* buffer = (uint16_t*) mmap(
- 0, finfo.smem_len,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fd, 0);
-
- if (buffer == MAP_FAILED)
- return -errno;
-
- // at least for now, always clear the fb
- memset(buffer, 0, finfo.smem_len);
-
- uint8_t* offscreen[2];
- offscreen[0] = (uint8_t*)buffer;
- if (flags & PAGE_FLIP) {
- offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres;
- } else {
- offscreen[1] = (uint8_t*)malloc(finfo.smem_len);
- if (offscreen[1] == 0) {
- munmap(buffer, finfo.smem_len);
- return -ENOMEM;
- }
- }
-
- mFlags = flags;
- mInfo = info;
- mFinfo = finfo;
- mSize = finfo.smem_len;
- mIndex = 0;
- for (int i=0 ; i<2 ; i++) {
- mFb[i].version = sizeof(GGLSurface);
- mFb[i].width = info.xres;
- mFb[i].height = info.yres;
- mFb[i].stride = finfo.line_length / (info.bits_per_pixel >> 3);
- mFb[i].data = (uint8_t*)(offscreen[i]);
- mFb[i].format = NATIVE_PIXEL_FORMAT_RGB_565;
- }
- return fd;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
diff --git a/opengl/tests/sfsim/egl_surface.h b/opengl/tests/sfsim/egl_surface.h
deleted file mode 100644
index 70a94fc..0000000
--- a/opengl/tests/sfsim/egl_surface.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_SIM_EGL_SURFACE_H
-#define ANDROID_SIM_EGL_SURFACE_H
-
-#include <stdint.h>
-#include <errno.h>
-#include <sys/types.h>
-
-#include <GLES/eglnatives.h>
-
-#include <linux/fb.h>
-
-typedef struct {
- ssize_t version; // always set to sizeof(GGLSurface)
- uint32_t width; // width in pixels
- uint32_t height; // height in pixels
- int32_t stride; // stride in pixels
- uint8_t* data; // pointer to the bits
- uint8_t format; // pixel format
- uint8_t rfu[3]; // must be zero
- void* reserved;
-} GGLSurface;
-
-// ---------------------------------------------------------------------------
-namespace android {
-// ---------------------------------------------------------------------------
-
-template <class TYPE>
-class EGLNativeSurface : public egl_native_window_t
-{
-public:
- EGLNativeSurface() : mCount(0) {
- memset(egl_native_window_t::reserved, 0,
- sizeof(egl_native_window_t::reserved));
- memset(egl_native_window_t::reserved_proc, 0,
- sizeof(egl_native_window_t::reserved_proc));
- memset(egl_native_window_t::oem, 0,
- sizeof(egl_native_window_t::oem));
- }
- inline void incStrong(void*) const {
- /* in a real implementation, the inc must be atomic */
- mCount++;
- }
- inline void decStrong(void*) const {
- /* in a real implementation, the dec must be atomic */
- if (--mCount == 1) {
- delete static_cast<const TYPE*>(this);
- }
- }
-protected:
- EGLNativeSurface& operator = (const EGLNativeSurface& rhs);
- EGLNativeSurface(const EGLNativeSurface& rhs);
- inline ~EGLNativeSurface() { };
- mutable volatile int32_t mCount;
-};
-
-
-class EGLDisplaySurface : public EGLNativeSurface<EGLDisplaySurface>
-{
-public:
- EGLDisplaySurface();
- ~EGLDisplaySurface();
-
- int32_t getPageFlipCount() const;
-
-private:
- static void hook_incRef(NativeWindowType window);
- static void hook_decRef(NativeWindowType window);
- static uint32_t hook_swapBuffers(NativeWindowType window);
- static void hook_setSwapRectangle(NativeWindowType window, int l, int t, int w, int h);
- static uint32_t hook_nextBuffer(NativeWindowType window);
-
- uint32_t swapBuffers();
- uint32_t nextBuffer();
- void setSwapRectangle(int l, int t, int w, int h);
-
- int mapFrameBuffer();
-
- enum {
- PAGE_FLIP = 0x00000001
- };
- GGLSurface mFb[2];
- int mIndex;
- uint32_t mFlags;
- size_t mSize;
- fb_var_screeninfo mInfo;
- fb_fix_screeninfo mFinfo;
- int32_t mPageFlipCount;
- int32_t mSwapCount;
- uint32_t mFeatureFlags;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_SIM_EGL_SURFACE_H
-
diff --git a/opengl/tests/sfsim/sfsim.c b/opengl/tests/sfsim/sfsim.c
deleted file mode 100644
index 14ba490..0000000
--- a/opengl/tests/sfsim/sfsim.c
+++ /dev/null
@@ -1,112 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <GLES/egl.h>
-
-int main(int argc, char** argv)
-{
- if (argc != 2) {
- printf("usage: %s <0-6>\n", argv[0]);
- return 0;
- }
-
- const int test = atoi(argv[1]);
-
- EGLint s_configAttribs[] = {
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 6,
- EGL_BLUE_SIZE, 5,
- EGL_NONE
- };
-
- EGLint numConfigs = -1;
- EGLint majorVersion;
- EGLint minorVersion;
- EGLConfig config;
- EGLContext context;
- EGLSurface surface;
- EGLint w, h;
-
- EGLDisplay dpy;
-
- dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(dpy, &majorVersion, &minorVersion);
- eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
- surface = eglCreateWindowSurface(dpy, config,
- android_createDisplaySurface(), NULL);
- context = eglCreateContext(dpy, config, NULL, NULL);
- eglMakeCurrent(dpy, surface, surface, context);
- eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
- eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
- GLint dim = w<h ? w : h;
-
- glClear(GL_COLOR_BUFFER_BIT);
-
- GLint crop[4] = { 0, 4, 4, -4 };
- glBindTexture(GL_TEXTURE_2D, 0);
- glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glEnable(GL_TEXTURE_2D);
- glColor4f(1,1,1,1);
-
- // packing is always 4
- uint8_t t8[] = {
- 0x00, 0x55, 0x00, 0x55,
- 0xAA, 0xFF, 0xAA, 0xFF,
- 0x00, 0x55, 0x00, 0x55,
- 0xAA, 0xFF, 0xAA, 0xFF };
-
- uint16_t t16[] = {
- 0x0000, 0x5555, 0x0000, 0x5555,
- 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF,
- 0x0000, 0x5555, 0x0000, 0x5555,
- 0xAAAA, 0xFFFF, 0xAAAA, 0xFFFF };
-
- uint16_t t5551[] = {
- 0x0000, 0xFFFF, 0x0000, 0xFFFF,
- 0xFFFF, 0x0000, 0xFFFF, 0x0000,
- 0x0000, 0xFFFF, 0x0000, 0xFFFF,
- 0xFFFF, 0x0000, 0xFFFF, 0x0000 };
-
- uint32_t t32[] = {
- 0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
- 0xFF00FF00, 0xFFFF0000, 0xFF000000, 0xFF0000FF,
- 0xFF00FFFF, 0xFF00FF00, 0x00FF00FF, 0xFFFFFF00,
- 0xFF000000, 0xFFFF00FF, 0xFF00FFFF, 0xFFFFFFFF
- };
-
- switch(test)
- {
- case 1:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
- 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, t8);
- break;
- case 2:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- 4, 4, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t16);
- break;
- case 3:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
- 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t16);
- break;
- case 4:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
- 4, 4, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, t16);
- break;
- case 5:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
- 4, 4, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, t5551);
- break;
- case 6:
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
- 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
- break;
- }
-
- glDrawTexiOES(0, 0, 0, dim, dim);
-
- eglSwapBuffers(dpy, surface);
- return 0;
-}
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
index b0c9021..a8c6220 100644
--- a/opengl/tests/textures/Android.mk
+++ b/opengl/tests/textures/Android.mk
@@ -6,7 +6,8 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libcutils \
- libGLES_CM \
+ libEGL \
+ libGLESv1_CM \
libui
LOCAL_MODULE:= test-opengl-textures
diff --git a/opengl/tests/textures/textures.c b/opengl/tests/textures/textures.c
index 98e3be1..214291b 100644
--- a/opengl/tests/textures/textures.c
+++ b/opengl/tests/textures/textures.c
@@ -18,7 +18,9 @@
#include <stdlib.h>
#include <stdio.h>
-#include <GLES/egl.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
int main(int argc, char** argv)
{
diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk
index 4edac4c..5cd1f04 100644
--- a/opengl/tests/tritex/Android.mk
+++ b/opengl/tests/tritex/Android.mk
@@ -6,7 +6,8 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libcutils \
- libGLES_CM \
+ libEGL \
+ libGLESv1_CM \
libui
LOCAL_MODULE:= test-opengl-tritex
diff --git a/opengl/tests/tritex/tritex.c b/opengl/tests/tritex/tritex.c
index 8ebe7d4..60a7feb 100644
--- a/opengl/tests/tritex/tritex.c
+++ b/opengl/tests/tritex/tritex.c
@@ -4,7 +4,9 @@
//
// Ported from a Java version by Google.
-#include <GLES/egl.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index 330a673..724e988 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := user development
+LOCAL_MODULE_TAGS := user
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/packages/SettingsProvider/etc/Android.mk b/packages/SettingsProvider/etc/Android.mk
index e3f958c..d73175f 100644
--- a/packages/SettingsProvider/etc/Android.mk
+++ b/packages/SettingsProvider/etc/Android.mk
@@ -21,7 +21,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := bookmarks.xml
-LOCAL_MODULE_TAGS := user development
+LOCAL_MODULE_TAGS := user
# This will install the file in /system/etc
#
@@ -36,7 +36,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := favorites.xml
-LOCAL_MODULE_TAGS := user development
+LOCAL_MODULE_TAGS := user
# This will install the file in /system/etc
#
diff --git a/packages/SettingsProvider/etc/bookmarks.xml b/packages/SettingsProvider/etc/bookmarks.xml
index 235e2ed..5fb6608 100644
--- a/packages/SettingsProvider/etc/bookmarks.xml
+++ b/packages/SettingsProvider/etc/bookmarks.xml
@@ -15,14 +15,44 @@
-->
<bookmarks>
- <bookmark package="com.android.browser" class="com.android.browser.BrowserActivity" shortcut="b" />
- <bookmark package="com.android.calendar" class="com.android.calendar.LaunchActivity" shortcut="l" />
- <bookmark package="com.android.contacts" class="com.android.contacts.DialtactsContactsEntryActivity" shortcut="c" />
- <bookmark package="com.google.android.gm" class="com.google.android.gm.ConversationListActivityGmail" shortcut="g" />
- <bookmark package="com.android.email" class="com.android.email.activity.Welcome" shortcut="e" />
- <bookmark package="com.android.im" class="com.android.im.app.ChooseAccountActivity" shortcut="i" />
- <bookmark package="com.google.android.apps.maps" class="com.google.android.maps.MapsActivity" shortcut="m" />
- <bookmark package="com.android.music" class="com.android.music.MusicBrowserActivity" shortcut="p" />
- <bookmark package="com.android.mms" class="com.android.mms.ui.ConversationList" shortcut="s" />
- <bookmark package="com.google.android.youtube" class="com.google.android.youtube.HomePage" shortcut="y" />
-</bookmarks>
+ <bookmark
+ package="com.android.browser"
+ class="com.android.browser.BrowserActivity"
+ shortcut="b" />
+ <bookmark
+ package="com.android.contacts"
+ class="com.android.contacts.DialtactsContactsEntryActivity"
+ shortcut="c" />
+ <bookmark
+ package="com.android.email"
+ class="com.android.email.activity.Welcome"
+ shortcut="e" />
+ <bookmark
+ package="com.google.android.gm"
+ class="com.google.android.gm.ConversationListActivityGmail"
+ shortcut="g" />
+ <bookmark
+ package="com.android.providers.im"
+ class="com.android.providers.im.LandingPage"
+ shortcut="i" />
+ <bookmark
+ package="com.android.calendar"
+ class="com.android.calendar.LaunchActivity"
+ shortcut="l" />
+ <bookmark
+ package="com.google.android.apps.maps"
+ class="com.google.android.maps.MapsActivity"
+ shortcut="m" />
+ <bookmark
+ package="com.android.music"
+ class="com.android.music.MusicBrowserActivity"
+ shortcut="p" />
+ <bookmark
+ package="com.android.mms"
+ class="com.android.mms.ui.ConversationList"
+ shortcut="s" />
+ <bookmark
+ package="com.google.android.youtube"
+ class="com.google.android.youtube.HomePage"
+ shortcut="y" />
+</bookmarks> \ No newline at end of file
diff --git a/packages/SettingsProvider/etc/favorites.xml b/packages/SettingsProvider/etc/favorites.xml
index 0ecf8a6..ae74b8e 100644
--- a/packages/SettingsProvider/etc/favorites.xml
+++ b/packages/SettingsProvider/etc/favorites.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!-- 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.
@@ -19,4 +19,5 @@
<favorite package="com.android.contacts" class="com.android.contacts.DialtactsContactsEntryActivity" screen="1" x="1" y="3" />
<favorite package="com.android.browser" class="com.android.browser.BrowserActivity" screen="1" x="2" y="3" />
<favorite package="com.google.android.apps.maps" class="com.google.android.maps.MapsActivity" screen="1" x="3" y="3" />
+ <favorite package="com.android.vending" class="com.android.vending.AssetBrowserActivity" screen="1" x="0" y="2" />
</favorites>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
new file mode 100644
index 0000000..275ff3a
--- /dev/null
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources>
+ <bool name="def_dim_screen">true</bool>
+ <integer name="def_screen_off_timeout">60000</integer>
+ <bool name="def_airplane_mode_on">false</bool>
+ <!-- Comma-separated list of bluetooth, wifi, and cell. -->
+ <string name="def_airplane_mode_radios">cell,bluetooth,wifi</string>
+ <bool name="def_auto_time">true</bool>
+ <bool name="def_accelerometer_rotation">true</bool>
+ <!-- Default screen brightness, from 0 to 255. 102 is 40%. -->
+ <integer name="def_screen_brightness">102</integer>
+ <fraction name="def_window_animation_scale">100%</fraction>
+ <fraction name="def_window_transition_scale">0%</fraction>
+
+ <bool name="def_bluetooth_on">false</bool>
+ <bool name="def_install_non_market_apps">false</bool>
+ <!-- Comma-separated list of providers. -->
+ <string name="def_location_providers_allowed">network</string>
+ <!-- 0 == mobile, 1 == wifi. -->
+ <integer name="def_network_preference">1</integer>
+ <bool name="def_usb_mass_storage_enabled">true</bool>
+ <bool name="def_wifi_on">false</bool>
+ <bool name="def_networks_available_notification_on">true</bool>
+</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 2182271..c6f54a3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -22,11 +22,11 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
-import android.location.LocationManager;
import android.media.AudioManager;
import android.media.AudioService;
import android.net.ConnectivityManager;
@@ -63,7 +63,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "SettingsProvider";
private static final String DATABASE_NAME = "settings.db";
- private static final int DATABASE_VERSION = 31;
+ private static final int DATABASE_VERSION = 34;
private Context mContext;
@@ -332,6 +332,58 @@ public class DatabaseHelper extends SQLiteOpenHelper {
upgradeVersion = 31;
}
+ if (upgradeVersion == 31) {
+ /*
+ * Animations are now managed in preferences, and may be
+ * enabled or disabled based on product resources.
+ */
+ db.beginTransaction();
+ try {
+ db.execSQL("DELETE FROM system WHERE name='"
+ + Settings.System.WINDOW_ANIMATION_SCALE + "'");
+ db.execSQL("DELETE FROM system WHERE name='"
+ + Settings.System.TRANSITION_ANIMATION_SCALE + "'");
+ SQLiteStatement stmt = db.compileStatement("INSERT INTO system(name,value)"
+ + " VALUES(?,?);");
+ loadDefaultAnimationSettings(stmt);
+ stmt.close();
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ upgradeVersion = 32;
+ }
+
+ if (upgradeVersion == 32) {
+ // The Wi-Fi watchdog SSID list is now seeded with the value of
+ // the property ro.com.android.wifi-watchlist
+ String wifiWatchList = SystemProperties.get("ro.com.android.wifi-watchlist");
+ if (!TextUtils.isEmpty(wifiWatchList)) {
+ db.beginTransaction();
+ try {
+ db.execSQL("INSERT OR IGNORE INTO secure(name,value) values('" +
+ Settings.Secure.WIFI_WATCHDOG_WATCH_LIST + "','" +
+ wifiWatchList + "');");
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+ upgradeVersion = 33;
+ }
+
+ if (upgradeVersion == 33) {
+ // Set the default zoom controls to: tap-twice to bring up +/-
+ db.beginTransaction();
+ try {
+ db.execSQL("INSERT INTO system(name,value) values('zoom','2');");
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ upgradeVersion = 34;
+ }
+
if (upgradeVersion != currentVersion) {
Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
+ ", must wipe the settings provider");
@@ -529,28 +581,31 @@ public class DatabaseHelper extends SQLiteOpenHelper {
SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
+ " VALUES(?,?);");
- loadSetting(stmt, Settings.System.DIM_SCREEN, 1);
+ Resources r = mContext.getResources();
+ loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,
+ R.bool.def_dim_screen);
loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN,
"1".equals(SystemProperties.get("ro.kernel.qemu")) ? 1 : 0);
- loadSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT, 60000);
- // Allow airplane mode to turn off cell radio
- loadSetting(stmt, Settings.System.AIRPLANE_MODE_RADIOS,
- Settings.System.RADIO_CELL + ","
- + Settings.System.RADIO_BLUETOOTH + "," + Settings.System.RADIO_WIFI);
+ loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
+ R.integer.def_screen_off_timeout);
+
+ loadBooleanSetting(stmt, Settings.System.AIRPLANE_MODE_ON,
+ R.bool.def_airplane_mode_on);
- loadSetting(stmt, Settings.System.AIRPLANE_MODE_ON, 0);
+ loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_RADIOS,
+ R.string.def_airplane_mode_radios);
- loadSetting(stmt, Settings.System.AUTO_TIME, 1); // Sync time to NITZ
+ loadBooleanSetting(stmt, Settings.System.AUTO_TIME,
+ R.bool.def_auto_time); // Sync time to NITZ
- // Set default brightness to 40%
- loadSetting(stmt, Settings.System.SCREEN_BRIGHTNESS,
- (int) (android.os.Power.BRIGHTNESS_ON * 0.4f));
+ loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS,
+ R.integer.def_screen_brightness);
- // Enable normal window animations (menus, toasts); disable
- // activity transition animations.
- loadSetting(stmt, Settings.System.WINDOW_ANIMATION_SCALE, "1");
- loadSetting(stmt, Settings.System.TRANSITION_ANIMATION_SCALE, "1");
+ loadDefaultAnimationSettings(stmt);
+ loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
+ R.bool.def_accelerometer_rotation);
+
// Default date format based on build
loadSetting(stmt, Settings.System.DATE_FORMAT,
SystemProperties.get("ro.com.android.dateformat",
@@ -558,12 +613,19 @@ public class DatabaseHelper extends SQLiteOpenHelper {
stmt.close();
}
+ private void loadDefaultAnimationSettings(SQLiteStatement stmt) {
+ loadFractionSetting(stmt, Settings.System.WINDOW_ANIMATION_SCALE,
+ R.fraction.def_window_animation_scale, 1);
+ loadFractionSetting(stmt, Settings.System.TRANSITION_ANIMATION_SCALE,
+ R.fraction.def_window_transition_scale, 1);
+ }
+
private void loadSecureSettings(SQLiteDatabase db) {
SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
+ " VALUES(?,?);");
- // Bluetooth off
- loadSetting(stmt, Settings.Secure.BLUETOOTH_ON, 0);
+ loadBooleanSetting(stmt, Settings.Secure.BLUETOOTH_ON,
+ R.bool.def_bluetooth_on);
// Data roaming default, based on build
loadSetting(stmt, Settings.Secure.DATA_ROAMING,
@@ -571,27 +633,36 @@ public class DatabaseHelper extends SQLiteOpenHelper {
SystemProperties.get("ro.com.android.dataroaming",
"false")) ? 1 : 0);
- // Don't allow non-market apps to be installed
- loadSetting(stmt, Settings.Secure.INSTALL_NON_MARKET_APPS, 0);
+ loadBooleanSetting(stmt, Settings.Secure.INSTALL_NON_MARKET_APPS,
+ R.bool.def_install_non_market_apps);
- // Set the default location providers to network based (cell-id)
- loadSetting(stmt, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- LocationManager.NETWORK_PROVIDER);
+ loadStringSetting(stmt, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ R.string.def_location_providers_allowed);
- loadSetting(stmt, Settings.Secure.NETWORK_PREFERENCE,
- ConnectivityManager.DEFAULT_NETWORK_PREFERENCE);
-
- // USB mass storage on by default
- loadSetting(stmt, Settings.Secure.USB_MASS_STORAGE_ENABLED, 1);
+ loadIntegerSetting(stmt, Settings.Secure.NETWORK_PREFERENCE,
+ R.integer.def_network_preference);
- // WIFI on, notify about available networks
- loadSetting(stmt, Settings.Secure.WIFI_ON, 0);
- loadSetting(stmt, Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1);
+ loadBooleanSetting(stmt, Settings.Secure.USB_MASS_STORAGE_ENABLED,
+ R.bool.def_usb_mass_storage_enabled);
+ loadBooleanSetting(stmt, Settings.Secure.WIFI_ON,
+ R.bool.def_wifi_on);
+ loadBooleanSetting(stmt, Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+ R.bool.def_networks_available_notification_on);
+
+ String wifiWatchList = SystemProperties.get("ro.com.android.wifi-watchlist");
+ if (!TextUtils.isEmpty(wifiWatchList)) {
+ loadSetting(stmt, Settings.Secure.WIFI_WATCHDOG_WATCH_LIST, wifiWatchList);
+ }
+
// Don't do this. The SystemServer will initialize ADB_ENABLED from a
// persistent system property instead.
//loadSetting(stmt, Settings.Secure.ADB_ENABLED, 0);
+ // Allow mock locations default, based on build
+ loadSetting(stmt, Settings.Secure.ALLOW_MOCK_LOCATION,
+ "1".equals(SystemProperties.get("ro.allow.mock.location")) ? 1 : 0);
+
stmt.close();
}
@@ -600,4 +671,23 @@ public class DatabaseHelper extends SQLiteOpenHelper {
stmt.bindString(2, value.toString());
stmt.execute();
}
+
+ private void loadStringSetting(SQLiteStatement stmt, String key, int resid) {
+ loadSetting(stmt, key, mContext.getResources().getString(resid));
+ }
+
+ private void loadBooleanSetting(SQLiteStatement stmt, String key, int resid) {
+ loadSetting(stmt, key,
+ mContext.getResources().getBoolean(resid) ? "1" : "0");
+ }
+
+ private void loadIntegerSetting(SQLiteStatement stmt, String key, int resid) {
+ loadSetting(stmt, key,
+ Integer.toString(mContext.getResources().getInteger(resid)));
+ }
+
+ private void loadFractionSetting(SQLiteStatement stmt, String key, int resid, int base) {
+ loadSetting(stmt, key,
+ Float.toString(mContext.getResources().getFraction(resid, base, base)));
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 0101ece..8d52070 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -40,6 +40,9 @@ public class SettingsProvider extends ContentProvider {
private static final String TAG = "SettingsProvider";
private static final boolean LOCAL_LOGV = false;
+ private static final String TABLE_FAVORITES = "favorites";
+ private static final String TABLE_OLD_FAVORITES = "old_favorites";
+
protected DatabaseHelper mOpenHelper;
/**
@@ -47,7 +50,7 @@ public class SettingsProvider extends ContentProvider {
* used to access the corresponding database rows.
*/
private static class SqlArguments {
- public final String table;
+ public String table;
public final String where;
public final String[] args;
@@ -175,17 +178,30 @@ public class SettingsProvider extends ContentProvider {
@Override
public Cursor query(Uri url, String[] select, String where, String[] whereArgs, String sort) {
SqlArguments args = new SqlArguments(url, where, whereArgs);
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+
// The favorites table was moved from this provider to a provider inside Home
// Home still need to query this table to upgrade from pre-cupcake builds
// However, a cupcake+ build with no data does not contain this table which will
// cause an exception in the SQL stack. The following line is a special case to
// let the caller of the query have a chance to recover and avoid the exception
- if ("favorites".equals(args.table)) return null;
+ if (TABLE_FAVORITES.equals(args.table)) {
+ return null;
+ } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
+ args.table = TABLE_FAVORITES;
+ Cursor cursor = db.rawQuery("PRAGMA table_info(favorites);", null);
+ if (cursor != null) {
+ boolean exists = cursor.getCount() > 0;
+ cursor.close();
+ if (!exists) return null;
+ } else {
+ return null;
+ }
+ }
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(args.table);
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor ret = qb.query(db, select, args.where, args.args, null, null, sort);
ret.setNotificationUri(getContext().getContentResolver(), url);
return ret;
@@ -206,6 +222,9 @@ public class SettingsProvider extends ContentProvider {
@Override
public int bulkInsert(Uri uri, ContentValues[] values) {
SqlArguments args = new SqlArguments(uri);
+ if (TABLE_FAVORITES.equals(args.table)) {
+ return 0;
+ }
checkWritePermissions(args);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
@@ -228,6 +247,9 @@ public class SettingsProvider extends ContentProvider {
@Override
public Uri insert(Uri url, ContentValues initialValues) {
SqlArguments args = new SqlArguments(url);
+ if (TABLE_FAVORITES.equals(args.table)) {
+ return null;
+ }
checkWritePermissions(args);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
@@ -243,6 +265,11 @@ public class SettingsProvider extends ContentProvider {
@Override
public int delete(Uri url, String where, String[] whereArgs) {
SqlArguments args = new SqlArguments(url, where, whereArgs);
+ if (TABLE_FAVORITES.equals(args.table)) {
+ return 0;
+ } else if (TABLE_OLD_FAVORITES.equals(args.table)) {
+ args.table = TABLE_FAVORITES;
+ }
checkWritePermissions(args);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
@@ -255,6 +282,9 @@ public class SettingsProvider extends ContentProvider {
@Override
public int update(Uri url, ContentValues initialValues, String where, String[] whereArgs) {
SqlArguments args = new SqlArguments(url, where, whereArgs);
+ if (TABLE_FAVORITES.equals(args.table)) {
+ return 0;
+ }
checkWritePermissions(args);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
diff --git a/packages/SubscribedFeedsProvider/AndroidManifest.xml b/packages/SubscribedFeedsProvider/AndroidManifest.xml
index 94c4be5..6ecda48 100644
--- a/packages/SubscribedFeedsProvider/AndroidManifest.xml
+++ b/packages/SubscribedFeedsProvider/AndroidManifest.xml
@@ -6,7 +6,7 @@
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_READ" />
<uses-permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE" />
-
+
<application android:process="system"
android:allowClearUserData="false"
android:icon="@drawable/app_icon"
@@ -17,7 +17,7 @@
android:multiprocess="false"
android:readPermission="android.permission.SUBSCRIBED_FEEDS_READ"
android:writePermission="android.permission.SUBSCRIBED_FEEDS_WRITE" />
- <receiver android:name="SubscribedFeedsService">
+ <receiver android:name="SubscribedFeedsBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.GTALK_DATA_MESSAGE_RECEIVED" />
<category android:name="GSYNC_TICKLE"/>
@@ -29,5 +29,6 @@
<action android:name="com.android.subscribedfeeds.action.REFRESH" />
</intent-filter>
</receiver>
+ <service android:name="SubscribedFeedsIntentService"/>
</application>
</manifest>
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
new file mode 100644
index 0000000..3513215
--- /dev/null
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java
@@ -0,0 +1,41 @@
+/*
+** Copyright 2006, 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.providers.subscribedfeeds;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+/**
+ * Handles the XMPP_CONNECTED_ACTION intent by updating all the
+ * subscribed feeds with the new jabber id and initiating a sync
+ * for all subscriptions.
+ *
+ * Handles the TICKLE_ACTION intent by finding the matching
+ * subscribed feed and intiating a sync for it.
+ */
+public class SubscribedFeedsBroadcastReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "Sync";
+
+ public void onReceive(Context context, Intent intent) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received intent " + intent);
+ intent.setClass(context, SubscribedFeedsIntentService.class);
+ context.startService(intent);
+ }
+}
diff --git a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsService.java b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
index 4a1de59..df599c7 100644
--- a/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsService.java
+++ b/packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsIntentService.java
@@ -1,61 +1,35 @@
-/*
-** Copyright 2006, 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.providers.subscribedfeeds;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.Context;
import android.content.ContentResolver;
import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.SubscribedFeeds;
+import android.util.Log;
+import android.util.Config;
+import android.util.EventLog;
+import android.app.IntentService;
import android.provider.Sync;
+import android.provider.SubscribedFeeds;
import android.provider.SyncConstValue;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteFullException;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.os.Bundle;
+import android.os.Debug;
import android.text.TextUtils;
-import android.util.Config;
-import android.util.EventLog;
-import android.util.Log;
+import android.net.Uri;
import java.util.ArrayList;
import java.util.Calendar;
/**
- * Handles the XMPP_CONNECTED_ACTION intent by updating all the
- * subscribed feeds with the new jabber id and initiating a sync
- * for all subscriptions.
- *
- * Handles the TICKLE_ACTION intent by finding the matching
- * subscribed feed and intiating a sync for it.
+ * A service to handle various intents asynchronously.
*/
-public class SubscribedFeedsService extends BroadcastReceiver {
-
+public class SubscribedFeedsIntentService extends IntentService {
private static final String TAG = "Sync";
- private static final String SUBSCRIBED_FEEDS_REFRESH_ACTION =
- "com.android.subscribedfeeds.action.REFRESH";
-
- private static final Intent sSubscribedFeedsRefreshIntent =
- new Intent(SUBSCRIBED_FEEDS_REFRESH_ACTION);
-
private static final String[] sAccountProjection =
new String[] {SubscribedFeeds.Accounts._SYNC_ACCOUNT};
@@ -66,11 +40,20 @@ public class SubscribedFeedsService extends BroadcastReceiver {
private static final String sSubscribedFeedsPrefs = "subscribedFeeds";
- static final int LOG_TICKLE = 2742;
+ private static final String GTALK_DATA_MESSAGE_RECEIVED =
+ "android.intent.action.GTALK_DATA_MESSAGE_RECEIVED";
- public void onReceive(Context context, Intent intent) {
- if ("android.intent.action.GTALK_DATA_MESSAGE_RECEIVED".equals(
- intent.getAction())) {
+ private static final String SUBSCRIBED_FEEDS_REFRESH_ACTION =
+ "com.android.subscribedfeeds.action.REFRESH";
+
+ private static final int LOG_TICKLE = 2742;
+
+ public SubscribedFeedsIntentService() {
+ super("SubscribedFeedsIntentService");
+ }
+
+ protected void onHandleIntent(Intent intent) {
+ if (GTALK_DATA_MESSAGE_RECEIVED.equals(intent.getAction())) {
boolean fromTrustedServer = intent.getBooleanExtra("from_trusted_server", false);
if (fromTrustedServer) {
String account = intent.getStringExtra("account");
@@ -88,7 +71,7 @@ public class SubscribedFeedsService extends BroadcastReceiver {
+ account + " - " + token);
}
- handleTickle(context, account, token);
+ handleTickle(this, account, token);
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Ignoring tickle -- not from trusted server.");
@@ -101,25 +84,23 @@ public class SubscribedFeedsService extends BroadcastReceiver {
Log.d(TAG, "Received boot completed action");
}
// load the time from the shared preferences and schedule an alarm
- long refreshTime = context.getSharedPreferences(
+ long refreshTime = getSharedPreferences(
sSubscribedFeedsPrefs,
Context.MODE_WORLD_READABLE).getLong(sRefreshTime, 0);
- scheduleRefresh(context, refreshTime);
- } else if (sSubscribedFeedsRefreshIntent.getAction().equals(
- intent.getAction())) {
+ scheduleRefresh(this, refreshTime);
+ } else if (SUBSCRIBED_FEEDS_REFRESH_ACTION.equals(intent.getAction())) {
if (Config.LOGD) {
Log.d(TAG, "Received sSubscribedFeedsRefreshIntent");
}
- handleRefreshAlarm(context);
+ handleRefreshAlarm(this);
}
}
-
private void scheduleRefresh(Context context, long when) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(
Context.ALARM_SERVICE);
- PendingIntent sender = PendingIntent.getBroadcast(context,
- 0, sSubscribedFeedsRefreshIntent, 0);
- alarmManager.set(AlarmManager.RTC, when, sender);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
+ 0, new Intent(SUBSCRIBED_FEEDS_REFRESH_ACTION), 0);
+ alarmManager.set(AlarmManager.RTC, when, pendingIntent);
}
private void handleTickle(Context context, String account, String feed) {
@@ -189,20 +170,22 @@ public class SubscribedFeedsService extends BroadcastReceiver {
// mark the feeds dirty, by setting the accounts to the same value,
// which will trigger a sync.
- ContentValues values = new ContentValues();
- for (String account : accounts) {
- values.put(SyncConstValue._SYNC_ACCOUNT, account);
- contentResolver.update(SubscribedFeeds.Feeds.CONTENT_URI, values,
- SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?", new String[] {account});
+ try {
+ ContentValues values = new ContentValues();
+ for (String account : accounts) {
+ values.put(SyncConstValue._SYNC_ACCOUNT, account);
+ contentResolver.update(SubscribedFeeds.Feeds.CONTENT_URI, values,
+ SubscribedFeeds.Feeds._SYNC_ACCOUNT + "=?", new String[] {account});
+ }
+ } catch (SQLiteFullException e) {
+ Log.w(TAG, "disk full while trying to mark the feeds as dirty, skipping");
}
// Schedule a refresh.
long refreshTime = Calendar.getInstance().getTimeInMillis() + SUBSCRIPTION_REFRESH_INTERVAL;
scheduleRefresh(context, refreshTime);
- SharedPreferences preferences = context
- .getSharedPreferences(sSubscribedFeedsPrefs,
- Context.MODE_WORLD_READABLE);
- SharedPreferences.Editor editor = preferences.edit();
+ SharedPreferences.Editor editor = context.getSharedPreferences(sSubscribedFeedsPrefs,
+ Context.MODE_WORLD_READABLE).edit();
editor.putLong(sRefreshTime, refreshTime);
editor.commit();
}
diff --git a/preloaded-classes b/preloaded-classes
index 160ebef..b91f41b 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -160,7 +160,7 @@ android.graphics.drawable.DrawableContainer
android.graphics.drawable.GradientDrawable
android.graphics.drawable.LayerDrawable
android.graphics.drawable.LayerDrawable$LayerState
-android.graphics.drawable.LayerDrawable$Rec
+android.graphics.drawable.LayerDrawable$ChildDrawable
android.graphics.drawable.NinePatchDrawable
android.graphics.drawable.NinePatchDrawable$NinePatchState
android.graphics.drawable.PaintDrawable
@@ -340,7 +340,7 @@ android.view.TouchDelegate
android.view.VelocityTracker
android.view.View
android.view.View$AttachInfo
-android.view.View$AttachInfo$SoundEffectPlayer
+android.view.View$AttachInfo$Callbacks
android.view.View$BaseSavedState$1
android.view.View$MeasureSpec
android.view.View$ScrollabilityCache
@@ -366,7 +366,6 @@ android.view.animation.Transformation
android.view.inputmethod.BaseInputConnection
android.view.inputmethod.CompletionInfo$1
android.view.inputmethod.CompletionInfo
-android.view.inputmethod.DefaultInputMethod
android.view.inputmethod.EditorInfo$1
android.view.inputmethod.EditorInfo
android.view.inputmethod.ExtractedText$1
@@ -376,23 +375,16 @@ android.view.inputmethod.ExtractedTextRequest
android.view.inputmethod.InputBinding$1
android.view.inputmethod.InputBinding
android.view.inputmethod.InputConnection
-android.view.inputmethod.InputConnectionWrapper
android.view.inputmethod.InputMethod$SessionCallback
android.view.inputmethod.InputMethod
android.view.inputmethod.InputMethodInfo$1
android.view.inputmethod.InputMethodInfo
android.view.inputmethod.InputMethodManager$1
android.view.inputmethod.InputMethodManager$2
-android.view.inputmethod.InputMethodManager$3
-android.view.inputmethod.InputMethodManager$NoOpInputConnection
+android.view.inputmethod.InputMethodManager$ControlledInputConnectionWrapper
android.view.inputmethod.InputMethodManager
android.view.inputmethod.InputMethodSession$EventCallback
android.view.inputmethod.InputMethodSession
-android.view.inputmethod.MutableInputConnectionWrapper
-android.view.inputmethod.SimpleInputMethod$InputMethodSessionCallbackWrapper
-android.view.inputmethod.SimpleInputMethod$Session$InputMethodEventCallbackWrapper
-android.view.inputmethod.SimpleInputMethod$Session
-android.view.inputmethod.SimpleInputMethod
android.webkit.BrowserFrame
android.webkit.CacheManager
android.webkit.CallbackProxy
@@ -507,8 +499,6 @@ com.android.internal.logging.AndroidConfig
com.android.internal.logging.AndroidHandler
com.android.internal.os.AndroidPrintStream
com.android.internal.os.BinderInternal$GcWatcher
-com.android.internal.os.HandlerHelper
-com.android.internal.os.HandlerThread
com.android.internal.os.LoggingPrintStream
com.android.internal.os.LoggingPrintStream$1
com.android.internal.os.RuntimeInit
@@ -793,7 +783,7 @@ org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl
org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream
org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream
org.apache.harmony.xnet.provider.jsse.SSLParameters
-org.apache.harmony.xnet.provider.jsse.SSLSessionContextImpl$1
+org.apache.harmony.xnet.provider.jsse.ClientSessionContext
org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl
org.apache.harmony.xnet.provider.jsse.TrustManagerImpl
org.apache.http.HttpHost
diff --git a/services/Android.mk b/services/java/Android.mk
index 5e912d6..5e912d6 100644
--- a/services/Android.mk
+++ b/services/java/Android.mk
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 1625853..d66c6e5 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -34,21 +34,26 @@ import android.os.PowerManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
-import android.util.Config;
+import android.text.format.Time;
+import android.util.EventLog;
import android.util.Log;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TimeZone;
class AlarmManagerService extends IAlarmManager.Stub {
+ // The threshold for how long an alarm can be late before we print a
+ // warning message. The time duration is in milliseconds.
+ private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
+
private static final int RTC_WAKEUP_MASK = 1 << AlarmManager.RTC_WAKEUP;
private static final int RTC_MASK = 1 << AlarmManager.RTC;
private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << AlarmManager.ELAPSED_REALTIME_WAKEUP;
@@ -72,6 +77,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
private final ArrayList<Alarm> mRtcAlarms = new ArrayList<Alarm>();
private final ArrayList<Alarm> mElapsedRealtimeWakeupAlarms = new ArrayList<Alarm>();
private final ArrayList<Alarm> mElapsedRealtimeAlarms = new ArrayList<Alarm>();
+ private final IncreasingTimeOrder mIncreasingTimeOrder = new IncreasingTimeOrder();
// slots corresponding with the inexact-repeat interval buckets,
// ordered from shortest to longest
@@ -250,12 +256,12 @@ class AlarmManagerService extends IAlarmManager.Stub {
if (localLOGV) Log.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
timeZoneWasChanged = true;
SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
-
- // Update the kernel timezone information
- // Kernel tracks time offsets as 'minutes west of GMT'
- int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000;
- setKernelTimezone(mDescriptor, -(gmtOffset));
}
+
+ // Update the kernel timezone information
+ // Kernel tracks time offsets as 'minutes west of GMT'
+ int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000;
+ setKernelTimezone(mDescriptor, -(gmtOffset));
}
TimeZone.setDefault(null);
@@ -338,11 +344,26 @@ class AlarmManagerService extends IAlarmManager.Stub {
private int addAlarmLocked(Alarm alarm) {
ArrayList<Alarm> alarmList = getAlarmList(alarm.type);
- int index = Collections.binarySearch(alarmList, alarm);
- index = (index < 0) ? ((index + 1) * -1) : index;
- if (localLOGV) Log.v(
- TAG, "Adding alarm " + alarm + " at " + index);
+ int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder);
+ if (index < 0) {
+ index = 0 - index - 1;
+ }
+ if (localLOGV) Log.v(TAG, "Adding alarm " + alarm + " at " + index);
alarmList.add(index, alarm);
+
+ if (localLOGV) {
+ // Display the list of alarms for this alarm type
+ Log.v(TAG, "alarms: " + alarmList.size() + " type: " + alarm.type);
+ int position = 0;
+ for (Alarm a : alarmList) {
+ Time time = new Time();
+ time.set(a.when);
+ String timeStr = time.format("%b %d %I:%M:%S %p");
+ Log.v(TAG, position + ": " + timeStr
+ + " " + a.operation.getTargetPackage());
+ position += 1;
+ }
+ }
return index;
}
@@ -382,7 +403,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingPermission("android.permission.DUMP")
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump AlarmManager from from pid="
+ Binder.getCallingPid()
@@ -459,14 +480,22 @@ class AlarmManagerService extends IAlarmManager.Stub {
if (localLOGV) Log.v(TAG, "Checking active alarm when=" + alarm.when + " " + alarm);
- if (alarm.when > now)
- {
+ if (alarm.when > now) {
// don't fire alarms in the future
break;
}
+
+ // If the alarm is late, then print a warning message.
+ // Note that this can happen if the user creates a new event on
+ // the Calendar app with a reminder that is in the past. In that
+ // case, the reminder alarm will fire immediately.
+ if (localLOGV && now - alarm.when > LATE_ALARM_THRESHOLD) {
+ Log.v(TAG, "alarm is late! alarm time: " + alarm.when
+ + " now: " + now + " delay (in seconds): "
+ + (now - alarm.when) / 1000);
+ }
- // add it to the trigger list so we can trigger it without the lock held.
- // recurring alarms may have passed several alarm intervals while the
+ // Recurring alarms may have passed several alarm intervals while the
// phone was asleep or off, so pass a trigger count when sending them.
if (localLOGV) Log.v(TAG, "Alarm triggering: " + alarm);
alarm.count = 1;
@@ -481,28 +510,42 @@ class AlarmManagerService extends IAlarmManager.Stub {
it.remove();
// if it repeats queue it up to be read-added to the list
- if (alarm.repeatInterval > 0)
- {
+ if (alarm.repeatInterval > 0) {
repeats.add(alarm);
}
}
// reset any repeating alarms.
it = repeats.iterator();
- while (it.hasNext())
- {
+ while (it.hasNext()) {
Alarm alarm = it.next();
alarm.when += alarm.count * alarm.repeatInterval;
addAlarmLocked(alarm);
}
- if (alarmList.size() > 0)
- {
+ if (alarmList.size() > 0) {
setLocked(alarmList.get(0));
}
}
- private class Alarm implements Comparable<Alarm> {
+ /**
+ * This Comparator sorts Alarms into increasing time order.
+ */
+ public static class IncreasingTimeOrder implements Comparator<Alarm> {
+ public int compare(Alarm a1, Alarm a2) {
+ long when1 = a1.when;
+ long when2 = a2.when;
+ if (when1 - when2 > 0) {
+ return 1;
+ }
+ if (when1 - when2 < 0) {
+ return -1;
+ }
+ return 0;
+ }
+ }
+
+ private static class Alarm {
public int type;
public int count;
public long when;
@@ -515,15 +558,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
operation = null;
}
- public int compareTo(Alarm obj)
- {
- if (obj.when > this.when) return -1;
- if (obj.when < this.when) return 1;
- if (obj.operation.equals(this.operation)
- && obj.repeatInterval == this.repeatInterval) return 0;
- return -1;
- }
-
+ @Override
public String toString()
{
return "Alarm{"
@@ -701,11 +736,11 @@ class AlarmManagerService extends IAlarmManager.Stub {
public void scheduleDateChangedEvent() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
- calendar.add(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
+ calendar.add(Calendar.DAY_OF_MONTH, 1);
set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender);
}
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
new file mode 100644
index 0000000..de5d0ac
--- /dev/null
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -0,0 +1,1148 @@
+/*
+ * Copyright (C) 2007 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;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+import android.widget.RemoteViews;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.appwidget.IAppWidgetHost;
+import com.android.internal.util.XmlUtils;
+import com.android.internal.util.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+class AppWidgetService extends IAppWidgetService.Stub
+{
+ private static final String TAG = "AppWidgetService";
+
+ private static final String SETTINGS_FILENAME = "appwidgets.xml";
+ private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp";
+
+ /*
+ * When identifying a Host or Provider based on the calling process, use the uid field.
+ * When identifying a Host or Provider based on a package manager broadcast, use the
+ * package given.
+ */
+
+ static class Provider {
+ int uid;
+ AppWidgetProviderInfo info;
+ ArrayList<AppWidgetId> instances = new ArrayList();
+ PendingIntent broadcast;
+ boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
+
+ int tag; // for use while saving state (the index)
+ }
+
+ static class Host {
+ int uid;
+ int hostId;
+ String packageName;
+ ArrayList<AppWidgetId> instances = new ArrayList();
+ IAppWidgetHost callbacks;
+ boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
+
+ int tag; // for use while saving state (the index)
+ }
+
+ static class AppWidgetId {
+ int appWidgetId;
+ Provider provider;
+ RemoteViews views;
+ Host host;
+ }
+
+ Context mContext;
+ PackageManager mPackageManager;
+ AlarmManager mAlarmManager;
+ ArrayList<Provider> mInstalledProviders = new ArrayList();
+ int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
+ ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList();
+ ArrayList<Host> mHosts = new ArrayList();
+ boolean mSafeMode;
+
+ AppWidgetService(Context context) {
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+ mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ }
+
+ public void systemReady(boolean safeMode) {
+ mSafeMode = safeMode;
+
+ loadAppWidgetList();
+ loadStateLocked();
+
+ // Register for the boot completed broadcast, so we can send the
+ // ENABLE broacasts. If we try to send them now, they time out,
+ // because the system isn't ready to handle them yet.
+ mContext.registerReceiver(mBroadcastReceiver,
+ new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+
+ // Register for broadcasts about package install, etc., so we can
+ // update the provider list.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ synchronized (mAppWidgetIds) {
+ int N = mInstalledProviders.size();
+ pw.println("Providers: (size=" + N + ")");
+ for (int i=0; i<N; i++) {
+ Provider p = mInstalledProviders.get(i);
+ AppWidgetProviderInfo info = p.info;
+ pw.println(" [" + i + "] provder=" + info.provider
+ + " min=(" + info.minWidth + "x" + info.minHeight + ")"
+ + " updatePeriodMillis=" + info.updatePeriodMillis
+ + " initialLayout=" + info.initialLayout + " zombie=" + p.zombie);
+ }
+
+ N = mAppWidgetIds.size();
+ pw.println("AppWidgetIds: (size=" + N + ")");
+ for (int i=0; i<N; i++) {
+ AppWidgetId id = mAppWidgetIds.get(i);
+ pw.println(" [" + i + "] appWidgetId=" + id.appWidgetId
+ + " host=" + id.host.hostId + "/" + id.host.packageName + " provider="
+ + (id.provider == null ? "null" : id.provider.info.provider)
+ + " host.callbacks=" + (id.host != null ? id.host.callbacks : "(no host)")
+ + " views=" + id.views);
+ }
+
+ N = mHosts.size();
+ pw.println("Hosts: (size=" + N + ")");
+ for (int i=0; i<N; i++) {
+ Host host = mHosts.get(i);
+ pw.println(" [" + i + "] packageName=" + host.packageName + " uid=" + host.uid
+ + " hostId=" + host.hostId + " callbacks=" + host.callbacks
+ + " instances.size=" + host.instances.size() + " zombie=" + host.zombie);
+ }
+ }
+ }
+
+ public int allocateAppWidgetId(String packageName, int hostId) {
+ int callingUid = enforceCallingUid(packageName);
+ synchronized (mAppWidgetIds) {
+ int appWidgetId = mNextAppWidgetId++;
+
+ Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
+
+ AppWidgetId id = new AppWidgetId();
+ id.appWidgetId = appWidgetId;
+ id.host = host;
+
+ host.instances.add(id);
+ mAppWidgetIds.add(id);
+
+ saveStateLocked();
+
+ return appWidgetId;
+ }
+ }
+
+ public void deleteAppWidgetId(int appWidgetId) {
+ synchronized (mAppWidgetIds) {
+ AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+ if (id != null) {
+ deleteAppWidgetLocked(id);
+ saveStateLocked();
+ }
+ }
+ }
+
+ public void deleteHost(int hostId) {
+ synchronized (mAppWidgetIds) {
+ int callingUid = getCallingUid();
+ Host host = lookupHostLocked(callingUid, hostId);
+ if (host != null) {
+ deleteHostLocked(host);
+ saveStateLocked();
+ }
+ }
+ }
+
+ public void deleteAllHosts() {
+ synchronized (mAppWidgetIds) {
+ int callingUid = getCallingUid();
+ final int N = mHosts.size();
+ boolean changed = false;
+ for (int i=N-1; i>=0; i--) {
+ Host host = mHosts.get(i);
+ if (host.uid == callingUid) {
+ deleteHostLocked(host);
+ changed = true;
+ }
+ }
+ if (changed) {
+ saveStateLocked();
+ }
+ }
+ }
+
+ void deleteHostLocked(Host host) {
+ final int N = host.instances.size();
+ for (int i=N-1; i>=0; i--) {
+ AppWidgetId id = host.instances.get(i);
+ deleteAppWidgetLocked(id);
+ }
+ host.instances.clear();
+ mHosts.remove(host);
+ // it's gone or going away, abruptly drop the callback connection
+ host.callbacks = null;
+ }
+
+ void deleteAppWidgetLocked(AppWidgetId id) {
+ Host host = id.host;
+ host.instances.remove(id);
+ pruneHostLocked(host);
+
+ mAppWidgetIds.remove(id);
+
+ Provider p = id.provider;
+ if (p != null) {
+ p.instances.remove(id);
+ if (!p.zombie) {
+ // send the broacast saying that this appWidgetId has been deleted
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
+ intent.setComponent(p.info.provider);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
+ mContext.sendBroadcast(intent);
+ if (p.instances.size() == 0) {
+ // cancel the future updates
+ cancelBroadcasts(p);
+
+ // send the broacast saying that the provider is not in use any more
+ intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
+ intent.setComponent(p.info.provider);
+ mContext.sendBroadcast(intent);
+ }
+ }
+ }
+ }
+
+ void cancelBroadcasts(Provider p) {
+ if (p.broadcast != null) {
+ mAlarmManager.cancel(p.broadcast);
+ long token = Binder.clearCallingIdentity();
+ try {
+ p.broadcast.cancel();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ p.broadcast = null;
+ }
+ }
+
+ public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
+ mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET,
+ "bindGagetId appWidgetId=" + appWidgetId + " provider=" + provider);
+ synchronized (mAppWidgetIds) {
+ AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+ if (id == null) {
+ throw new IllegalArgumentException("bad appWidgetId");
+ }
+ if (id.provider != null) {
+ throw new IllegalArgumentException("appWidgetId " + appWidgetId + " already bound to "
+ + id.provider.info.provider);
+ }
+ Provider p = lookupProviderLocked(provider);
+ if (p == null) {
+ throw new IllegalArgumentException("not a appwidget provider: " + provider);
+ }
+ if (p.zombie) {
+ throw new IllegalArgumentException("can't bind to a 3rd party provider in"
+ + " safe mode: " + provider);
+ }
+
+ id.provider = p;
+ p.instances.add(id);
+ int instancesSize = p.instances.size();
+ if (instancesSize == 1) {
+ // tell the provider that it's ready
+ sendEnableIntentLocked(p);
+ }
+
+ // send an update now -- We need this update now, and just for this appWidgetId.
+ // It's less critical when the next one happens, so when we schdule the next one,
+ // we add updatePeriodMillis to its start time. That time will have some slop,
+ // but that's okay.
+ sendUpdateIntentLocked(p, new int[] { appWidgetId });
+
+ // schedule the future updates
+ registerForBroadcastsLocked(p, getAppWidgetIds(p));
+ saveStateLocked();
+ }
+ }
+
+ public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
+ synchronized (mAppWidgetIds) {
+ AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+ if (id != null && id.provider != null && !id.provider.zombie) {
+ return id.provider.info;
+ }
+ return null;
+ }
+ }
+
+ public RemoteViews getAppWidgetViews(int appWidgetId) {
+ synchronized (mAppWidgetIds) {
+ AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+ if (id != null) {
+ return id.views;
+ }
+ return null;
+ }
+ }
+
+ public List<AppWidgetProviderInfo> getInstalledProviders() {
+ synchronized (mAppWidgetIds) {
+ final int N = mInstalledProviders.size();
+ ArrayList<AppWidgetProviderInfo> result = new ArrayList(N);
+ for (int i=0; i<N; i++) {
+ Provider p = mInstalledProviders.get(i);
+ if (!p.zombie) {
+ result.add(p.info);
+ }
+ }
+ return result;
+ }
+ }
+
+ public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
+ if (appWidgetIds == null) {
+ return;
+ }
+ if (appWidgetIds.length == 0) {
+ return;
+ }
+ final int N = appWidgetIds.length;
+
+ synchronized (mAppWidgetIds) {
+ for (int i=0; i<N; i++) {
+ AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
+ updateAppWidgetInstanceLocked(id, views);
+ }
+ }
+ }
+
+ public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) {
+ synchronized (mAppWidgetIds) {
+ Provider p = lookupProviderLocked(provider);
+ if (p == null) {
+ Log.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider);
+ return;
+ }
+ ArrayList<AppWidgetId> instances = p.instances;
+ final int N = instances.size();
+ for (int i=0; i<N; i++) {
+ AppWidgetId id = instances.get(i);
+ updateAppWidgetInstanceLocked(id, views);
+ }
+ }
+ }
+
+ void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) {
+ // allow for stale appWidgetIds and other badness
+ // lookup also checks that the calling process can access the appWidgetId
+ // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
+ if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
+ id.views = views;
+
+ // is anyone listening?
+ if (id.host.callbacks != null) {
+ try {
+ // the lock is held, but this is a oneway call
+ id.host.callbacks.updateAppWidget(id.appWidgetId, views);
+ } catch (RemoteException e) {
+ // It failed; remove the callback. No need to prune because
+ // we know that this host is still referenced by this instance.
+ id.host.callbacks = null;
+ }
+ }
+ }
+ }
+
+ public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
+ List<RemoteViews> updatedViews) {
+ int callingUid = enforceCallingUid(packageName);
+ synchronized (mAppWidgetIds) {
+ Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
+ host.callbacks = callbacks;
+
+ updatedViews.clear();
+
+ ArrayList<AppWidgetId> instances = host.instances;
+ int N = instances.size();
+ int[] updatedIds = new int[N];
+ for (int i=0; i<N; i++) {
+ AppWidgetId id = instances.get(i);
+ updatedIds[i] = id.appWidgetId;
+ updatedViews.add(id.views);
+ }
+ return updatedIds;
+ }
+ }
+
+ public void stopListening(int hostId) {
+ synchronized (mAppWidgetIds) {
+ Host host = lookupHostLocked(getCallingUid(), hostId);
+ host.callbacks = null;
+ pruneHostLocked(host);
+ }
+ }
+
+ boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) {
+ if (id.host.uid == callingUid) {
+ // Apps hosting the AppWidget have access to it.
+ return true;
+ }
+ if (id.provider != null && id.provider.uid == callingUid) {
+ // Apps providing the AppWidget have access to it (if the appWidgetId has been bound)
+ return true;
+ }
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET)
+ == PackageManager.PERMISSION_GRANTED) {
+ // Apps that can bind have access to all appWidgetIds.
+ return true;
+ }
+ // Nobody else can access it.
+ return false;
+ }
+
+ AppWidgetId lookupAppWidgetIdLocked(int appWidgetId) {
+ int callingUid = getCallingUid();
+ final int N = mAppWidgetIds.size();
+ for (int i=0; i<N; i++) {
+ AppWidgetId id = mAppWidgetIds.get(i);
+ if (id.appWidgetId == appWidgetId && canAccessAppWidgetId(id, callingUid)) {
+ return id;
+ }
+ }
+ return null;
+ }
+
+ Provider lookupProviderLocked(ComponentName provider) {
+ final int N = mInstalledProviders.size();
+ for (int i=0; i<N; i++) {
+ Provider p = mInstalledProviders.get(i);
+ if (p.info.provider.equals(provider)) {
+ return p;
+ }
+ }
+ return null;
+ }
+
+ Host lookupHostLocked(int uid, int hostId) {
+ final int N = mHosts.size();
+ for (int i=0; i<N; i++) {
+ Host h = mHosts.get(i);
+ if (h.uid == uid && h.hostId == hostId) {
+ return h;
+ }
+ }
+ return null;
+ }
+
+ Host lookupOrAddHostLocked(int uid, String packageName, int hostId) {
+ final int N = mHosts.size();
+ for (int i=0; i<N; i++) {
+ Host h = mHosts.get(i);
+ if (h.hostId == hostId && h.packageName.equals(packageName)) {
+ return h;
+ }
+ }
+ Host host = new Host();
+ host.packageName = packageName;
+ host.uid = uid;
+ host.hostId = hostId;
+ mHosts.add(host);
+ return host;
+ }
+
+ void pruneHostLocked(Host host) {
+ if (host.instances.size() == 0 && host.callbacks == null) {
+ mHosts.remove(host);
+ }
+ }
+
+ void loadAppWidgetList() {
+ PackageManager pm = mPackageManager;
+
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
+ PackageManager.GET_META_DATA);
+
+ final int N = broadcastReceivers.size();
+ for (int i=0; i<N; i++) {
+ ResolveInfo ri = broadcastReceivers.get(i);
+ addProviderLocked(ri);
+ }
+ }
+
+ boolean addProviderLocked(ResolveInfo ri) {
+ Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
+ ri.activityInfo.name), ri);
+ if (p != null) {
+ mInstalledProviders.add(p);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void removeProviderLocked(int index, Provider p) {
+ int N = p.instances.size();
+ for (int i=0; i<N; i++) {
+ AppWidgetId id = p.instances.get(i);
+ // Call back with empty RemoteViews
+ updateAppWidgetInstanceLocked(id, null);
+ // Stop telling the host about updates for this from now on
+ cancelBroadcasts(p);
+ // clear out references to this appWidgetId
+ id.host.instances.remove(id);
+ mAppWidgetIds.remove(id);
+ id.provider = null;
+ pruneHostLocked(id.host);
+ id.host = null;
+ }
+ p.instances.clear();
+ mInstalledProviders.remove(index);
+ // no need to send the DISABLE broadcast, since the receiver is gone anyway
+ cancelBroadcasts(p);
+ }
+
+ void sendEnableIntentLocked(Provider p) {
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
+ intent.setComponent(p.info.provider);
+ mContext.sendBroadcast(intent);
+ }
+
+ void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) {
+ if (appWidgetIds != null && appWidgetIds.length > 0) {
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
+ intent.setComponent(p.info.provider);
+ mContext.sendBroadcast(intent);
+ }
+ }
+
+ void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) {
+ if (p.info.updatePeriodMillis > 0) {
+ // if this is the first instance, set the alarm. otherwise,
+ // rely on the fact that we've already set it and that
+ // PendingIntent.getBroadcast will update the extras.
+ boolean alreadyRegistered = p.broadcast != null;
+ int instancesSize = p.instances.size();
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
+ intent.setComponent(p.info.provider);
+ long token = Binder.clearCallingIdentity();
+ try {
+ p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ if (!alreadyRegistered) {
+ mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + p.info.updatePeriodMillis,
+ p.info.updatePeriodMillis, p.broadcast);
+ }
+ }
+ }
+
+ static int[] getAppWidgetIds(Provider p) {
+ int instancesSize = p.instances.size();
+ int appWidgetIds[] = new int[instancesSize];
+ for (int i=0; i<instancesSize; i++) {
+ appWidgetIds[i] = p.instances.get(i).appWidgetId;
+ }
+ return appWidgetIds;
+ }
+
+ public int[] getAppWidgetIds(ComponentName provider) {
+ synchronized (mAppWidgetIds) {
+ Provider p = lookupProviderLocked(provider);
+ if (p != null && getCallingUid() == p.uid) {
+ return getAppWidgetIds(p);
+ } else {
+ return new int[0];
+ }
+ }
+ }
+
+ private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
+ Provider p = null;
+
+ ActivityInfo activityInfo = ri.activityInfo;
+ XmlResourceParser parser = null;
+ try {
+ parser = activityInfo.loadXmlMetaData(mPackageManager,
+ AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
+ if (parser == null) {
+ Log.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for "
+ + "AppWidget provider '" + component + '\'');
+ return null;
+ }
+
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ // drain whitespace, comments, etc.
+ }
+
+ String nodeName = parser.getName();
+ if (!"appwidget-provider".equals(nodeName)) {
+ Log.w(TAG, "Meta-data does not start with appwidget-provider tag for"
+ + " AppWidget provider '" + component + '\'');
+ return null;
+ }
+
+ p = new Provider();
+ AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo();
+
+ info.provider = component;
+ p.uid = activityInfo.applicationInfo.uid;
+
+ TypedArray sa = mContext.getResources().obtainAttributes(attrs,
+ com.android.internal.R.styleable.AppWidgetProviderInfo);
+ info.minWidth = sa.getDimensionPixelSize(
+ com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth, 0);
+ info.minHeight = sa.getDimensionPixelSize(
+ com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight, 0);
+ info.updatePeriodMillis = sa.getInt(
+ com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
+ info.initialLayout = sa.getResourceId(
+ com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
+ String className = sa.getString(
+ com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
+ if (className != null) {
+ info.configure = new ComponentName(component.getPackageName(), className);
+ }
+ info.label = activityInfo.loadLabel(mPackageManager).toString();
+ info.icon = ri.getIconResource();
+ sa.recycle();
+ } catch (Exception e) {
+ // Ok to catch Exception here, because anything going wrong because
+ // of what a client process passes to us should not be fatal for the
+ // system process.
+ Log.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e);
+ return null;
+ } finally {
+ if (parser != null) parser.close();
+ }
+ return p;
+ }
+
+ int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException {
+ PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
+ if (pkgInfo == null || pkgInfo.applicationInfo == null) {
+ throw new PackageManager.NameNotFoundException();
+ }
+ return pkgInfo.applicationInfo.uid;
+ }
+
+ int enforceCallingUid(String packageName) throws IllegalArgumentException {
+ int callingUid = getCallingUid();
+ int packageUid;
+ try {
+ packageUid = getUidForPackage(packageName);
+ } catch (PackageManager.NameNotFoundException ex) {
+ throw new IllegalArgumentException("packageName and uid don't match packageName="
+ + packageName);
+ }
+ if (callingUid != packageUid) {
+ throw new IllegalArgumentException("packageName and uid don't match packageName="
+ + packageName);
+ }
+ return callingUid;
+ }
+
+ void sendInitialBroadcasts() {
+ synchronized (mAppWidgetIds) {
+ final int N = mInstalledProviders.size();
+ for (int i=0; i<N; i++) {
+ Provider p = mInstalledProviders.get(i);
+ if (p.instances.size() > 0) {
+ sendEnableIntentLocked(p);
+ int[] appWidgetIds = getAppWidgetIds(p);
+ sendUpdateIntentLocked(p, appWidgetIds);
+ registerForBroadcastsLocked(p, appWidgetIds);
+ }
+ }
+ }
+ }
+
+ // only call from initialization -- it assumes that the data structures are all empty
+ void loadStateLocked() {
+ File temp = savedStateTempFile();
+ File real = savedStateRealFile();
+
+ // prefer the real file. If it doesn't exist, use the temp one, and then copy it to the
+ // real one. if there is both a real file and a temp one, assume that the temp one isn't
+ // fully written and delete it.
+ if (real.exists()) {
+ readStateFromFileLocked(real);
+ if (temp.exists()) {
+ temp.delete();
+ }
+ } else if (temp.exists()) {
+ readStateFromFileLocked(temp);
+ temp.renameTo(real);
+ }
+ }
+
+ void saveStateLocked() {
+ File temp = savedStateTempFile();
+ File real = savedStateRealFile();
+
+ if (!real.exists()) {
+ // If the real one doesn't exist, it's either because this is the first time
+ // or because something went wrong while copying them. In this case, we can't
+ // trust anything that's in temp. In order to have the loadState code not
+ // use the temporary one until it's fully written, create an empty file
+ // for real, which will we'll shortly delete.
+ try {
+ real.createNewFile();
+ } catch (IOException e) {
+ }
+ }
+
+ if (temp.exists()) {
+ temp.delete();
+ }
+
+ writeStateToFileLocked(temp);
+
+ real.delete();
+ temp.renameTo(real);
+ }
+
+ void writeStateToFileLocked(File file) {
+ FileOutputStream stream = null;
+ int N;
+
+ try {
+ stream = new FileOutputStream(file, false);
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, "utf-8");
+ out.startDocument(null, true);
+
+
+ out.startTag(null, "gs");
+
+ int providerIndex = 0;
+ N = mInstalledProviders.size();
+ for (int i=0; i<N; i++) {
+ Provider p = mInstalledProviders.get(i);
+ if (p.instances.size() > 0) {
+ out.startTag(null, "p");
+ out.attribute(null, "pkg", p.info.provider.getPackageName());
+ out.attribute(null, "cl", p.info.provider.getClassName());
+ out.endTag(null, "h");
+ p.tag = providerIndex;
+ providerIndex++;
+ }
+ }
+
+ N = mHosts.size();
+ for (int i=0; i<N; i++) {
+ Host host = mHosts.get(i);
+ out.startTag(null, "h");
+ out.attribute(null, "pkg", host.packageName);
+ out.attribute(null, "id", Integer.toHexString(host.hostId));
+ out.endTag(null, "h");
+ host.tag = i;
+ }
+
+ N = mAppWidgetIds.size();
+ for (int i=0; i<N; i++) {
+ AppWidgetId id = mAppWidgetIds.get(i);
+ out.startTag(null, "g");
+ out.attribute(null, "id", Integer.toHexString(id.appWidgetId));
+ out.attribute(null, "h", Integer.toHexString(id.host.tag));
+ if (id.provider != null) {
+ out.attribute(null, "p", Integer.toHexString(id.provider.tag));
+ }
+ out.endTag(null, "g");
+ }
+
+ out.endTag(null, "gs");
+
+ out.endDocument();
+ stream.close();
+ } catch (IOException e) {
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException ex) {
+ }
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+ }
+
+ void readStateFromFileLocked(File file) {
+ FileInputStream stream = null;
+
+ boolean success = false;
+
+ try {
+ stream = new FileInputStream(file);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+
+ int type;
+ int providerIndex = 0;
+ HashMap<Integer,Provider> loadedProviders = new HashMap();
+ do {
+ type = parser.next();
+ if (type == XmlPullParser.START_TAG) {
+ String tag = parser.getName();
+ if ("p".equals(tag)) {
+ // TODO: do we need to check that this package has the same signature
+ // as before?
+ String pkg = parser.getAttributeValue(null, "pkg");
+ String cl = parser.getAttributeValue(null, "cl");
+ Provider p = lookupProviderLocked(new ComponentName(pkg, cl));
+ if (p == null && mSafeMode) {
+ // if we're in safe mode, make a temporary one
+ p = new Provider();
+ p.info = new AppWidgetProviderInfo();
+ p.info.provider = new ComponentName(pkg, cl);
+ p.zombie = true;
+ mInstalledProviders.add(p);
+ }
+ if (p != null) {
+ // if it wasn't uninstalled or something
+ loadedProviders.put(providerIndex, p);
+ }
+ providerIndex++;
+ }
+ else if ("h".equals(tag)) {
+ Host host = new Host();
+
+ // TODO: do we need to check that this package has the same signature
+ // as before?
+ host.packageName = parser.getAttributeValue(null, "pkg");
+ try {
+ host.uid = getUidForPackage(host.packageName);
+ } catch (PackageManager.NameNotFoundException ex) {
+ host.zombie = true;
+ }
+ if (!host.zombie || mSafeMode) {
+ // In safe mode, we don't discard the hosts we don't recognize
+ // so that they're not pruned from our list. Otherwise, we do.
+ host.hostId = Integer.parseInt(
+ parser.getAttributeValue(null, "id"), 16);
+ mHosts.add(host);
+ }
+ }
+ else if ("g".equals(tag)) {
+ AppWidgetId id = new AppWidgetId();
+ id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16);
+ if (id.appWidgetId >= mNextAppWidgetId) {
+ mNextAppWidgetId = id.appWidgetId + 1;
+ }
+
+ String providerString = parser.getAttributeValue(null, "p");
+ if (providerString != null) {
+ // there's no provider if it hasn't been bound yet.
+ // maybe we don't have to save this, but it brings the system
+ // to the state it was in.
+ int pIndex = Integer.parseInt(providerString, 16);
+ id.provider = loadedProviders.get(pIndex);
+ if (false) {
+ Log.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider "
+ + pIndex + " which is " + id.provider);
+ }
+ if (id.provider == null) {
+ // This provider is gone. We just let the host figure out
+ // that this happened when it fails to load it.
+ continue;
+ }
+ }
+
+ int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16);
+ id.host = mHosts.get(hIndex);
+ if (id.host == null) {
+ // This host is gone.
+ continue;
+ }
+
+ if (id.provider != null) {
+ id.provider.instances.add(id);
+ }
+ id.host.instances.add(id);
+ mAppWidgetIds.add(id);
+ }
+ }
+ } while (type != XmlPullParser.END_DOCUMENT);
+ success = true;
+ } catch (NullPointerException e) {
+ Log.w(TAG, "failed parsing " + file, e);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "failed parsing " + file, e);
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "failed parsing " + file, e);
+ } catch (IOException e) {
+ Log.w(TAG, "failed parsing " + file, e);
+ } catch (IndexOutOfBoundsException e) {
+ Log.w(TAG, "failed parsing " + file, e);
+ }
+ try {
+ if (stream != null) {
+ stream.close();
+ }
+ } catch (IOException e) {
+ }
+
+ if (success) {
+ // delete any hosts that didn't manage to get connected (should happen)
+ // if it matters, they'll be reconnected.
+ final int N = mHosts.size();
+ for (int i=0; i<N; i++) {
+ pruneHostLocked(mHosts.get(i));
+ }
+ } else {
+ // failed reading, clean up
+ mAppWidgetIds.clear();
+ mHosts.clear();
+ final int N = mInstalledProviders.size();
+ for (int i=0; i<N; i++) {
+ mInstalledProviders.get(i).instances.clear();
+ }
+ }
+ }
+
+ File savedStateTempFile() {
+ return new File("/data/system/" + SETTINGS_TMP_FILENAME);
+ //return new File(mContext.getFilesDir(), SETTINGS_FILENAME);
+ }
+
+ File savedStateRealFile() {
+ return new File("/data/system/" + SETTINGS_FILENAME);
+ //return new File(mContext.getFilesDir(), SETTINGS_TMP_FILENAME);
+ }
+
+ BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ //Log.d(TAG, "received " + action);
+ if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ sendInitialBroadcasts();
+ } else {
+ Uri uri = intent.getData();
+ if (uri == null) {
+ return;
+ }
+ String pkgName = uri.getSchemeSpecificPart();
+ if (pkgName == null) {
+ return;
+ }
+
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ synchronized (mAppWidgetIds) {
+ Bundle extras = intent.getExtras();
+ if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+ // The package was just upgraded
+ updateProvidersForPackageLocked(pkgName);
+ } else {
+ // The package was just added
+ addProvidersForPackageLocked(pkgName);
+ }
+ saveStateLocked();
+ }
+ }
+ else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ Bundle extras = intent.getExtras();
+ if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+ // The package is being updated. We'll receive a PACKAGE_ADDED shortly.
+ } else {
+ synchronized (mAppWidgetIds) {
+ removeProvidersForPackageLocked(pkgName);
+ saveStateLocked();
+ }
+ }
+ }
+ }
+ }
+ };
+
+ // TODO: If there's a better way of matching an intent filter against the
+ // packages for a given package, use that.
+ void addProvidersForPackageLocked(String pkgName) {
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
+ PackageManager.GET_META_DATA);
+
+ final int N = broadcastReceivers.size();
+ for (int i=0; i<N; i++) {
+ ResolveInfo ri = broadcastReceivers.get(i);
+ ActivityInfo ai = ri.activityInfo;
+
+ if (pkgName.equals(ai.packageName)) {
+ addProviderLocked(ri);
+ }
+ }
+ }
+
+ // TODO: If there's a better way of matching an intent filter against the
+ // packages for a given package, use that.
+ void updateProvidersForPackageLocked(String pkgName) {
+ HashSet<String> keep = new HashSet();
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
+ PackageManager.GET_META_DATA);
+
+ // add the missing ones and collect which ones to keep
+ int N = broadcastReceivers.size();
+ for (int i=0; i<N; i++) {
+ ResolveInfo ri = broadcastReceivers.get(i);
+ ActivityInfo ai = ri.activityInfo;
+ if (pkgName.equals(ai.packageName)) {
+ ComponentName component = new ComponentName(ai.packageName, ai.name);
+ Provider p = lookupProviderLocked(component);
+ if (p == null) {
+ if (addProviderLocked(ri)) {
+ keep.add(ai.name);
+ }
+ } else {
+ Provider parsed = parseProviderInfoXml(component, ri);
+ if (parsed != null) {
+ keep.add(ai.name);
+ // Use the new AppWidgetProviderInfo.
+ AppWidgetProviderInfo oldInfo = p.info;
+ p.info = parsed.info;
+ // If it's enabled
+ final int M = p.instances.size();
+ if (M > 0) {
+ int[] appWidgetIds = getAppWidgetIds(p);
+ // Reschedule for the new updatePeriodMillis (don't worry about handling
+ // it specially if updatePeriodMillis didn't change because we just sent
+ // an update, and the next one will be updatePeriodMillis from now).
+ cancelBroadcasts(p);
+ registerForBroadcastsLocked(p, appWidgetIds);
+ // If it's currently showing, call back with the new AppWidgetProviderInfo.
+ for (int j=0; j<M; j++) {
+ AppWidgetId id = p.instances.get(j);
+ if (id.host != null && id.host.callbacks != null) {
+ try {
+ id.host.callbacks.providerChanged(id.appWidgetId, p.info);
+ } catch (RemoteException ex) {
+ // It failed; remove the callback. No need to prune because
+ // we know that this host is still referenced by this
+ // instance.
+ id.host.callbacks = null;
+ }
+ }
+ }
+ // Now that we've told the host, push out an update.
+ sendUpdateIntentLocked(p, appWidgetIds);
+ }
+ }
+ }
+ }
+ }
+
+ // prune the ones we don't want to keep
+ N = mInstalledProviders.size();
+ for (int i=N-1; i>=0; i--) {
+ Provider p = mInstalledProviders.get(i);
+ if (pkgName.equals(p.info.provider.getPackageName())
+ && !keep.contains(p.info.provider.getClassName())) {
+ removeProviderLocked(i, p);
+ }
+ }
+ }
+
+ void removeProvidersForPackageLocked(String pkgName) {
+ int N = mInstalledProviders.size();
+ for (int i=N-1; i>=0; i--) {
+ Provider p = mInstalledProviders.get(i);
+ if (pkgName.equals(p.info.provider.getPackageName())) {
+ removeProviderLocked(i, p);
+ }
+ }
+
+ // Delete the hosts for this package too
+ //
+ // By now, we have removed any AppWidgets that were in any hosts here,
+ // so we don't need to worry about sending DISABLE broadcasts to them.
+ N = mHosts.size();
+ for (int i=N-1; i>=0; i--) {
+ Host host = mHosts.get(i);
+ if (pkgName.equals(host.packageName)) {
+ deleteHostLocked(host);
+ }
+ }
+ }
+}
+
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index ed53272..618b317 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -20,19 +20,31 @@ import com.android.internal.app.IBatteryStats;
import com.android.server.am.BatteryStatsService;
import android.app.ActivityManagerNative;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.BatteryManager;
import android.os.Binder;
+import android.os.Debug;
+import android.os.IBinder;
import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.UEventObserver;
+import android.provider.Checkin;
+import android.provider.Settings;
import android.util.EventLog;
import android.util.Log;
+import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.PrintWriter;
-import java.lang.String;
+
+
/**
* <p>BatteryService monitors the charging status, and charge level of the device
@@ -59,11 +71,27 @@ import java.lang.String;
class BatteryService extends Binder {
private static final String TAG = BatteryService.class.getSimpleName();
+ private static final boolean LOCAL_LOGV = false;
+
static final int LOG_BATTERY_LEVEL = 2722;
static final int LOG_BATTERY_STATUS = 2723;
+ static final int LOG_BATTERY_DISCHARGE_STATUS = 2730;
static final int BATTERY_SCALE = 100; // battery capacity is a percentage
+ // Used locally for determining when to make a last ditch effort to log
+ // discharge stats before the device dies.
+ private static final int CRITICAL_BATTERY_LEVEL = 4;
+
+ private static final int DUMP_MAX_LENGTH = 24 * 1024;
+ private static final String[] DUMPSYS_ARGS = new String[] { "-c", "-u" };
+ private static final String BATTERY_STATS_SERVICE_NAME = "batteryinfo";
+
+ private static final String DUMPSYS_DATA_PATH = "/data/system/";
+
+ // This should probably be exposed in the API, though it's not critical
+ private static final int BATTERY_PLUGGED_NONE = 0;
+
private final Context mContext;
private final IBatteryStats mBatteryStats;
@@ -76,6 +104,7 @@ class BatteryService extends Binder {
private int mBatteryVoltage;
private int mBatteryTemperature;
private String mBatteryTechnology;
+ private boolean mBatteryLevelCritical;
private int mLastBatteryStatus;
private int mLastBatteryHealth;
@@ -83,9 +112,14 @@ class BatteryService extends Binder {
private int mLastBatteryLevel;
private int mLastBatteryVoltage;
private int mLastBatteryTemperature;
+ private boolean mLastBatteryLevelCritical;
private int mPlugType;
- private int mLastPlugType;
+ private int mLastPlugType = -1; // Extra state so we can detect first run
+
+ private long mDischargeStartTime;
+ private int mDischargeStartLevel;
+
public BatteryService(Context context) {
mContext = context;
@@ -113,9 +147,10 @@ class BatteryService extends Binder {
}
int plugTypeBit = 0;
if (mAcOnline) {
- plugTypeBit = BatteryManager.BATTERY_PLUGGED_AC;
- } else if (mUsbOnline) {
- plugTypeBit = BatteryManager.BATTERY_PLUGGED_USB;
+ plugTypeBit |= BatteryManager.BATTERY_PLUGGED_AC;
+ }
+ if (mUsbOnline) {
+ plugTypeBit |= BatteryManager.BATTERY_PLUGGED_USB;
}
return (plugTypeSet & plugTypeBit) != 0;
}
@@ -140,12 +175,14 @@ class BatteryService extends Binder {
private synchronized final void update() {
native_update();
+
+ mBatteryLevelCritical = mBatteryLevel <= CRITICAL_BATTERY_LEVEL;
if (mAcOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
} else if (mUsbOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
} else {
- mPlugType = 0;
+ mPlugType = BATTERY_PLUGGED_NONE;
}
if (mBatteryStatus != mLastBatteryStatus ||
mBatteryHealth != mLastBatteryHealth ||
@@ -155,6 +192,27 @@ class BatteryService extends Binder {
mBatteryVoltage != mLastBatteryVoltage ||
mBatteryTemperature != mLastBatteryTemperature) {
+ if (mPlugType != mLastPlugType) {
+ if (mLastPlugType == BATTERY_PLUGGED_NONE) {
+ // discharging -> charging
+
+ // 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,
+ 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
+ mDischargeStartTime = SystemClock.elapsedRealtime();
+ mDischargeStartLevel = mBatteryLevel;
+ }
+ }
if (mBatteryStatus != mLastBatteryStatus ||
mBatteryHealth != mLastBatteryHealth ||
mBatteryPresent != mLastBatteryPresent ||
@@ -169,6 +227,12 @@ class BatteryService extends Binder {
EventLog.writeEvent(LOG_BATTERY_LEVEL,
mBatteryLevel, mBatteryVoltage, mBatteryTemperature);
}
+ if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
+ 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);
+ }
// Separate broadcast is sent for power connected / not connected
// since the standard intent will not wake any applications and some
@@ -187,6 +251,7 @@ class BatteryService extends Binder {
mLastPlugType = mPlugType;
mLastBatteryVoltage = mBatteryVoltage;
mLastBatteryTemperature = mBatteryTemperature;
+ mLastBatteryLevelCritical = mBatteryLevelCritical;
sendIntent();
}
@@ -197,7 +262,7 @@ class BatteryService extends Binder {
Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
try {
- mBatteryStats.setOnBattery(mPlugType == 0);
+ mBatteryStats.setOnBattery(mPlugType == BATTERY_PLUGGED_NONE);
} catch (RemoteException e) {
// Should never happen.
}
@@ -229,6 +294,83 @@ class BatteryService extends Binder {
ActivityManagerNative.broadcastStickyIntent(intent, null);
}
+ private final void logBatteryStats() {
+
+ IBinder batteryInfoService = ServiceManager.getService(BATTERY_STATS_SERVICE_NAME);
+ if (batteryInfoService != null) {
+ byte[] buffer = new byte[DUMP_MAX_LENGTH];
+ File dumpFile = null;
+ FileOutputStream dumpStream = null;
+ try {
+ // dump the service to a file
+ dumpFile = new File(DUMPSYS_DATA_PATH + BATTERY_STATS_SERVICE_NAME + ".dump");
+ dumpStream = new FileOutputStream(dumpFile);
+ batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
+ dumpStream.getFD().sync();
+
+ // read dumped file above into buffer truncated to DUMP_MAX_LENGTH
+ // and insert into events table.
+ int length = (int) Math.min(dumpFile.length(), DUMP_MAX_LENGTH);
+ FileInputStream fileInputStream = new FileInputStream(dumpFile);
+ int nread = fileInputStream.read(buffer, 0, length);
+ if (nread > 0) {
+ Checkin.logEvent(mContext.getContentResolver(),
+ Checkin.Events.Tag.BATTERY_DISCHARGE_INFO,
+ new String(buffer, 0, nread));
+ if (LOCAL_LOGV) Log.v(TAG, "dumped " + nread + "b from " +
+ batteryInfoService + "to log");
+ if (LOCAL_LOGV) Log.v(TAG, "actual dump:" + new String(buffer, 0, nread));
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to dump service '" + BATTERY_STATS_SERVICE_NAME +
+ "':" + e);
+ } catch (IOException e) {
+ Log.e(TAG, "failed to write dumpsys file: " + e);
+ } finally {
+ // make sure we clean up
+ if (dumpStream != null) {
+ try {
+ dumpStream.close();
+ } catch (IOException e) {
+ Log.e(TAG, "failed to close dumpsys output stream");
+ }
+ }
+ if (dumpFile != null && !dumpFile.delete()) {
+ Log.e(TAG, "failed to delete temporary dumpsys file: "
+ + dumpFile.getAbsolutePath());
+ }
+ }
+ }
+ }
+
+ private final void logOutlier(long duration) {
+ ContentResolver cr = mContext.getContentResolver();
+ String dischargeThresholdString = Settings.Gservices.getString(cr,
+ Settings.Gservices.BATTERY_DISCHARGE_THRESHOLD);
+ String durationThresholdString = Settings.Gservices.getString(cr,
+ Settings.Gservices.BATTERY_DISCHARGE_DURATION_THRESHOLD);
+
+ if (dischargeThresholdString != null && durationThresholdString != null) {
+ try {
+ long durationThreshold = Long.parseLong(durationThresholdString);
+ int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
+ if (duration <= durationThreshold &&
+ mDischargeStartLevel - mBatteryLevel >= dischargeThreshold) {
+ // If the discharge cycle is bad enough we want to know about it.
+ logBatteryStats();
+ }
+ if (LOCAL_LOGV) Log.v(TAG, "duration threshold: " + durationThreshold +
+ " discharge threshold: " + dischargeThreshold);
+ if (LOCAL_LOGV) Log.v(TAG, "duration: " + duration + " discharge: " +
+ (mDischargeStartLevel - mBatteryLevel));
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Invalid DischargeThresholds GService string: " +
+ durationThresholdString + " or " + dischargeThresholdString);
+ return;
+ }
+ }
+ }
+
private final int getIcon(int level) {
if (mBatteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
return com.android.internal.R.drawable.stat_sys_battery_charge;
@@ -243,7 +385,7 @@ class BatteryService extends Binder {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingPermission("android.permission.DUMP")
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump Battery service from from pid="
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 65e3650..760988d 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -35,6 +35,7 @@ import android.os.Message;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.provider.Sync;
import android.util.EventLog;
import android.util.Log;
@@ -333,6 +334,32 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
+ /**
+ * @see ConnectivityManager#getBackgroundDataSetting()
+ */
+ public boolean getBackgroundDataSetting() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.BACKGROUND_DATA, 1) == 1;
+ }
+
+ /**
+ * @see ConnectivityManager#setBackgroundDataSetting(boolean)
+ */
+ public void setBackgroundDataSetting(boolean allowBackgroundDataUsage) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
+ "ConnectivityService");
+
+ if (getBackgroundDataSetting() == allowBackgroundDataUsage) return;
+
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.BACKGROUND_DATA, allowBackgroundDataUsage ? 1 : 0);
+
+ Intent broadcast = new Intent(
+ ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
+ mContext.sendBroadcast(broadcast);
+ }
+
private int getNumConnectedNetworks() {
int numConnectedNets = 0;
@@ -632,7 +659,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingPermission(android.Manifest.permission.DUMP)
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump ConnectivityService from from pid="
+ Binder.getCallingPid()
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java
index 44f70f0..85861bb 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/DeviceStorageMonitorService.java
@@ -67,6 +67,7 @@ class DeviceStorageMonitorService extends Binder {
private static final int EVENT_LOG_LOW_STORAGE_NOTIFICATION = 2745;
private static final int EVENT_LOG_FREE_STORAGE_LEFT = 2746;
private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB
+ private static final long DEFAULT_CHECK_INTERVAL = MONITOR_INTERVAL*60*1000;
private long mFreeMem;
private long mLastReportedFreeMem;
private long mLastReportedFreeMemTime;
@@ -82,6 +83,9 @@ class DeviceStorageMonitorService extends Binder {
boolean mClearingCache;
private Intent mStorageLowIntent;
private Intent mStorageOkIntent;
+ private CachePackageDataObserver mClearCacheObserver;
+ private static final int _TRUE = 1;
+ private static final int _FALSE = 0;
/**
* This string is used for ServiceManager access to this class.
@@ -100,7 +104,7 @@ class DeviceStorageMonitorService extends Binder {
Log.e(TAG, "Will not process invalid message");
return;
}
- checkMemory();
+ checkMemory(msg.arg1 == _TRUE);
}
};
@@ -109,7 +113,8 @@ class DeviceStorageMonitorService extends Binder {
mClearSucceeded = succeeded;
mClearingCache = false;
if(localLOGV) Log.i(TAG, " Clear succeeded:"+mClearSucceeded
- +", mClearingCache:"+mClearingCache);
+ +", mClearingCache:"+mClearingCache+" Forcing memory check");
+ postCheckMemoryMsg(false, 0);
}
}
@@ -145,11 +150,15 @@ class DeviceStorageMonitorService extends Binder {
}
private final void clearCache() {
- CachePackageDataObserver observer = new CachePackageDataObserver();
+ if (mClearCacheObserver == null) {
+ // Lazy instantiation
+ mClearCacheObserver = new CachePackageDataObserver();
+ }
mClearingCache = true;
try {
+ if (localLOGV) Log.i(TAG, "Clearing cache");
IPackageManager.Stub.asInterface(ServiceManager.getService("package")).
- freeStorageAndNotify(getMemThreshold(), observer);
+ freeStorageAndNotify(getMemThreshold(), mClearCacheObserver);
} catch (RemoteException e) {
Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
mClearingCache = false;
@@ -157,7 +166,7 @@ class DeviceStorageMonitorService extends Binder {
}
}
- private final void checkMemory() {
+ private final void checkMemory(boolean checkCache) {
//if the thread that was started to clear cache is still running do nothing till its
//finished clearing cache. Ideally this flag could be modified by clearCache
// and should be accessed via a lock but even if it does this test will fail now and
@@ -172,16 +181,23 @@ class DeviceStorageMonitorService extends Binder {
} else {
restatDataDir();
if (localLOGV) Log.v(TAG, "freeMemory="+mFreeMem);
+
//post intent to NotificationManager to display icon if necessary
long memThreshold = getMemThreshold();
if (mFreeMem < memThreshold) {
if (!mLowMemFlag) {
- //see if clearing cache helps
- mThreadStartTime = System.currentTimeMillis();
- clearCache();
- Log.i(TAG, "Running low on memory. Sending notification");
- sendNotification();
- mLowMemFlag = true;
+ if (checkCache) {
+ // See if clearing cache helps
+ // Note that clearing cache is asynchronous and so we do a
+ // memory check again once the cache has been cleared.
+ mThreadStartTime = System.currentTimeMillis();
+ mClearSucceeded = false;
+ clearCache();
+ } else {
+ Log.i(TAG, "Running low on memory. Sending notification");
+ sendNotification();
+ mLowMemFlag = true;
+ }
} else {
if (localLOGV) Log.v(TAG, "Running low on memory " +
"notification already sent. do nothing");
@@ -196,8 +212,15 @@ class DeviceStorageMonitorService extends Binder {
}
if(localLOGV) Log.i(TAG, "Posting Message again");
//keep posting messages to itself periodically
- mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT),
- MONITOR_INTERVAL*60*1000);
+ postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL);
+ }
+
+ private void postCheckMemoryMsg(boolean clearCache, long delay) {
+ // Remove queued messages
+ mHandler.removeMessages(DEVICE_MEMORY_WHAT);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT,
+ clearCache ?_TRUE : _FALSE, 0),
+ delay);
}
/*
@@ -231,7 +254,7 @@ class DeviceStorageMonitorService extends Binder {
mTotalMemory = (mFileStats.getBlockCount()*mBlkSize)/100;
mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW);
mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK);
- checkMemory();
+ checkMemory(true);
}
@@ -281,14 +304,11 @@ class DeviceStorageMonitorService extends Binder {
}
public void updateMemory() {
- ActivityManagerService ams = (ActivityManagerService)ServiceManager.getService("activity");
int callingUid = getCallingUid();
if(callingUid != Process.SYSTEM_UID) {
return;
}
- //remove queued messages
- mHandler.removeMessages(DEVICE_MEMORY_WHAT);
- //force an early check
- checkMemory();
+ // force an early check
+ postCheckMemoryMsg(true, 0);
}
}
diff --git a/services/java/com/android/server/FallbackCheckinService.java b/services/java/com/android/server/FallbackCheckinService.java
new file mode 100644
index 0000000..cf22446
--- /dev/null
+++ b/services/java/com/android/server/FallbackCheckinService.java
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.ICheckinService;
+import android.os.IParentalControlCallback;
+import android.util.Log;
+
+import java.io.IOException;
+
+import com.android.internal.os.RecoverySystem;
+import com.google.android.net.ParentalControlState;
+
+/**
+ * @hide
+ */
+public final class FallbackCheckinService extends ICheckinService.Stub {
+ static final String TAG = "FallbackCheckinService";
+ final Context mContext;
+
+ public FallbackCheckinService(Context context) {
+ mContext = context;
+ }
+
+ public boolean checkin() {
+ return false; // failure, because not implemented
+ }
+
+ public void reportCrashSync(byte[] crashData) {
+ }
+
+ public void reportCrashAsync(byte[] crashData) {
+ }
+
+ public void masterClear() {
+ if (mContext.checkCallingOrSelfPermission("android.permission.MASTER_CLEAR") !=
+ PackageManager.PERMISSION_GRANTED) {
+ Log.e(TAG, "Permission Denial: can't invoke masterClear from "
+ + "pid=" + Binder.getCallingPid() + ", "
+ + "uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ // Save the android ID so the new system can get it erased.
+ try {
+ RecoverySystem.rebootAndWipe();
+ } catch (IOException e) {
+ Log.e(TAG, "Reboot for masterClear() failed", e);
+ }
+ }
+
+ public void getParentalControlState(IParentalControlCallback p, String requestingApp)
+ throws android.os.RemoteException {
+ ParentalControlState state = new ParentalControlState();
+ state.isEnabled = false;
+ p.onResult(state);
+ }
+}
diff --git a/services/java/com/android/server/GadgetService.java b/services/java/com/android/server/GadgetService.java
deleted file mode 100644
index 4be9ed5..0000000
--- a/services/java/com/android/server/GadgetService.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2007 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;
-
-import android.content.ComponentName;
-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.content.pm.PackageItemInfo;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.gadget.GadgetManager;
-import android.gadget.GadgetInfo;
-import android.os.Binder;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Xml;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.android.internal.gadget.IGadgetService;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-class GadgetService extends IGadgetService.Stub
-{
- private static final String TAG = "GadgetService";
-
- static class GadgetId {
- int gadgetId;
- String hostPackage;
- GadgetInfo info;
- }
-
- Context mContext;
- PackageManager mPackageManager;
- ArrayList<GadgetInfo> mInstalledProviders;
- int mNextGadgetId = 1;
- ArrayList<GadgetId> mGadgetIds = new ArrayList();
-
- GadgetService(Context context) {
- mContext = context;
- mPackageManager = context.getPackageManager();
- mInstalledProviders = getGadgetList();
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
- synchronized (mGadgetIds) {
- int N = mInstalledProviders.size();
- pw.println("Providers: (size=" + N + ")");
- for (int i=0; i<N; i++) {
- GadgetInfo info = mInstalledProviders.get(i);
- pw.println(" [" + i + "] provder=" + info.provider
- + " min=(" + info.minWidth + "x" + info.minHeight + ")"
- + " updatePeriodMillis=" + info.updatePeriodMillis
- + " initialLayout=" + info.initialLayout);
- }
-
- N = mGadgetIds.size();
- pw.println("GadgetIds: (size=" + N + ")");
- for (int i=0; i<N; i++) {
- GadgetId id = mGadgetIds.get(i);
- pw.println(" [" + i + "] gadgetId=" + id.gadgetId + " host=" + id.hostPackage
- + " provider=" + (id.info == null ? "null" : id.info.provider));
- }
- }
- }
-
- public int allocateGadgetId(String hostPackage) {
- synchronized (mGadgetIds) {
- // TODO: Check for pick permission
- int gadgetId = mNextGadgetId++;
-
- GadgetId id = new GadgetId();
- id.gadgetId = gadgetId;
- id.hostPackage = hostPackage;
-
- mGadgetIds.add(id);
-
- return gadgetId;
- }
- }
-
- public void deleteGadgetId(int gadgetId) {
- synchronized (mGadgetIds) {
- String callingPackage = getCallingPackage();
- final int N = mGadgetIds.size();
- for (int i=0; i<N; i++) {
- GadgetId id = mGadgetIds.get(i);
- if (canAccessGadgetId(id, callingPackage)) {
- mGadgetIds.remove(i);
- // TODO: Notify someone?
- return;
- }
- }
- }
- }
-
- public void bindGadgetId(int gadgetId, ComponentName provider) {
- synchronized (mGadgetIds) {
- GadgetId id = lookupGadgetIdLocked(gadgetId);
- if (id == null) {
- throw new IllegalArgumentException("bad gadgetId"); // TODO: use a better exception
- }
- if (id.info != null) {
- throw new IllegalArgumentException("gadgetId " + gadgetId + " already bound to "
- + id.info.provider);
- }
- GadgetInfo info = lookupGadgetInfoLocked(provider);
- if (info == null) {
- throw new IllegalArgumentException("not a gadget provider: " + provider);
- }
-
- id.info = info;
- }
- }
-
- public GadgetInfo getGadgetInfo(int gadgetId) {
- synchronized (mGadgetIds) {
- GadgetId id = lookupGadgetIdLocked(gadgetId);
- if (id != null) {
- return id.info;
- }
- return null;
- }
- }
-
- public List<GadgetInfo> getInstalledProviders() {
- synchronized (mGadgetIds) {
- return new ArrayList<GadgetInfo>(mInstalledProviders);
- }
- }
-
- boolean canAccessGadgetId(GadgetId id, String callingPackage) {
- if (id.hostPackage.equals(callingPackage)) {
- return true;
- }
- if (id.info != null && id.info.provider.getPackageName().equals(callingPackage)) {
- return true;
- }
- // TODO: Check for the pick permission
- //if (has permission) {
- // return true;
- //}
- //return false;
- return true;
- }
-
- private GadgetId lookupGadgetIdLocked(int gadgetId) {
- String callingPackage = getCallingPackage();
- final int N = mGadgetIds.size();
- for (int i=0; i<N; i++) {
- GadgetId id = mGadgetIds.get(i);
- if (canAccessGadgetId(id, callingPackage)) {
- return id;
- }
- }
- return null;
- }
-
- GadgetInfo lookupGadgetInfoLocked(ComponentName provider) {
- final int N = mInstalledProviders.size();
- for (int i=0; i<N; i++) {
- GadgetInfo info = mInstalledProviders.get(i);
- if (info.provider.equals(provider)) {
- return info;
- }
- }
- return null;
- }
-
- ArrayList<GadgetInfo> getGadgetList() {
- PackageManager pm = mPackageManager;
-
- // TODO: We have these as different actions. I wonder if it makes more sense to
- // have like a GADGET_ACTION, and then subcommands. It's kind of arbitrary that
- // we look for GADGET_UPDATE_ACTION and not any of the other gadget actions.
- Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION);
- List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
- PackageManager.GET_META_DATA);
-
- ArrayList<GadgetInfo> result = new ArrayList<GadgetInfo>();
-
- final int N = broadcastReceivers.size();
- for (int i=0; i<N; i++) {
- ResolveInfo ri = broadcastReceivers.get(i);
- ActivityInfo ai = ri.activityInfo;
- GadgetInfo gi = parseGadgetInfoXml(new ComponentName(ai.packageName, ai.name),
- ri.activityInfo);
- if (gi != null) {
- result.add(gi);
- }
- }
-
- return result;
- }
-
- private GadgetInfo parseGadgetInfoXml(ComponentName component,
- PackageItemInfo packageItemInfo) {
- GadgetInfo gi = null;
-
- XmlResourceParser parser = null;
- try {
- parser = packageItemInfo.loadXmlMetaData(mPackageManager,
- GadgetManager.GADGET_PROVIDER_META_DATA);
- if (parser == null) {
- Log.w(TAG, "No " + GadgetManager.GADGET_PROVIDER_META_DATA + " meta-data for "
- + "gadget provider '" + component + '\'');
- return null;
- }
-
- AttributeSet attrs = Xml.asAttributeSet(parser);
-
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && type != XmlPullParser.START_TAG) {
- // drain whitespace, comments, etc.
- }
-
- String nodeName = parser.getName();
- if (!"gadget-provider".equals(nodeName)) {
- Log.w(TAG, "Meta-data does not start with gadget-provider tag for"
- + " gadget provider '" + component + '\'');
- return null;
- }
-
- gi = new GadgetInfo();
-
- gi.provider = component;
-
- TypedArray sa = mContext.getResources().obtainAttributes(attrs,
- com.android.internal.R.styleable.GadgetProviderInfo);
- gi.minWidth = sa.getDimensionPixelSize(
- com.android.internal.R.styleable.GadgetProviderInfo_minWidth, 0);
- gi.minHeight = sa.getDimensionPixelSize(
- com.android.internal.R.styleable.GadgetProviderInfo_minHeight, 0);
- gi.updatePeriodMillis = sa.getInt(
- com.android.internal.R.styleable.GadgetProviderInfo_updatePeriodMillis, 0);
- gi.initialLayout = sa.getResourceId(
- com.android.internal.R.styleable.GadgetProviderInfo_initialLayout, 0);
- sa.recycle();
- } catch (Exception e) {
- // Ok to catch Exception here, because anything going wrong because
- // of what a client process passes to us should not be fatal for the
- // system process.
- Log.w(TAG, "XML parsing failed for gadget provider '" + component + '\'', e);
- } finally {
- if (parser != null) parser.close();
- }
- return gi;
- }
-
- void sendEnabled(ComponentName provider) {
- Intent intent = new Intent(GadgetManager.GADGET_ENABLE_ACTION);
- intent.setComponent(provider);
- mContext.sendBroadcast(intent);
- }
-
- String getCallingPackage() {
- return mPackageManager.getNameForUid(getCallingUid());
- }
-}
-
diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java
index 22ad7bd..2131ffd 100755
--- a/services/java/com/android/server/HardwareService.java
+++ b/services/java/com/android/server/HardwareService.java
@@ -25,6 +25,7 @@ import android.os.Hardware;
import android.os.IHardwareService;
import android.os.Power;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Binder;
@@ -35,6 +36,10 @@ public class HardwareService extends IHardwareService.Stub {
private static final String TAG = "HardwareService";
HardwareService(Context context) {
+ // Reset the hardware to a default state, in case this is a runtime
+ // restart instead of a fresh boot.
+ vibratorOff();
+
mContext = context;
PowerManager pm = (PowerManager)context.getSystemService(
Context.POWER_SERVICE);
@@ -201,7 +206,7 @@ public class HardwareService extends IHardwareService.Stub {
mThread.notify();
}
mThread = null;
- off();
+ vibratorOff();
}
}
}
@@ -217,49 +222,66 @@ public class HardwareService extends IHardwareService.Stub {
mWakeLock.acquire();
}
+ private void delay(long duration) {
+ if (duration > 0) {
+ long bedtime = SystemClock.uptimeMillis();
+ do {
+ try {
+ this.wait(duration);
+ }
+ catch (InterruptedException e) {
+ }
+ if (mDone) {
+ break;
+ }
+ duration = duration
+ - SystemClock.uptimeMillis() - bedtime;
+ } while (duration > 0);
+ }
+ }
+
public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
synchronized (this) {
int index = 0;
- boolean nextState = false;
long[] pattern = mPattern;
- if (pattern[0] == 0) {
- index++;
- nextState = true;
- }
int len = pattern.length;
- long start = SystemClock.uptimeMillis();
+ long duration = 0;
while (!mDone) {
- if (nextState) {
- HardwareService.this.on();
- } else {
- HardwareService.this.off();
+ // add off-time duration to any accumulated on-time duration
+ if (index < len) {
+ duration += pattern[index++];
}
- nextState = !nextState;
- long bedtime = SystemClock.uptimeMillis();
- long duration = pattern[index];
- do {
- try {
- this.wait(duration);
- }
- catch (InterruptedException e) {
- }
- if (mDone) {
- break;
+
+ // sleep until it is time to start the vibrator
+ delay(duration);
+ if (mDone) {
+ break;
+ }
+
+ if (index < len) {
+ // read on-time duration and start the vibrator
+ // duration is saved for delay() at top of loop
+ duration = pattern[index++];
+ if (duration > 0) {
+ HardwareService.this.vibratorOn(duration);
}
- duration = duration
- - SystemClock.uptimeMillis() - bedtime;
- } while (duration > 0);
- index++;
- if (index >= len) {
+ } else {
if (mRepeat < 0) {
- HardwareService.this.off();
break;
} else {
index = mRepeat;
+ duration = 0;
}
}
}
+ if (mDone) {
+ // make sure vibrator is off if we were cancelled.
+ // otherwise, it will turn off automatically
+ // when the last timeout expires.
+ HardwareService.this.vibratorOff();
+ }
mWakeLock.release();
}
synchronized (HardwareService.this) {
@@ -301,6 +323,6 @@ public class HardwareService extends IHardwareService.Stub {
volatile Death mDeath;
volatile IBinder mToken;
- native static void on();
- native static void off();
+ 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 2bea731..855734d 100644
--- a/services/java/com/android/server/HeadsetObserver.java
+++ b/services/java/com/android/server/HeadsetObserver.java
@@ -19,6 +19,8 @@ package com.android.server;
import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
import android.os.UEventObserver;
import android.util.Log;
import android.media.AudioManager;
@@ -40,6 +42,8 @@ class HeadsetObserver extends UEventObserver {
private int mHeadsetState;
private String mHeadsetName;
+ private boolean mAudioRouteNeedsUpdate;
+ private AudioManager mAudioManager;
public HeadsetObserver(Context context) {
mContext = context;
@@ -60,7 +64,7 @@ class HeadsetObserver extends UEventObserver {
}
}
- private final void init() {
+ private synchronized final void init() {
char[] buffer = new char[1024];
String newName = mHeadsetName;
@@ -80,21 +84,33 @@ class HeadsetObserver extends UEventObserver {
Log.e(TAG, "" , e);
}
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
update(newName, newState);
}
private synchronized final void update(String newName, int newState) {
if (newName != mHeadsetName || newState != mHeadsetState) {
+ boolean isUnplug = (newState == 0 && mHeadsetState == 1);
mHeadsetName = newName;
mHeadsetState = newState;
- AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-
- audioManager.setWiredHeadsetOn(mHeadsetState == 1);
- sendIntent();
+ mAudioRouteNeedsUpdate = true;
+
+ 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.
+ // This could be improved once the audio sub-system provides an
+ // interface to clear the audio pipeline.
+ mHandler.sendEmptyMessageDelayed(0, 400);
+ } else {
+ updateAudioRoute();
+ }
}
}
- private synchronized final void sendIntent() {
+ private synchronized final void sendIntent(boolean isUnplug) {
// Pack up the values and broadcast them to everyone
Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -104,5 +120,25 @@ class HeadsetObserver extends UEventObserver {
// TODO: Should we require a permission?
ActivityManagerNative.broadcastStickyIntent(intent, null);
+
+ if (isUnplug) {
+ intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
+ }
}
+
+ private synchronized final void updateAudioRoute() {
+ if (mAudioRouteNeedsUpdate) {
+ mAudioManager.setWiredHeadsetOn(mHeadsetState == 1);
+ mAudioRouteNeedsUpdate = false;
+ }
+ }
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ updateAudioRoute();
+ }
+ };
+
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 139aaa3..9948322 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -30,6 +30,7 @@ import com.android.server.status.StatusBarService;
import org.xmlpull.v1.XmlPullParserException;
+import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -53,15 +54,17 @@ import android.os.IInterface;
import android.os.Message;
import android.os.Parcel;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.EventLog;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.view.IWindowManager;
import android.view.WindowManager;
-import android.view.inputmethod.DefaultInputMethod;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodInfo;
@@ -98,6 +101,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
static final int MSG_UNBIND_METHOD = 3000;
static final int MSG_BIND_METHOD = 3010;
+ static final long TIME_TO_RECONNECT = 10*1000;
+
+ static final int LOG_IMF_FORCE_RECONNECT_IME = 32000;
+
final Context mContext;
final Handler mHandler;
final SettingsObserver mSettingsObserver;
@@ -189,6 +196,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
ClientState mCurClient;
/**
+ * The last window token that gained focus.
+ */
+ IBinder mCurFocusedWindow;
+
+ /**
+ * The input context last provided by the current client.
+ */
+ IInputContext mCurInputContext;
+
+ /**
* The attributes last provided by the current client.
*/
EditorInfo mCurAttribute;
@@ -216,6 +233,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
boolean mShowExplicitlyRequested;
/**
+ * Set if we were forced to be shown.
+ */
+ boolean mShowForced;
+
+ /**
* Set if we last told the input method to show itself.
*/
boolean mInputShown;
@@ -238,6 +260,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
IInputMethod mCurMethod;
/**
+ * Time that we last initiated a bind to the input method, to determine
+ * if we should try to disconnect and reconnect to it.
+ */
+ long mLastBindTime;
+
+ /**
* Have we called mCurMethod.bindInput()?
*/
boolean mBoundToMethod;
@@ -281,7 +309,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
mScreenOn = false;
} else {
- Log.e(TAG, "Unexpected intent " + intent);
+ Log.w(TAG, "Unexpected intent " + intent);
}
// Inform the current client of the change in active status
@@ -290,7 +318,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurClient.client.setActive(mScreenOn);
}
} catch (RemoteException e) {
- Log.e(TAG, "Got RemoteException sending 'screen on/off' notification", e);
+ Log.w(TAG, "Got RemoteException sending 'screen on/off' notification to pid "
+ + mCurClient.pid + " uid " + mCurClient.uid);
}
}
}
@@ -475,7 +504,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
public void systemReady() {
-
}
public List<InputMethodInfo> getInputMethodList() {
@@ -534,7 +562,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- void unbindCurrentInputLocked() {
+ void unbindCurrentClientLocked() {
if (mCurClient != null) {
if (DEBUG) Log.v(TAG, "unbindCurrentInputLocked: client = "
+ mCurClient.client.asBinder());
@@ -553,12 +581,34 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
mCurClient.client.setActive(false);
} catch (RemoteException e) {
- Log.e(TAG, "Got RemoteException sending setActive(false) notification", e);
+ Log.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
+ + mCurClient.pid + " uid " + mCurClient.uid);
}
mCurClient = null;
}
}
+ private int getImeShowFlags() {
+ int flags = 0;
+ if (mShowForced) {
+ flags |= InputMethod.SHOW_FORCED
+ | InputMethod.SHOW_EXPLICIT;
+ } else if (mShowExplicitlyRequested) {
+ flags |= InputMethod.SHOW_EXPLICIT;
+ }
+ return flags;
+ }
+
+ private int getAppShowFlags() {
+ int flags = 0;
+ if (mShowForced) {
+ flags |= InputMethodManager.SHOW_FORCED;
+ } else if (!mShowExplicitlyRequested) {
+ flags |= InputMethodManager.SHOW_IMPLICIT;
+ }
+ return flags;
+ }
+
InputBindResult attachNewInputLocked(boolean initial, boolean needResult) {
if (!mBoundToMethod) {
executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
@@ -567,16 +617,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
final SessionState session = mCurClient.curSession;
if (initial) {
- executeOrSendMessage(session.method, mCaller.obtainMessageOO(
- MSG_START_INPUT, session, mCurAttribute));
+ executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
+ MSG_START_INPUT, session, mCurInputContext, mCurAttribute));
} else {
- executeOrSendMessage(session.method, mCaller.obtainMessageOO(
- MSG_RESTART_INPUT, session, mCurAttribute));
+ executeOrSendMessage(session.method, mCaller.obtainMessageOOO(
+ MSG_RESTART_INPUT, session, mCurInputContext, mCurAttribute));
}
if (mShowRequested) {
if (DEBUG) Log.v(TAG, "Attach new input asks to show input");
- showCurrentInputLocked(mShowExplicitlyRequested
- ? 0 : InputMethodManager.SHOW_IMPLICIT);
+ showCurrentInputLocked(getAppShowFlags(), null);
}
return needResult
? new InputBindResult(session.session, mCurId, mCurSeq)
@@ -584,7 +633,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
InputBindResult startInputLocked(IInputMethodClient client,
- EditorInfo attribute, boolean initial, boolean needResult) {
+ IInputContext inputContext, EditorInfo attribute,
+ boolean initial, boolean needResult) {
// If no method is currently selected, do nothing.
if (mCurMethodId == null) {
return mNoBinding;
@@ -613,7 +663,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (mCurClient != cs) {
// If the client is changing, we need to switch over to the new
// one.
- unbindCurrentInputLocked();
+ unbindCurrentClientLocked();
if (DEBUG) Log.v(TAG, "switching to client: client = "
+ cs.client.asBinder());
@@ -622,7 +672,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
cs.client.setActive(mScreenOn);
} catch (RemoteException e) {
- Log.e(TAG, "Got RemoteException sending setActive notification", e);
+ Log.w(TAG, "Got RemoteException sending setActive notification to pid "
+ + cs.pid + " uid " + cs.uid);
}
}
}
@@ -631,6 +682,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurSeq++;
if (mCurSeq <= 0) mCurSeq = 1;
mCurClient = cs;
+ mCurInputContext = inputContext;
mCurAttribute = attribute;
// Check if the input method is changing.
@@ -641,14 +693,31 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return attachNewInputLocked(initial, needResult);
}
if (mHaveConnection) {
- if (mCurMethod != null && !cs.sessionRequested) {
- cs.sessionRequested = true;
- if (DEBUG) Log.v(TAG, "Creating new session for client " + cs);
- executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
- MSG_CREATE_SESSION, mCurMethod,
- new MethodCallback(mCurMethod)));
+ if (mCurMethod != null) {
+ if (!cs.sessionRequested) {
+ cs.sessionRequested = true;
+ if (DEBUG) Log.v(TAG, "Creating new session for client " + cs);
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
+ MSG_CREATE_SESSION, mCurMethod,
+ new MethodCallback(mCurMethod)));
+ }
+ // Return to client, and we will get back with it when
+ // we have had a session made for it.
+ return new InputBindResult(null, mCurId, mCurSeq);
+ } else if (SystemClock.uptimeMillis()
+ < (mLastBindTime+TIME_TO_RECONNECT)) {
+ // In this case we have connected to the service, but
+ // don't yet have its interface. If it hasn't been too
+ // long since we did the connection, we'll return to
+ // the client and wait to get the service interface so
+ // we can report back. If it has been too long, we want
+ // to fall through so we can try a disconnect/reconnect
+ // to see if we can get back in touch with the service.
+ return new InputBindResult(null, mCurId, mCurSeq);
+ } else {
+ EventLog.writeEvent(LOG_IMF_FORCE_RECONNECT_IME, mCurMethodId,
+ SystemClock.uptimeMillis()-mLastBindTime, 0);
}
- return new InputBindResult(null, mCurId, mCurSeq);
}
}
@@ -657,28 +726,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
}
- if (mCurToken != null) {
- try {
- mIWindowManager.removeWindowToken(mCurToken);
- } catch (RemoteException e) {
- }
- mCurToken = null;
- }
-
- if (mHaveConnection) {
- mContext.unbindService(this);
- mHaveConnection = false;
- }
-
- clearCurMethod();
+ unbindCurrentMethodLocked(false);
mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
mCurIntent.setComponent(info.getComponent());
if (mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE)) {
+ mLastBindTime = SystemClock.uptimeMillis();
mHaveConnection = true;
mCurId = info.getId();
mCurToken = new Binder();
try {
+ if (DEBUG) Log.v(TAG, "Adding window token: " + mCurToken);
mIWindowManager.addWindowToken(mCurToken,
WindowManager.LayoutParams.TYPE_INPUT_METHOD);
} catch (RemoteException e) {
@@ -686,18 +744,20 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return new InputBindResult(null, mCurId, mCurSeq);
} else {
mCurIntent = null;
- Log.e(TAG, "Failure connecting to input method service: "
+ Log.w(TAG, "Failure connecting to input method service: "
+ mCurIntent);
}
return null;
}
public InputBindResult startInput(IInputMethodClient client,
- EditorInfo attribute, boolean initial, boolean needResult) {
+ IInputContext inputContext, EditorInfo attribute,
+ boolean initial, boolean needResult) {
synchronized (mMethodMap) {
final long ident = Binder.clearCallingIdentity();
try {
- return startInputLocked(client, attribute, initial, needResult);
+ return startInputLocked(client, inputContext, attribute,
+ initial, needResult);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -712,6 +772,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
mCurMethod = IInputMethod.Stub.asInterface(service);
if (mCurClient != null) {
+ if (DEBUG) Log.v(TAG, "Initiating attach with token: " + mCurToken);
executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
MSG_ATTACH_TOKEN, mCurMethod, mCurToken));
if (mCurClient != null) {
@@ -728,7 +789,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
void onSessionCreated(IInputMethod method, IInputMethodSession session) {
synchronized (mMethodMap) {
- if (mCurMethod == method) {
+ if (mCurMethod != null && method != null
+ && mCurMethod.asBinder() == method.asBinder()) {
if (mCurClient != null) {
mCurClient.curSession = new SessionState(mCurClient,
method, session);
@@ -743,7 +805,30 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- void clearCurMethod() {
+ void unbindCurrentMethodLocked(boolean reportToClient) {
+ if (mHaveConnection) {
+ mContext.unbindService(this);
+ mHaveConnection = false;
+ }
+
+ if (mCurToken != null) {
+ try {
+ if (DEBUG) Log.v(TAG, "Removing window token: " + mCurToken);
+ mIWindowManager.removeWindowToken(mCurToken);
+ } catch (RemoteException e) {
+ }
+ mCurToken = null;
+ }
+
+ clearCurMethodLocked();
+
+ if (reportToClient && mCurClient != null) {
+ executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
+ MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
+ }
+ }
+
+ void clearCurMethodLocked() {
if (mCurMethod != null) {
for (ClientState cs : mClients.values()) {
cs.sessionRequested = false;
@@ -751,6 +836,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
mCurMethod = null;
}
+ mStatusBar.setIconVisibility(mInputMethodIcon, false);
}
public void onServiceDisconnected(ComponentName name) {
@@ -759,7 +845,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ " mCurIntent=" + mCurIntent);
if (mCurMethod != null && mCurIntent != null
&& name.equals(mCurIntent.getComponent())) {
- clearCurMethod();
+ clearCurMethodLocked();
+ // We consider this to be a new bind attempt, since the system
+ // should now try to restart the service for us.
+ mLastBindTime = SystemClock.uptimeMillis();
mShowRequested = mInputShown;
mInputShown = false;
if (mCurClient != null) {
@@ -770,35 +859,48 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- public void updateStatusIcon(int iconId, String iconPackage) {
- if (iconId == 0) {
- Log.d(TAG, "hide the small icon for the input method");
- mStatusBar.setIconVisibility(mInputMethodIcon, false);
- } else {
- Log.d(TAG, "show a small icon for the input method");
-
- if (iconPackage != null
- && iconPackage
- .equals(InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE)) {
- iconPackage = null;
+ public void updateStatusIcon(IBinder token, String packageName, int iconId) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (token == null || mCurToken != token) {
+ Log.w(TAG, "Ignoring setInputMethod of token: " + token);
+ return;
}
-
- mInputMethodData.iconId = iconId;
- mInputMethodData.iconPackage = iconPackage;
- mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null);
- mStatusBar.setIconVisibility(mInputMethodIcon, true);
+
+ synchronized (mMethodMap) {
+ if (iconId == 0) {
+ if (DEBUG) Log.d(TAG, "hide the small icon for the input method");
+ mStatusBar.setIconVisibility(mInputMethodIcon, false);
+ } else if (packageName != null) {
+ if (DEBUG) Log.d(TAG, "show a small icon for the input method");
+ mInputMethodData.iconId = iconId;
+ mInputMethodData.iconPackage = packageName;
+ mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null);
+ mStatusBar.setIconVisibility(mInputMethodIcon, true);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
void updateFromSettingsLocked() {
+ // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and
+ // ENABLED_INPUT_METHODS is taking care of keeping them correctly in
+ // sync, so we will never have a DEFAULT_INPUT_METHOD that is not
+ // enabled.
String id = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD);
- if (id != null) {
+ if (id != null && id.length() > 0) {
try {
setInputMethodLocked(id);
} catch (IllegalArgumentException e) {
Log.w(TAG, "Unknown input method from prefs: " + id, e);
+ unbindCurrentMethodLocked(true);
}
+ } else {
+ // There is no longer an input method set, so stop any current one.
+ unbindCurrentMethodLocked(true);
}
}
@@ -817,154 +919,217 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurMethodId = id;
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD, id);
-
- Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
- intent.putExtra("input_method_id", id);
- mContext.sendBroadcast(intent);
- unbindCurrentInputLocked();
+
+ if (ActivityManagerNative.isSystemReady()) {
+ Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
+ intent.putExtra("input_method_id", id);
+ mContext.sendBroadcast(intent);
+ }
+ unbindCurrentClientLocked();
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- public void showSoftInput(IInputMethodClient client, int flags) {
- synchronized (mMethodMap) {
- if (mCurClient == null || client == null
- || mCurClient.client.asBinder() != client.asBinder()) {
- try {
- // We need to check if this is the current client with
- // focus in the window manager, to allow this call to
- // be made before input is started in it.
- if (!mIWindowManager.inputMethodClientHasFocus(client)) {
- Log.w(TAG, "Ignoring showSoftInput of: " + client);
- return;
+ public boolean showSoftInput(IInputMethodClient client, int flags,
+ ResultReceiver resultReceiver) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mMethodMap) {
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ try {
+ // We need to check if this is the current client with
+ // focus in the window manager, to allow this call to
+ // be made before input is started in it.
+ if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+ Log.w(TAG, "Ignoring showSoftInput of: " + client);
+ return false;
+ }
+ } catch (RemoteException e) {
+ return false;
}
- } catch (RemoteException e) {
}
+
+ if (DEBUG) Log.v(TAG, "Client requesting input be shown");
+ return showCurrentInputLocked(flags, resultReceiver);
}
-
- if (DEBUG) Log.v(TAG, "Client requesting input be shown");
- showCurrentInputLocked(flags);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
- void showCurrentInputLocked(int flags) {
+ boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
mShowRequested = true;
if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
mShowExplicitlyRequested = true;
}
+ if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
+ mShowExplicitlyRequested = true;
+ mShowForced = true;
+ }
+ boolean res = false;
if (mCurMethod != null) {
- executeOrSendMessage(mCurMethod, mCaller.obtainMessageIO(
- MSG_SHOW_SOFT_INPUT, mShowExplicitlyRequested ? 1 : 0,
- mCurMethod));
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
+ MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod,
+ resultReceiver));
mInputShown = true;
+ res = true;
+ } else if (mHaveConnection && SystemClock.uptimeMillis()
+ < (mLastBindTime+TIME_TO_RECONNECT)) {
+ // The client has asked to have the input method shown, but
+ // we have been sitting here too long with a connection to the
+ // service and no interface received, so let's disconnect/connect
+ // to try to prod things along.
+ EventLog.writeEvent(LOG_IMF_FORCE_RECONNECT_IME, mCurMethodId,
+ SystemClock.uptimeMillis()-mLastBindTime,1);
+ mContext.unbindService(this);
+ mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE);
}
+
+ return res;
}
- public void hideSoftInput(IInputMethodClient client, int flags) {
- synchronized (mMethodMap) {
- if (mCurClient == null || client == null
- || mCurClient.client.asBinder() != client.asBinder()) {
- try {
- // We need to check if this is the current client with
- // focus in the window manager, to allow this call to
- // be made before input is started in it.
- if (!mIWindowManager.inputMethodClientHasFocus(client)) {
- Log.w(TAG, "Ignoring hideSoftInput of: " + client);
- return;
+ public boolean hideSoftInput(IInputMethodClient client, int flags,
+ ResultReceiver resultReceiver) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mMethodMap) {
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ try {
+ // We need to check if this is the current client with
+ // focus in the window manager, to allow this call to
+ // be made before input is started in it.
+ if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+ Log.w(TAG, "Ignoring hideSoftInput of: " + client);
+ return false;
+ }
+ } catch (RemoteException e) {
+ return false;
}
- } catch (RemoteException e) {
}
+
+ if (DEBUG) Log.v(TAG, "Client requesting input be hidden");
+ return hideCurrentInputLocked(flags, resultReceiver);
}
-
- if (DEBUG) Log.v(TAG, "Client requesting input be hidden");
- hideCurrentInputLocked(flags);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
- void hideCurrentInputLocked(int flags) {
+ boolean hideCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
if ((flags&InputMethodManager.HIDE_IMPLICIT_ONLY) != 0
- && mShowExplicitlyRequested) {
+ && (mShowExplicitlyRequested || mShowForced)) {
if (DEBUG) Log.v(TAG,
"Not hiding: explicit show not cancelled by non-explicit hide");
- return;
+ return false;
+ }
+ if (mShowForced && (flags&InputMethodManager.HIDE_NOT_ALWAYS) != 0) {
+ if (DEBUG) Log.v(TAG,
+ "Not hiding: forced show not cancelled by not-always hide");
+ return false;
}
+ boolean res;
if (mInputShown && mCurMethod != null) {
- executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
- MSG_HIDE_SOFT_INPUT, mCurMethod));
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
+ MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver));
+ res = true;
+ } else {
+ res = false;
}
mInputShown = false;
mShowRequested = false;
mShowExplicitlyRequested = false;
+ mShowForced = false;
+ return res;
}
- public void windowGainedFocus(IInputMethodClient client,
+ public void windowGainedFocus(IInputMethodClient client, IBinder windowToken,
boolean viewHasFocus, boolean isTextEditor, int softInputMode,
boolean first, int windowFlags) {
- synchronized (mMethodMap) {
- if (DEBUG) Log.v(TAG, "windowGainedFocus: " + client.asBinder()
- + " viewHasFocus=" + viewHasFocus
- + " isTextEditor=" + isTextEditor
- + " softInputMode=#" + Integer.toHexString(softInputMode)
- + " first=" + first + " flags=#"
- + Integer.toHexString(windowFlags));
-
- if (mCurClient == null || client == null
- || mCurClient.client.asBinder() != client.asBinder()) {
- try {
- // We need to check if this is the current client with
- // focus in the window manager, to allow this call to
- // be made before input is started in it.
- if (!mIWindowManager.inputMethodClientHasFocus(client)) {
- Log.w(TAG, "Ignoring focus gain of: " + client);
- return;
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mMethodMap) {
+ if (DEBUG) Log.v(TAG, "windowGainedFocus: " + client.asBinder()
+ + " viewHasFocus=" + viewHasFocus
+ + " isTextEditor=" + isTextEditor
+ + " softInputMode=#" + Integer.toHexString(softInputMode)
+ + " first=" + first + " flags=#"
+ + Integer.toHexString(windowFlags));
+
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ try {
+ // We need to check if this is the current client with
+ // focus in the window manager, to allow this call to
+ // be made before input is started in it.
+ if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+ Log.w(TAG, "Client not active, ignoring focus gain of: " + client);
+ return;
+ }
+ } catch (RemoteException e) {
}
- } catch (RemoteException e) {
}
- }
-
- switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
- case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
- if (!isTextEditor || (softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
- != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
- if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
- // There is no focus view, and this window will
- // be behind any soft input window, so hide the
- // soft input window if it is shown.
- if (DEBUG) Log.v(TAG, "Unspecified window will hide input");
- hideCurrentInputLocked(0);
+
+ if (mCurFocusedWindow == windowToken) {
+ Log.w(TAG, "Window already focused, ignoring focus gain of: " + client);
+ return;
+ }
+ mCurFocusedWindow = windowToken;
+
+ switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
+ if (!isTextEditor || (softInputMode &
+ WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+ if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
+ // There is no focus view, and this window will
+ // be behind any soft input window, so hide the
+ // soft input window if it is shown.
+ if (DEBUG) Log.v(TAG, "Unspecified window will hide input");
+ hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
+ }
+ } else if (isTextEditor && (softInputMode &
+ WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
+ && (softInputMode &
+ WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+ // There is a focus view, and we are navigating forward
+ // into the window, so show the input window for the user.
+ if (DEBUG) Log.v(TAG, "Unspecified window will show input");
+ showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
}
- } else if (isTextEditor && (softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
- == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
- && (softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
- // There is a focus view, and we are navigating forward
- // into the window, so show the input window for the user.
- if (DEBUG) Log.v(TAG, "Unspecified window will show input");
- showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
- }
- break;
- case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
- // Do nothing.
- break;
- case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
- if (DEBUG) Log.v(TAG, "Window asks to hide input");
- hideCurrentInputLocked(0);
- break;
- case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
- if ((softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
- if (DEBUG) Log.v(TAG, "Window asks to show input going forward");
- showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
- }
- break;
- case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
- if (DEBUG) Log.v(TAG, "Window asks to always show input");
- showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
- break;
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
+ // Do nothing.
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
+ if ((softInputMode &
+ WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+ if (DEBUG) Log.v(TAG, "Window asks to hide input going forward");
+ hideCurrentInputLocked(0, null);
+ }
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
+ if (DEBUG) Log.v(TAG, "Window asks to hide input");
+ hideCurrentInputLocked(0, null);
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
+ if ((softInputMode &
+ WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+ if (DEBUG) Log.v(TAG, "Window asks to show input going forward");
+ showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
+ }
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
+ if (DEBUG) Log.v(TAG, "Window asks to always show input");
+ showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
+ break;
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -981,7 +1146,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public void setInputMethod(IBinder token, String id) {
synchronized (mMethodMap) {
- if (mCurToken == null) {
+ if (token == null) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS)
!= PackageManager.PERMISSION_GRANTED) {
@@ -991,19 +1156,45 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
} else if (mCurToken != token) {
Log.w(TAG, "Ignoring setInputMethod of token: " + token);
+ return;
}
- setInputMethodLocked(id);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ setInputMethodLocked(id);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
public void hideMySoftInput(IBinder token, int flags) {
synchronized (mMethodMap) {
- if (mCurToken == null || mCurToken != token) {
+ if (token == null || mCurToken != token) {
Log.w(TAG, "Ignoring hideInputMethod of token: " + token);
+ return;
+ }
+ long ident = Binder.clearCallingIdentity();
+ try {
+ hideCurrentInputLocked(flags, null);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public void showMySoftInput(IBinder token, int flags) {
+ synchronized (mMethodMap) {
+ if (token == null || mCurToken != token) {
+ Log.w(TAG, "Ignoring hideInputMethod of token: " + token);
+ return;
+ }
+ long ident = Binder.clearCallingIdentity();
+ try {
+ showCurrentInputLocked(flags, null);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
-
- hideCurrentInputLocked(flags);
}
}
@@ -1051,20 +1242,25 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
return true;
case MSG_SHOW_SOFT_INPUT:
+ args = (HandlerCaller.SomeArgs)msg.obj;
try {
- ((IInputMethod)msg.obj).showSoftInput(msg.arg1 != 0);
+ ((IInputMethod)args.arg1).showSoftInput(msg.arg1,
+ (ResultReceiver)args.arg2);
} catch (RemoteException e) {
}
return true;
case MSG_HIDE_SOFT_INPUT:
+ args = (HandlerCaller.SomeArgs)msg.obj;
try {
- ((IInputMethod)msg.obj).hideSoftInput();
+ ((IInputMethod)args.arg1).hideSoftInput(0,
+ (ResultReceiver)args.arg2);
} catch (RemoteException e) {
}
return true;
case MSG_ATTACH_TOKEN:
args = (HandlerCaller.SomeArgs)msg.obj;
try {
+ if (DEBUG) Log.v(TAG, "Sending attach of token: " + args.arg2);
((IInputMethod)args.arg1).attachToken((IBinder)args.arg2);
} catch (RemoteException e) {
}
@@ -1077,7 +1273,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
} catch (RemoteException e) {
}
return true;
-
// ---------------------------------------------------------
case MSG_START_INPUT:
@@ -1085,7 +1280,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
SessionState session = (SessionState)args.arg1;
setEnabledSessionInMainThread(session);
- session.method.startInput((EditorInfo)args.arg2);
+ session.method.startInput((IInputContext)args.arg2,
+ (EditorInfo)args.arg3);
} catch (RemoteException e) {
}
return true;
@@ -1094,7 +1290,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
try {
SessionState session = (SessionState)args.arg1;
setEnabledSessionInMainThread(session);
- session.method.restartInput((EditorInfo)args.arg2);
+ session.method.restartInput((IInputContext)args.arg2,
+ (EditorInfo)args.arg3);
} catch (RemoteException e) {
}
return true;
@@ -1128,10 +1325,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
PackageManager pm = mContext.getPackageManager();
- Object[][] buildin = {{
- DefaultInputMethod.class.getName(),
- DefaultInputMethod.getMetaInfo()}};
-
List<ResolveInfo> services = pm.queryIntentServices(
new Intent(InputMethod.SERVICE_INTERFACE),
PackageManager.GET_META_DATA);
@@ -1150,39 +1343,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) Log.d(TAG, "Checking " + compName);
- /* Built-in input methods are not currently supported... this will
- * need to be reworked to bring them back (all input methods must
- * now be published in a manifest).
- */
- /*
- if (compName.getPackageName().equals(
- InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE)) {
- // System build-in input methods;
- String inputMethodName = null;
- int kbType = 0;
- String skbName = null;
-
- for (int j = 0; j < buildin.length; ++j) {
- Object[] obj = buildin[j];
- if (compName.getClassName().equals(obj[0])) {
- InputMethodMetaInfo imp = (InputMethodMetaInfo) obj[1];
- inputMethodName = imp.inputMethodName;
- }
- }
-
- InputMethodMetaInfo p = new InputMethodMetaInfo(compName,
- inputMethodName, "");
-
- list.add(p);
-
- if (DEBUG) {
- Log.d(TAG, "Found a build-in input method " + p);
- }
-
- continue;
- }
- */
-
try {
InputMethodInfo p = new InputMethodInfo(mContext, ri);
list.add(p);
@@ -1202,7 +1362,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// ----------------------------------------------------------------------
- public void showInputMethodMenu() {
+ void showInputMethodMenu() {
if (DEBUG) Log.v(TAG, "Show switching menu");
hideInputMethodMenu();
@@ -1302,91 +1462,96 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
- // Make sure this is a valid input method.
- InputMethodInfo imm = mMethodMap.get(id);
- if (imm == null) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ // Make sure this is a valid input method.
+ InputMethodInfo imm = mMethodMap.get(id);
if (imm == null) {
- throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
+ if (imm == null) {
+ throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
+ }
}
- }
-
- StringBuilder builder = new StringBuilder(256);
-
- boolean removed = false;
- String firstId = null;
-
- // Look through the currently enabled input methods.
- String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS);
- if (enabledStr != null) {
- final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
- splitter.setString(enabledStr);
- while (splitter.hasNext()) {
- String curId = splitter.next();
- if (curId.equals(id)) {
- if (enabled) {
- // We are enabling this input method, but it is
- // already enabled. Nothing to do. The previous
- // state was enabled.
- return true;
+
+ StringBuilder builder = new StringBuilder(256);
+
+ boolean removed = false;
+ String firstId = null;
+
+ // Look through the currently enabled input methods.
+ String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS);
+ if (enabledStr != null) {
+ final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+ splitter.setString(enabledStr);
+ while (splitter.hasNext()) {
+ String curId = splitter.next();
+ if (curId.equals(id)) {
+ if (enabled) {
+ // We are enabling this input method, but it is
+ // already enabled. Nothing to do. The previous
+ // state was enabled.
+ return true;
+ }
+ // We are disabling this input method, and it is
+ // currently enabled. Skip it to remove from the
+ // new list.
+ removed = true;
+ } else if (!enabled) {
+ // We are building a new list of input methods that
+ // doesn't contain the given one.
+ if (firstId == null) firstId = curId;
+ if (builder.length() > 0) builder.append(':');
+ builder.append(curId);
}
- // We are disabling this input method, and it is
- // currently enabled. Skip it to remove from the
- // new list.
- removed = true;
- } else if (!enabled) {
- // We are building a new list of input methods that
- // doesn't contain the given one.
- if (firstId == null) firstId = curId;
- if (builder.length() > 0) builder.append(':');
- builder.append(curId);
}
}
- }
-
- if (!enabled) {
- if (!removed) {
- // We are disabling the input method but it is already
- // disabled. Nothing to do. The previous state was
- // disabled.
- return false;
- }
- // Update the setting with the new list of input methods.
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
- // We the disabled input method is currently selected, switch
- // to another one.
- String selId = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.DEFAULT_INPUT_METHOD);
- if (id.equals(selId)) {
+
+ if (!enabled) {
+ if (!removed) {
+ // We are disabling the input method but it is already
+ // disabled. Nothing to do. The previous state was
+ // disabled.
+ return false;
+ }
+ // Update the setting with the new list of input methods.
Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.DEFAULT_INPUT_METHOD,
- firstId != null ? firstId : "");
+ Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
+ // We the disabled input method is currently selected, switch
+ // to another one.
+ String selId = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD);
+ if (id.equals(selId)) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD,
+ firstId != null ? firstId : "");
+ }
+ // Previous state was enabled.
+ return true;
}
- // Previous state was enabled.
- return true;
- }
-
- // Add in the newly enabled input method.
- if (enabledStr == null || enabledStr.length() == 0) {
- enabledStr = id;
- } else {
- enabledStr = enabledStr + ':' + id;
+
+ // Add in the newly enabled input method.
+ if (enabledStr == null || enabledStr.length() == 0) {
+ enabledStr = id;
+ } else {
+ enabledStr = enabledStr + ':' + id;
+ }
+
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
+
+ // Previous state was disabled.
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
-
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
-
- // Previous state was disabled.
- return false;
}
}
-
+
// ----------------------------------------------------------------------
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingPermission("android.permission.DUMP")
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump InputMethodManager from from pid="
@@ -1395,8 +1560,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return;
}
+ IInputMethod method;
+ ClientState client;
+
+ final Printer p = new PrintWriterPrinter(pw);
+
synchronized (mMethodMap) {
- final Printer p = new PrintWriterPrinter(pw);
p.println("Current Input Method Manager state:");
int N = mMethodList.size();
p.println(" Input Methods:");
@@ -1416,17 +1585,41 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
p.println(" mInputMethodIcon=" + mInputMethodIcon);
p.println(" mInputMethodData=" + mInputMethodData);
p.println(" mCurrentMethod=" + mCurMethodId);
- p.println(" mCurSeq=" + mCurSeq + " mCurClient=" + mCurClient);
+ client = mCurClient;
+ p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq);
+ p.println(" mCurFocusedWindow=" + mCurFocusedWindow);
p.println(" mCurId=" + mCurId + " mHaveConnect=" + mHaveConnection
+ " mBoundToMethod=" + mBoundToMethod);
p.println(" mCurToken=" + mCurToken);
p.println(" mCurIntent=" + mCurIntent);
+ method = mCurMethod;
p.println(" mCurMethod=" + mCurMethod);
p.println(" mEnabledSession=" + mEnabledSession);
p.println(" mShowRequested=" + mShowRequested
+ " mShowExplicitlyRequested=" + mShowExplicitlyRequested
+ + " mShowForced=" + mShowForced
+ " mInputShown=" + mInputShown);
p.println(" mScreenOn=" + mScreenOn);
}
+
+ if (client != null) {
+ p.println(" ");
+ pw.flush();
+ try {
+ client.client.asBinder().dump(fd, args);
+ } catch (RemoteException e) {
+ p.println("Input method client dead: " + e);
+ }
+ }
+
+ if (method != null) {
+ p.println(" ");
+ pw.flush();
+ try {
+ method.asBinder().dump(fd, args);
+ } catch (RemoteException e) {
+ p.println("Input method service dead: " + e);
+ }
+ }
}
}
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 9874042..63b486c 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -165,6 +165,7 @@ public abstract class KeyInputQueue {
public static native int getScancodeState(int deviceId, int sw);
public static native int getKeycodeState(int sw);
public static native int getKeycodeState(int deviceId, int sw);
+ public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
public static KeyEvent newKeyEvent(InputDevice device, long downTime,
long eventTime, boolean down, int keycode, int repeatCount,
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index ed9ee79..e48e047 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -18,14 +18,16 @@ package com.android.server;
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Locale;
+import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
@@ -46,6 +48,7 @@ import android.location.LocationManager;
import android.location.LocationProvider;
import android.location.LocationProviderImpl;
import android.net.ConnectivityManager;
+import android.net.Uri;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Binder;
@@ -57,19 +60,22 @@ import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Config;
import android.util.Log;
+import android.util.PrintWriterPrinter;
+import android.util.SparseIntArray;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.location.CellState;
import com.android.internal.location.GpsLocationProvider;
-import com.android.internal.location.LocationCollector;
-import com.android.internal.location.LocationMasfClient;
-import com.android.internal.location.NetworkLocationProvider;
+import com.android.internal.location.ILocationCollector;
+import com.android.internal.location.INetworkLocationManager;
+import com.android.internal.location.INetworkLocationProvider;
import com.android.internal.location.TrackProvider;
+import com.android.server.am.BatteryStatsService;
/**
* The service class that manages LocationProviders and issues location
@@ -77,7 +83,8 @@ import com.android.internal.location.TrackProvider;
*
* {@hide}
*/
-public class LocationManagerService extends ILocationManager.Stub {
+public class LocationManagerService extends ILocationManager.Stub
+ implements INetworkLocationManager {
private static final String TAG = "LocationManagerService";
// Minimum time interval between last known location writes, in milliseconds.
@@ -121,13 +128,16 @@ public class LocationManagerService extends ILocationManager.Stub {
private final Context mContext;
private GpsLocationProvider mGpsLocationProvider;
- private NetworkLocationProvider mNetworkLocationProvider;
+ private boolean mGpsNavigating;
+ private LocationProviderImpl mNetworkLocationProvider;
+ private INetworkLocationProvider mNetworkLocationInterface;
private LocationWorkerHandler mLocationHandler;
// Handler messages
private static final int MESSAGE_HEARTBEAT = 1;
private static final int MESSAGE_ACQUIRE_WAKE_LOCK = 2;
private static final int MESSAGE_RELEASE_WAKE_LOCK = 3;
+ private static final int MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER = 4;
// Alarm manager and wakelock variables
private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT";
@@ -143,33 +153,41 @@ public class LocationManagerService extends ILocationManager.Stub {
private boolean mWakeLockNetworkReceived = true;
private boolean mWifiWakeLockAcquired = false;
private boolean mCellWakeLockAcquired = false;
-
+
+ private final IBatteryStats mBatteryStats;
+
/**
* Mapping from listener IBinder/PendingIntent to local Listener wrappers.
*/
- private final HashMap<Object,Receiver> mListeners =
- new HashMap<Object,Receiver>();
+ private final ArrayList<Receiver> mListeners = new ArrayList<Receiver>();
/**
+ * Used for reporting which UIDs are causing the GPS to run.
+ */
+ private final SparseIntArray mReportedGpsUids = new SparseIntArray();
+ private int mReportedGpsSeq = 0;
+
+ /**
* Mapping from listener IBinder/PendingIntent to a map from provider name to UpdateRecord.
+ * This also serves as the lock for our state.
*/
- private final HashMap<Object,HashMap<String,UpdateRecord>> mLocationListeners =
- new HashMap<Object,HashMap<String,UpdateRecord>>();
+ private final HashMap<Receiver,HashMap<String,UpdateRecord>> mLocationListeners =
+ new HashMap<Receiver,HashMap<String,UpdateRecord>>();
/**
* Mapping from listener IBinder/PendingIntent to a map from provider name to last broadcast
* location.
*/
- private final HashMap<Object,HashMap<String,Location>> mLastFixBroadcast =
- new HashMap<Object,HashMap<String,Location>>();
- private final HashMap<Object,HashMap<String,Long>> mLastStatusBroadcast =
- new HashMap<Object,HashMap<String,Long>>();
+ private final HashMap<Receiver,HashMap<String,Location>> mLastFixBroadcast =
+ new HashMap<Receiver,HashMap<String,Location>>();
+ private final HashMap<Receiver,HashMap<String,Long>> mLastStatusBroadcast =
+ new HashMap<Receiver,HashMap<String,Long>>();
/**
* Mapping from provider name to all its UpdateRecords
*/
- private final HashMap<String,HashSet<UpdateRecord>> mRecordsByProvider =
- new HashMap<String,HashSet<UpdateRecord>>();
+ private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
+ new HashMap<String,ArrayList<UpdateRecord>>();
/**
* Mappings from provider name to object to use for current location. Locations
@@ -196,17 +214,16 @@ public class LocationManagerService extends ILocationManager.Stub {
// Last known cell service state
private TelephonyManager mTelephonyManager;
- private int mSignalStrength = -1;
// Location collector
- private LocationCollector mCollector;
-
- // Location MASF service
- private LocationMasfClient mMasfClient;
+ private ILocationCollector mCollector;
// Wifi Manager
private WifiManager mWifiManager;
+ private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
+ private boolean mWifiEnabled = false;
+
/**
* A wrapper class holding either an ILocationListener or a PendingIntent to receive
* location updates.
@@ -214,22 +231,48 @@ public class LocationManagerService extends ILocationManager.Stub {
private final class Receiver implements IBinder.DeathRecipient {
final ILocationListener mListener;
final PendingIntent mPendingIntent;
+ final int mUid;
+ final Object mKey;
- Receiver(ILocationListener listener) {
+ Receiver(ILocationListener listener, int uid) {
mListener = listener;
mPendingIntent = null;
+ mUid = uid;
+ mKey = listener.asBinder();
}
- Receiver(PendingIntent intent) {
+ Receiver(PendingIntent intent, int uid) {
mPendingIntent = intent;
mListener = null;
+ mUid = uid;
+ mKey = intent;
+ }
+
+ @Override
+ public boolean equals(Object otherObj) {
+ if (otherObj instanceof Receiver) {
+ return mKey.equals(
+ ((Receiver)otherObj).mKey);
+ }
+ return false;
}
- public Object getKey() {
+ @Override
+ public int hashCode() {
+ return mKey.hashCode();
+ }
+
+
+ @Override
+ public String toString() {
if (mListener != null) {
- return mListener.asBinder();
+ return "Receiver{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " uid " + mUid + " Listener " + mKey + "}";
} else {
- return mPendingIntent;
+ return "Receiver{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " uid " + mUid + " Intent " + mKey + "}";
}
}
@@ -255,10 +298,13 @@ public class LocationManagerService extends ILocationManager.Stub {
throw new IllegalStateException("Request for non-existent intent");
}
- public void onStatusChanged(String provider, int status, Bundle extras)
- throws RemoteException {
+ public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
if (mListener != null) {
- mListener.onStatusChanged(provider, status, extras);
+ try {
+ mListener.onStatusChanged(provider, status, extras);
+ } catch (RemoteException e) {
+ return false;
+ }
} else {
Intent statusChanged = new Intent();
statusChanged.putExtras(extras);
@@ -266,23 +312,29 @@ public class LocationManagerService extends ILocationManager.Stub {
try {
mPendingIntent.send(mContext, 0, statusChanged, null, null);
} catch (PendingIntent.CanceledException e) {
- _removeUpdates(this);
+ return false;
}
}
+ return true;
}
- public void onLocationChanged(Location location) throws RemoteException {
+ public boolean callLocationChangedLocked(Location location) {
if (mListener != null) {
- mListener.onLocationChanged(location);
+ try {
+ mListener.onLocationChanged(location);
+ } catch (RemoteException e) {
+ return false;
+ }
} else {
Intent locationChanged = new Intent();
locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
try {
mPendingIntent.send(mContext, 0, locationChanged, null, null);
} catch (PendingIntent.CanceledException e) {
- _removeUpdates(this);
+ return false;
}
}
+ return true;
}
public void binderDied() {
@@ -290,12 +342,12 @@ public class LocationManagerService extends ILocationManager.Stub {
Log.d(TAG, "Location listener died");
}
synchronized (mLocationListeners) {
- _removeUpdates(this);
+ removeUpdatesLocked(this);
}
}
}
- private Location readLastKnownLocation(String provider) {
+ private Location readLastKnownLocationLocked(String provider) {
Location location = null;
String s = null;
try {
@@ -338,7 +390,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return location;
}
- private void writeLastKnownLocation(String provider,
+ private void writeLastKnownLocationLocked(String provider,
Location location) {
long now = SystemClock.elapsedRealtime();
Long last = mLastWriteTime.get(provider);
@@ -396,36 +448,30 @@ public class LocationManagerService extends ILocationManager.Stub {
* properties
*/
private void loadProviders() {
- synchronized (LocationManagerService.class) {
+ synchronized (mLocationListeners) {
if (sProvidersLoaded) {
return;
}
// Load providers
- loadProvidersNoSync();
+ loadProvidersLocked();
sProvidersLoaded = true;
}
}
- private void loadProvidersNoSync() {
+ private void loadProvidersLocked() {
try {
- _loadProvidersNoSync();
+ _loadProvidersLocked();
} catch (Exception e) {
Log.e(TAG, "Exception loading providers:", e);
}
}
- private void _loadProvidersNoSync() {
+ private void _loadProvidersLocked() {
// Attempt to load "real" providers first
- if (NetworkLocationProvider.isSupported()) {
- // Create a network location provider
- mNetworkLocationProvider = new NetworkLocationProvider(mContext, mMasfClient);
- LocationProviderImpl.addProvider(mNetworkLocationProvider);
- }
-
if (GpsLocationProvider.isSupported()) {
// Create a gps location provider
- mGpsLocationProvider = new GpsLocationProvider(mContext, mCollector);
+ mGpsLocationProvider = new GpsLocationProvider(mContext);
LocationProviderImpl.addProvider(mGpsLocationProvider);
}
@@ -494,7 +540,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- updateProviders();
+ updateProvidersLocked();
}
/**
@@ -509,18 +555,15 @@ public class LocationManagerService extends ILocationManager.Stub {
Log.d(TAG, "Constructed LocationManager Service");
}
- // Initialize the LocationMasfClient
- mMasfClient = new LocationMasfClient(mContext);
-
- // Create location collector
- mCollector = new LocationCollector(mMasfClient);
-
// Alarm manager, needs to be done before calling loadProviders() below
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Create a wake lock, needs to be done before calling loadProviders() below
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
+
+ // Battery statistics service to be notified when GPS turns on or off
+ mBatteryStats = BatteryStatsService.getService();
// Load providers
loadProviders();
@@ -548,26 +591,71 @@ public class LocationManagerService extends ILocationManager.Stub {
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
context.registerReceiver(powerStateReceiver, intentFilter);
// Get the wifi manager
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
// Create a wifi lock for future use
- mWifiLock = getWifiWakelock();
-
- // There might be an existing wifi scan available
- if (mWifiManager != null) {
- List<ScanResult> wifiScanResults = mWifiManager.getScanResults();
- if (wifiScanResults != null && wifiScanResults.size() != 0) {
- if (mNetworkLocationProvider != null) {
- mNetworkLocationProvider.updateWifiScanResults(wifiScanResults);
+ mWifiLock = getWifiWakelockLocked();
+ }
+
+ public void setInstallCallback(InstallCallback callback) {
+ synchronized (mLocationListeners) {
+ mLocationHandler.removeMessages(MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER);
+ Message m = Message.obtain(mLocationHandler,
+ MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER, callback);
+ mLocationHandler.sendMessageAtFrontOfQueue(m);
+ }
+ }
+
+ public void setNetworkLocationProvider(INetworkLocationProvider provider) {
+ synchronized (mLocationListeners) {
+ mNetworkLocationInterface = provider;
+ provider.addListener(getPackageNames());
+ mNetworkLocationProvider = (LocationProviderImpl)provider;
+ LocationProviderImpl.addProvider(mNetworkLocationProvider);
+ updateProvidersLocked();
+
+ // notify NetworkLocationProvider of any events it might have missed
+ synchronized (mLocationListeners) {
+ mNetworkLocationProvider.updateNetworkState(mNetworkState);
+ mNetworkLocationInterface.updateWifiEnabledState(mWifiEnabled);
+ mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired);
+
+ if (mLastCellState != null) {
+ if (mCollector != null) {
+ mCollector.updateCellState(mLastCellState);
+ }
+ mNetworkLocationProvider.updateCellState(mLastCellState);
+ }
+
+ // There might be an existing wifi scan available
+ if (mWifiManager != null) {
+ List<ScanResult> wifiScanResults = mWifiManager.getScanResults();
+ if (wifiScanResults != null && wifiScanResults.size() != 0) {
+ mNetworkLocationInterface.updateWifiScanResults(wifiScanResults);
+ if (mCollector != null) {
+ mCollector.updateWifiScanResults(wifiScanResults);
+ }
+ }
}
}
}
}
- private WifiManager.WifiLock getWifiWakelock() {
+ public void setLocationCollector(ILocationCollector collector) {
+ synchronized (mLocationListeners) {
+ mCollector = collector;
+ if (mGpsLocationProvider != null) {
+ mGpsLocationProvider.setLocationCollector(mCollector);
+ }
+ }
+ }
+
+ private WifiManager.WifiLock getWifiWakelockLocked() {
if (mWifiLock == null && mWifiManager != null) {
mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY);
mWifiLock.setReferenceCounted(false);
@@ -575,7 +663,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return mWifiLock;
}
- private boolean isAllowedBySettings(String provider) {
+ private boolean isAllowedBySettingsLocked(String provider) {
if (mEnabledProviders.contains(provider)) {
return true;
}
@@ -590,7 +678,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return ((allowedProviders != null) && (allowedProviders.contains(provider)));
}
- private void checkPermissions(String provider) {
+ private void checkPermissionsSafe(String provider) {
if (LocationManager.GPS_PROVIDER.equals(provider)
&& (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)) {
@@ -606,7 +694,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private boolean isAllowedProvider(String provider) {
+ private boolean isAllowedProviderSafe(String provider) {
if (LocationManager.GPS_PROVIDER.equals(provider)
&& (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)) {
@@ -631,7 +719,9 @@ public class LocationManagerService extends ILocationManager.Stub {
public List<String> getAllProviders() {
try {
- return _getAllProviders();
+ synchronized (mLocationListeners) {
+ return _getAllProvidersLocked();
+ }
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -640,7 +730,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private List<String> _getAllProviders() {
+ private List<String> _getAllProvidersLocked() {
if (Config.LOGD) {
Log.d(TAG, "getAllProviders");
}
@@ -655,7 +745,9 @@ public class LocationManagerService extends ILocationManager.Stub {
public List<String> getProviders(boolean enabledOnly) {
try {
- return _getProviders(enabledOnly);
+ synchronized (mLocationListeners) {
+ return _getProvidersLocked(enabledOnly);
+ }
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -664,7 +756,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private List<String> _getProviders(boolean enabledOnly) {
+ private List<String> _getProvidersLocked(boolean enabledOnly) {
if (Config.LOGD) {
Log.d(TAG, "getProviders");
}
@@ -673,8 +765,8 @@ public class LocationManagerService extends ILocationManager.Stub {
for (LocationProviderImpl p : providers) {
String name = p.getName();
- if (isAllowedProvider(name)) {
- if (enabledOnly && !isAllowedBySettings(name)) {
+ if (isAllowedProviderSafe(name)) {
+ if (enabledOnly && !isAllowedBySettingsLocked(name)) {
continue;
}
out.add(name);
@@ -684,26 +776,33 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public void updateProviders() {
+ synchronized (mLocationListeners) {
+ updateProvidersLocked();
+ }
+ }
+
+ private void updateProvidersLocked() {
for (LocationProviderImpl p : LocationProviderImpl.getProviders()) {
boolean isEnabled = p.isEnabled();
String name = p.getName();
- boolean shouldBeEnabled = isAllowedBySettings(name);
+ boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
// Collection is only allowed when network provider is being used
- if (p.getName().equals(LocationManager.NETWORK_PROVIDER)) {
+ if (mCollector != null &&
+ p.getName().equals(LocationManager.NETWORK_PROVIDER)) {
mCollector.updateNetworkProviderStatus(shouldBeEnabled);
}
if (isEnabled && !shouldBeEnabled) {
- updateProviderListeners(name, false);
+ updateProviderListenersLocked(name, false);
} else if (!isEnabled && shouldBeEnabled) {
- updateProviderListeners(name, true);
+ updateProviderListenersLocked(name, true);
}
}
}
- private void updateProviderListeners(String provider, boolean enabled) {
+ private void updateProviderListenersLocked(String provider, boolean enabled) {
int listeners = 0;
LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
@@ -711,49 +810,63 @@ public class LocationManagerService extends ILocationManager.Stub {
return;
}
- synchronized (mRecordsByProvider) {
- HashSet<UpdateRecord> records = mRecordsByProvider.get(provider);
- if (records != null) {
- for (UpdateRecord record : records) {
- // Sends a notification message to the receiver
- try {
- Receiver receiver = record.mReceiver;
- if (receiver.isListener()) {
- if (enabled) {
- receiver.getListener().onProviderEnabled(provider);
- } else {
- receiver.getListener().onProviderDisabled(provider);
- }
+ ArrayList<Receiver> deadReceivers = null;
+
+ ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+ if (records != null) {
+ final int N = records.size();
+ for (int i=0; i<N; i++) {
+ UpdateRecord record = records.get(i);
+ // Sends a notification message to the receiver
+ try {
+ Receiver receiver = record.mReceiver;
+ if (receiver.isListener()) {
+ if (enabled) {
+ receiver.getListener().onProviderEnabled(provider);
} else {
- PendingIntent intent = receiver.getPendingIntent();
- Intent providerIntent = new Intent();
- providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
- try {
- receiver.getPendingIntent().send(mContext, 0,
- providerIntent, null, null);
- } catch (PendingIntent.CanceledException e) {
- _removeUpdates(receiver);
+ receiver.getListener().onProviderDisabled(provider);
+ }
+ } else {
+ Intent providerIntent = new Intent();
+ providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
+ try {
+ receiver.getPendingIntent().send(mContext, 0,
+ providerIntent, null, null);
+ } catch (PendingIntent.CanceledException e) {
+ if (deadReceivers == null) {
+ deadReceivers = new ArrayList<Receiver>();
+ deadReceivers.add(receiver);
}
}
- } catch (RemoteException e) {
- // The death link will clean this up.
}
- listeners++;
+ } catch (RemoteException e) {
+ // The death link will clean this up.
}
+ listeners++;
}
}
+ if (deadReceivers != null) {
+ for (int i=deadReceivers.size()-1; i>=0; i--) {
+ removeUpdatesLocked(deadReceivers.get(i));
+ }
+ }
+
if (enabled) {
p.enable();
if (listeners > 0) {
- p.setMinTime(getMinTime(provider));
+ p.setMinTime(getMinTimeLocked(provider));
p.enableLocationTracking(true);
- updateWakelockStatus(mScreenOn);
+ updateWakelockStatusLocked(mScreenOn);
}
} else {
p.enableLocationTracking(false);
+ if (p == mGpsLocationProvider) {
+ mGpsNavigating = false;
+ reportStopGpsLocked();
+ }
p.disable();
- updateWakelockStatus(mScreenOn);
+ updateWakelockStatusLocked(mScreenOn);
}
if (enabled && listeners > 0) {
@@ -765,40 +878,43 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private long getMinTime(String provider) {
+ private long getMinTimeLocked(String provider) {
long minTime = Long.MAX_VALUE;
- synchronized (mRecordsByProvider) {
- HashSet<UpdateRecord> records = mRecordsByProvider.get(provider);
- if (records != null) {
- for (UpdateRecord r : records) {
- minTime = Math.min(minTime, r.mMinTime);
- }
+ ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+ if (records != null) {
+ for (int i=records.size()-1; i>=0; i--) {
+ minTime = Math.min(minTime, records.get(i).mMinTime);
}
}
return minTime;
}
private class UpdateRecord {
- String mProvider;
- Receiver mReceiver;
- long mMinTime;
- float mMinDistance;
- String[] mPackages;
+ final String mProvider;
+ final Receiver mReceiver;
+ final long mMinTime;
+ final float mMinDistance;
+ final int mUid;
+ final String[] mPackages;
+ /**
+ * Note: must be constructed with lock held.
+ */
UpdateRecord(String provider, long minTime, float minDistance,
- Receiver receiver, String[] packages) {
+ Receiver receiver, int uid, String[] packages) {
mProvider = provider;
mReceiver = receiver;
mMinTime = minTime;
mMinDistance = minDistance;
+ mUid = uid;
mPackages = packages;
- synchronized (mRecordsByProvider) {
- HashSet<UpdateRecord> records = mRecordsByProvider.get(provider);
- if (records == null) {
- records = new HashSet<UpdateRecord>();
- mRecordsByProvider.put(provider, records);
- }
+ ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+ if (records == null) {
+ records = new ArrayList<UpdateRecord>();
+ mRecordsByProvider.put(provider, records);
+ }
+ if (!records.contains(this)) {
records.add(this);
}
}
@@ -807,18 +923,39 @@ public class LocationManagerService extends ILocationManager.Stub {
* Method to be called when a record will no longer be used. Calling this multiple times
* must have the same effect as calling it once.
*/
- public void dispose() {
- synchronized (mRecordsByProvider) {
- HashSet<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
- records.remove(this);
- }
+ void disposeLocked() {
+ ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
+ records.remove(this);
}
+ @Override
+ public String toString() {
+ return "UpdateRecord{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + mProvider + " " + mReceiver + "}";
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + this);
+ pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
+ pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
+ StringBuilder sb = new StringBuilder();
+ if (mPackages != null) {
+ for (int i=0; i<mPackages.length; i++) {
+ if (i > 0) sb.append(", ");
+ sb.append(mPackages[i]);
+ }
+ }
+ pw.println(prefix + "mUid=" + mUid + " mPackages=" + sb);
+ }
+
/**
* Calls dispose().
*/
@Override protected void finalize() {
- dispose();
+ synchronized (mLocationListeners) {
+ disposeLocked();
+ }
}
}
@@ -826,8 +963,10 @@ public class LocationManagerService extends ILocationManager.Stub {
long minTime, float minDistance, ILocationListener listener) {
try {
- _requestLocationUpdates(provider, minTime, minDistance,
- new Receiver(listener));
+ synchronized (mLocationListeners) {
+ requestLocationUpdatesLocked(provider, minTime, minDistance,
+ new Receiver(listener, Binder.getCallingUid()));
+ }
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -838,8 +977,10 @@ public class LocationManagerService extends ILocationManager.Stub {
public void requestLocationUpdatesPI(String provider,
long minTime, float minDistance, PendingIntent intent) {
try {
- _requestLocationUpdates(provider, minTime, minDistance,
- new Receiver(intent));
+ synchronized (mLocationListeners) {
+ requestLocationUpdatesLocked(provider, minTime, minDistance,
+ new Receiver(intent, Binder.getCallingUid()));
+ }
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -847,11 +988,10 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void _requestLocationUpdates(String provider,
+ private void requestLocationUpdatesLocked(String provider,
long minTime, float minDistance, Receiver receiver) {
- Object key = receiver.getKey();
if (Config.LOGD) {
- Log.d(TAG, "_requestLocationUpdates: listener = " + key);
+ Log.d(TAG, "_requestLocationUpdates: listener = " + receiver);
}
LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
@@ -859,62 +999,63 @@ public class LocationManagerService extends ILocationManager.Stub {
throw new IllegalArgumentException("provider=" + provider);
}
- checkPermissions(provider);
+ checkPermissionsSafe(provider);
String[] packages = getPackageNames();
// so wakelock calls will succeed
+ final int callingUid = Binder.getCallingUid();
long identity = Binder.clearCallingIdentity();
try {
- UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, packages);
- synchronized (mLocationListeners) {
- if (mListeners.get(key) == null) {
- try {
- if (receiver.isListener()) {
- receiver.getListener().asBinder().linkToDeath(receiver, 0);
- }
- mListeners.put(key, receiver);
- } catch (RemoteException e) {
- return;
+ UpdateRecord r = new UpdateRecord(provider, minTime, minDistance,
+ receiver, callingUid, packages);
+ if (!mListeners.contains(receiver)) {
+ try {
+ if (receiver.isListener()) {
+ receiver.getListener().asBinder().linkToDeath(receiver, 0);
}
+ mListeners.add(receiver);
+ } catch (RemoteException e) {
+ return;
}
+ }
- HashMap<String,UpdateRecord> records = mLocationListeners.get(key);
- if (records == null) {
- records = new HashMap<String,UpdateRecord>();
- mLocationListeners.put(key, records);
- }
- UpdateRecord oldRecord = records.put(provider, r);
- if (oldRecord != null) {
- oldRecord.dispose();
- }
-
- if (impl instanceof NetworkLocationProvider) {
- ((NetworkLocationProvider) impl).addListener(packages);
- }
-
- boolean isProviderEnabled = isAllowedBySettings(provider);
- if (isProviderEnabled) {
- long minTimeForProvider = getMinTime(provider);
- impl.setMinTime(minTimeForProvider);
- impl.enableLocationTracking(true);
- updateWakelockStatus(mScreenOn);
+ HashMap<String,UpdateRecord> records = mLocationListeners.get(receiver);
+ if (records == null) {
+ records = new HashMap<String,UpdateRecord>();
+ mLocationListeners.put(receiver, records);
+ }
+ UpdateRecord oldRecord = records.put(provider, r);
+ if (oldRecord != null) {
+ oldRecord.disposeLocked();
+ }
- // Clear heartbeats if any before starting a new one
- mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
- Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider);
- mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
+ boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
+ if (isProviderEnabled) {
+ long minTimeForProvider = getMinTimeLocked(provider);
+ impl.setMinTime(minTimeForProvider);
+ impl.enableLocationTracking(true);
+ updateWakelockStatusLocked(mScreenOn);
- } else {
- try {
- // Notify the listener that updates are currently disabled
- if (receiver.isListener()) {
- receiver.getListener().onProviderDisabled(provider);
- }
- } catch(RemoteException e) {
- Log.w(TAG, "RemoteException calling onProviderDisabled on " +
- receiver.getListener());
+ if (provider.equals(LocationManager.GPS_PROVIDER)) {
+ if (mGpsNavigating) {
+ updateReportedGpsLocked();
+ }
+ }
+
+ // Clear heartbeats if any before starting a new one
+ mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
+ Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider);
+ mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
+ } else {
+ try {
+ // Notify the listener that updates are currently disabled
+ if (receiver.isListener()) {
+ receiver.getListener().onProviderDisabled(provider);
}
+ } catch(RemoteException e) {
+ Log.w(TAG, "RemoteException calling onProviderDisabled on " +
+ receiver.getListener());
}
}
} finally {
@@ -924,7 +1065,9 @@ public class LocationManagerService extends ILocationManager.Stub {
public void removeUpdates(ILocationListener listener) {
try {
- _removeUpdates(new Receiver(listener));
+ synchronized (mLocationListeners) {
+ removeUpdatesLocked(new Receiver(listener, Binder.getCallingUid()));
+ }
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -934,7 +1077,9 @@ public class LocationManagerService extends ILocationManager.Stub {
public void removeUpdatesPI(PendingIntent intent) {
try {
- _removeUpdates(new Receiver(intent));
+ synchronized (mLocationListeners) {
+ removeUpdatesLocked(new Receiver(intent, Binder.getCallingUid()));
+ }
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -942,72 +1087,75 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void _removeUpdates(Receiver receiver) {
- Object key = receiver.getKey();
+ private void removeUpdatesLocked(Receiver receiver) {
if (Config.LOGD) {
- Log.d(TAG, "_removeUpdates: listener = " + key);
+ Log.d(TAG, "_removeUpdates: listener = " + receiver);
}
// so wakelock calls will succeed
+ final int callingUid = Binder.getCallingUid();
long identity = Binder.clearCallingIdentity();
try {
- synchronized (mLocationListeners) {
- Receiver myReceiver = mListeners.remove(key);
- if ((myReceiver != null) && (myReceiver.isListener())) {
+ int idx = mListeners.indexOf(receiver);
+ if (idx >= 0) {
+ Receiver myReceiver = mListeners.remove(idx);
+ if (myReceiver.isListener()) {
myReceiver.getListener().asBinder().unlinkToDeath(myReceiver, 0);
}
+ }
- // Record which providers were associated with this listener
- HashSet<String> providers = new HashSet<String>();
- HashMap<String,UpdateRecord> oldRecords = mLocationListeners.get(key);
- if (oldRecords != null) {
- // Call dispose() on the obsolete update records.
- for (UpdateRecord record : oldRecords.values()) {
- if (record.mProvider.equals(LocationManager.NETWORK_PROVIDER)) {
- if (mNetworkLocationProvider != null) {
- mNetworkLocationProvider.removeListener(record.mPackages);
- }
+ // Record which providers were associated with this listener
+ HashSet<String> providers = new HashSet<String>();
+ HashMap<String,UpdateRecord> oldRecords = mLocationListeners.get(receiver);
+ if (oldRecords != null) {
+ // Call dispose() on the obsolete update records.
+ for (UpdateRecord record : oldRecords.values()) {
+ if (record.mProvider.equals(LocationManager.NETWORK_PROVIDER)) {
+ if (mNetworkLocationInterface != null) {
+ mNetworkLocationInterface.removeListener(record.mPackages);
}
- record.dispose();
}
- // Accumulate providers
- providers.addAll(oldRecords.keySet());
+ record.disposeLocked();
+ }
+ // Accumulate providers
+ providers.addAll(oldRecords.keySet());
+ }
+
+ mLocationListeners.remove(receiver);
+ mLastFixBroadcast.remove(receiver);
+ mLastStatusBroadcast.remove(receiver);
+
+ // See if the providers associated with this listener have any
+ // other listeners; if one does, inform it of the new smallest minTime
+ // value; if one does not, disable location tracking for it
+ for (String provider : providers) {
+ // If provider is already disabled, don't need to do anything
+ if (!isAllowedBySettingsLocked(provider)) {
+ continue;
}
- mLocationListeners.remove(key);
- mLastFixBroadcast.remove(key);
- mLastStatusBroadcast.remove(key);
-
- // See if the providers associated with this listener have any
- // other listeners; if one does, inform it of the new smallest minTime
- // value; if one does not, disable location tracking for it
- for (String provider : providers) {
- // If provider is already disabled, don't need to do anything
- if (!isAllowedBySettings(provider)) {
- continue;
- }
+ boolean hasOtherListener = false;
+ ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
+ if (recordsForProvider != null && recordsForProvider.size() > 0) {
+ hasOtherListener = true;
+ }
- boolean hasOtherListener = false;
- synchronized (mRecordsByProvider) {
- HashSet<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
- if (recordsForProvider != null && recordsForProvider.size() > 0) {
- hasOtherListener = true;
- }
+ LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
+ if (p != null) {
+ if (hasOtherListener) {
+ p.setMinTime(getMinTimeLocked(provider));
+ } else {
+ mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
+ p.enableLocationTracking(false);
}
-
- LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
- if (p != null) {
- if (hasOtherListener) {
- p.setMinTime(getMinTime(provider));
- } else {
- mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
- p.enableLocationTracking(false);
- }
+
+ if (p == mGpsLocationProvider && mGpsNavigating) {
+ updateReportedGpsLocked();
}
}
-
- updateWakelockStatus(mScreenOn);
}
+
+ updateWakelockStatusLocked(mScreenOn);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1018,7 +1166,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return false;
}
if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
- PackageManager.PERMISSION_GRANTED) {
+ PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
}
@@ -1032,36 +1180,42 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public void removeGpsStatusListener(IGpsStatusListener listener) {
- mGpsLocationProvider.removeGpsStatusListener(listener);
+ synchronized (mLocationListeners) {
+ mGpsLocationProvider.removeGpsStatusListener(listener);
+ }
}
public boolean sendExtraCommand(String provider, String command, Bundle extras) {
// first check for permission to the provider
- checkPermissions(provider);
+ checkPermissionsSafe(provider);
// and check for ACCESS_LOCATION_EXTRA_COMMANDS
if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
!= PackageManager.PERMISSION_GRANTED)) {
throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
}
- LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
- if (provider == null) {
- return false;
+ synchronized (mLocationListeners) {
+ LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
+ if (provider == null) {
+ return false;
+ }
+
+ return impl.sendExtraCommand(command, extras);
}
-
- return impl.sendExtraCommand(command, extras);
}
class ProximityAlert {
- double mLatitude;
- double mLongitude;
- float mRadius;
- long mExpiration;
- PendingIntent mIntent;
- Location mLocation;
-
- public ProximityAlert(double latitude, double longitude,
+ final int mUid;
+ final double mLatitude;
+ final double mLongitude;
+ final float mRadius;
+ final long mExpiration;
+ final PendingIntent mIntent;
+ final Location mLocation;
+
+ public ProximityAlert(int uid, double latitude, double longitude,
float radius, long expiration, PendingIntent intent) {
+ mUid = uid;
mLatitude = latitude;
mLongitude = longitude;
mRadius = radius;
@@ -1073,15 +1227,15 @@ public class LocationManagerService extends ILocationManager.Stub {
mLocation.setLongitude(longitude);
}
- public long getExpiration() {
+ long getExpiration() {
return mExpiration;
}
- public PendingIntent getIntent() {
+ PendingIntent getIntent() {
return mIntent;
}
- public boolean isInProximity(double latitude, double longitude) {
+ boolean isInProximity(double latitude, double longitude) {
Location loc = new Location("");
loc.setLatitude(latitude);
loc.setLongitude(longitude);
@@ -1089,6 +1243,22 @@ public class LocationManagerService extends ILocationManager.Stub {
double radius = loc.distanceTo(mLocation);
return radius <= mRadius;
}
+
+ @Override
+ public String toString() {
+ return "ProximityAlert{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " uid " + mUid + mIntent + "}";
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + this);
+ pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
+ pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
+ pw.println(prefix + "mIntent=" + mIntent);
+ pw.println(prefix + "mLocation:");
+ mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
+ }
}
// Listener for receiving locations to trigger proximity alerts
@@ -1096,6 +1266,7 @@ public class LocationManagerService extends ILocationManager.Stub {
boolean isGpsAvailable = false;
+ // Note: this is called with the lock held.
public void onLocationChanged(Location loc) {
// If Gps is available, then ignore updates from NetworkLocationProvider
@@ -1180,16 +1351,19 @@ public class LocationManagerService extends ILocationManager.Stub {
}
+ // Note: this is called with the lock held.
public void onProviderDisabled(String provider) {
if (provider.equals(LocationManager.GPS_PROVIDER)) {
isGpsAvailable = false;
}
}
+ // Note: this is called with the lock held.
public void onProviderEnabled(String provider) {
// ignore
}
+ // Note: this is called with the lock held.
public void onStatusChanged(String provider, int status, Bundle extras) {
if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
(status != LocationProvider.AVAILABLE)) {
@@ -1201,7 +1375,9 @@ public class LocationManagerService extends ILocationManager.Stub {
public void addProximityAlert(double latitude, double longitude,
float radius, long expiration, PendingIntent intent) {
try {
- _addProximityAlert(latitude, longitude, radius, expiration, intent);
+ synchronized (mLocationListeners) {
+ addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
+ }
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -1209,7 +1385,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void _addProximityAlert(double latitude, double longitude,
+ private void addProximityAlertLocked(double latitude, double longitude,
float radius, long expiration, PendingIntent intent) {
if (Config.LOGD) {
Log.d(TAG, "addProximityAlert: latitude = " + latitude +
@@ -1219,37 +1395,42 @@ public class LocationManagerService extends ILocationManager.Stub {
}
// Require ability to access all providers for now
- if (!isAllowedProvider(LocationManager.GPS_PROVIDER) ||
- !isAllowedProvider(LocationManager.NETWORK_PROVIDER)) {
+ if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
+ !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
}
if (expiration != -1) {
expiration += System.currentTimeMillis();
}
- ProximityAlert alert = new ProximityAlert(latitude, longitude, radius, expiration, intent);
+ ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
+ latitude, longitude, radius, expiration, intent);
mProximityAlerts.put(intent, alert);
if (mProximityListener == null) {
- mProximityListener = new Receiver(new ProximityListener());
+ mProximityListener = new Receiver(new ProximityListener(), -1);
LocationProvider provider = LocationProviderImpl.getProvider(
LocationManager.GPS_PROVIDER);
if (provider != null) {
- _requestLocationUpdates(provider.getName(), 1000L, 1.0f, mProximityListener);
+ requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener);
}
provider =
LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER);
if (provider != null) {
- _requestLocationUpdates(provider.getName(), 1000L, 1.0f, mProximityListener);
+ requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener);
}
+ } else if (mGpsNavigating) {
+ updateReportedGpsLocked();
}
}
public void removeProximityAlert(PendingIntent intent) {
try {
- _removeProximityAlert(intent);
+ synchronized (mLocationListeners) {
+ removeProximityAlertLocked(intent);
+ }
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -1257,15 +1438,17 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void _removeProximityAlert(PendingIntent intent) {
+ private void removeProximityAlertLocked(PendingIntent intent) {
if (Config.LOGD) {
Log.d(TAG, "removeProximityAlert: intent = " + intent);
}
mProximityAlerts.remove(intent);
if (mProximityAlerts.size() == 0) {
- _removeUpdates(mProximityListener);
+ removeUpdatesLocked(mProximityListener);
mProximityListener = null;
+ } else if (mGpsNavigating) {
+ updateReportedGpsLocked();
}
}
@@ -1276,7 +1459,9 @@ public class LocationManagerService extends ILocationManager.Stub {
*/
public Bundle getProviderInfo(String provider) {
try {
- return _getProviderInfo(provider);
+ synchronized (mLocationListeners) {
+ return _getProviderInfoLocked(provider);
+ }
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -1285,13 +1470,13 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private Bundle _getProviderInfo(String provider) {
+ private Bundle _getProviderInfoLocked(String provider) {
LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
if (p == null) {
return null;
}
- checkPermissions(provider);
+ checkPermissionsSafe(provider);
Bundle b = new Bundle();
b.putBoolean("network", p.requiresNetwork());
@@ -1309,7 +1494,9 @@ public class LocationManagerService extends ILocationManager.Stub {
public boolean isProviderEnabled(String provider) {
try {
- return _isProviderEnabled(provider);
+ synchronized (mLocationListeners) {
+ return _isProviderEnabledLocked(provider);
+ }
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -1318,19 +1505,21 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private boolean _isProviderEnabled(String provider) {
- checkPermissions(provider);
+ private boolean _isProviderEnabledLocked(String provider) {
+ checkPermissionsSafe(provider);
LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
if (p == null) {
throw new IllegalArgumentException("provider=" + provider);
}
- return isAllowedBySettings(provider);
+ return isAllowedBySettingsLocked(provider);
}
public Location getLastKnownLocation(String provider) {
try {
- return _getLastKnownLocation(provider);
+ synchronized (mLocationListeners) {
+ return _getLastKnownLocationLocked(provider);
+ }
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -1339,22 +1528,22 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private Location _getLastKnownLocation(String provider) {
- checkPermissions(provider);
+ private Location _getLastKnownLocationLocked(String provider) {
+ checkPermissionsSafe(provider);
LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
if (p == null) {
throw new IllegalArgumentException("provider=" + provider);
}
- if (!isAllowedBySettings(provider)) {
+ if (!isAllowedBySettingsLocked(provider)) {
return null;
}
Location location = mLastKnownLocation.get(provider);
if (location == null) {
// Get the persistent last known location for the provider
- location = readLastKnownLocation(provider);
+ location = readLastKnownLocationLocked(provider);
if (location != null) {
mLastKnownLocation.put(provider, location);
}
@@ -1363,7 +1552,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return location;
}
- private boolean shouldBroadcast(Location loc, Location lastLoc, UpdateRecord record) {
+ private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
// Always broadcast the first update
if (lastLoc == null) {
return true;
@@ -1386,8 +1575,8 @@ public class LocationManagerService extends ILocationManager.Stub {
return true;
}
- private void handleLocationChanged(String provider) {
- HashSet<UpdateRecord> records = mRecordsByProvider.get(provider);
+ private void handleLocationChangedLocked(String provider) {
+ ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
if (records == null || records.size() == 0) {
return;
}
@@ -1424,9 +1613,9 @@ public class LocationManagerService extends ILocationManager.Stub {
} else {
location.set(loc);
}
- writeLastKnownLocation(provider, loc);
+ writeLastKnownLocationLocked(provider, loc);
- if (p instanceof NetworkLocationProvider) {
+ if (p instanceof INetworkLocationProvider) {
mWakeLockNetworkReceived = true;
} else if (p instanceof GpsLocationProvider) {
// Gps location received signal is in NetworkStateBroadcastReceiver
@@ -1459,40 +1648,44 @@ public class LocationManagerService extends ILocationManager.Stub {
extras.putAll(mockExtras);
}
+ ArrayList<Receiver> deadReceivers = null;
+
// Broadcast location or status to all listeners
- for (UpdateRecord r : records) {
+ final int N = records.size();
+ for (int i=0; i<N; i++) {
+ UpdateRecord r = records.get(i);
Receiver receiver = r.mReceiver;
- Object key = receiver.getKey();
// Broadcast location only if it is valid
if (locationValid) {
- HashMap<String,Location> map = mLastFixBroadcast.get(key);
+ HashMap<String,Location> map = mLastFixBroadcast.get(receiver);
if (map == null) {
map = new HashMap<String,Location>();
- mLastFixBroadcast.put(key, map);
+ mLastFixBroadcast.put(receiver, map);
}
Location lastLoc = map.get(provider);
- if ((lastLoc == null) || shouldBroadcast(loc, lastLoc, r)) {
+ if ((lastLoc == null) || shouldBroadcastSafe(loc, lastLoc, r)) {
if (lastLoc == null) {
lastLoc = new Location(loc);
map.put(provider, lastLoc);
} else {
lastLoc.set(loc);
}
- try {
- receiver.onLocationChanged(loc);
- } catch (RemoteException doe) {
+ if (!receiver.callLocationChangedLocked(loc)) {
Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
- _removeUpdates(receiver);
+ if (deadReceivers == null) {
+ deadReceivers = new ArrayList<Receiver>();
+ }
+ deadReceivers.add(receiver);
}
}
}
// Broadcast status message
- HashMap<String,Long> statusMap = mLastStatusBroadcast.get(key);
+ HashMap<String,Long> statusMap = mLastStatusBroadcast.get(receiver);
if (statusMap == null) {
statusMap = new HashMap<String,Long>();
- mLastStatusBroadcast.put(key, statusMap);
+ mLastStatusBroadcast.put(receiver, statusMap);
}
long prevStatusUpdateTime =
(statusMap.get(provider) != null) ? statusMap.get(provider) : 0;
@@ -1501,14 +1694,23 @@ public class LocationManagerService extends ILocationManager.Stub {
(prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
statusMap.put(provider, newStatusUpdateTime);
- try {
- receiver.onStatusChanged(provider, status, extras);
- } catch (RemoteException doe) {
+ if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
- _removeUpdates(receiver);
+ if (deadReceivers == null) {
+ deadReceivers = new ArrayList<Receiver>();
+ }
+ if (!deadReceivers.contains(receiver)) {
+ deadReceivers.add(receiver);
+ }
}
}
}
+
+ if (deadReceivers != null) {
+ for (int i=deadReceivers.size()-1; i>=0; i--) {
+ removeUpdatesLocked(deadReceivers.get(i));
+ }
+ }
}
private class LocationWorkerHandler extends Handler {
@@ -1519,57 +1721,68 @@ public class LocationManagerService extends ILocationManager.Stub {
if (msg.what == MESSAGE_HEARTBEAT) {
// log("LocationWorkerHandler: Heartbeat!");
- synchronized (mRecordsByProvider) {
+ synchronized (mLocationListeners) {
String provider = (String) msg.obj;
- if (!isAllowedBySettings(provider)) {
+ if (!isAllowedBySettingsLocked(provider)) {
return;
}
// Process the location fix if the screen is on or we're holding a wakelock
if (mScreenOn || (mWakeLockAcquireTime != 0)) {
- handleLocationChanged(provider);
+ handleLocationChangedLocked(provider);
}
// If it continues to have listeners
- HashSet<UpdateRecord> records = mRecordsByProvider.get(provider);
+ ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
if (records != null && records.size() > 0) {
Message m = Message.obtain(this, MESSAGE_HEARTBEAT, provider);
sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
}
- }
-
- if ((mWakeLockAcquireTime != 0) &&
- (SystemClock.elapsedRealtime() - mWakeLockAcquireTime
- > MAX_TIME_FOR_WAKE_LOCK)) {
-
- removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
- removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
-
- log("LocationWorkerHandler: Exceeded max time for wake lock");
- Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
- sendMessageAtFrontOfQueue(m);
-
- } else if (mWakeLockAcquireTime != 0 &&
- mWakeLockGpsReceived && mWakeLockNetworkReceived) {
-
- removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
- removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
- log("LocationWorkerHandler: Locations received.");
- mWakeLockAcquireTime = 0;
- Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
- sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK);
+ if ((mWakeLockAcquireTime != 0) &&
+ (SystemClock.elapsedRealtime() - mWakeLockAcquireTime
+ > MAX_TIME_FOR_WAKE_LOCK)) {
+
+ removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
+ removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
+
+ log("LocationWorkerHandler: Exceeded max time for wake lock");
+ Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
+ sendMessageAtFrontOfQueue(m);
+
+ } else if (mWakeLockAcquireTime != 0 &&
+ mWakeLockGpsReceived && mWakeLockNetworkReceived) {
+
+ removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
+ removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
+
+ log("LocationWorkerHandler: Locations received.");
+ mWakeLockAcquireTime = 0;
+ Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
+ sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK);
+ }
}
} else if (msg.what == MESSAGE_ACQUIRE_WAKE_LOCK) {
log("LocationWorkerHandler: Acquire");
- acquireWakeLock();
+ synchronized (mLocationListeners) {
+ acquireWakeLockLocked();
+ }
} else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) {
log("LocationWorkerHandler: Release");
// Update wakelock status so the next alarm is set before releasing wakelock
- updateWakelockStatus(mScreenOn);
- releaseWakeLock();
+ synchronized (mLocationListeners) {
+ updateWakelockStatusLocked(mScreenOn);
+ releaseWakeLockLocked();
+ }
+ } else if (msg.what == MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER) {
+ synchronized (mLocationListeners) {
+ Log.d(TAG, "installing network location provider");
+ INetworkLocationManager.InstallCallback callback =
+ (INetworkLocationManager.InstallCallback)msg.obj;
+ callback.installNetworkLocationProvider(LocationManagerService.this);
+ }
}
} catch (Exception e) {
// Log, don't crash!
@@ -1578,45 +1791,113 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
+ class CellLocationUpdater extends Thread {
+ CellLocation mNextLocation;
+
+ CellLocationUpdater() {
+ super("CellLocationUpdater");
+ }
+
+ @Override
+ public void run() {
+ int curAsu = -1;
+ CellLocation curLocation = null;
+
+ while (true) {
+ // See if there is more work to do...
+ synchronized (mLocationListeners) {
+ if (curLocation == mNextLocation) {
+ mCellLocationUpdater = null;
+ break;
+ }
+
+ curLocation = mNextLocation;
+ if (curLocation == null) {
+ mCellLocationUpdater = null;
+ break;
+ }
+
+ curAsu = mLastSignalStrength;
+
+ mNextLocation = null;
+ }
+
+ try {
+ // Gets cell state. This can block so must be done without
+ // locks held.
+ CellState cs = new CellState(mTelephonyManager, curLocation, curAsu);
+
+ synchronized (mLocationListeners) {
+ mLastCellState = cs;
+
+ cs.updateSignalStrength(mLastSignalStrength);
+ cs.updateRadioType(mLastRadioType);
+
+ // Notify collector
+ if (mCollector != null) {
+ mCollector.updateCellState(cs);
+ }
+
+ // Updates providers
+ List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
+ for (LocationProviderImpl provider : providers) {
+ if (provider.requiresCell()) {
+ provider.updateCellState(cs);
+ }
+ }
+ }
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Exception in PhoneStateListener.onCellLocationChanged:", e);
+ }
+ }
+ }
+ }
+
+ CellLocationUpdater mCellLocationUpdater = null;
+ CellState mLastCellState = null;
+ int mLastSignalStrength = -1;
+ int mLastRadioType = -1;
+
PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
- private CellState mLastCellState = null;
@Override
public void onCellLocationChanged(CellLocation cellLocation) {
- try {
- int asu = mSignalStrength;
-
- // Gets cell state
- mLastCellState = new CellState(mTelephonyManager, cellLocation, asu);
-
- // Notify collector
- mCollector.updateCellState(mLastCellState);
-
- // Updates providers
- List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
- for (LocationProviderImpl provider : providers) {
- if (provider.requiresCell()) {
- provider.updateCellState(mLastCellState);
- }
+ synchronized (mLocationListeners) {
+ if (mCellLocationUpdater == null) {
+ mCellLocationUpdater = new CellLocationUpdater();
+ mCellLocationUpdater.start();
}
- } catch (Exception e) {
- Log.e(TAG, "Exception in PhoneStateListener.onCellLocationCahnged:", e);
+ mCellLocationUpdater.mNextLocation = cellLocation;
}
}
@Override
public void onSignalStrengthChanged(int asu) {
- mSignalStrength = asu;
-
- if (mLastCellState != null) {
- mLastCellState.updateSignalStrength(asu);
+ synchronized (mLocationListeners) {
+ mLastSignalStrength = asu;
+
+ if (mLastCellState != null) {
+ mLastCellState.updateSignalStrength(asu);
+ }
}
}
@Override
public void onDataConnectionStateChanged(int state) {
- if (mLastCellState != null) {
- mLastCellState.updateRadioType(mTelephonyManager);
+ synchronized (mLocationListeners) {
+ // Get radio type
+ int radioType = mTelephonyManager.getNetworkType();
+ if (radioType == TelephonyManager.NETWORK_TYPE_GPRS ||
+ radioType == TelephonyManager.NETWORK_TYPE_EDGE) {
+ radioType = CellState.RADIO_TYPE_GPRS;
+ } else if (radioType == TelephonyManager.NETWORK_TYPE_UMTS) {
+ radioType = CellState.RADIO_TYPE_WCDMA;
+ }
+ mLastRadioType = radioType;
+
+ if (mLastCellState != null) {
+ mLastCellState.updateRadioType(radioType);
+ }
}
}
};
@@ -1626,29 +1907,82 @@ public class LocationManagerService extends ILocationManager.Stub {
String action = intent.getAction();
if (action.equals(ALARM_INTENT)) {
- mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
- mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
-
- log("PowerStateBroadcastReceiver: Alarm received");
- Message m = mLocationHandler.obtainMessage(MESSAGE_ACQUIRE_WAKE_LOCK);
- mLocationHandler.sendMessageAtFrontOfQueue(m);
+ synchronized (mLocationListeners) {
+ log("PowerStateBroadcastReceiver: Alarm received");
+ mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
+ // Have to do this immediately, rather than posting a
+ // message, so we execute our code while the system
+ // is holding a wake lock until the alarm broadcast
+ // is finished.
+ acquireWakeLockLocked();
+ }
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
log("PowerStateBroadcastReceiver: Screen off");
- updateWakelockStatus(false);
+ synchronized (mLocationListeners) {
+ updateWakelockStatusLocked(false);
+ }
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
log("PowerStateBroadcastReceiver: Screen on");
- updateWakelockStatus(true);
+ synchronized (mLocationListeners) {
+ updateWakelockStatusLocked(true);
+ }
} else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
log("PowerStateBroadcastReceiver: Battery changed");
- int scale = intent.getIntExtra(BATTERY_EXTRA_SCALE, 100);
- int level = intent.getIntExtra(BATTERY_EXTRA_LEVEL, 0);
- boolean plugged = intent.getIntExtra(BATTERY_EXTRA_PLUGGED, 0) != 0;
-
- // Notify collector battery state
- mCollector.updateBatteryState(scale, level, plugged);
+ synchronized (mLocationListeners) {
+ int scale = intent.getIntExtra(BATTERY_EXTRA_SCALE, 100);
+ int level = intent.getIntExtra(BATTERY_EXTRA_LEVEL, 0);
+ boolean plugged = intent.getIntExtra(BATTERY_EXTRA_PLUGGED, 0) != 0;
+
+ // Notify collector battery state
+ if (mCollector != null) {
+ mCollector.updateBatteryState(scale, level, plugged);
+ }
+ }
+ } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
+ || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
+ synchronized (mLocationListeners) {
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (uid >= 0) {
+ ArrayList<Receiver> removedRecs = null;
+ for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
+ for (int j=i.size()-1; j>=0; j--) {
+ UpdateRecord ur = i.get(j);
+ if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
+ if (removedRecs == null) {
+ removedRecs = new ArrayList<Receiver>();
+ }
+ if (!removedRecs.contains(ur.mReceiver)) {
+ removedRecs.add(ur.mReceiver);
+ }
+ }
+ }
+ }
+ ArrayList<ProximityAlert> removedAlerts = null;
+ for (ProximityAlert i : mProximityAlerts.values()) {
+ if (i.mUid == uid) {
+ if (removedAlerts == null) {
+ removedAlerts = new ArrayList<ProximityAlert>();
+ }
+ if (!removedAlerts.contains(i)) {
+ removedAlerts.add(i);
+ }
+ }
+ }
+ if (removedRecs != null) {
+ for (int i=removedRecs.size()-1; i>=0; i--) {
+ removeUpdatesLocked(removedRecs.get(i));
+ }
+ }
+ if (removedAlerts != null) {
+ for (int i=removedAlerts.size()-1; i>=0; i--) {
+ removeProximityAlertLocked(removedAlerts.get(i).mIntent);
+ }
+ }
+ }
+ }
}
}
}
@@ -1666,25 +2000,31 @@ public class LocationManagerService extends ILocationManager.Stub {
}
// Notify provider and collector of Wifi scan results
- mCollector.updateWifiScanResults(wifiScanResults);
- if (mNetworkLocationProvider != null) {
- mNetworkLocationProvider.updateWifiScanResults(wifiScanResults);
+ synchronized (mLocationListeners) {
+ if (mCollector != null) {
+ mCollector.updateWifiScanResults(wifiScanResults);
+ }
+ if (mNetworkLocationInterface != null) {
+ mNetworkLocationInterface.updateWifiScanResults(wifiScanResults);
+ }
}
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
- int networkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
-
boolean noConnectivity =
intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if (!noConnectivity) {
- networkState = LocationProvider.AVAILABLE;
+ mNetworkState = LocationProvider.AVAILABLE;
+ } else {
+ mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
}
// Notify location providers of current network state
- List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
- for (LocationProviderImpl provider : providers) {
- if (provider.requiresNetwork()) {
- provider.updateNetworkState(networkState);
+ synchronized (mLocationListeners) {
+ List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
+ for (LocationProviderImpl provider : providers) {
+ if (provider.requiresNetwork()) {
+ provider.updateNetworkState(mNetworkState);
+ }
}
}
@@ -1692,18 +2032,19 @@ public class LocationManagerService extends ILocationManager.Stub {
int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN);
- boolean enabled;
if (state == WifiManager.WIFI_STATE_ENABLED) {
- enabled = true;
+ mWifiEnabled = true;
} else if (state == WifiManager.WIFI_STATE_DISABLED) {
- enabled = false;
+ mWifiEnabled = false;
} else {
return;
}
// Notify network provider of current wifi enabled state
- if (mNetworkLocationProvider != null) {
- mNetworkLocationProvider.updateWifiEnabledState(enabled);
+ synchronized (mLocationListeners) {
+ if (mNetworkLocationInterface != null) {
+ mNetworkLocationInterface.updateWifiEnabledState(mWifiEnabled);
+ }
}
} else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) {
@@ -1711,9 +2052,16 @@ public class LocationManagerService extends ILocationManager.Stub {
final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED,
false);
- if (!enabled) {
- // When GPS is disabled, we are OK to release wake-lock
- mWakeLockGpsReceived = true;
+ synchronized (mLocationListeners) {
+ if (enabled) {
+ updateReportedGpsLocked();
+ mGpsNavigating = true;
+ } else {
+ reportStopGpsLocked();
+ mGpsNavigating = false;
+ // When GPS is disabled, we are OK to release wake-lock
+ mWakeLockGpsReceived = true;
+ }
}
}
@@ -1722,7 +2070,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// Wake locks
- private void updateWakelockStatus(boolean screenOn) {
+ private void updateWakelockStatusLocked(boolean screenOn) {
log("updateWakelockStatus(): " + screenOn);
boolean needsLock = false;
@@ -1737,11 +2085,10 @@ public class LocationManagerService extends ILocationManager.Stub {
needsLock = true;
minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime);
if (screenOn) {
- startGps();
+ startGpsLocked();
} else if (mScreenOn && !screenOn) {
-
// We just turned the screen off so stop navigating
- stopGps();
+ stopGpsLocked();
}
}
@@ -1767,13 +2114,13 @@ public class LocationManagerService extends ILocationManager.Stub {
// Clear out existing wakelocks
mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
- releaseWakeLock();
+ releaseWakeLockLocked();
}
}
- private void acquireWakeLock() {
+ private void acquireWakeLockLocked() {
try {
- acquireWakeLockX();
+ acquireWakeLockXLocked();
} catch (Exception e) {
// This is to catch a runtime exception thrown when we try to release an
// already released lock.
@@ -1781,7 +2128,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void acquireWakeLockX() {
+ private void acquireWakeLockXLocked() {
if (mWakeLock.isHeld()) {
log("Must release wakelock before acquiring");
mWakeLockAcquireTime = 0;
@@ -1808,7 +2155,7 @@ public class LocationManagerService extends ILocationManager.Stub {
log("Acquired wakelock");
// Start the gps provider
- startGps();
+ startGpsLocked();
// Acquire cell lock
if (mCellWakeLockAcquired) {
@@ -1821,12 +2168,12 @@ public class LocationManagerService extends ILocationManager.Stub {
}
// Notify NetworkLocationProvider
- if (mNetworkLocationProvider != null) {
- mNetworkLocationProvider.updateCellLockStatus(mCellWakeLockAcquired);
+ if (mNetworkLocationInterface != null) {
+ mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired);
}
// Acquire wifi lock
- WifiManager.WifiLock wifiLock = getWifiWakelock();
+ WifiManager.WifiLock wifiLock = getWifiWakelockLocked();
if (wifiLock != null) {
if (mWifiWakeLockAcquired) {
// Lock is already acquired
@@ -1840,7 +2187,86 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void startGps() {
+ private boolean reportGpsUidLocked(int curSeq, int nextSeq, int uid) {
+ int seq = mReportedGpsUids.get(uid, -1);
+ if (seq == curSeq) {
+ // Already reported; propagate to next sequence.
+ mReportedGpsUids.put(uid, nextSeq);
+ return true;
+ } else if (seq != nextSeq) {
+ try {
+ // New UID; report it.
+ mBatteryStats.noteStartGps(uid);
+ mReportedGpsUids.put(uid, nextSeq);
+ return true;
+ } catch (RemoteException e) {
+ }
+ }
+ return false;
+ }
+
+ private void updateReportedGpsLocked() {
+ if (mGpsLocationProvider == null) {
+ return;
+ }
+
+ final String name = mGpsLocationProvider.getName();
+ final int curSeq = mReportedGpsSeq;
+ final int nextSeq = (curSeq+1) >= 0 ? (curSeq+1) : 0;
+ mReportedGpsSeq = nextSeq;
+
+ ArrayList<UpdateRecord> urs = mRecordsByProvider.get(name);
+ int num = 0;
+ final int N = urs.size();
+ for (int i=0; i<N; i++) {
+ UpdateRecord ur = urs.get(i);
+ if (ur.mReceiver == mProximityListener) {
+ // We don't want the system to take the blame for this one.
+ continue;
+ }
+ if (reportGpsUidLocked(curSeq, nextSeq, ur.mUid)) {
+ num++;
+ }
+ }
+
+ for (ProximityAlert pe : mProximityAlerts.values()) {
+ if (reportGpsUidLocked(curSeq, nextSeq, pe.mUid)) {
+ num++;
+ }
+ }
+
+ if (num != mReportedGpsUids.size()) {
+ // The number of uids is processed is different than the
+ // array; report any that are no longer active.
+ for (int i=mReportedGpsUids.size()-1; i>=0; i--) {
+ if (mReportedGpsUids.valueAt(i) != nextSeq) {
+ try {
+ mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i));
+ } catch (RemoteException e) {
+ }
+ mReportedGpsUids.removeAt(i);
+ }
+ }
+ }
+ }
+
+ private void reportStopGpsLocked() {
+ int curSeq = mReportedGpsSeq;
+ for (int i=mReportedGpsUids.size()-1; i>=0; i--) {
+ if (mReportedGpsUids.valueAt(i) == curSeq) {
+ try {
+ mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i));
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ curSeq++;
+ if (curSeq < 0) curSeq = 0;
+ mReportedGpsSeq = curSeq;
+ mReportedGpsUids.clear();
+ }
+
+ private void startGpsLocked() {
boolean gpsActive = (mGpsLocationProvider != null)
&& mGpsLocationProvider.isLocationTracking();
if (gpsActive) {
@@ -1848,7 +2274,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void stopGps() {
+ private void stopGpsLocked() {
boolean gpsActive = mGpsLocationProvider != null
&& mGpsLocationProvider.isLocationTracking();
if (gpsActive) {
@@ -1856,9 +2282,9 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void releaseWakeLock() {
+ private void releaseWakeLockLocked() {
try {
- releaseWakeLockX();
+ releaseWakeLockXLocked();
} catch (Exception e) {
// This is to catch a runtime exception thrown when we try to release an
// already released lock.
@@ -1866,9 +2292,9 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void releaseWakeLockX() {
+ private void releaseWakeLockXLocked() {
// Release wifi lock
- WifiManager.WifiLock wifiLock = getWifiWakelock();
+ WifiManager.WifiLock wifiLock = getWifiWakelockLocked();
if (wifiLock != null) {
if (mWifiWakeLockAcquired) {
wifiLock.release();
@@ -1877,9 +2303,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
if (!mScreenOn) {
-
// Stop the gps
- stopGps();
+ stopGpsLocked();
}
// Release cell lock
@@ -1889,8 +2314,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
// Notify NetworkLocationProvider
- if (mNetworkLocationProvider != null) {
- mNetworkLocationProvider.updateCellLockStatus(mCellWakeLockAcquired);
+ if (mNetworkLocationInterface != null) {
+ mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired);
}
// Release wake lock
@@ -1907,15 +2332,13 @@ public class LocationManagerService extends ILocationManager.Stub {
public String getFromLocation(double latitude, double longitude, int maxResults,
String language, String country, String variant, String appName, List<Address> addrs) {
- try {
- Locale locale = new Locale(language, country, variant);
- mMasfClient.reverseGeocode(locale, appName, latitude, longitude, maxResults, addrs);
- return null;
- } catch(IOException e) {
- return e.getMessage();
- } catch(Exception e) {
- Log.e(TAG, "getFromLocation got exception:", e);
- return null;
+ synchronized (mLocationListeners) {
+ if (mNetworkLocationInterface != null) {
+ return mNetworkLocationInterface.getFromLocation(latitude, longitude, maxResults,
+ language, country, variant, appName, addrs);
+ } else {
+ return null;
+ }
}
}
@@ -1923,18 +2346,14 @@ public class LocationManagerService extends ILocationManager.Stub {
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude, int maxResults,
String language, String country, String variant, String appName, List<Address> addrs) {
-
- try {
- Locale locale = new Locale(language, country, variant);
- mMasfClient.forwardGeocode(locale, appName, locationName,
- lowerLeftLatitude, lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, addrs);
- return null;
- } catch(IOException e) {
- return e.getMessage();
- } catch(Exception e) {
- Log.e(TAG, "getFromLocationName got exception:", e);
- return null;
+ synchronized (mLocationListeners) {
+ if (mNetworkLocationInterface != null) {
+ return mNetworkLocationInterface.getFromLocationName(locationName, lowerLeftLatitude,
+ lowerLeftLongitude, upperRightLatitude, upperRightLongitude, maxResults,
+ language, country, variant, appName, addrs);
+ } else {
+ return null;
+ }
}
}
@@ -1970,43 +2389,63 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void disable() {
String name = getName();
- mEnabledProviders.remove(name);
- mDisabledProviders.add(name);
+ // We shouldn't normally need to lock, since this should only be called
+ // by the service with the lock held, but let's be paranid.
+ synchronized (mLocationListeners) {
+ mEnabledProviders.remove(name);
+ mDisabledProviders.add(name);
+ }
}
@Override
public void enable() {
String name = getName();
- mEnabledProviders.add(name);
- mDisabledProviders.remove(name);
+ // We shouldn't normally need to lock, since this should only be called
+ // by the service with the lock held, but let's be paranid.
+ synchronized (mLocationListeners) {
+ mEnabledProviders.add(name);
+ mDisabledProviders.remove(name);
+ }
}
@Override
public boolean getLocation(Location l) {
- Location loc = mMockProviderLocation.get(getName());
- if (loc == null) {
- return false;
+ // We shouldn't normally need to lock, since this should only be called
+ // by the service with the lock held, but let's be paranid.
+ synchronized (mLocationListeners) {
+ Location loc = mMockProviderLocation.get(getName());
+ if (loc == null) {
+ return false;
+ }
+ l.set(loc);
+ return true;
}
- l.set(loc);
- return true;
}
@Override
public int getStatus(Bundle extras) {
- String name = getName();
- Integer s = mMockProviderStatus.get(name);
- int status = (s == null) ? AVAILABLE : s.intValue();
- Bundle newExtras = mMockProviderStatusExtras.get(name);
- if (newExtras != null) {
- extras.clear();
- extras.putAll(newExtras);
+ // We shouldn't normally need to lock, since this should only be called
+ // by the service with the lock held, but let's be paranid.
+ synchronized (mLocationListeners) {
+ String name = getName();
+ Integer s = mMockProviderStatus.get(name);
+ int status = (s == null) ? AVAILABLE : s.intValue();
+ Bundle newExtras = mMockProviderStatusExtras.get(name);
+ if (newExtras != null) {
+ extras.clear();
+ extras.putAll(newExtras);
+ }
+ return status;
}
- return status;
}
@Override
public boolean isEnabled() {
- return mEnabledProviders.contains(getName());
+ // We shouldn't normally need to lock, since this should only be called
+ // by the service with the lock held, but let's be paranid.
+ synchronized (mLocationListeners) {
+ return mEnabledProviders.contains(getName());
+ }
}
@Override
@@ -2055,14 +2494,9 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void checkMockPermissions() {
- boolean allowMocks = false;
- try {
- allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.ALLOW_MOCK_LOCATION) == 1;
- } catch (SettingNotFoundException e) {
- // Do nothing
- }
+ private void checkMockPermissionsSafe() {
+ boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
if (!allowMocks) {
throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
}
@@ -2076,87 +2510,103 @@ public class LocationManagerService extends ILocationManager.Stub {
public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
- checkMockPermissions();
-
- MockProvider provider = new MockProvider(name, requiresNetwork, requiresSatellite,
- requiresCell, hasMonetaryCost, supportsAltitude,
- supportsSpeed, supportsBearing, powerRequirement, accuracy);
- if (LocationProviderImpl.getProvider(name) != null) {
- throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
+ checkMockPermissionsSafe();
+
+ synchronized (mLocationListeners) {
+ MockProvider provider = new MockProvider(name, requiresNetwork, requiresSatellite,
+ requiresCell, hasMonetaryCost, supportsAltitude,
+ supportsSpeed, supportsBearing, powerRequirement, accuracy);
+ if (LocationProviderImpl.getProvider(name) != null) {
+ throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
+ }
+ LocationProviderImpl.addProvider(provider);
+ updateProvidersLocked();
}
- LocationProviderImpl.addProvider(provider);
- updateProviders();
}
public void removeTestProvider(String provider) {
- checkMockPermissions();
- LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
- if (p == null) {
- throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ checkMockPermissionsSafe();
+ synchronized (mLocationListeners) {
+ LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
+ if (p == null) {
+ throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ }
+ LocationProviderImpl.removeProvider(p);
+ updateProvidersLocked();
}
- LocationProviderImpl.removeProvider(p);
- updateProviders();
}
public void setTestProviderLocation(String provider, Location loc) {
- checkMockPermissions();
- if (LocationProviderImpl.getProvider(provider) == null) {
- throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ checkMockPermissionsSafe();
+ synchronized (mLocationListeners) {
+ if (LocationProviderImpl.getProvider(provider) == null) {
+ throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ }
+ mMockProviderLocation.put(provider, loc);
}
- mMockProviderLocation.put(provider, loc);
}
public void clearTestProviderLocation(String provider) {
- checkMockPermissions();
- if (LocationProviderImpl.getProvider(provider) == null) {
- throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ checkMockPermissionsSafe();
+ synchronized (mLocationListeners) {
+ if (LocationProviderImpl.getProvider(provider) == null) {
+ throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ }
+ mMockProviderLocation.remove(provider);
}
- mMockProviderLocation.remove(provider);
}
public void setTestProviderEnabled(String provider, boolean enabled) {
- checkMockPermissions();
- if (LocationProviderImpl.getProvider(provider) == null) {
- throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
- }
- if (enabled) {
- mEnabledProviders.add(provider);
- mDisabledProviders.remove(provider);
- } else {
- mEnabledProviders.remove(provider);
- mDisabledProviders.add(provider);
+ checkMockPermissionsSafe();
+ synchronized (mLocationListeners) {
+ if (LocationProviderImpl.getProvider(provider) == null) {
+ throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ }
+ if (enabled) {
+ mEnabledProviders.add(provider);
+ mDisabledProviders.remove(provider);
+ } else {
+ mEnabledProviders.remove(provider);
+ mDisabledProviders.add(provider);
+ }
+ updateProvidersLocked();
}
- updateProviders();
}
public void clearTestProviderEnabled(String provider) {
- checkMockPermissions();
- if (LocationProviderImpl.getProvider(provider) == null) {
- throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ checkMockPermissionsSafe();
+ synchronized (mLocationListeners) {
+ if (LocationProviderImpl.getProvider(provider) == null) {
+ throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ }
+ mEnabledProviders.remove(provider);
+ mDisabledProviders.remove(provider);
+ updateProvidersLocked();
}
- mEnabledProviders.remove(provider);
- mDisabledProviders.remove(provider);
- updateProviders();
}
public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
- checkMockPermissions();
- if (LocationProviderImpl.getProvider(provider) == null) {
- throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ checkMockPermissionsSafe();
+ synchronized (mLocationListeners) {
+ if (LocationProviderImpl.getProvider(provider) == null) {
+ throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ }
+ mMockProviderStatus.put(provider, new Integer(status));
+ mMockProviderStatusExtras.put(provider, extras);
+ mMockProviderStatusUpdateTime.put(provider, new Long(updateTime));
}
- mMockProviderStatus.put(provider, new Integer(status));
- mMockProviderStatusExtras.put(provider, extras);
- mMockProviderStatusUpdateTime.put(provider, new Long(updateTime));
}
public void clearTestProviderStatus(String provider) {
- checkMockPermissions();
- if (LocationProviderImpl.getProvider(provider) == null) {
- throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ checkMockPermissionsSafe();
+ synchronized (mLocationListeners) {
+ if (LocationProviderImpl.getProvider(provider) == null) {
+ throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ }
+ mMockProviderStatus.remove(provider);
+ mMockProviderStatusExtras.remove(provider);
+ mMockProviderStatusUpdateTime.remove(provider);
}
- mMockProviderStatus.remove(provider);
- mMockProviderStatusExtras.remove(provider);
- mMockProviderStatusUpdateTime.remove(provider);
}
private void log(String log) {
@@ -2164,5 +2614,157 @@ public class LocationManagerService extends ILocationManager.Stub {
Log.d(TAG, log);
}
}
+
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump AlarmManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ synchronized (mLocationListeners) {
+ pw.println("Current Location Manager state:");
+ pw.println(" sProvidersLoaded=" + sProvidersLoaded);
+ pw.println(" mGpsLocationProvider=" + mGpsLocationProvider);
+ pw.println(" mGpsNavigating=" + mGpsNavigating);
+ pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider);
+ pw.println(" mNetworkLocationInterface=" + mNetworkLocationInterface);
+ pw.println(" mLastSignalStrength=" + mLastSignalStrength
+ + " mLastRadioType=" + mLastRadioType);
+ pw.println(" mCellLocationUpdater=" + mCellLocationUpdater);
+ pw.println(" mLastCellState=" + mLastCellState);
+ pw.println(" mCollector=" + mCollector);
+ pw.println(" mAlarmInterval=" + mAlarmInterval
+ + " mScreenOn=" + mScreenOn
+ + " mWakeLockAcquireTime=" + mWakeLockAcquireTime);
+ pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived
+ + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived);
+ pw.println(" mWifiWakeLockAcquired=" + mWifiWakeLockAcquired
+ + " mCellWakeLockAcquired=" + mCellWakeLockAcquired);
+ pw.println(" Listeners:");
+ int N = mListeners.size();
+ for (int i=0; i<N; i++) {
+ pw.println(" " + mListeners.get(i));
+ }
+ pw.println(" Location Listeners:");
+ for (Map.Entry<Receiver, HashMap<String,UpdateRecord>> i
+ : mLocationListeners.entrySet()) {
+ pw.println(" " + i.getKey() + ":");
+ for (Map.Entry<String,UpdateRecord> j : i.getValue().entrySet()) {
+ pw.println(" " + j.getKey() + ":");
+ j.getValue().dump(pw, " ");
+ }
+ }
+ pw.println(" Last Fix Broadcasts:");
+ for (Map.Entry<Receiver, HashMap<String,Location>> i
+ : mLastFixBroadcast.entrySet()) {
+ pw.println(" " + i.getKey() + ":");
+ for (Map.Entry<String,Location> j : i.getValue().entrySet()) {
+ pw.println(" " + j.getKey() + ":");
+ j.getValue().dump(new PrintWriterPrinter(pw), " ");
+ }
+ }
+ pw.println(" Last Status Broadcasts:");
+ for (Map.Entry<Receiver, HashMap<String,Long>> i
+ : mLastStatusBroadcast.entrySet()) {
+ pw.println(" " + i.getKey() + ":");
+ for (Map.Entry<String,Long> j : i.getValue().entrySet()) {
+ pw.println(" " + j.getKey() + " -> 0x"
+ + Long.toHexString(j.getValue()));
+ }
+ }
+ pw.println(" Records by Provider:");
+ for (Map.Entry<String, ArrayList<UpdateRecord>> i
+ : mRecordsByProvider.entrySet()) {
+ pw.println(" " + i.getKey() + ":");
+ for (UpdateRecord j : i.getValue()) {
+ pw.println(" " + j + ":");
+ j.dump(pw, " ");
+ }
+ }
+ pw.println(" Locations by Provider:");
+ for (Map.Entry<String, Location> i
+ : mLocationsByProvider.entrySet()) {
+ pw.println(" " + i.getKey() + ":");
+ i.getValue().dump(new PrintWriterPrinter(pw), " ");
+ }
+ pw.println(" Last Known Locations:");
+ for (Map.Entry<String, Location> i
+ : mLastKnownLocation.entrySet()) {
+ pw.println(" " + i.getKey() + ":");
+ i.getValue().dump(new PrintWriterPrinter(pw), " ");
+ }
+ if (mProximityAlerts.size() > 0) {
+ pw.println(" Proximity Alerts:");
+ for (Map.Entry<PendingIntent, ProximityAlert> i
+ : mProximityAlerts.entrySet()) {
+ pw.println(" " + i.getKey() + ":");
+ i.getValue().dump(pw, " ");
+ }
+ }
+ if (mProximitiesEntered.size() > 0) {
+ pw.println(" Proximities Entered:");
+ for (ProximityAlert i : mProximitiesEntered) {
+ pw.println(" " + i + ":");
+ i.dump(pw, " ");
+ }
+ }
+ pw.println(" mProximityListener=" + mProximityListener);
+ if (mEnabledProviders.size() > 0) {
+ pw.println(" Enabled Providers:");
+ for (String i : mEnabledProviders) {
+ pw.println(" " + i);
+ }
+
+ }
+ if (mDisabledProviders.size() > 0) {
+ pw.println(" Disabled Providers:");
+ for (String i : mDisabledProviders) {
+ pw.println(" " + i);
+ }
+
+ }
+ if (mMockProviders.size() > 0) {
+ pw.println(" Mock Providers:");
+ for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
+ pw.println(" " + i.getKey() + " -> " + i.getValue());
+ }
+ }
+ if (mMockProviderLocation.size() > 0) {
+ pw.println(" Mock Provider Location:");
+ for (Map.Entry<String, Location> i : mMockProviderLocation.entrySet()) {
+ pw.println(" " + i.getKey() + ":");
+ i.getValue().dump(new PrintWriterPrinter(pw), " ");
+ }
+ }
+ if (mMockProviderStatus.size() > 0) {
+ pw.println(" Mock Provider Status:");
+ for (Map.Entry<String, Integer> i : mMockProviderStatus.entrySet()) {
+ pw.println(" " + i.getKey() + " -> 0x"
+ + Integer.toHexString(i.getValue()));
+ }
+ }
+ if (mMockProviderStatusExtras.size() > 0) {
+ pw.println(" Mock Provider Status Extras:");
+ for (Map.Entry<String, Bundle> i : mMockProviderStatusExtras.entrySet()) {
+ pw.println(" " + i.getKey() + " -> " + i.getValue());
+ }
+ }
+ if (mMockProviderStatusUpdateTime.size() > 0) {
+ pw.println(" Mock Provider Status Update Time:");
+ for (Map.Entry<String, Long> i : mMockProviderStatusUpdateTime.entrySet()) {
+ pw.println(" " + i.getKey() + " -> " + i.getValue());
+ }
+ }
+ pw.println(" Reported GPS UIDs @ seq " + mReportedGpsSeq + ":");
+ N = mReportedGpsUids.size();
+ for (int i=0; i<N; i++) {
+ pw.println(" UID " + mReportedGpsUids.keyAt(i)
+ + " seq=" + mReportedGpsUids.valueAt(i));
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/MountListener.java b/services/java/com/android/server/MountListener.java
index 40d1b72..2e430c8 100644
--- a/services/java/com/android/server/MountListener.java
+++ b/services/java/com/android/server/MountListener.java
@@ -30,7 +30,7 @@ import java.io.OutputStream;
import java.net.Socket;
/**
- * Thread for communicating with the mount service daemon via a local socket.
+ * Thread for communicating with the vol service daemon via a local socket.
* Events received from the daemon are passed to the MountService instance,
* and the MountService instance calls MountListener to send commands to the daemon.
*/
@@ -38,39 +38,43 @@ final class MountListener implements Runnable {
private static final String TAG = "MountListener";
- // ** THE FOLLOWING STRING CONSTANTS MUST MATCH VALUES IN system/mountd/mountd.h
+ // ** THE FOLLOWING STRING CONSTANTS MUST MATCH VALUES IN system/vold/
- // socket name for connecting to mountd
- private static final String MOUNTD_SOCKET = "mountd";
+ // socket name for connecting to vold
+ private static final String VOLD_SOCKET = "vold";
- // mountd commands
- private static final String MOUNTD_ENABLE_UMS = "enable_ums";
- private static final String MOUNTD_DISABLE_UMS = "disable_ums";
- private static final String MOUNTD_SEND_STATUS = "send_status";
- private static final String MOUNTD_MOUNT_MEDIA = "mount_media:";
- private static final String MOUNTD_EJECT_MEDIA = "eject_media:";
+ // vold commands
+ private static final String VOLD_CMD_ENABLE_UMS = "enable_ums";
+ private static final String VOLD_CMD_DISABLE_UMS = "disable_ums";
+ private static final String VOLD_CMD_SEND_UMS_STATUS = "send_ums_status";
+ private static final String VOLD_CMD_MOUNT_VOLUME = "mount_volume:";
+ private static final String VOLD_CMD_EJECT_MEDIA = "eject_media:";
+ private static final String VOLD_CMD_FORMAT_MEDIA = "format_media:";
- // mountd events
- private static final String MOUNTD_UMS_ENABLED = "ums_enabled";
- private static final String MOUNTD_UMS_DISABLED = "ums_disabled";
- private static final String MOUNTD_UMS_CONNECTED = "ums_connected";
- private static final String MOUNTD_UMS_DISCONNECTED = "ums_disconnected";
- private static final String MOUNTD_MEDIA_REMOVED = "media_removed:";
- private static final String MOUNTD_MEDIA_UNMOUNTED = "media_unmounted:";
- private static final String MOUNTD_MEDIA_MOUNTED = "media_mounted:";
- private static final String MOUNTD_MEDIA_MOUNTED_READ_ONLY = "media_mounted_ro:";
- private static final String MOUNTD_MEDIA_SHARED = "media_shared:";
- private static final String MOUNTD_MEDIA_BAD_REMOVAL = "media_bad_removal:";
- private static final String MOUNTD_MEDIA_UNMOUNTABLE = "media_unmountable:";
- private static final String MOUNTD_REQUEST_EJECT = "request_eject:";
+ // vold events
+ private static final String VOLD_EVT_UMS_ENABLED = "ums_enabled";
+ private static final String VOLD_EVT_UMS_DISABLED = "ums_disabled";
+ private static final String VOLD_EVT_UMS_CONNECTED = "ums_connected";
+ private static final String VOLD_EVT_UMS_DISCONNECTED = "ums_disconnected";
+
+ private static final String VOLD_EVT_NOMEDIA = "volume_nomedia:";
+ private static final String VOLD_EVT_UNMOUNTED = "volume_unmounted:";
+ private static final String VOLD_EVT_MOUNTED = "volume_mounted:";
+ private static final String VOLD_EVT_MOUNTED_RO = "volume_mounted_ro:";
+ private static final String VOLD_EVT_UMS = "volume_ums";
+ private static final String VOLD_EVT_BAD_REMOVAL = "volume_badremoval:";
+ private static final String VOLD_EVT_DAMAGED = "volume_damaged:";
+ private static final String VOLD_EVT_CHECKING = "volume_checking:";
+ private static final String VOLD_EVT_NOFS = "volume_nofs:";
+ private static final String VOLD_EVT_EJECTING = "volume_ejecting:";
/**
- * MountService that handles events received from the mount service daemon
+ * MountService that handles events received from the vol service daemon
*/
private MountService mService;
/**
- * Stream for sending commands to the mount service daemon.
+ * Stream for sending commands to the vol service daemon.
*/
private OutputStream mOutputStream;
@@ -95,9 +99,9 @@ final class MountListener implements Runnable {
}
/**
- * Process and dispatches events received from the mount service daemon
+ * Process and dispatches events received from the vol service daemon
*
- * @param event An event received from the mount service daemon
+ * @param event An event received from the vol service daemon
*/
private void handleEvent(String event) {
if (Config.LOGD) Log.d(TAG, "handleEvent " + event);
@@ -105,34 +109,38 @@ final class MountListener implements Runnable {
int colonIndex = event.indexOf(':');
String path = (colonIndex > 0 ? event.substring(colonIndex + 1) : null);
- if (event.equals(MOUNTD_UMS_ENABLED)) {
+ if (event.equals(VOLD_EVT_UMS_ENABLED)) {
mUmsEnabled = true;
- } else if (event.equals(MOUNTD_UMS_DISABLED)) {
+ } else if (event.equals(VOLD_EVT_UMS_DISABLED)) {
mUmsEnabled = false;
- } else if (event.equals(MOUNTD_UMS_CONNECTED)) {
+ } else if (event.equals(VOLD_EVT_UMS_CONNECTED)) {
mUmsConnected = true;
mService.notifyUmsConnected();
- } else if (event.equals(MOUNTD_UMS_DISCONNECTED)) {
+ } else if (event.equals(VOLD_EVT_UMS_DISCONNECTED)) {
mUmsConnected = false;
mService.notifyUmsDisconnected();
- } else if (event.startsWith(MOUNTD_MEDIA_REMOVED)) {
+ } else if (event.startsWith(VOLD_EVT_NOMEDIA)) {
mService.notifyMediaRemoved(path);
- } else if (event.startsWith(MOUNTD_MEDIA_UNMOUNTED)) {
+ } else if (event.startsWith(VOLD_EVT_UNMOUNTED)) {
mService.notifyMediaUnmounted(path);
- } else if (event.startsWith(MOUNTD_MEDIA_MOUNTED)) {
+ } else if (event.startsWith(VOLD_EVT_CHECKING)) {
+ mService.notifyMediaChecking(path);
+ } else if (event.startsWith(VOLD_EVT_NOFS)) {
+ mService.notifyMediaNoFs(path);
+ } else if (event.startsWith(VOLD_EVT_MOUNTED)) {
mService.notifyMediaMounted(path, false);
- } else if (event.startsWith(MOUNTD_MEDIA_MOUNTED_READ_ONLY)) {
+ } else if (event.startsWith(VOLD_EVT_MOUNTED_RO)) {
mService.notifyMediaMounted(path, true);
- } else if (event.startsWith(MOUNTD_MEDIA_SHARED)) {
+ } else if (event.startsWith(VOLD_EVT_UMS)) {
mService.notifyMediaShared(path);
- } else if (event.startsWith(MOUNTD_MEDIA_BAD_REMOVAL)) {
+ } else if (event.startsWith(VOLD_EVT_BAD_REMOVAL)) {
mService.notifyMediaBadRemoval(path);
// also send media eject intent, to notify apps to close any open
// files on the media.
mService.notifyMediaEject(path);
- } else if (event.startsWith(MOUNTD_MEDIA_UNMOUNTABLE)) {
+ } else if (event.startsWith(VOLD_EVT_DAMAGED)) {
mService.notifyMediaUnmountable(path);
- } else if (event.startsWith(MOUNTD_REQUEST_EJECT)) {
+ } else if (event.startsWith(VOLD_EVT_EJECTING)) {
mService.notifyMediaEject(path);
}
}
@@ -156,7 +164,7 @@ final class MountListener implements Runnable {
private void writeCommand2(String command, String argument) {
synchronized (this) {
if (mOutputStream == null) {
- Log.e(TAG, "No connection to mountd", new IllegalStateException());
+ Log.e(TAG, "No connection to vold", new IllegalStateException());
} else {
StringBuilder builder = new StringBuilder(command);
if (argument != null) {
@@ -183,7 +191,7 @@ final class MountListener implements Runnable {
try {
socket = new LocalSocket();
- LocalSocketAddress address = new LocalSocketAddress(MOUNTD_SOCKET,
+ LocalSocketAddress address = new LocalSocketAddress(VOLD_SOCKET,
LocalSocketAddress.Namespace.RESERVED);
socket.connect(address);
@@ -193,7 +201,7 @@ final class MountListener implements Runnable {
byte[] buffer = new byte[100];
- writeCommand(MOUNTD_SEND_STATUS);
+ writeCommand(VOLD_CMD_SEND_UMS_STATUS);
while (true) {
int count = inputStream.read(buffer);
@@ -242,7 +250,7 @@ final class MountListener implements Runnable {
* create tons of throwaway LocalSockets, making
* system_server GC constantly.
*/
- Log.e(TAG, "Failed to connect to mountd", new IllegalStateException());
+ Log.e(TAG, "Failed to connect to vold", new IllegalStateException());
SystemClock.sleep(2000);
}
@@ -283,7 +291,7 @@ final class MountListener implements Runnable {
* @param enable true to enable USB mass storage support
*/
void setMassStorageEnabled(boolean enable) {
- writeCommand(enable ? MOUNTD_ENABLE_UMS : MOUNTD_DISABLE_UMS);
+ writeCommand(enable ? VOLD_CMD_ENABLE_UMS : VOLD_CMD_DISABLE_UMS);
}
/**
@@ -297,14 +305,20 @@ final class MountListener implements Runnable {
* Mount media at given mount point.
*/
public void mountMedia(String mountPoint) {
- writeCommand2(MOUNTD_MOUNT_MEDIA, mountPoint);
+ writeCommand2(VOLD_CMD_MOUNT_VOLUME, mountPoint);
}
/**
* Unmount media at given mount point.
*/
public void ejectMedia(String mountPoint) {
- writeCommand2(MOUNTD_EJECT_MEDIA, mountPoint);
+ writeCommand2(VOLD_CMD_EJECT_MEDIA, mountPoint);
}
-}
+ /**
+ * Format media at given mount point.
+ */
+ public void formatMedia(String mountPoint) {
+ writeCommand2(VOLD_CMD_FORMAT_MEDIA, mountPoint);
+ }
+}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 002ebed..f81c519 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -19,15 +19,19 @@ package com.android.server;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.IMountService;
import android.os.Environment;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.UEventObserver;
+import android.text.TextUtils;
import android.util.Log;
import java.io.File;
@@ -52,24 +56,34 @@ class MountService extends IMountService.Stub {
private MountListener mListener;
/**
- * The notification that is shown when USB is connected. It leads the user
- * to a dialog to enable mass storage mode.
+ * The notification that is shown when a USB mass storage host
+ * is connected.
* <p>
- * This is lazily created, so use {@link #getUsbStorageNotification()}.
+ * This is lazily created, so use {@link #setUsbStorageNotification()}.
*/
private Notification mUsbStorageNotification;
- private class SdDoorListener extends UEventObserver {
- static final String SD_DOOR_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/sd-door";
- static final String SD_DOOR_SWITCH_NAME = "sd-door";
- public void onUEvent(UEvent event) {
- if (SD_DOOR_SWITCH_NAME.equals(event.get("SWITCH_NAME"))) {
- sdDoorStateChanged(event.get("SWITCH_STATE"));
- }
- }
- };
+ /**
+ * The notification that is shown when the following media events occur:
+ * - Media is being checked
+ * - Media is blank (or unknown filesystem)
+ * - Media is corrupt
+ * - Media is safe to unmount
+ * - Media is missing
+ * <p>
+ * This is lazily created, so use {@link #setMediaStorageNotification()}.
+ */
+ private Notification mMediaStorageNotification;
+ private boolean mShowSafeUnmountNotificationWhenUnmounted;
+
+ private boolean mPlaySounds;
+
+ private boolean mMounted;
+
+ private boolean mAutoStartUms;
+
/**
* Constructs a new MountService instance
*
@@ -77,13 +91,30 @@ class MountService extends IMountService.Stub {
*/
public MountService(Context context) {
mContext = context;
+
+ // Register a BOOT_COMPLETED handler so that we can start
+ // MountListener. We defer the startup so that we don't
+ // start processing events before we ought-to
+ mContext.registerReceiver(mBroadcastReceiver,
+ new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+
mListener = new MountListener(this);
- Thread thread = new Thread(mListener, MountListener.class.getName());
- thread.start();
- SdDoorListener sdDoorListener = new SdDoorListener();
- sdDoorListener.startObserving(SdDoorListener.SD_DOOR_UEVENT_MATCH);
+ mShowSafeUnmountNotificationWhenUnmounted = false;
+
+ mPlaySounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
+
+ mAutoStartUms = SystemProperties.get("persist.service.mount.umsauto", "0").equals("1");
}
+ BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
+ Thread thread = new Thread(mListener, MountListener.class.getName());
+ thread.start();
+ }
+ }
+ };
+
/**
* @return true if USB mass storage support is enabled.
*/
@@ -129,19 +160,119 @@ class MountService extends IMountService.Stub {
throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
}
+ // Set a flag so that when we get the unmounted event, we know
+ // to display the notification
+ mShowSafeUnmountNotificationWhenUnmounted = true;
+
// tell mountd to unmount the media
mListener.ejectMedia(mountPath);
}
/**
+ * Attempt to format external media
+ */
+ public void formatMedia(String formatPath) throws RemoteException {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires MOUNT_FORMAT_FILESYSTEMS permission");
+ }
+
+ mListener.formatMedia(formatPath);
+ }
+
+ /**
+ * Returns true if we're playing media notification sounds.
+ */
+ public boolean getPlayNotificationSounds() {
+ return mPlaySounds;
+ }
+
+ /**
+ * Set whether or not we're playing media notification sounds.
+ */
+ public void setPlayNotificationSounds(boolean enabled) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires WRITE_SETTINGS permission");
+ }
+ mPlaySounds = enabled;
+ SystemProperties.set("persist.service.mount.playsnd", (enabled ? "1" : "0"));
+ }
+
+ /**
+ * Returns true if we auto-start UMS on cable insertion.
+ */
+ public boolean getAutoStartUms() {
+ return mAutoStartUms;
+ }
+
+ /**
+ * Set whether or not we're playing media notification sounds.
+ */
+ public void setAutoStartUms(boolean enabled) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires WRITE_SETTINGS permission");
+ }
+ mAutoStartUms = enabled;
+ SystemProperties.set("persist.service.mount.umsauto", (enabled ? "1" : "0"));
+ }
+
+ /**
+ * Update the state of the USB mass storage notification
+ */
+ void updateUsbMassStorageNotification(boolean suppressIfConnected, boolean sound) {
+
+ try {
+
+ if (getMassStorageConnected() && !suppressIfConnected) {
+ Intent intent = new Intent();
+ intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+ setUsbStorageNotification(
+ com.android.internal.R.string.usb_storage_notification_title,
+ com.android.internal.R.string.usb_storage_notification_message,
+ com.android.internal.R.drawable.stat_sys_data_usb,
+ sound, true, pi);
+ } else {
+ setUsbStorageNotification(0, 0, 0, false, false, null);
+ }
+ } catch (RemoteException e) {
+ // Nothing to do
+ }
+ }
+
+ void handlePossibleExplicitUnmountBroadcast(String path) {
+ if (mMounted) {
+ mMounted = false;
+ Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED,
+ Uri.parse("file://" + path));
+ mContext.sendBroadcast(intent);
+ }
+ }
+
+ /**
* Broadcasts the USB mass storage connected event to all clients.
*/
void notifyUmsConnected() {
String storageState = Environment.getExternalStorageState();
if (!storageState.equals(Environment.MEDIA_REMOVED) &&
- !storageState.equals(Environment.MEDIA_BAD_REMOVAL)) {
- setUsbStorageNotificationVisibility(true);
+ !storageState.equals(Environment.MEDIA_BAD_REMOVAL) &&
+ !storageState.equals(Environment.MEDIA_CHECKING)) {
+
+ if (mAutoStartUms) {
+ try {
+ setMassStorageEnabled(true);
+ } catch (RemoteException e) {
+ }
+ } else {
+ updateUsbMassStorageNotification(false, true);
+ }
}
+
Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);
mContext.sendBroadcast(intent);
}
@@ -150,7 +281,7 @@ class MountService extends IMountService.Stub {
* Broadcasts the USB mass storage disconnected event to all clients.
*/
void notifyUmsDisconnected() {
- setUsbStorageNotificationVisibility(false);
+ updateUsbMassStorageNotification(false, false);
Intent intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
mContext.sendBroadcast(intent);
}
@@ -159,6 +290,15 @@ class MountService extends IMountService.Stub {
* Broadcasts the media removed event to all clients.
*/
void notifyMediaRemoved(String path) {
+ updateUsbMassStorageNotification(true, false);
+
+ setMediaStorageNotification(
+ com.android.internal.R.string.ext_media_nomedia_notification_title,
+ com.android.internal.R.string.ext_media_nomedia_notification_message,
+ com.android.internal.R.drawable.stat_sys_no_sim,
+ true, false, null);
+ handlePossibleExplicitUnmountBroadcast(path);
+
Intent intent = new Intent(Intent.ACTION_MEDIA_REMOVED,
Uri.parse("file://" + path));
mContext.sendBroadcast(intent);
@@ -168,18 +308,68 @@ class MountService extends IMountService.Stub {
* Broadcasts the media unmounted event to all clients.
*/
void notifyMediaUnmounted(String path) {
+ if (mShowSafeUnmountNotificationWhenUnmounted) {
+ setMediaStorageNotification(
+ com.android.internal.R.string.ext_media_safe_unmount_notification_title,
+ com.android.internal.R.string.ext_media_safe_unmount_notification_message,
+ com.android.internal.R.drawable.stat_notify_sim_toolkit,
+ true, true, null);
+ mShowSafeUnmountNotificationWhenUnmounted = false;
+ } else {
+ setMediaStorageNotification(0, 0, 0, false, false, null);
+ }
+ updateUsbMassStorageNotification(false, false);
+
Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTED,
Uri.parse("file://" + path));
mContext.sendBroadcast(intent);
}
/**
+ * Broadcasts the media checking event to all clients.
+ */
+ void notifyMediaChecking(String path) {
+ setMediaStorageNotification(
+ com.android.internal.R.string.ext_media_checking_notification_title,
+ com.android.internal.R.string.ext_media_checking_notification_message,
+ com.android.internal.R.drawable.stat_notify_sim_toolkit,
+ true, false, null);
+
+ updateUsbMassStorageNotification(true, false);
+ Intent intent = new Intent(Intent.ACTION_MEDIA_CHECKING,
+ Uri.parse("file://" + path));
+ mContext.sendBroadcast(intent);
+ }
+
+ /**
+ * Broadcasts the media nofs event to all clients.
+ */
+ void notifyMediaNoFs(String path) {
+
+ Intent intent = new Intent();
+ intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+
+ setMediaStorageNotification(com.android.internal.R.string.ext_media_nofs_notification_title,
+ com.android.internal.R.string.ext_media_nofs_notification_message,
+ com.android.internal.R.drawable.stat_sys_no_sim,
+ true, false, pi);
+ updateUsbMassStorageNotification(false, false);
+ intent = new Intent(Intent.ACTION_MEDIA_NOFS,
+ Uri.parse("file://" + path));
+ mContext.sendBroadcast(intent);
+ }
+
+ /**
* Broadcasts the media mounted event to all clients.
*/
void notifyMediaMounted(String path, boolean readOnly) {
+ setMediaStorageNotification(0, 0, 0, false, false, null);
+ updateUsbMassStorageNotification(false, false);
Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + path));
intent.putExtra("read-only", readOnly);
+ mMounted = true;
mContext.sendBroadcast(intent);
}
@@ -187,7 +377,15 @@ class MountService extends IMountService.Stub {
* Broadcasts the media shared event to all clients.
*/
void notifyMediaShared(String path) {
- Intent intent = new Intent(Intent.ACTION_MEDIA_SHARED,
+ Intent intent = new Intent();
+ intent.setClass(mContext, com.android.internal.app.UsbStorageStopActivity.class);
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+ setUsbStorageNotification(com.android.internal.R.string.usb_storage_stop_notification_title,
+ com.android.internal.R.string.usb_storage_stop_notification_message,
+ com.android.internal.R.drawable.stat_sys_warning,
+ false, true, pi);
+ handlePossibleExplicitUnmountBroadcast(path);
+ intent = new Intent(Intent.ACTION_MEDIA_SHARED,
Uri.parse("file://" + path));
mContext.sendBroadcast(intent);
}
@@ -196,16 +394,39 @@ class MountService extends IMountService.Stub {
* Broadcasts the media bad removal event to all clients.
*/
void notifyMediaBadRemoval(String path) {
+ updateUsbMassStorageNotification(true, false);
+ setMediaStorageNotification(com.android.internal.R.string.ext_media_badremoval_notification_title,
+ com.android.internal.R.string.ext_media_badremoval_notification_message,
+ com.android.internal.R.drawable.stat_sys_warning,
+ true, true, null);
+
+ handlePossibleExplicitUnmountBroadcast(path);
Intent intent = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL,
Uri.parse("file://" + path));
mContext.sendBroadcast(intent);
+
+ intent = new Intent(Intent.ACTION_MEDIA_REMOVED,
+ Uri.parse("file://" + path));
+ mContext.sendBroadcast(intent);
}
/**
* Broadcasts the media unmountable event to all clients.
*/
void notifyMediaUnmountable(String path) {
- Intent intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE,
+ Intent intent = new Intent();
+ intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
+
+ setMediaStorageNotification(com.android.internal.R.string.ext_media_unmountable_notification_title,
+ com.android.internal.R.string.ext_media_unmountable_notification_message,
+ com.android.internal.R.drawable.stat_sys_no_sim,
+ true, false, pi);
+ updateUsbMassStorageNotification(false, false);
+
+ handlePossibleExplicitUnmountBroadcast(path);
+
+ intent = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE,
Uri.parse("file://" + path));
mContext.sendBroadcast(intent);
}
@@ -219,90 +440,132 @@ class MountService extends IMountService.Stub {
mContext.sendBroadcast(intent);
}
- private void sdDoorStateChanged(String doorState) {
- File directory = Environment.getExternalStorageDirectory();
- String storageState = Environment.getExternalStorageState();
-
- if (directory != null) {
- try {
- if (doorState.equals("open") && (storageState.equals(Environment.MEDIA_MOUNTED) ||
- storageState.equals(Environment.MEDIA_MOUNTED_READ_ONLY))) {
- // request SD card unmount if SD card door is opened
- unmountMedia(directory.getPath());
- } else if (doorState.equals("closed") && storageState.equals(Environment.MEDIA_UNMOUNTED)) {
- // attempt to remount SD card
- mountMedia(directory.getPath());
- }
- } catch (RemoteException e) {
- // Nothing to do.
- }
- }
- }
-
/**
- * Sets the visibility of the USB storage notification. This should be
- * called when a USB cable is connected and also when it is disconnected.
- *
- * @param visible Whether to show or hide the notification.
+ * Sets the USB storage notification.
*/
- private void setUsbStorageNotificationVisibility(boolean visible) {
+ private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon, boolean sound, boolean visible,
+ PendingIntent pi) {
+
+ if (!visible && mUsbStorageNotification == null) {
+ return;
+ }
+
NotificationManager notificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
+
if (notificationManager == null) {
return;
}
-
- /*
- * The convention for notification IDs is to use the icon's resource ID
- * when the icon is only used by a single notification type, which is
- * the case here.
- */
- Notification notification = getUsbStorageNotification();
- final int notificationId = notification.icon;
if (visible) {
- notificationManager.notify(notificationId, notification);
+ Resources r = Resources.getSystem();
+ CharSequence title = r.getText(titleId);
+ CharSequence message = r.getText(messageId);
+
+ if (mUsbStorageNotification == null) {
+ mUsbStorageNotification = new Notification();
+ mUsbStorageNotification.icon = icon;
+ mUsbStorageNotification.when = 0;
+ }
+
+ if (sound && mPlaySounds) {
+ mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
+ } else {
+ mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
+ }
+
+ mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
+
+ mUsbStorageNotification.tickerText = title;
+ if (pi == null) {
+ Intent intent = new Intent();
+ pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ }
+
+ mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+ }
+
+ final int notificationId = mUsbStorageNotification.icon;
+ if (visible) {
+ notificationManager.notify(notificationId, mUsbStorageNotification);
} else {
notificationManager.cancel(notificationId);
}
}
+ private synchronized boolean getMediaStorageNotificationDismissable() {
+ if ((mMediaStorageNotification != null) &&
+ ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) ==
+ Notification.FLAG_AUTO_CANCEL))
+ return true;
+
+ return false;
+ }
+
/**
- * Gets the USB storage notification.
- *
- * @return A {@link Notification} that leads to the dialog to enable USB storage.
+ * Sets the media storage notification.
*/
- private synchronized Notification getUsbStorageNotification() {
- Resources r = Resources.getSystem();
- CharSequence title =
- r.getText(com.android.internal.R.string.usb_storage_notification_title);
- CharSequence message =
- r.getText(com.android.internal.R.string.usb_storage_notification_message);
-
- if (mUsbStorageNotification == null) {
- mUsbStorageNotification = new Notification();
- mUsbStorageNotification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
- mUsbStorageNotification.when = 0;
- mUsbStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
- mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
+ private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible,
+ boolean dismissable, PendingIntent pi) {
+
+ if (!visible && mMediaStorageNotification == null) {
+ return;
}
- mUsbStorageNotification.tickerText = title;
- mUsbStorageNotification.setLatestEventInfo(mContext, title, message,
- getUsbStorageDialogIntent());
+ NotificationManager notificationManager = (NotificationManager) mContext
+ .getSystemService(Context.NOTIFICATION_SERVICE);
- return mUsbStorageNotification;
- }
+ if (notificationManager == null) {
+ return;
+ }
+
+ if (mMediaStorageNotification != null && visible) {
+ /*
+ * Dismiss the previous notification - we're about to
+ * re-use it.
+ */
+ final int notificationId = mMediaStorageNotification.icon;
+ notificationManager.cancel(notificationId);
+ }
+
+ if (visible) {
+ Resources r = Resources.getSystem();
+ CharSequence title = r.getText(titleId);
+ CharSequence message = r.getText(messageId);
+
+ if (mMediaStorageNotification == null) {
+ mMediaStorageNotification = new Notification();
+ mMediaStorageNotification.when = 0;
+ }
+
+ if (mPlaySounds) {
+ mMediaStorageNotification.defaults |= Notification.DEFAULT_SOUND;
+ } else {
+ mMediaStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
+ }
+
+ if (dismissable) {
+ mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
+ } else {
+ mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
+ }
+
+ mMediaStorageNotification.tickerText = title;
+ if (pi == null) {
+ Intent intent = new Intent();
+ pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ }
+
+ mMediaStorageNotification.icon = icon;
+ mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+ }
- /**
- * Creates a pending intent to start the USB storage activity.
- *
- * @return A {@link PendingIntent} that start the USB storage activity.
- */
- private PendingIntent getUsbStorageDialogIntent() {
- Intent intent = new Intent();
- intent.setClass(mContext, com.android.internal.app.UsbStorageActivity.class);
- return PendingIntent.getActivity(mContext, 0, intent, 0);
+ final int notificationId = mMediaStorageNotification.icon;
+ if (visible) {
+ notificationManager.notify(notificationId, mMediaStorageNotification);
+ } else {
+ notificationManager.cancel(notificationId);
+ }
}
}
diff --git a/services/java/com/android/server/NetStatService.java b/services/java/com/android/server/NetStatService.java
index 11dbe63..1ea0bac 100644
--- a/services/java/com/android/server/NetStatService.java
+++ b/services/java/com/android/server/NetStatService.java
@@ -26,20 +26,35 @@ public class NetStatService extends INetStatService.Stub {
}
- public int getTxPackets() {
- return NetStat.netStatGetTxPkts();
+ public long getMobileTxPackets() {
+ return NetStat.getMobileTxPkts();
}
- public int getRxPackets() {
- return NetStat.netStatGetRxPkts();
+ public long getMobileRxPackets() {
+ return NetStat.getMobileRxPkts();
}
- public int getTxBytes() {
- return NetStat.netStatGetTxBytes();
+ public long getMobileTxBytes() {
+ return NetStat.getMobileTxBytes();
}
- public int getRxBytes() {
- return NetStat.netStatGetRxBytes();
+ public long getMobileRxBytes() {
+ return NetStat.getMobileRxBytes();
}
+ public long getTotalTxPackets() {
+ return NetStat.getTotalTxPkts();
+ }
+
+ public long getTotalRxPackets() {
+ return NetStat.getTotalRxPkts();
+ }
+
+ public long getTotalTxBytes() {
+ return NetStat.getTotalTxBytes();
+ }
+
+ public long getTotalRxBytes() {
+ return NetStat.getTotalRxBytes();
+ }
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index eb9ebe9..bc4b169 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -311,6 +311,17 @@ class NotificationManagerService extends INotificationManager.Stub
mBatteryFull = batteryFull;
updateLights();
}
+ } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
+ || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
+ Uri uri = intent.getData();
+ if (uri == null) {
+ return;
+ }
+ String pkgName = uri.getSchemeSpecificPart();
+ if (pkgName == null) {
+ return;
+ }
+ cancelAllNotifications(pkgName);
}
}
};
@@ -331,6 +342,8 @@ class NotificationManagerService extends INotificationManager.Stub
// register for battery changed notifications
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
mContext.registerReceiver(mIntentReceiver, filter);
}
@@ -865,7 +878,7 @@ class NotificationManagerService extends INotificationManager.Stub
// ======================================================================
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingPermission("android.permission.DUMP")
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump NotificationManager from from pid="
+ Binder.getCallingPid()
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 58ad426..9f428e9 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -97,6 +97,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
@@ -983,6 +984,20 @@ class PackageManagerService extends IPackageManager.Stub {
}
return null;
}
+
+ public String[] getSystemSharedLibraryNames() {
+ Set<String> libSet;
+ synchronized (mPackages) {
+ libSet = mSharedLibraries.keySet();
+ }
+ int size = libSet.size();
+ if (size > 0) {
+ String[] libs = new String[size];
+ libSet.toArray(libs);
+ return libs;
+ }
+ return null;
+ }
public int checkPermission(String permName, String pkgName) {
synchronized (mPackages) {
@@ -1813,7 +1828,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
return true;
}
-
+
private PackageParser.Package scanPackageLI(
File scanFile, File destCodeFile, File destResourceFile,
PackageParser.Package pkg, int parseFlags, int scanMode) {
@@ -1910,19 +1925,18 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ // Just create the setting, don't add it yet
pkgSetting = mSettings.getPackageLP(pkg, suid, destCodeFile,
- destResourceFile, pkg.applicationInfo.flags, true);
+ destResourceFile, pkg.applicationInfo.flags, true, false);
if (pkgSetting == null) {
Log.w(TAG, "Creating application package " + pkgName + " failed");
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
- synchronized(mPackages) {
- if(mSettings.mDisabledSysPackages.get(pkg.packageName) != null) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
- }
+ if(mSettings.mDisabledSysPackages.get(pkg.packageName) != null) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
-
+
pkg.applicationInfo.uid = pkgSetting.userId;
pkg.mExtras = pkgSetting;
@@ -1970,24 +1984,12 @@ class PackageManagerService extends IPackageManager.Stub {
long scanFileTime = scanFile.lastModified();
final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.getTimeStamp();
-
- // At this point we know it is okay to accept the package, though
- // errors can still happen as we try to install...
-
- if ((scanMode&SCAN_MONITOR) != 0) {
- pkg.mPath = destCodeFile.getAbsolutePath();
- mAppDirs.put(pkg.mPath, pkg);
- }
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName,
pkg.applicationInfo.uid);
pkg.applicationInfo.publicSourceDir = pkgSetting.resourcePathString;
- synchronized (mPackages) {
- mPackages.put(pkg.applicationInfo.packageName, pkg);
- }
-
File dataPath;
if (mPlatformPackage == pkg) {
// The system package is special.
@@ -2030,8 +2032,7 @@ class PackageManagerService extends IPackageManager.Stub {
return null;
}
}
-
- }
+ }
if (!recovered) {
mHasSystemUidErrors = true;
}
@@ -2063,7 +2064,7 @@ class PackageManagerService extends IPackageManager.Stub {
int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
pkg.applicationInfo.uid);
if(ret < 0) {
- //error from installer
+ // Error from installer
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
@@ -2133,8 +2134,17 @@ class PackageManagerService extends IPackageManager.Stub {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
}
+ if ((scanMode&SCAN_MONITOR) != 0) {
+ pkg.mPath = destCodeFile.getAbsolutePath();
+ mAppDirs.put(pkg.mPath, pkg);
+ }
+
synchronized (mPackages) {
-
+ // We don't expect installation to fail beyond this point
+ // Add the new setting to mSettings
+ mSettings.insertPackageSettingLP(pkgSetting, pkg.packageName, suid);
+ // Add the new setting to mPackages
+ mPackages.put(pkg.applicationInfo.packageName, pkg);
int N = pkg.providers.size();
StringBuilder r = null;
int i;
@@ -2678,7 +2688,7 @@ class PackageManagerService extends IPackageManager.Stub {
grantPermissionsLP(pkg, false);
}
}
-
+
private void grantPermissionsLP(PackageParser.Package pkg, boolean replace) {
final PackageSetting ps = (PackageSetting)pkg.mExtras;
if (ps == null) {
@@ -2724,7 +2734,19 @@ class PackageManagerService extends IPackageManager.Stub {
== PackageManager.SIGNATURE_MATCH);
if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
- allowed = true;
+ // For updated system applications, the signatureOrSystem permission
+ // is granted only if it had been defined by the original application.
+ if ((pkg.applicationInfo.flags
+ & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+ PackageSetting sysPs = mSettings.getDisabledSystemPkg(pkg.packageName);
+ if(sysPs.grantedPermissions.contains(perm)) {
+ allowed = true;
+ } else {
+ allowed = false;
+ }
+ } else {
+ allowed = true;
+ }
}
}
} else {
@@ -3157,6 +3179,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (removedPackage != null) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, removedUid);
+ extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
}
if (addedPackage != null) {
@@ -3169,7 +3192,7 @@ class PackageManagerService extends IPackageManager.Stub {
private final String mRootDir;
private final boolean mIsRom;
}
-
+
/* Called when a downloaded package installation has been confirmed by the user */
public void installPackage(
final Uri packageURI, final IPackageInstallObserver observer, final int flags) {
@@ -3191,12 +3214,15 @@ class PackageManagerService extends IPackageManager.Stub {
Log.i(TAG, "Observer no longer exists.");
}
}
- // There appears to be a subtle deadlock condition if the sendPackageBroadcast call appears
- // in the synchronized block above.
+ // There appears to be a subtle deadlock condition if the sendPackageBroadcast
+ // call appears in the synchronized block above.
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- res.removedInfo.sendBroadcast();
+ res.removedInfo.sendBroadcast(false, true);
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
+ if (res.removedInfo.removedPackage != null) {
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ }
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
res.pkg.applicationInfo.packageName,
extras);
@@ -3217,7 +3243,7 @@ class PackageManagerService extends IPackageManager.Stub {
/*
* Install a non-existing package.
*/
- private void installNewPackageLI(String pkgName, int parseFlags,
+ private void installNewPackageLI(String pkgName,
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked,
@@ -3241,7 +3267,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
PackageParser.Package newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
- destResourceFile, pkg, parseFlags,
+ destResourceFile, pkg, 0,
SCAN_MONITOR | SCAN_FORCE_DEX
| SCAN_UPDATE_SIGNATURE
| (forwardLocked ? SCAN_FORWARD_LOCKED : 0));
@@ -3273,7 +3299,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- private void replacePackageLI(String pkgName, int parseFlags,
+ private void replacePackageLI(String pkgName,
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked,
@@ -3290,16 +3316,15 @@ class PackageManagerService extends IPackageManager.Stub {
boolean sysPkg = ((deletedPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
if(sysPkg) {
replaceSystemPackageLI(deletedPackage,
- parseFlags,
tmpPackageFile, destFilePath,
destPackageFile, destResourceFile, pkg, forwardLocked, res);
} else {
- replaceNonSystemPackageLI(deletedPackage, parseFlags, tmpPackageFile, destFilePath,
+ replaceNonSystemPackageLI(deletedPackage, tmpPackageFile, destFilePath,
destPackageFile, destResourceFile, pkg, forwardLocked, res);
}
}
- private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage, int parseFlags,
+ private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked,
@@ -3308,6 +3333,7 @@ class PackageManagerService extends IPackageManager.Stub {
String pkgName = deletedPackage.packageName;
boolean deletedPkg = true;
boolean updatedSettings = false;
+ int parseFlags = PackageManager.REPLACE_EXISTING_PACKAGE;
// First delete the existing package while retaining the data directory
if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
res.removedInfo)) {
@@ -3383,14 +3409,15 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- private void replaceSystemPackageLI(PackageParser.Package deletedPackage, int parseFlags,
+ private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
File tmpPackageFile,
String destFilePath, File destPackageFile, File destResourceFile,
PackageParser.Package pkg, boolean forwardLocked,
PackageInstalledInfo res) {
PackageParser.Package newPackage = null;
boolean updatedSettings = false;
- parseFlags |= PackageParser.PARSE_IS_SYSTEM;
+ int parseFlags = PackageManager.REPLACE_EXISTING_PACKAGE |
+ PackageParser.PARSE_IS_SYSTEM;
String packageName = deletedPackage.packageName;
res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
if (packageName == null) {
@@ -3534,7 +3561,6 @@ class PackageManagerService extends IPackageManager.Stub {
String pkgName = null;
boolean forwardLocked = false;
boolean replacingExistingPackage = false;
-
// Result object to be returned
PackageInstalledInfo res = new PackageInstalledInfo();
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
@@ -3640,13 +3666,13 @@ class PackageManagerService extends IPackageManager.Stub {
}
if(replacingExistingPackage) {
- replacePackageLI(pkgName, pFlags,
+ replacePackageLI(pkgName,
tmpPackageFile,
destFilePath, destPackageFile, destResourceFile,
pkg, forwardLocked,
res);
} else {
- installNewPackageLI(pkgName, pFlags,
+ installNewPackageLI(pkgName,
tmpPackageFile,
destFilePath, destPackageFile, destResourceFile,
pkg, forwardLocked,
@@ -3842,7 +3868,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
if(res && sendBroadCast) {
- info.sendBroadcast();
+ info.sendBroadcast(deleteCodeAndResources, false);
}
return res;
}
@@ -3852,9 +3878,13 @@ class PackageManagerService extends IPackageManager.Stub {
int uid = -1;
int removedUid = -1;
- void sendBroadcast() {
+ void sendBroadcast(boolean fullRemove, boolean replacing) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, removedUid >= 0 ? removedUid : uid);
+ extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove);
+ if (replacing) {
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ }
if (removedPackage != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras);
}
@@ -3967,7 +3997,6 @@ class PackageManagerService extends IPackageManager.Stub {
File sourceFile = new File(applicationInfo.sourceDir);
if (!sourceFile.exists()) {
Log.w(TAG, "Package source " + applicationInfo.sourceDir + " does not exist.");
- return false;
}
outInfo.uid = applicationInfo.uid;
@@ -4463,6 +4492,10 @@ class PackageManagerService extends IPackageManager.Stub {
mSystemReady = true;
}
+ public boolean isSafeMode() {
+ return mSafeMode;
+ }
+
public boolean hasSystemUidErrors() {
return mHasSystemUidErrors;
}
@@ -4482,7 +4515,7 @@ class PackageManagerService extends IPackageManager.Stub {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingPermission(android.Manifest.permission.DUMP)
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump ActivityManager from from pid="
+ Binder.getCallingPid()
@@ -5279,10 +5312,10 @@ class PackageManagerService extends IPackageManager.Stub {
PackageSetting getPackageLP(PackageParser.Package pkg,
SharedUserSetting sharedUser, File codePath, File resourcePath,
- int pkgFlags, boolean create) {
+ int pkgFlags, boolean create, boolean add) {
final String name = pkg.packageName;
PackageSetting p = getPackageLP(name, sharedUser, codePath,
- resourcePath, pkgFlags, create);
+ resourcePath, pkgFlags, create, add);
if (p != null) {
p.pkg = pkg;
@@ -5413,7 +5446,7 @@ class PackageManagerService extends IPackageManager.Stub {
private PackageSetting getPackageLP(String name,
SharedUserSetting sharedUser, File codePath, File resourcePath,
- int pkgFlags, boolean create) {
+ int pkgFlags, boolean create, boolean add) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (!p.codePath.equals(codePath)) {
@@ -5427,6 +5460,12 @@ class PackageManagerService extends IPackageManager.Stub {
// has to delete the one installed in the data partition in order to pick up the
// new system package.
return p;
+ } else if ((p.pkg != null) && (p.pkg.applicationInfo != null) &&
+ ((p.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
+ // Check for non-system apps
+ reportSettingsProblem(Log.WARN,
+ "Package " + name + " codePath changed from " + p.codePath
+ + " to " + codePath + "; Retaining data and using new code");
} else {
reportSettingsProblem(Log.WARN,
"Package " + name + " codePath changed from " + p.codePath
@@ -5458,15 +5497,25 @@ class PackageManagerService extends IPackageManager.Stub {
} else {
p.userId = FIRST_APPLICATION_UID;
}
-
if (p.userId < 0) {
reportSettingsProblem(Log.WARN,
"Package " + name + " could not be assigned a valid uid");
return null;
}
- mPackages.put(name, p);
+ if (add) {
+ // Finish adding new package by adding it and updating shared
+ // user preferences
+ insertPackageSettingLP(p, name, sharedUser);
+ }
}
-
+ return p;
+ }
+
+ // Utility method that adds a PackageSetting to mPackages and
+ // completes updating the shared user attributes
+ private void insertPackageSettingLP(PackageSetting p, String name,
+ SharedUserSetting sharedUser) {
+ mPackages.put(name, p);
if (sharedUser != null) {
if (p.sharedUser != null && p.sharedUser != sharedUser) {
reportSettingsProblem(Log.ERROR,
@@ -5476,17 +5525,16 @@ class PackageManagerService extends IPackageManager.Stub {
p.sharedUser.packages.remove(p);
} else if (p.userId != sharedUser.userId) {
reportSettingsProblem(Log.ERROR,
- "Package " + p.name + " was user id " + p.userId
- + " but is now user " + sharedUser
- + " with id " + sharedUser.userId
- + "; I am not changing its files so it will probably fail!");
+ "Package " + p.name + " was user id " + p.userId
+ + " but is now user " + sharedUser
+ + " with id " + sharedUser.userId
+ + "; I am not changing its files so it will probably fail!");
}
sharedUser.packages.add(p);
p.sharedUser = sharedUser;
p.userId = sharedUser.userId;
}
- return p;
}
private void updateSharedUserPerms (PackageSetting deletedPs) {
@@ -5637,23 +5685,8 @@ class PackageManagerService extends IPackageManager.Stub {
}
for (PackageSetting pkg : mDisabledSysPackages.values()) {
- serializer.startTag(null, "updated-package");
- serializer.attribute(null, "name", pkg.name);
- serializer.attribute(null, "codePath", pkg.codePathString);
- serializer.attribute(null, "ts", pkg.getTimeStampStr());
- if (!pkg.resourcePathString.equals(pkg.codePathString)) {
- serializer.attribute(null, "resourcePath", pkg.resourcePathString);
- }
- if (pkg.sharedUser == null) {
- serializer.attribute(null, "userId",
- Integer.toString(pkg.userId));
- } else {
- serializer.attribute(null, "sharedUserId",
- Integer.toString(pkg.userId));
- }
- serializer.endTag(null, "updated-package");
+ writeDisabledSysPackage(serializer, pkg);
}
-
serializer.startTag(null, "preferred-packages");
int N = mPreferredPackages.size();
@@ -5716,6 +5749,43 @@ class PackageManagerService extends IPackageManager.Stub {
//Debug.stopMethodTracing();
}
+ void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg)
+ throws java.io.IOException {
+ serializer.startTag(null, "updated-package");
+ serializer.attribute(null, "name", pkg.name);
+ serializer.attribute(null, "codePath", pkg.codePathString);
+ serializer.attribute(null, "ts", pkg.getTimeStampStr());
+ if (!pkg.resourcePathString.equals(pkg.codePathString)) {
+ serializer.attribute(null, "resourcePath", pkg.resourcePathString);
+ }
+ if (pkg.sharedUser == null) {
+ serializer.attribute(null, "userId",
+ Integer.toString(pkg.userId));
+ } else {
+ serializer.attribute(null, "sharedUserId",
+ Integer.toString(pkg.userId));
+ }
+ serializer.startTag(null, "perms");
+ if (pkg.sharedUser == null) {
+ // If this is a shared user, the permissions will
+ // be written there. We still need to write an
+ // empty permissions list so permissionsFixed will
+ // be set.
+ for (final String name : pkg.grantedPermissions) {
+ BasePermission bp = mPermissions.get(name);
+ if ((bp != null) && (bp.perm != null) && (bp.perm.info != null)) {
+ // We only need to write signature or system permissions but this wont
+ // match the semantics of grantedPermissions. So write all permissions.
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ }
+ }
+ serializer.endTag(null, "perms");
+ serializer.endTag(null, "updated-package");
+ }
+
void writePackage(XmlSerializer serializer, final PackageSetting pkg)
throws java.io.IOException {
serializer.startTag(null, "package");
@@ -5892,33 +5962,7 @@ class PackageManagerService extends IPackageManager.Stub {
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLP(parser);
} else if(tagName.equals("updated-package")) {
- String name = parser.getAttributeValue(null, "name");
- String codePathStr = parser.getAttributeValue(null, "codePath");
- String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
- if(resourcePathStr == null) {
- resourcePathStr = codePathStr;
- }
-
- int pkgFlags = 0;
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
- PackageSetting ps = new PackageSetting(name,
- new File(codePathStr),
- new File(resourcePathStr), pkgFlags);
- String timeStampStr = parser.getAttributeValue(null, "ts");
- if (timeStampStr != null) {
- try {
- long timeStamp = Long.parseLong(timeStampStr);
- ps.setTimeStamp(timeStamp, timeStampStr);
- } catch (NumberFormatException e) {
- }
- }
- String idStr = parser.getAttributeValue(null, "userId");
- ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
- if(ps.userId <= 0) {
- String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
- ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
- }
- mDisabledSysPackages.put(name, ps);
+ readDisabledSysPackageLP(parser);
} else {
Log.w(TAG, "Unknown element under <packages>: "
+ parser.getName());
@@ -5945,7 +5989,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (idObj != null && idObj instanceof SharedUserSetting) {
PackageSetting p = getPackageLP(pp.name,
(SharedUserSetting)idObj, pp.codePath, pp.resourcePath,
- pp.pkgFlags, true);
+ pp.pkgFlags, true, true);
if (p == null) {
Log.w(TAG, "Unable to create application package for "
+ pp.name);
@@ -6056,6 +6100,58 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ private void readDisabledSysPackageLP(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String name = parser.getAttributeValue(null, "name");
+ String codePathStr = parser.getAttributeValue(null, "codePath");
+ String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+ if(resourcePathStr == null) {
+ resourcePathStr = codePathStr;
+ }
+
+ int pkgFlags = 0;
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ PackageSetting ps = new PackageSetting(name,
+ new File(codePathStr),
+ new File(resourcePathStr), pkgFlags);
+ String timeStampStr = parser.getAttributeValue(null, "ts");
+ if (timeStampStr != null) {
+ try {
+ long timeStamp = Long.parseLong(timeStampStr);
+ ps.setTimeStamp(timeStamp, timeStampStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+ String idStr = parser.getAttributeValue(null, "userId");
+ ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
+ if(ps.userId <= 0) {
+ String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
+ ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
+ }
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("perms")) {
+ readGrantedPermissionsLP(parser,
+ ps.grantedPermissions);
+ } else {
+ reportSettingsProblem(Log.WARN,
+ "Unknown element under <updated-package>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ mDisabledSysPackages.put(name, ps);
+ }
+
private void readPackageLP(XmlPullParser parser)
throws XmlPullParserException, IOException {
String name = null;
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index ca0ad1a..ad30ffc 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -182,6 +182,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
private long mScreenOnTime;
private long mScreenOnStartTime;
private boolean mPreventScreenOn;
+ private int mScreenBrightnessOverride = -1;
// Used when logging number and duration of touch-down cycles
private long mTotalTouchDownTime;
@@ -245,7 +246,13 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
public void acquire() {
if (!mRefCounted || mCount++ == 0) {
- PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken, mTag);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
+ MY_UID, mTag);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
@@ -486,12 +493,18 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
public void acquireWakeLock(int flags, IBinder lock, String tag) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
- synchronized (mLocks) {
- acquireWakeLockLocked(flags, lock, tag);
+ int uid = Binder.getCallingUid();
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLocks) {
+ acquireWakeLockLocked(flags, lock, uid, tag);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
- public void acquireWakeLockLocked(int flags, IBinder lock, String tag) {
+ public void acquireWakeLockLocked(int flags, IBinder lock, int uid, String tag) {
int acquireUid = -1;
String acquireName = null;
int acquireType = -1;
@@ -504,7 +517,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
WakeLock wl;
boolean newlock;
if (index < 0) {
- wl = new WakeLock(flags, lock, tag, Binder.getCallingUid());
+ wl = new WakeLock(flags, lock, tag, uid);
switch (wl.flags & LOCK_MASK)
{
case PowerManager.FULL_WAKE_LOCK:
@@ -573,9 +586,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
if (acquireType >= 0) {
try {
- long origId = Binder.clearCallingIdentity();
mBatteryStats.noteStartWakelock(acquireUid, acquireName, acquireType);
- Binder.restoreCallingIdentity(origId);
} catch (RemoteException e) {
// Ignore
}
@@ -627,12 +638,13 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
releaseType = wl.monitorType;
if (releaseType >= 0) {
+ long origId = Binder.clearCallingIdentity();
try {
- long origId = Binder.clearCallingIdentity();
mBatteryStats.noteStopWakelock(releaseUid, releaseName, releaseType);
- Binder.restoreCallingIdentity(origId);
} catch (RemoteException e) {
// Ignore
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
}
}
@@ -757,7 +769,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingPermission(android.Manifest.permission.DUMP)
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump PowerManager from from pid="
+ Binder.getCallingPid()
@@ -790,6 +802,8 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
+ " mUserActivityAllowed=" + mUserActivityAllowed);
pw.println(" mKeylightDelay=" + mKeylightDelay + " mDimDelay=" + mDimDelay
+ " mScreenOffDelay=" + mScreenOffDelay);
+ pw.println(" mPreventScreenOn=" + mPreventScreenOn
+ + " mScreenBrightnessOverride=" + mScreenBrightnessOverride);
pw.println(" mTotalDelaySetting=" + mTotalDelaySetting);
pw.println(" mBroadcastWakeLock=" + mBroadcastWakeLock);
pw.println(" mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
@@ -959,7 +973,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
if (mSpew) {
Log.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock);
}
- if (mContext != null) {
+ if (mContext != null && ActivityManagerNative.isSystemReady()) {
mContext.sendOrderedBroadcast(mScreenOnIntent, null,
mScreenOnBroadcastDone, mHandler, 0, null, null);
} else {
@@ -980,7 +994,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
// ignore it.
}
- if (mContext != null) {
+ if (mContext != null && ActivityManagerNative.isSystemReady()) {
mContext.sendOrderedBroadcast(mScreenOffIntent, null,
mScreenOffBroadcastDone, mHandler, 0, null, null);
} else {
@@ -992,11 +1006,9 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
}
else {
- synchronized (mLocks) {
- EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 4,
- mBroadcastWakeLock.mCount);
- mBroadcastWakeLock.release();
- }
+ // If we're in this case, then this handler is running for a previous
+ // paired transaction. mBroadcastWakeLock will already have been released
+ // in sendNotificationLocked.
}
}
};
@@ -1070,7 +1082,6 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
* lock (rather than an IPowerManager call).
*/
public void preventScreenOn(boolean prevent) {
- // TODO: use a totally new permission (separate from DEVICE_POWER) for this?
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
synchronized (mLocks) {
@@ -1119,6 +1130,17 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
}
+ public void setScreenBrightnessOverride(int brightness) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+ synchronized (mLocks) {
+ if (mScreenBrightnessOverride != brightness) {
+ mScreenBrightnessOverride = brightness;
+ updateLightsLocked(mPowerState, SCREEN_ON_BIT);
+ }
+ }
+ }
+
/**
* Sanity-check that gets called 5 seconds after any call to
* preventScreenOn(true). This ensures that the original call
@@ -1204,7 +1226,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
if (mPowerState != newState) {
- err = updateLightsLocked(newState, becauseOfUser);
+ err = updateLightsLocked(newState, 0);
if (err != 0) {
return;
}
@@ -1232,6 +1254,14 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
if (reallyTurnScreenOn) {
err = Power.setScreenState(true);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteScreenOn();
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
} else {
Power.setScreenState(false);
// But continue as if we really did turn the screen on...
@@ -1250,8 +1280,17 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
} else {
mScreenOffTime = SystemClock.elapsedRealtime();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteScreenOff();
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException calling noteScreenOff on BatteryStatsService", e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ mPowerState &= ~SCREEN_ON_BIT;
if (!mScreenBrightness.animating) {
- err = turnScreenOffLocked(becauseOfUser);
+ err = screenOffFinishedAnimating(becauseOfUser);
} else {
mOffBecauseOfUser = becauseOfUser;
err = 0;
@@ -1262,24 +1301,25 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
}
- private int turnScreenOffLocked(boolean becauseOfUser) {
- if ((mPowerState&SCREEN_ON_BIT) != 0) {
- EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 0, becauseOfUser ? 1 : 0,
- mTotalTouchDownTime, mTouchCycles);
- mLastTouchDown = 0;
- int err = Power.setScreenState(false);
+ private int screenOffFinishedAnimating(boolean becauseOfUser) {
+ // I don't think we need to check the current state here because all of these
+ // Power.setScreenState and sendNotificationLocked can both handle being
+ // called multiple times in the same state. -joeo
+ EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 0, becauseOfUser ? 1 : 0,
+ mTotalTouchDownTime, mTouchCycles);
+ mLastTouchDown = 0;
+ int err = Power.setScreenState(false);
+ if (mScreenOnStartTime != 0) {
mScreenOnTime += SystemClock.elapsedRealtime() - mScreenOnStartTime;
mScreenOnStartTime = 0;
- if (err == 0) {
- mPowerState &= ~SCREEN_ON_BIT;
- int why = becauseOfUser
- ? WindowManagerPolicy.OFF_BECAUSE_OF_USER
- : WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
- sendNotificationLocked(false, why);
- }
- return err;
}
- return 0;
+ if (err == 0) {
+ int why = becauseOfUser
+ ? WindowManagerPolicy.OFF_BECAUSE_OF_USER
+ : WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
+ sendNotificationLocked(false, why);
+ }
+ return err;
}
private boolean batteryIsLow() {
@@ -1287,9 +1327,9 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
mBatteryService.getBatteryLevel() <= Power.LOW_BATTERY_THRESHOLD);
}
- private int updateLightsLocked(int newState, boolean becauseOfUser) {
+ private int updateLightsLocked(int newState, int forceState) {
int oldState = mPowerState;
- int difference = newState ^ oldState;
+ int difference = (newState ^ oldState) | forceState;
if (difference == 0) {
return 0;
}
@@ -1494,7 +1534,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
animating = more;
if (!more) {
if (mask == Power.SCREEN_LIGHT && curIntValue == Power.BRIGHTNESS_OFF) {
- turnScreenOffLocked(mOffBecauseOfUser);
+ screenOffFinishedAnimating(mOffBecauseOfUser);
}
}
return more;
@@ -1521,6 +1561,9 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
private int getPreferredBrightness() {
try {
+ if (mScreenBrightnessOverride >= 0) {
+ return mScreenBrightnessOverride;
+ }
final int brightness = Settings.System.getInt(mContext.getContentResolver(),
SCREEN_BRIGHTNESS);
// Don't let applications turn the screen all the way off
diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java
index f56088c..b253038 100644
--- a/services/java/com/android/server/SensorService.java
+++ b/services/java/com/android/server/SensorService.java
@@ -45,7 +45,7 @@ class SensorService extends ISensorService.Stub {
private static final int SENSOR_DISABLE = -1;
/**
- * Battery statistics to be updated when sensors are enabled and diabled.
+ * Battery statistics to be updated when sensors are enabled and disabled.
*/
final IBatteryStats mBatteryStats = BatteryStatsService.getService();
@@ -105,9 +105,9 @@ class SensorService extends ISensorService.Stub {
return _sensors_control_open();
}
- public boolean enableSensor(IBinder binder, int sensor, int enable)
+ public boolean enableSensor(IBinder binder, String name, int sensor, int enable)
throws RemoteException {
- if (localLOGV) Log.d(TAG, "enableSensor " + sensor + " " + enable);
+ if (localLOGV) Log.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable);
// Inform battery statistics service of status change
int uid = Binder.getCallingUid();
@@ -119,7 +119,10 @@ class SensorService extends ISensorService.Stub {
}
Binder.restoreCallingIdentity(identity);
- if (binder == null) throw new NullPointerException("listener is null in enableSensor");
+ if (binder == null) {
+ Log.w(TAG, "listener is null (sensor=" + name + ", id=" + sensor + ")");
+ return false;
+ }
synchronized(mListeners) {
if (enable!=SENSOR_DISABLE && !_sensors_control_activate(sensor, true)) {
@@ -145,7 +148,11 @@ class SensorService extends ISensorService.Stub {
}
if (l == null) {
- throw new NullPointerException("no Listener object in enableSensor");
+ // by construction, this means we're disabling a listener we
+ // don't know about...
+ Log.w(TAG, "listener with binder " + binder +
+ ", doesn't exist (sensor=" + name + ", id=" + sensor + ")");
+ return false;
}
if (minDelay >= 0) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7f7a52e..a629ec6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -16,35 +16,36 @@
package com.android.server;
+import com.android.server.am.ActivityManagerService;
+import com.android.server.status.StatusBarService;
+
+import dalvik.system.PathClassLoader;
+import dalvik.system.VMRuntime;
+
import android.app.ActivityManagerNative;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentService;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.IPackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.media.AudioService;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.IBinder;
-import android.provider.Settings;
import android.provider.Contacts.People;
-import android.server.BluetoothDeviceService;
+import android.provider.Settings;
import android.server.BluetoothA2dpService;
-import android.server.checkin.FallbackCheckinService;
+import android.server.BluetoothDeviceService;
import android.server.search.SearchManagerService;
import android.util.EventLog;
import android.util.Log;
-import dalvik.system.TouchDex;
-import dalvik.system.VMRuntime;
-
-import com.android.server.am.ActivityManagerService;
-import com.android.server.status.StatusBarService;
-
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -180,13 +181,13 @@ class ServerThread extends Thread {
StatusBarService statusBar = null;
InputMethodManagerService imm = null;
-
+ AppWidgetService appWidget = null;
+
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
try {
Log.i(TAG, "Starting Status Bar Service.");
statusBar = new StatusBarService(context);
ServiceManager.addService("statusbar", statusBar);
- com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
} catch (Throwable e) {
Log.e(TAG, "Failure starting StatusBarService", e);
}
@@ -205,7 +206,7 @@ class ServerThread extends Thread {
} catch (Throwable e) {
Log.e(TAG, "Failure starting Input Manager Service", e);
}
-
+
try {
Log.i(TAG, "Starting Hardware Service.");
ServiceManager.addService("hardware", new HardwareService(context));
@@ -272,9 +273,14 @@ class ServerThread extends Thread {
}
try {
- Log.i(TAG, "Starting Checkin Service");
- addService(context, "checkin", "com.google.android.server.checkin.CheckinService",
- FallbackCheckinService.class);
+ Log.i(TAG, "Starting Checkin Service.");
+ Intent intent = new Intent().setComponent(new ComponentName(
+ "com.google.android.server.checkin",
+ "com.google.android.server.checkin.CheckinService"));
+ if (context.startService(intent) == null) {
+ Log.w(TAG, "Using fallback Checkin Service.");
+ ServiceManager.addService("checkin", new FallbackCheckinService(context));
+ }
} catch (Throwable e) {
Log.e(TAG, "Failure starting Checkin Service", e);
}
@@ -302,10 +308,17 @@ class ServerThread extends Thread {
}
try {
- Log.i(TAG, "Starting Gadget Service");
- ServiceManager.addService(Context.GADGET_SERVICE, new GadgetService(context));
+ Log.i(TAG, "Starting AppWidget Service");
+ appWidget = new AppWidgetService(context);
+ ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget);
} catch (Throwable e) {
- Log.e(TAG, "Failure starting Gadget Service", e);
+ Log.e(TAG, "Failure starting AppWidget Service", e);
+ }
+
+ try {
+ com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure installing status bar icons", e);
}
}
@@ -318,6 +331,7 @@ class ServerThread extends Thread {
false, new AdbSettingsObserver());
// It is now time to start up the app processes...
+ boolean safeMode = wm.detectSafeMode();
if (statusBar != null) {
statusBar.systemReady();
}
@@ -330,6 +344,9 @@ class ServerThread extends Thread {
pm.systemReady();
} catch (RemoteException e) {
}
+ if (appWidget != null) {
+ appWidget.systemReady(safeMode);
+ }
// After making the following code, third party code may be running...
try {
@@ -342,51 +359,6 @@ class ServerThread extends Thread {
Looper.loop();
Log.d(TAG, "System ServerThread is exiting!");
}
-
- private void addService(Context context, String name, String serviceClass,
- Class<? extends IBinder> fallback) {
-
- final IBinder service = findService(context, serviceClass, fallback);
- if (service != null) {
- ServiceManager.addService(name, service);
- } else {
- Log.e(TAG, "Failure starting service '" + name + "' with class " + serviceClass);
- }
- }
-
- private IBinder findService(Context context, String serviceClass,
- Class<? extends IBinder> fallback) {
-
- IBinder service = null;
- try {
- Class<?> klass = Class.forName(serviceClass);
- Constructor<?> c = klass.getConstructor(Context.class);
- service = (IBinder) c.newInstance(context);
- } catch (ClassNotFoundException e) {
- // Ignore
- } catch (IllegalAccessException e) {
- // Ignore
- } catch (NoSuchMethodException e) {
- // Ignore
- } catch (InvocationTargetException e) {
- // Ignore
- } catch (InstantiationException e) {
- // Ignore
- }
-
- if (service == null && fallback != null) {
- Log.w(TAG, "Could not find " + serviceClass + ", trying fallback");
- try {
- service = fallback.newInstance();
- } catch (IllegalAccessException e) {
- // Ignore
- } catch (InstantiationException e) {
- // Ignore
- }
- }
-
- return service;
- }
}
class DemoThread extends Thread
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index dbaf086..a74915c 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -28,17 +28,20 @@ import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.Log;
import java.util.ArrayList;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.DefaultPhoneNotifier;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneStateIntentReceiver;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.server.am.BatteryStatsService;
/**
@@ -55,8 +58,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
int events;
}
- private Context mContext;
- private ArrayList<Record> mRecords = new ArrayList();
+ private final Context mContext;
+ private final ArrayList<Record> mRecords = new ArrayList();
+ private final IBatteryStats mBatteryStats;
private int mCallState = TelephonyManager.CALL_STATE_IDLE;
private String mCallIncomingNumber = "";
@@ -81,6 +85,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
TelephonyRegistry(Context context) {
CellLocation.getEmpty().fillInNotifierBundle(mCellLocation);
mContext = context;
+ mBatteryStats = BatteryStatsService.getService();
}
public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
@@ -183,6 +188,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyCallState(int state, String incomingNumber) {
+ if (!checkPhoneStatePermission("notifyCallState()")) {
+ return;
+ }
synchronized (mRecords) {
mCallState = state;
mCallIncomingNumber = incomingNumber;
@@ -202,6 +210,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyServiceState(ServiceState state) {
+ if (!checkPhoneStatePermission("notifyServiceState()")) {
+ return;
+ }
synchronized (mRecords) {
mServiceState = state;
final int N = mRecords.size();
@@ -216,6 +227,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifySignalStrength(int signalStrengthASU) {
+ if (!checkPhoneStatePermission("notifySignalStrength()")) {
+ return;
+ }
synchronized (mRecords) {
mSignalStrength = signalStrengthASU;
final int N = mRecords.size();
@@ -234,6 +248,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyMessageWaitingChanged(boolean mwi) {
+ if (!checkPhoneStatePermission("notifyMessageWaitingChanged()")) {
+ return;
+ }
synchronized (mRecords) {
mMessageWaiting = mwi;
final int N = mRecords.size();
@@ -251,6 +268,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyCallForwardingChanged(boolean cfi) {
+ if (!checkPhoneStatePermission("notifyCallForwardingChanged()")) {
+ return;
+ }
synchronized (mRecords) {
mCallForwarding = cfi;
final int N = mRecords.size();
@@ -268,6 +288,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyDataActivity(int state) {
+ if (!checkPhoneStatePermission("notifyDataActivity()")) {
+ return;
+ }
synchronized (mRecords) {
mDataActivity = state;
final int N = mRecords.size();
@@ -286,6 +309,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
public void notifyDataConnection(int state, boolean isDataConnectivityPissible,
String reason, String apn, String interfaceName) {
+ if (!checkPhoneStatePermission("notifyDataConnection()")) {
+ return;
+ }
synchronized (mRecords) {
mDataConnectionState = state;
mDataConnectionPossible = isDataConnectivityPissible;
@@ -309,6 +335,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyDataConnectionFailed(String reason) {
+ if (!checkPhoneStatePermission("notifyDataConnectionFailed()")) {
+ return;
+ }
/*
* This is commented out because there is on onDataConnectionFailed callback
* on PhoneStateListener. There should be.
@@ -327,6 +356,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
public void notifyCellLocation(Bundle cellLocation) {
+ if (!checkPhoneStatePermission("notifyCellLocation()")) {
+ return;
+ }
synchronized (mRecords) {
mCellLocation = cellLocation;
final int N = mRecords.size();
@@ -363,7 +395,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingPermission(android.Manifest.permission.DUMP)
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump telephony.registry from from pid="
+ Binder.getCallingPid()
@@ -414,6 +446,18 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
private void broadcastCallStateChanged(int state, String incomingNumber) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (state == TelephonyManager.CALL_STATE_IDLE) {
+ mBatteryStats.notePhoneOff();
+ } else {
+ mBatteryStats.notePhoneOn();
+ }
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
intent.putExtra(Phone.STATE_KEY,
DefaultPhoneNotifier.convertCallState(state).toString());
@@ -443,4 +487,16 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
intent.putExtra(Phone.FAILURE_REASON_KEY, reason);
mContext.sendStickyBroadcast(intent);
}
+
+ private boolean checkPhoneStatePermission(String method) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ String msg = "Modify Phone State Permission Denial: " + method + " from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid();
+ Log.w(TAG, msg);
+ return false;
+ }
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 2d61b1e..e298f49 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -24,6 +24,7 @@ import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
import android.app.AlarmManager;
import android.app.PendingIntent;
+import android.bluetooth.BluetoothA2dp;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -86,10 +87,13 @@ public class WifiService extends IWifiManager.Stub {
private final LockList mLocks = new LockList();
/**
- * See {@link Settings.System#WIFI_IDLE_MS}. This is the default value if a
- * Settings.System value is not present.
+ * 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
+ * the approximate point at which the battery drain caused by Wi-Fi
+ * being enabled but not active exceeds the battery drain caused by
+ * re-establishing a connection to the mobile data network.
*/
- private static final long DEFAULT_IDLE_MILLIS = 2 * 60 * 1000; /* 2 minutes */
+ private static final long DEFAULT_IDLE_MILLIS = 15 * 60 * 1000; /* 15 minutes */
private static final String WAKELOCK_TAG = "WifiService";
@@ -100,7 +104,7 @@ public class WifiService extends IWifiManager.Stub {
* provides a bit of extra margin.
* <p>
* See {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}.
- * This is the default value if a Settings.System value is not present.
+ * This is the default value if a Settings.Secure value is not present.
*/
private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000;
@@ -204,8 +208,6 @@ public class WifiService extends IWifiManager.Stub {
mWifiHandler.removeMessages(MESSAGE_RELEASE_WAKELOCK);
synchronized (sDriverStopWakeLock) {
if (sDriverStopWakeLock.isHeld()) {
- if (DBG) Log.d(TAG, "Releasing driver-stop wakelock " +
- sDriverStopWakeLock);
sDriverStopWakeLock.release();
}
}
@@ -213,9 +215,18 @@ public class WifiService extends IWifiManager.Stub {
}
);
- Log.d(TAG, "WifiService starting up with Wi-Fi " +
- (wifiEnabled ? "enabled" : "disabled"));
- registerForBroadcasts();
+ Log.i(TAG, "WifiService starting up with Wi-Fi " +
+ (wifiEnabled ? "enabled" : "disabled"));
+
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateWifiState();
+ }
+ },
+ new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
+
setWifiEnabledBlocking(wifiEnabled, false);
}
@@ -293,7 +304,7 @@ public class WifiService extends IWifiManager.Stub {
decrementHiddentNetworkPresentCounter();
}
}
- mIsHiddenNetworkPresent.put(netId, new Boolean(present));
+ mIsHiddenNetworkPresent.put(netId, present);
}
} else {
Log.e(TAG, "addOrUpdateHiddenNetwork(): Invalid (negative) network id!");
@@ -422,6 +433,7 @@ public class WifiService extends IWifiManager.Stub {
/**
* see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
+ * @param enable {@code true} to enable, {@code false} to disable.
* @return {@code true} if the enable/disable operation was
* started or is already in the queue.
*/
@@ -429,10 +441,6 @@ public class WifiService extends IWifiManager.Stub {
enforceChangePermission();
if (mWifiHandler == null) return false;
- /*
- * Remove any enable/disable Wi-Fi messages we may have in the queue
- * before adding a new one
- */
synchronized (mWifiHandler) {
sWakeLock.acquire();
sendEnableMessage(enable, true);
@@ -458,40 +466,42 @@ public class WifiService extends IWifiManager.Stub {
return false;
}
- updateWifiState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING);
+ setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING);
if (enable) {
if (!WifiNative.loadDriver()) {
Log.e(TAG, "Failed to load Wi-Fi driver.");
- updateWifiState(WIFI_STATE_UNKNOWN);
+ setWifiEnabledState(WIFI_STATE_UNKNOWN);
return false;
}
if (!WifiNative.startSupplicant()) {
WifiNative.unloadDriver();
Log.e(TAG, "Failed to start supplicant daemon.");
- updateWifiState(WIFI_STATE_UNKNOWN);
+ setWifiEnabledState(WIFI_STATE_UNKNOWN);
return false;
}
+ registerForBroadcasts();
mWifiStateTracker.startEventLoop();
} else {
- // Remove notification (it will no-op if it isn't visible)
+ mContext.unregisterReceiver(mReceiver);
+ // Remove notification (it will no-op if it isn't visible)
mWifiStateTracker.setNotificationVisible(false, 0, false, 0);
boolean failedToStopSupplicantOrUnloadDriver = false;
if (!WifiNative.stopSupplicant()) {
Log.e(TAG, "Failed to stop supplicant daemon.");
- updateWifiState(WIFI_STATE_UNKNOWN);
+ setWifiEnabledState(WIFI_STATE_UNKNOWN);
failedToStopSupplicantOrUnloadDriver = true;
}
-
+
// We must reset the interface before we unload the driver
mWifiStateTracker.resetInterface();
-
+
if (!WifiNative.unloadDriver()) {
Log.e(TAG, "Failed to unload Wi-Fi driver.");
if (!failedToStopSupplicantOrUnloadDriver) {
- updateWifiState(WIFI_STATE_UNKNOWN);
+ setWifiEnabledState(WIFI_STATE_UNKNOWN);
failedToStopSupplicantOrUnloadDriver = true;
}
}
@@ -505,7 +515,7 @@ public class WifiService extends IWifiManager.Stub {
if (persist) {
persistWifiEnabled(enable);
}
- updateWifiState(eventualWifiState);
+ setWifiEnabledState(eventualWifiState);
/*
* Initialize the hidden networks state and the number of allowed
@@ -519,7 +529,7 @@ public class WifiService extends IWifiManager.Stub {
return true;
}
- private void updateWifiState(int wifiState) {
+ private void setWifiEnabledState(int wifiState) {
final int previousWifiState = mWifiState;
// Update state
@@ -527,6 +537,7 @@ public class WifiService extends IWifiManager.Stub {
// Broadcast
final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
mContext.sendStickyBroadcast(intent);
@@ -551,7 +562,7 @@ public class WifiService extends IWifiManager.Stub {
* {@link WifiManager#WIFI_STATE_ENABLING},
* {@link WifiManager#WIFI_STATE_UNKNOWN}
*/
- public int getWifiState() {
+ public int getWifiEnabledState() {
enforceAccessPermission();
return mWifiState;
}
@@ -1082,9 +1093,7 @@ public class WifiService extends IWifiManager.Stub {
*/
removeNetworkIfHidden(netId);
- synchronized (mWifiStateTracker) {
- return WifiNative.removeNetworkCommand(netId);
- }
+ return mWifiStateTracker.removeNetwork(netId);
}
/**
@@ -1221,7 +1230,6 @@ public class WifiService extends IWifiManager.Stub {
if (scanResult != null) {
scanResult.level = -scanResultLevel;
scanList.add(scanResult);
- //if (DBG) Log.d(TAG, "ScanResult: " + scanResult);
}
} else if (DBG) {
Log.w(TAG,
@@ -1344,7 +1352,7 @@ public class WifiService extends IWifiManager.Stub {
if (result && mNeedReconfig) {
mNeedReconfig = false;
result = WifiNative.reloadConfigCommand();
-
+
if (result) {
Intent intent = new Intent(WifiManager.NETWORK_IDS_CHANGED_ACTION);
mContext.sendBroadcast(intent);
@@ -1359,7 +1367,7 @@ public class WifiService extends IWifiManager.Stub {
* in the current regulatory domain. This method should be used only
* if the correct number of channels cannot be determined automatically
* for some reason. If the operation is successful, the new value is
- * persisted as a System setting.
+ * persisted as a Secure setting.
* @param numChannels the number of allowed channels. Must be greater than 0
* and less than or equal to 16.
* @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
@@ -1441,14 +1449,12 @@ public class WifiService extends IWifiManager.Stub {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- long idleMillis = Settings.System.getLong(mContext.getContentResolver(),
- Settings.System.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
+ long idleMillis = Settings.Gservices.getLong(mContext.getContentResolver(),
+ Settings.Gservices.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
int stayAwakeConditions =
Settings.System.getInt(mContext.getContentResolver(),
Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
- if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
- /* do nothing, we'll check isAirplaneModeOn later. */
- } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
+ if (action.equals(Intent.ACTION_SCREEN_ON)) {
mAlarmManager.cancel(mIdleIntent);
mDeviceIdle = false;
mScreenOff = false;
@@ -1485,6 +1491,12 @@ public class WifiService extends IWifiManager.Stub {
return;
}
mPluggedType = pluggedType;
+ } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
+ boolean isBluetoothPlaying =
+ intent.getIntExtra(
+ BluetoothA2dp.SINK_STATE,
+ BluetoothA2dp.STATE_DISCONNECTED) == BluetoothA2dp.STATE_PLAYING;
+ mWifiStateTracker.setBluetoothScanMode(isBluetoothPlaying);
} else {
return;
}
@@ -1543,7 +1555,6 @@ public class WifiService extends IWifiManager.Stub {
}
private void sendStartMessage(boolean scanOnlyMode) {
- if (DBG) Log.d(TAG, "sendStartMessage(" + scanOnlyMode + ")");
Message.obtain(mWifiHandler, MESSAGE_START_WIFI, scanOnlyMode ? 1 : 0, 0).sendToTarget();
}
@@ -1561,6 +1572,9 @@ public class WifiService extends IWifiManager.Stub {
}
synchronized (mWifiHandler) {
+ if (mWifiState == WIFI_STATE_ENABLING && !airplaneMode) {
+ return;
+ }
if (wifiShouldBeEnabled) {
if (wifiShouldBeStarted) {
sWakeLock.acquire();
@@ -1573,6 +1587,15 @@ public class WifiService extends IWifiManager.Stub {
mContext.getContentResolver(),
Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
DEFAULT_WAKELOCK_TIMEOUT);
+ /*
+ * The following wakelock is held in order to ensure
+ * that the connectivity manager has time to fail over
+ * to the mobile data network. The connectivity manager
+ * releases it once mobile data connectivity has been
+ * established. If connectivity cannot be established,
+ * the wakelock is released after wakeLockTimeout
+ * milliseconds have elapsed.
+ */
sDriverStopWakeLock.acquire();
mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI);
mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, wakeLockTimeout);
@@ -1585,18 +1608,13 @@ public class WifiService extends IWifiManager.Stub {
}
private void registerForBroadcasts() {
- if (isAirplaneSensitive()) {
- mContext.registerReceiver(mReceiver,
- new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
- }
- mContext.registerReceiver(mReceiver,
- new IntentFilter(Intent.ACTION_SCREEN_ON));
- mContext.registerReceiver(mReceiver,
- new IntentFilter(Intent.ACTION_SCREEN_OFF));
- mContext.registerReceiver(mReceiver,
- new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- mContext.registerReceiver(mReceiver,
- new IntentFilter(ACTION_DEVICE_IDLE));
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+ intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+ intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ intentFilter.addAction(ACTION_DEVICE_IDLE);
+ intentFilter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
+ mContext.registerReceiver(mReceiver, intentFilter);
}
private boolean isAirplaneSensitive() {
@@ -1664,7 +1682,7 @@ public class WifiService extends IWifiManager.Stub {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingPermission(android.Manifest.permission.DUMP)
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump WifiService from from pid="
+ Binder.getCallingPid()
@@ -1672,11 +1690,14 @@ public class WifiService extends IWifiManager.Stub {
return;
}
pw.println("Wi-Fi is " + stateName(mWifiState));
- pw.println("stay-awake conditions: " +
+ pw.println("Stay-awake conditions: " +
Settings.System.getInt(mContext.getContentResolver(),
Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
pw.println();
+ pw.println("Internal state:");
+ pw.println(mWifiStateTracker);
+ pw.println();
pw.println("Latest scan results:");
List<ScanResult> scanResults = mWifiStateTracker.getScanResultsList();
if (scanResults != null && scanResults.size() != 0) {
@@ -1786,13 +1807,6 @@ public class WifiService extends IWifiManager.Stub {
return -1;
}
- private synchronized void clear() {
- if (!mList.isEmpty()) {
- mList.clear();
- updateWifiState();
- }
- }
-
private void dump(PrintWriter pw) {
for (WifiLock l : mList) {
pw.print(" ");
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 7ed0aec..e4bd3c3 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -66,6 +66,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
+import android.os.Power;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -122,7 +123,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
static final boolean DEBUG = false;
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_ANIM = false;
+ static final boolean DEBUG_LAYERS = false;
static final boolean DEBUG_INPUT = false;
+ static final boolean DEBUG_INPUT_METHOD = false;
static final boolean DEBUG_VISIBILITY = false;
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
@@ -202,6 +205,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final boolean mHaveInputMethods;
+ final boolean mLimitedAlphaCompositing;
+
final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
final IActivityManager mActivityManager;
@@ -306,6 +311,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final float[] mTmpFloats = new float[9];
+ boolean mSafeMode;
boolean mDisplayEnabled = false;
boolean mSystemBooted = false;
int mRotation = 0;
@@ -316,12 +322,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean mLayoutNeeded = true;
boolean mAnimationPending = false;
- boolean mSurfacesChanged = false;
boolean mDisplayFrozen = false;
boolean mWindowsFreezingScreen = false;
long mFreezeGcPending = 0;
int mAppsFreezingScreen = 0;
+ // This is held as long as we have the screen frozen, to give us time to
+ // perform a rotation animation when turning off shows the lock screen which
+ // changes the orientation.
+ PowerManager.WakeLock mScreenFrozenLock;
+
// State management of app transitions. When we are preparing for a
// transition, mNextAppTransition will be the kind of transition to
// perform or TRANSIT_NONE if we are not waiting. If we are waiting,
@@ -347,6 +357,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// This just indicates the window the input method is on top of, not
// necessarily the window its input is going to.
WindowState mInputMethodTarget = null;
+ WindowState mUpcomingInputMethodTarget = null;
+ boolean mInputMethodTargetWaitingAnim;
+ int mInputMethodAnimLayerAdjustment;
WindowState mInputMethodWindow = null;
final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
@@ -461,9 +474,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean haveInputMethods) {
mContext = context;
mHaveInputMethods = haveInputMethods;
+ mLimitedAlphaCompositing = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_sf_limitedAlpha);
mPowerManager = pm;
mPowerManager.setPolicy(mPolicy);
+ PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "SCREEN_FROZEN");
+ mScreenFrozenLock.setReferenceCounted(false);
mActivityManager = ActivityManagerNative.getDefault();
mBatteryStats = BatteryStatsService.getService();
@@ -734,7 +753,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
- int findDesiredInputMethodWindowIndexLocked() {
+ static boolean canBeImeTarget(WindowState w) {
+ final int fl = w.mAttrs.flags
+ & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
+ if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
+ return w.isVisibleOrAdding();
+ }
+ return false;
+ }
+
+ int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
final ArrayList localmWindows = mWindows;
final int N = localmWindows.size();
WindowState w = null;
@@ -742,28 +770,120 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
while (i > 0) {
i--;
w = (WindowState)localmWindows.get(i);
- final int fl = w.mAttrs.flags
- & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
+
//Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
- // + Integer.toHexString(fl));
- if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
+ // + Integer.toHexString(w.mAttrs.flags));
+ if (canBeImeTarget(w)) {
//Log.i(TAG, "Putting input method here!");
- if (w.isVisibleOrAdding()) {
- break;
+
+ // Yet more tricksyness! If this window is a "starting"
+ // window, we do actually want to be on top of it, but
+ // it is not -really- where input will go. So if the caller
+ // is not actually looking to move the IME, look down below
+ // for a real window to target...
+ if (!willMove
+ && w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
+ && i > 0) {
+ WindowState wb = (WindowState)localmWindows.get(i-1);
+ if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) {
+ i--;
+ w = wb;
+ }
}
+ break;
}
}
+
+ mUpcomingInputMethodTarget = w;
+
+ if (DEBUG_INPUT_METHOD) Log.v(TAG, "Desired input method target="
+ + w + " willMove=" + willMove);
+
+ if (willMove && w != null) {
+ final WindowState curTarget = mInputMethodTarget;
+ if (curTarget != null && curTarget.mAppToken != null) {
+
+ // Now some fun for dealing with window animations that
+ // modify the Z order. We need to look at all windows below
+ // the current target that are in this app, finding the highest
+ // visible one in layering.
+ AppWindowToken token = curTarget.mAppToken;
+ WindowState highestTarget = null;
+ int highestPos = 0;
+ if (token.animating || token.animation != null) {
+ int pos = 0;
+ pos = localmWindows.indexOf(curTarget);
+ while (pos >= 0) {
+ WindowState win = (WindowState)localmWindows.get(pos);
+ if (win.mAppToken != token) {
+ break;
+ }
+ if (!win.mRemoved) {
+ if (highestTarget == null || win.mAnimLayer >
+ highestTarget.mAnimLayer) {
+ highestTarget = win;
+ highestPos = pos;
+ }
+ }
+ pos--;
+ }
+ }
+
+ if (highestTarget != null) {
+ if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
+ + mNextAppTransition + " " + highestTarget
+ + " animating=" + highestTarget.isAnimating()
+ + " layer=" + highestTarget.mAnimLayer
+ + " new layer=" + w.mAnimLayer);
+
+ if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+ // If we are currently setting up for an animation,
+ // hold everything until we can find out what will happen.
+ mInputMethodTargetWaitingAnim = true;
+ mInputMethodTarget = highestTarget;
+ return highestPos + 1;
+ } else if (highestTarget.isAnimating() &&
+ highestTarget.mAnimLayer > w.mAnimLayer) {
+ // If the window we are currently targeting is involved
+ // with an animation, and it is on top of the next target
+ // we will be over, then hold off on moving until
+ // that is done.
+ mInputMethodTarget = highestTarget;
+ return highestPos + 1;
+ }
+ }
+ }
+ }
+
//Log.i(TAG, "Placing input method @" + (i+1));
if (w != null) {
- mInputMethodTarget = w;
+ if (willMove) {
+ RuntimeException e = new RuntimeException();
+ e.fillInStackTrace();
+ if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
+ + mInputMethodTarget + " to " + w, e);
+ mInputMethodTarget = w;
+ if (w.mAppToken != null) {
+ setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment);
+ } else {
+ setInputMethodAnimLayerAdjustment(0);
+ }
+ }
return i+1;
}
- mInputMethodTarget = null;
+ if (willMove) {
+ RuntimeException e = new RuntimeException();
+ e.fillInStackTrace();
+ if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
+ + mInputMethodTarget + " to null", e);
+ mInputMethodTarget = null;
+ setInputMethodAnimLayerAdjustment(0);
+ }
return -1;
}
void addInputMethodWindowToListLocked(WindowState win) {
- int pos = findDesiredInputMethodWindowIndexLocked();
+ int pos = findDesiredInputMethodWindowIndexLocked(true);
if (pos >= 0) {
win.mTargetAppToken = mInputMethodTarget.mAppToken;
mWindows.add(pos, win);
@@ -775,6 +895,33 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
moveInputMethodDialogsLocked(pos);
}
+ void setInputMethodAnimLayerAdjustment(int adj) {
+ if (DEBUG_LAYERS) Log.v(TAG, "Setting im layer adj to " + adj);
+ mInputMethodAnimLayerAdjustment = adj;
+ WindowState imw = mInputMethodWindow;
+ if (imw != null) {
+ imw.mAnimLayer = imw.mLayer + adj;
+ if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
+ + " anim layer: " + imw.mAnimLayer);
+ int wi = imw.mChildWindows.size();
+ while (wi > 0) {
+ wi--;
+ WindowState cw = (WindowState)imw.mChildWindows.get(wi);
+ cw.mAnimLayer = cw.mLayer + adj;
+ if (DEBUG_LAYERS) Log.v(TAG, "IM win " + cw
+ + " anim layer: " + cw.mAnimLayer);
+ }
+ }
+ int di = mInputMethodDialogs.size();
+ while (di > 0) {
+ di --;
+ imw = mInputMethodDialogs.get(di);
+ imw.mAnimLayer = imw.mLayer + adj;
+ if (DEBUG_LAYERS) Log.v(TAG, "IM win " + imw
+ + " anim layer: " + imw.mAnimLayer);
+ }
+ }
+
private int tmpRemoveWindowLocked(int interestingPos, WindowState win) {
int wpos = mWindows.indexOf(win);
if (wpos >= 0) {
@@ -806,29 +953,55 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ void logWindowList(String prefix) {
+ int N = mWindows.size();
+ while (N > 0) {
+ N--;
+ Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
+ }
+ }
+
void moveInputMethodDialogsLocked(int pos) {
ArrayList<WindowState> dialogs = mInputMethodDialogs;
+
final int N = dialogs.size();
+ if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos);
for (int i=0; i<N; i++) {
pos = tmpRemoveWindowLocked(pos, dialogs.get(i));
}
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "Window list w/pos=" + pos);
+ logWindowList(" ");
+ }
+
if (pos >= 0) {
final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
- WindowState wp = (WindowState)mWindows.get(pos);
- if (wp == mInputMethodWindow) {
- pos++;
+ if (pos < mWindows.size()) {
+ WindowState wp = (WindowState)mWindows.get(pos);
+ if (wp == mInputMethodWindow) {
+ pos++;
+ }
}
+ if (DEBUG_INPUT_METHOD) Log.v(TAG, "Adding " + N + " dialogs at pos=" + pos);
for (int i=0; i<N; i++) {
WindowState win = dialogs.get(i);
win.mTargetAppToken = targetAppToken;
pos = reAddWindowLocked(pos, win);
}
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "Final window list:");
+ logWindowList(" ");
+ }
return;
}
for (int i=0; i<N; i++) {
WindowState win = dialogs.get(i);
win.mTargetAppToken = null;
reAddWindowToListInOrderLocked(win);
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "No IM target, final list:");
+ logWindowList(" ");
+ }
}
}
@@ -839,7 +1012,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return false;
}
- int imPos = findDesiredInputMethodWindowIndexLocked();
+ int imPos = findDesiredInputMethodWindowIndexLocked(true);
if (imPos >= 0) {
// In this case, the input method windows are to be placed
// immediately above the window they are targeting.
@@ -884,9 +1057,21 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
if (imWin != null) {
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "Moving IM from " + imPos);
+ logWindowList(" ");
+ }
imPos = tmpRemoveWindowLocked(imPos, imWin);
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "List after moving with new pos " + imPos + ":");
+ logWindowList(" ");
+ }
imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
reAddWindowLocked(imPos, imWin);
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "List after moving IM to " + imPos + ":");
+ logWindowList(" ");
+ }
if (DN > 0) moveInputMethodDialogsLocked(imPos+1);
} else {
moveInputMethodDialogsLocked(imPos);
@@ -897,9 +1082,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// because they aren't currently associated with a focus window.
if (imWin != null) {
+ if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos);
tmpRemoveWindowLocked(0, imWin);
imWin.mTargetAppToken = null;
reAddWindowToListInOrderLocked(imWin);
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "List with no IM target:");
+ logWindowList(" ");
+ }
if (DN > 0) moveInputMethodDialogsLocked(-1);;
} else {
moveInputMethodDialogsLocked(-1);;
@@ -915,7 +1105,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
void adjustInputMethodDialogsLocked() {
- moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked());
+ moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
}
public int addWindow(Session session, IWindow client,
@@ -975,7 +1165,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
- token = new WindowToken(attrs.token, -1);
+ token = new WindowToken(attrs.token, -1, false);
addToken = true;
} else if (attrs.type >= FIRST_APPLICATION_WINDOW
&& attrs.type <= LAST_APPLICATION_WINDOW) {
@@ -1053,8 +1243,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
addWindowToListInOrderLocked(win, true);
}
- Binder.restoreCallingIdentity(origId);
-
win.mEnterAnimationPending = true;
mPolicy.getContentInsetHintLw(attrs, outContentInsets);
@@ -1066,8 +1254,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
}
+ boolean focusChanged = false;
if (win.canReceiveKeys()) {
- if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS)) {
+ if ((focusChanged=updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS))
+ == true) {
imMayMove = false;
}
}
@@ -1082,16 +1272,34 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
//dump();
+ if (focusChanged) {
+ if (mCurrentFocus != null) {
+ mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
+ }
+ }
+
if (localLOGV) Log.v(
TAG, "New client " + client.asBinder()
+ ": window=" + win);
}
+ // sendNewConfiguration() checks caller permissions so we must call it with
+ // privilege. updateOrientationFromAppTokens() clears and resets the caller
+ // identity anyway, so it's safe to just clear & restore around this whole
+ // block.
+ final long origId = Binder.clearCallingIdentity();
if (reportNewConfig) {
- final long origId = Binder.clearCallingIdentity();
sendNewConfiguration();
- Binder.restoreCallingIdentity(origId);
+ } else {
+ // Update Orientation after adding a window, only if the window needs to be
+ // displayed right away
+ if (win.isVisibleOrAdding()) {
+ if (updateOrientationFromAppTokens(null) != null) {
+ sendNewConfiguration();
+ }
+ }
}
+ Binder.restoreCallingIdentity(origId);
return res;
}
@@ -1125,7 +1333,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ " inPendingTransaction="
+ (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
+ " mDisplayFrozen=" + mDisplayFrozen);
-
+ // Visibility of the removed window. Will be used later to update orientation later on.
+ boolean wasVisible = false;
// First, see if we need to run an animation. If we do, we have
// to hold off on removing the window until the animation is done.
// If the display is frozen, just remove immediately, since the
@@ -1133,7 +1342,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (win.mSurface != null && !mDisplayFrozen) {
// If we are not currently running the exit animation, we
// need to see about starting one.
- if (win.isVisibleLw()) {
+ if (wasVisible=win.isWinVisibleLw()) {
+
int transit = WindowManagerPolicy.TRANSIT_EXIT;
if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
@@ -1161,6 +1371,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
removeWindowInnerLocked(session, win);
+ // Removing a visible window will effect the computed orientation
+ // So just update orientation if needed.
+ if (wasVisible && computeForcedAppOrientationLocked()
+ != mForcedAppOrientation) {
+ mH.sendMessage(mH.obtainMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION));
+ }
updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
Binder.restoreCallingIdentity(origId);
}
@@ -1169,6 +1385,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mKeyWaiter.releasePendingPointerLocked(win.mSession);
mKeyWaiter.releasePendingTrackballLocked(win.mSession);
+ win.mRemoved = true;
+
+ if (mInputMethodTarget == win) {
+ moveInputMethodWindowsIfNeededLocked(false);
+ }
+
mPolicy.removeWindowLw(win);
win.removeLocked();
@@ -1191,10 +1413,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
TAG, "**** Removing window " + win + ": count="
+ token.windows.size());
if (token.windows.size() == 0) {
- if (atoken != token) {
+ if (!token.explicit) {
mTokenMap.remove(token.token);
mTokenList.remove(token);
- } else {
+ } else if (atoken != null) {
atoken.firstWindowDrawn = false;
}
}
@@ -1287,7 +1509,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Surface outSurface) {
boolean displayed = false;
boolean inTouchMode;
-
+ Configuration newConfig = null;
long origId = Binder.clearCallingIdentity();
synchronized(mWindowMap) {
@@ -1359,6 +1581,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
&& !win.mCommitDrawPending && !mDisplayFrozen) {
applyEnterAnimationLocked(win);
}
+ if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
+ // To change the format, we need to re-build the surface.
+ win.destroySurfaceLocked();
+ displayed = true;
+ }
try {
Surface surface = win.createSurfaceLocked();
if (surface != null) {
@@ -1393,7 +1620,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
- if (win.isVisibleLw() &&
+ if (win.isWinVisibleLw() &&
applyAnimationLocked(win, transit, false)) {
win.mExiting = true;
mKeyWaiter.finishedKey(session, client, true,
@@ -1403,27 +1630,28 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// an exit.
win.mExiting = true;
} else {
+ if (mInputMethodWindow == win) {
+ mInputMethodWindow = null;
+ }
win.destroySurfaceLocked();
}
}
}
- if (mInputMethodWindow == win) {
- mInputMethodWindow = null;
- }
outSurface.clear();
}
- boolean assignLayers = false;
-
if (focusMayChange) {
//System.out.println("Focus may change: " + win.mAttrs.getTitle());
if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
- assignLayers = true;
imMayMove = false;
}
//System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
}
+ // updateFocusedWindowLocked() already assigned layers so we only need to
+ // reassign them at this point if the IM window state gets shuffled
+ boolean assignLayers = false;
+
if (imMayMove) {
if (moveInputMethodWindowsIfNeededLocked(false)) {
assignLayers = true;
@@ -1435,6 +1663,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (assignLayers) {
assignLayersLocked();
}
+ newConfig = updateOrientationFromAppTokensLocked(null);
performLayoutAndPlaceSurfacesLocked();
if (win.mAppToken != null) {
win.mAppToken.updateReportedVisibilityLocked();
@@ -1456,6 +1685,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
inTouchMode = mInTouchMode;
}
+ if (newConfig != null) {
+ sendNewConfiguration();
+ }
+
Binder.restoreCallingIdentity(origId);
return (inTouchMode ? WindowManagerImpl.RELAYOUT_IN_TOUCH_MODE : 0)
@@ -1507,7 +1740,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private boolean applyAnimationLocked(WindowState win,
int transit, boolean isEntrance) {
- if (win.mAnimating && win.mAnimationIsEntrance == isEntrance) {
+ if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
// If we are trying to apply an animation, but already running
// an animation of the same type, then just leave that one alone.
return true;
@@ -1553,6 +1786,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.v(TAG, "Loaded animation " + a + " for " + win, e);
}
win.setAnimation(a);
+ win.mAnimationIsEntrance = isEntrance;
}
} else {
win.clearAnimation();
@@ -1708,7 +1942,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.w(TAG, "Attempted to add existing input method token: " + token);
return;
}
- wtoken = new WindowToken(token, type);
+ wtoken = new WindowToken(token, type, true);
mTokenMap.put(token, wtoken);
mTokenList.add(wtoken);
}
@@ -1812,15 +2046,36 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
- public Configuration updateOrientationFromAppTokens(
- IBinder freezeThisOneIfNeeded) {
- boolean changed = false;
- synchronized(mWindowMap) {
+ public int getOrientationFromWindowsLocked() {
+ int pos = mWindows.size() - 1;
+ while (pos >= 0) {
+ WindowState wtoken = (WindowState) mWindows.get(pos);
+ pos--;
+ if (wtoken.mAppToken != null) {
+ // We hit an application window. so the orientation will be determined by the
+ // app window. No point in continuing further.
+ return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ }
+ if (!wtoken.isVisibleLw()) {
+ continue;
+ }
+ int req = wtoken.mAttrs.screenOrientation;
+ if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
+ (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
+ continue;
+ } else {
+ return req;
+ }
+ }
+ return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ }
+
+ public int getOrientationFromAppTokensLocked() {
int pos = mAppTokens.size() - 1;
- int req = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
int curGroup = 0;
int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
boolean haveGroup = false;
+ boolean lastFullscreen = false;
while (pos >= 0) {
AppWindowToken wtoken = mAppTokens.get(pos);
pos--;
@@ -1835,13 +2090,21 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else if (curGroup != wtoken.groupId) {
// If we have hit a new application group, and the bottom
// of the previous group didn't explicitly say to use
- // the orientation behind it, then we'll stick with the
+ // the orientation behind it, and the last app was
+ // full screen, then we'll stick with the
// user's orientation.
- if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
- break;
+ if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
+ && lastFullscreen) {
+ return lastOrientation;
}
}
int or = wtoken.requestedOrientation;
+ // If this application is fullscreen, then just take whatever
+ // orientation it has and ignores whatever is under it.
+ lastFullscreen = wtoken.appFullscreen;
+ if (lastFullscreen) {
+ return or;
+ }
// If this application has requested an explicit orientation,
// then use it.
if (or == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
@@ -1849,16 +2112,47 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
or == ActivityInfo.SCREEN_ORIENTATION_SENSOR ||
or == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR ||
or == ActivityInfo.SCREEN_ORIENTATION_USER) {
- req = or;
- break;
+ return or;
}
}
+ return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ }
+
+ public Configuration updateOrientationFromAppTokens(
+ IBinder freezeThisOneIfNeeded) {
+ Configuration config;
+ long ident = Binder.clearCallingIdentity();
+ synchronized(mWindowMap) {
+ config = updateOrientationFromAppTokensLocked(freezeThisOneIfNeeded);
+ }
+ if (config != null) {
+ mLayoutNeeded = true;
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ Binder.restoreCallingIdentity(ident);
+ return config;
+ }
+
+ /*
+ * The orientation is computed from non-application windows first. If none of
+ * the non-application windows specify orientation, the orientation is computed from
+ * application tokens.
+ * @see android.view.IWindowManager#updateOrientationFromAppTokens(
+ * android.os.IBinder)
+ */
+ Configuration updateOrientationFromAppTokensLocked(
+ IBinder freezeThisOneIfNeeded) {
+ boolean changed = false;
+ long ident = Binder.clearCallingIdentity();
+ try {
+ int req = computeForcedAppOrientationLocked();
+
if (req != mForcedAppOrientation) {
changed = true;
mForcedAppOrientation = req;
//send a message to Policy indicating orientation change to take
//action like disabling/enabling sensors etc.,
- mPolicy.setCurrentOrientation(req);
+ mPolicy.setCurrentOrientationLw(req);
}
if (changed) {
@@ -1873,19 +2167,24 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
ActivityInfo.CONFIG_ORIENTATION);
}
}
- Configuration config = computeNewConfigurationLocked();
- if (config != null) {
- mLayoutNeeded = true;
- performLayoutAndPlaceSurfacesLocked();
- }
- return config;
+ return computeNewConfiguration();
}
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
return null;
}
+ int computeForcedAppOrientationLocked() {
+ int req = getOrientationFromWindowsLocked();
+ if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
+ req = getOrientationFromAppTokensLocked();
+ }
+ return req;
+ }
+
public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"setAppOrientation()")) {
@@ -2088,7 +2387,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
- assignLayersLocked();
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
Binder.restoreCallingIdentity(origId);
@@ -2230,7 +2528,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (changed && performLayout) {
mLayoutNeeded = true;
updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
- assignLayersLocked();
performLayoutAndPlaceSurfacesLocked();
}
}
@@ -2559,7 +2856,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean added = false;
for (int j=0; j<NCW; j++) {
WindowState cwin = (WindowState)win.mChildWindows.get(j);
- if (cwin.mSubLayer >= 0) {
+ if (!added && cwin.mSubLayer >= 0) {
mWindows.add(index, win);
index++;
added = true;
@@ -2611,7 +2908,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_REORDER) Log.v(TAG, "Final window list:");
if (DEBUG_REORDER) dumpWindowsLocked();
updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
- assignLayersLocked();
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
}
@@ -2659,7 +2955,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
- assignLayersLocked();
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
@@ -2871,6 +3166,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return KeyInputQueue.getKeycodeState(devid, sw);
}
+ public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
+ return KeyInputQueue.hasKeys(keycodes, keyExists);
+ }
+
public void enableScreenAfterBoot() {
synchronized(mWindowMap) {
if (mSystemBooted) {
@@ -2987,18 +3286,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else {
mRequestedRotation = rotation;
}
- if (DEBUG_ORIENTATION) Log.v(TAG, "Overwriting rotation value from "+rotation);
- rotation = mPolicy.rotationForOrientation(mForcedAppOrientation);
- if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to "+rotation);
+ if (DEBUG_ORIENTATION) Log.v(TAG, "Overwriting rotation value from " + rotation);
+ rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
+ mRotation, mDisplayEnabled);
+ if (DEBUG_ORIENTATION) Log.v(TAG, "new rotation is set to " + rotation);
changed = mDisplayEnabled && mRotation != rotation;
if (changed) {
- mRotation = rotation;
if (DEBUG_ORIENTATION) Log.v(TAG,
"Rotation changed to " + rotation
+ " from " + mRotation
+ " (forceApp=" + mForcedAppOrientation
+ ", req=" + mRequestedRotation + ")");
+ mRotation = rotation;
mWindowsFreezingScreen = true;
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
@@ -3298,21 +3598,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return null;
}
+ /*
+ * Instruct the Activity Manager to fetch the current configuration and broadcast
+ * that to config-changed listeners if appropriate.
+ */
void sendNewConfiguration() {
- Configuration config;
- synchronized (mWindowMap) {
- config = computeNewConfigurationLocked();
- }
-
- if (config != null) {
- try {
- mActivityManager.updateConfiguration(config);
- } catch (RemoteException e) {
- }
+ try {
+ mActivityManager.updateConfiguration(null);
+ } catch (RemoteException e) {
}
}
- Configuration computeNewConfigurationLocked() {
+ public Configuration computeNewConfiguration() {
synchronized (mWindowMap) {
if (mDisplay == null) {
return null;
@@ -3669,6 +3966,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
synchronized(mWindowMap) {
mKeyWaiter.bindTargetWindowLocked(focus);
}
+
+ // NOSHIP extra state logging
+ mKeyWaiter.recordDispatchState(event, focus);
+ // END NOSHIP
try {
if (DEBUG_INPUT || DEBUG_FOCUS) {
@@ -3812,6 +4113,58 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
* but not the other way around.
*/
final class KeyWaiter {
+ // NOSHIP debugging
+ public class DispatchState {
+ private KeyEvent event;
+ private WindowState focus;
+ private long time;
+ private WindowState lastWin;
+ private IBinder lastBinder;
+ private boolean finished;
+ private boolean gotFirstWindow;
+ private boolean eventDispatching;
+ private long timeToSwitch;
+ private boolean wasFrozen;
+ private boolean focusPaused;
+ private WindowState curFocus;
+
+ DispatchState(KeyEvent theEvent, WindowState theFocus) {
+ focus = theFocus;
+ event = theEvent;
+ time = System.currentTimeMillis();
+ // snapshot KeyWaiter state
+ lastWin = mLastWin;
+ lastBinder = mLastBinder;
+ finished = mFinished;
+ gotFirstWindow = mGotFirstWindow;
+ eventDispatching = mEventDispatching;
+ timeToSwitch = mTimeToSwitch;
+ wasFrozen = mWasFrozen;
+ curFocus = mCurrentFocus;
+ // cache the paused state at ctor time as well
+ if (theFocus == null || theFocus.mToken == null) {
+ Log.i(TAG, "focus " + theFocus + " mToken is null at event dispatch!");
+ focusPaused = false;
+ } else {
+ focusPaused = theFocus.mToken.paused;
+ }
+ }
+
+ public String toString() {
+ return "{{" + event + " to " + focus + " @ " + time
+ + " lw=" + lastWin + " lb=" + lastBinder
+ + " fin=" + finished + " gfw=" + gotFirstWindow
+ + " ed=" + eventDispatching + " tts=" + timeToSwitch
+ + " wf=" + wasFrozen + " fp=" + focusPaused
+ + " mcf=" + mCurrentFocus + "}}";
+ }
+ };
+ private DispatchState mDispatchState = null;
+ public void recordDispatchState(KeyEvent theEvent, WindowState theFocus) {
+ mDispatchState = new DispatchState(theEvent, theFocus);
+ }
+ // END NOSHIP
+
public static final int RETURN_NOTHING = 0;
public static final int RETURN_PENDING_POINTER = 1;
public static final int RETURN_PENDING_TRACKBALL = 2;
@@ -3923,7 +4276,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ " targetIsNew=" + targetIsNew
+ " paused="
+ (targetWin != null ? targetWin.mToken.paused : false)
- + " mFocusedApp=" + mFocusedApp);
+ + " mFocusedApp=" + mFocusedApp
+ + " mCurrentFocus=" + mCurrentFocus);
targetApp = targetWin != null
? targetWin.mAppToken : mFocusedApp;
@@ -3952,7 +4306,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
wait(curTimeout);
if (DEBUG_INPUT) Log.v(TAG, "Finished waiting @"
+ SystemClock.uptimeMillis() + " startTime="
- + startTime + " switchTime=" + mTimeToSwitch);
+ + startTime + " switchTime=" + mTimeToSwitch
+ + " target=" + targetWin + " mLW=" + mLastWin
+ + " mLB=" + mLastBinder + " fin=" + mFinished
+ + " mCurrentFocus=" + mCurrentFocus);
} catch (InterruptedException e) {
}
}
@@ -3973,6 +4330,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.w(TAG, "Key dispatching timed out sending to " +
(targetWin != null ? targetWin.mAttrs.getTitle()
: "<null>"));
+ // NOSHIP debugging
+ Log.w(TAG, "Dispatch state: " + mDispatchState);
+ Log.w(TAG, "Current state: " + new DispatchState(nextKey, targetWin));
+ // END NOSHIP
//dump();
if (targetWin != null) {
at = targetWin.getAppToken();
@@ -4355,7 +4716,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
newWindow.mToken.paused = false;
mGotFirstWindow = true;
- boolean doNotify = true;
if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
if (DEBUG_INPUT) Log.v(TAG,
@@ -4372,20 +4732,21 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
TAG, "Last win layer=" + mLastWin.mLayer
+ ", new win layer=" + newWindow.mLayer);
if (newWindow.mLayer >= mLastWin.mLayer) {
- if (!mLastWin.canReceiveKeys()) {
- mLastWin.mToken.paused = false;
- doFinishedKeyLocked(true); // does a notifyAll()
- doNotify = false;
- }
- } else {
- // the new window is lower; no need to wake key waiters
- doNotify = false;
+ // The new window is above the old; finish pending input to the last
+ // window and start directing it to the new one.
+ mLastWin.mToken.paused = false;
+ doFinishedKeyLocked(true); // does a notifyAll()
}
+ // Either the new window is lower, so there is no need to wake key waiters,
+ // or we just finished key input to the previous window, which implicitly
+ // notified the key waiters. In both cases, we don't need to issue the
+ // notification here.
+ return;
}
- if (doNotify) {
- notifyAll();
- }
+ // Now that we've put a new window state in place, make the event waiter
+ // take notice and retarget its attentions.
+ notifyAll();
}
}
@@ -4478,8 +4839,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
KeyQ() {
super(mContext);
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
- mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- | PowerManager.ON_AFTER_RELEASE, "KEEP_SCREEN_ON_FLAG");
+ mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
+ "KEEP_SCREEN_ON_FLAG");
mHoldingScreen.setReferenceCounted(false);
}
@@ -4602,14 +4963,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (holding) {
mHoldingScreen.acquire();
} else {
- long curTime = SystemClock.uptimeMillis();
- mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
+ mPolicy.screenOnStoppedLw();
mHoldingScreen.release();
}
}
}
};
+ public boolean detectSafeMode() {
+ mSafeMode = mPolicy.detectSafeMode();
+ return mSafeMode;
+ }
+
public void systemReady() {
mPolicy.systemReady();
}
@@ -4923,6 +5288,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ public boolean performHapticFeedback(IWindow window, int effectId,
+ boolean always) {
+ synchronized(mWindowMap) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return mPolicy.performHapticFeedbackLw(
+ windowForClientLocked(this, window), effectId, always);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
void windowAddedLocked() {
if (mSurfaceSession == null) {
if (localLOGV) Log.v(
@@ -5083,9 +5461,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Currently running animation.
boolean mAnimating;
+ boolean mLocalAnimating;
Animation mAnimation;
boolean mAnimationIsEntrance;
boolean mHasTransformation;
+ boolean mHasLocalTransformation;
final Transformation mTransformation = new Transformation();
// This is set after IWindowSession.relayout() has been called at
@@ -5125,6 +5505,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// been updated for the new orientation.
boolean mOrientationChanging;
+ // Is this window now (or just being) removed?
+ boolean mRemoved;
+
WindowState(Session s, IWindow c, WindowToken token,
WindowState attachedWindow, WindowManager.LayoutParams a,
int viewVisibility) {
@@ -5292,6 +5675,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return mFrame;
}
+ public Rect getShownFrameLw() {
+ return mShownFrame;
+ }
+
public Rect getDisplayFrameLw() {
return mDisplayFrame;
}
@@ -5344,6 +5731,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (localLOGV) Log.v(
TAG, "Setting animation in " + this + ": " + anim);
mAnimating = false;
+ mLocalAnimating = false;
mAnimation = anim;
mAnimation.restrictDuration(MAX_ANIMATION_DURATION);
mAnimation.scaleCurrentDuration(mWindowAnimationScale);
@@ -5352,6 +5740,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public void clearAnimation() {
if (mAnimation != null) {
mAnimating = true;
+ mLocalAnimating = false;
mAnimation = null;
}
}
@@ -5580,13 +5969,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (!mDrawPending && !mCommitDrawPending && mAnimation != null) {
mHasTransformation = true;
- if (!mAnimating) {
+ mHasLocalTransformation = true;
+ if (!mLocalAnimating) {
if (DEBUG_ANIM) Log.v(
TAG, "Starting animation in " + this +
" @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
" dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale);
mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
mAnimation.setStartTime(currentTime);
+ mLocalAnimating = true;
mAnimating = true;
}
mTransformation.clear();
@@ -5595,9 +5986,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_ANIM) Log.v(
TAG, "Stepped animation in " + this +
": more=" + more + ", xform=" + mTransformation);
- if (mAppToken != null && mAppToken.hasTransformation) {
- mTransformation.compose(mAppToken.transformation);
- }
if (more) {
// we're not done!
return true;
@@ -5608,10 +5996,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mAnimation = null;
//WindowManagerService.this.dump();
}
- if (mAppToken != null && mAppToken.hasTransformation) {
+ mHasLocalTransformation = false;
+ if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
+ && mAppToken.hasTransformation) {
+ // When our app token is animating, we kind-of pretend like
+ // we are as well. Note the mLocalAnimating mAnimationIsEntrance
+ // part of this check means that we will only do this if
+ // our window is not currently exiting, or it is not
+ // locally animating itself. The idea being that one that
+ // is exiting and doing a local animation should be removed
+ // once that animation is done.
mAnimating = true;
mHasTransformation = true;
- mTransformation.set(mAppToken.transformation);
+ mTransformation.clear();
return false;
} else if (mHasTransformation) {
// Little trick to get through the path below to act like
@@ -5624,10 +6021,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// If the display is frozen, and there is a pending animation,
// clear it and make sure we run the cleanup code.
mAnimating = true;
+ mLocalAnimating = true;
mAnimation = null;
}
- if (!mAnimating) {
+ if (!mAnimating && !mLocalAnimating) {
return false;
}
@@ -5637,9 +6035,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ (mAppToken != null ? mAppToken.reportedVisible : false));
mAnimating = false;
+ mLocalAnimating = false;
mAnimation = null;
mAnimLayer = mLayer;
+ if (mIsImWindow) {
+ mAnimLayer += mInputMethodAnimLayerAdjustment;
+ }
+ if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
+ + " anim layer: " + mAnimLayer);
mHasTransformation = false;
+ mHasLocalTransformation = false;
mPolicyVisibility = mPolicyVisibilityAfterAnim;
mTransformation.clear();
if (mHasDrawn
@@ -5714,10 +6119,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
void computeShownFrameLocked() {
- final boolean selfTransformation = mHasTransformation;
- final boolean attachedTransformation = (mAttachedWindow != null
- && mAttachedWindow.mHasTransformation);
- if (selfTransformation || attachedTransformation) {
+ final boolean selfTransformation = mHasLocalTransformation;
+ Transformation attachedTransformation =
+ (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation)
+ ? mAttachedWindow.mTransformation : null;
+ Transformation appTransformation =
+ (mAppToken != null && mAppToken.hasTransformation)
+ ? mAppToken.transformation : null;
+ if (selfTransformation || attachedTransformation != null
+ || appTransformation != null) {
// cache often used attributes locally
final Rect frame = mFrame;
final float tmpFloats[] = mTmpFloats;
@@ -5728,8 +6138,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (selfTransformation) {
tmpMatrix.preConcat(mTransformation.getMatrix());
}
- if (attachedTransformation) {
- tmpMatrix.preConcat(mAttachedWindow.mTransformation.getMatrix());
+ if (attachedTransformation != null) {
+ tmpMatrix.preConcat(attachedTransformation.getMatrix());
+ }
+ if (appTransformation != null) {
+ tmpMatrix.preConcat(appTransformation.getMatrix());
}
// "convert" it into SurfaceFlinger's format
@@ -5755,15 +6168,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// transforming since it is more important to have that
// animation be smooth.
mShownAlpha = mAlpha;
- if (false && (!PixelFormat.formatHasAlpha(mAttrs.format)
+ if (!mLimitedAlphaCompositing
+ || (!PixelFormat.formatHasAlpha(mAttrs.format)
|| (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
&& x == frame.left && y == frame.top))) {
//Log.i(TAG, "Applying alpha transform");
if (selfTransformation) {
mShownAlpha *= mTransformation.getAlpha();
}
- if (attachedTransformation) {
- mShownAlpha *= mAttachedWindow.mTransformation.getAlpha();
+ if (attachedTransformation != null) {
+ mShownAlpha *= attachedTransformation.getAlpha();
+ }
+ if (appTransformation != null) {
+ mShownAlpha *= appTransformation.getAlpha();
}
} else {
//Log.i(TAG, "Not applying alpha transform");
@@ -5787,7 +6204,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
/**
* Is this window visible? It is not visible if there is no
* surface, or we are in the process of running an exit animation
- * that will remove the surface.
+ * that will remove the surface, or its app token has been hidden.
*/
public boolean isVisibleLw() {
final AppWindowToken atoken = mAppToken;
@@ -5797,6 +6214,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
/**
+ * Is this window visible, ignoring its app token? It is not visible
+ * if there is no surface, or we are in the process of running an exit animation
+ * that will remove the surface.
+ */
+ public boolean isWinVisibleLw() {
+ final AppWindowToken atoken = mAppToken;
+ return mSurface != null && mPolicyVisibility && !mAttachedHidden
+ && (atoken == null || !atoken.hiddenRequested || atoken.animating)
+ && !mExiting && !mDestroying;
+ }
+
+ /**
* The same as isVisible(), but follows the current hidden state of
* the associated app token, not the pending requested hidden state.
*/
@@ -5877,10 +6306,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
public boolean fillsScreenLw(int screenWidth, int screenHeight,
- boolean shownFrame) {
+ boolean shownFrame, boolean onlyOpaque) {
if (mSurface == null) {
return false;
}
+ if (mAppToken != null && !mAppToken.appFullscreen) {
+ return false;
+ }
+ if (onlyOpaque && mAttrs.format != PixelFormat.OPAQUE) {
+ return false;
+ }
final Rect frame = shownFrame ? mShownFrame : mFrame;
if (frame.left <= 0 && frame.top <= 0
&& frame.right >= screenWidth
@@ -5944,21 +6379,23 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return mHasDrawn;
}
- public void showLw(boolean doAnimation) {
+ public boolean showLw(boolean doAnimation) {
if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim) {
- mSurfacesChanged = true;
mPolicyVisibility = true;
mPolicyVisibilityAfterAnim = true;
if (doAnimation) {
applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
}
requestAnimationLocked(0);
+ return true;
}
+ return false;
}
- public void hideLw(boolean doAnimation) {
- if (mPolicyVisibility || mPolicyVisibilityAfterAnim) {
- mSurfacesChanged = true;
+ public boolean hideLw(boolean doAnimation) {
+ boolean current = doAnimation ? mPolicyVisibilityAfterAnim
+ : mPolicyVisibility;
+ if (current) {
if (doAnimation) {
applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false);
if (mAnimation == null) {
@@ -5968,10 +6405,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (doAnimation) {
mPolicyVisibilityAfterAnim = false;
} else {
+ mPolicyVisibilityAfterAnim = false;
mPolicyVisibility = false;
}
requestAnimationLocked(0);
+ return true;
}
+ return false;
}
void dump(PrintWriter pw, String prefix) {
@@ -6020,6 +6460,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.println(prefix + "mShownAlpha=" + mShownAlpha
+ " mAlpha=" + mAlpha + " mLastAlpha=" + mLastAlpha);
pw.println(prefix + "mAnimating=" + mAnimating
+ + " mLocalAnimating=" + mLocalAnimating
+ " mAnimationIsEntrance=" + mAnimationIsEntrance
+ " mAnimation=" + mAnimation);
pw.println(prefix + "XForm: has=" + mHasTransformation
@@ -6030,7 +6471,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ " mHasDrawn=" + mHasDrawn);
pw.println(prefix + "mExiting=" + mExiting
+ " mRemoveOnExit=" + mRemoveOnExit
- + " mDestroying=" + mDestroying);
+ + " mDestroying=" + mDestroying
+ + " mRemoved=" + mRemoved);
pw.println(prefix + "mOrientationChanging=" + mOrientationChanging
+ " mAppFreezing=" + mAppFreezing);
}
@@ -6039,7 +6481,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public String toString() {
return "Window{"
+ Integer.toHexString(System.identityHashCode(this))
- + " " + mAttrs.getTitle() + "}";
+ + " " + mAttrs.getTitle() + " paused=" + mToken.paused + "}";
}
}
@@ -6054,6 +6496,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// The type of window this token is for, as per WindowManager.LayoutParams.
final int windowType;
+ // Set if this token was explicitly added by a client, so should
+ // not be removed when all windows are removed.
+ final boolean explicit;
+
// If this is an AppWindowToken, this is non-null.
AppWindowToken appWindowToken;
@@ -6069,9 +6515,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Temporary for finding which tokens no longer have visible windows.
boolean hasVisible;
- WindowToken(IBinder _token, int type) {
+ WindowToken(IBinder _token, int type, boolean _explicit) {
token = _token;
windowType = type;
+ explicit = _explicit;
}
void dump(PrintWriter pw, String prefix) {
@@ -6151,7 +6598,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean firstWindowDrawn;
AppWindowToken(IApplicationToken _token) {
- super(_token.asBinder(), WindowManager.LayoutParams.TYPE_APPLICATION);
+ super(_token.asBinder(),
+ WindowManager.LayoutParams.TYPE_APPLICATION, true);
appWindowToken = this;
appToken = _token;
}
@@ -6198,17 +6646,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
for (int i=0; i<N; i++) {
WindowState w = allAppWindows.get(i);
w.mAnimLayer = w.mLayer + adj;
+ if (DEBUG_LAYERS) Log.v(TAG, "Updating layer " + w + ": "
+ + w.mAnimLayer);
if (w == mInputMethodTarget) {
- WindowState imw = mInputMethodWindow;
- if (imw != null) {
- imw.mAnimLayer = imw.mLayer + adj;
- }
- int di = mInputMethodDialogs.size();
- while (di > 0) {
- di --;
- imw = mInputMethodDialogs.get(di);
- imw.mAnimLayer = imw.mLayer + adj;
- }
+ setInputMethodAnimLayerAdjustment(adj);
}
}
}
@@ -6295,7 +6736,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
clearAnimation();
animating = false;
-
+ if (mInputMethodTarget != null && mInputMethodTarget.mAppToken == this) {
+ moveInputMethodWindowsIfNeededLocked(true);
+ }
+
if (DEBUG_ANIM) Log.v(
TAG, "Animation done in " + this
+ ": reportedVisible=" + reportedVisible);
@@ -6503,6 +6947,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public static final int FORCE_GC = 15;
public static final int ENABLE_SCREEN = 16;
public static final int APP_FREEZE_TIMEOUT = 17;
+ public static final int COMPUTE_AND_SEND_NEW_CONFIGURATION = 18;
private Session mLastReportedHold;
@@ -6519,6 +6964,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
synchronized(mWindowMap) {
lastFocus = mLastFocus;
newFocus = mCurrentFocus;
+ if (lastFocus == newFocus) {
+ // Focus is not changing, so nothing to do.
+ return;
+ }
mLastFocus = newFocus;
//Log.i(TAG, "Focus moving from " + lastFocus
// + " to " + newFocus);
@@ -6829,6 +7278,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
break;
}
+ case COMPUTE_AND_SEND_NEW_CONFIGURATION: {
+ if (updateOrientationFromAppTokens(null) != null) {
+ sendNewConfiguration();
+ }
+ break;
+ }
+
}
}
}
@@ -6848,12 +7304,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
synchronized (mWindowMap) {
// The focus for the client is the window immediately below
// where we would place the input method window.
- int idx = findDesiredInputMethodWindowIndexLocked();
+ int idx = findDesiredInputMethodWindowIndexLocked(false);
+ WindowState imFocus;
if (idx > 0) {
- WindowState imFocus = (WindowState)mWindows.get(idx-1);
- if (imFocus != null && imFocus.mSession.mClient != null &&
- imFocus.mSession.mClient.asBinder() == client.asBinder()) {
- return true;
+ imFocus = (WindowState)mWindows.get(idx-1);
+ if (imFocus != null) {
+ if (imFocus.mSession.mClient != null &&
+ imFocus.mSession.mClient.asBinder() == client.asBinder()) {
+ return true;
+ }
}
}
}
@@ -6888,13 +7347,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
private final void assignLayersLocked() {
- if (mInLayout) {
- if (Config.DEBUG) {
- throw new RuntimeException("Recursive call!");
- }
- return;
- }
-
int N = mWindows.size();
int curBaseLayer = 0;
int curLayer = 0;
@@ -6916,6 +7368,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} else {
w.mAnimLayer = w.mLayer;
}
+ if (w.mIsImWindow) {
+ w.mAnimLayer += mInputMethodAnimLayerAdjustment;
+ }
+ if (DEBUG_LAYERS) Log.v(TAG, "Assign layer " + w + ": "
+ + w.mAnimLayer);
//System.out.println(
// "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
}
@@ -6927,6 +7384,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (Config.DEBUG) {
throw new RuntimeException("Recursive call!");
}
+ Log.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
return;
}
@@ -6999,7 +7457,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
WindowState win = (WindowState) mWindows.get(i);
boolean gone = win.mViewVisibility == View.GONE
- || !win.mRelayoutCalled;
+ || !win.mRelayoutCalled
+ || win.mToken.hidden;
// If this view is GONE, then skip it -- keep the current
// frame, and let the caller know so they can ignore it
@@ -7073,6 +7532,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean orientationChangeComplete = true;
Session holdScreen = null;
+ float screenBrightness = -1;
boolean focusDisplayed = false;
boolean animating = false;
@@ -7285,6 +7745,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// This has changed the visibility of windows, so perform
// a new layout to get them all up-to-date.
mLayoutNeeded = true;
+ moveInputMethodWindowsIfNeededLocked(true);
performLayoutLockedInner();
updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES);
@@ -7297,12 +7758,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final boolean someoneLosingFocus = mLosingFocus.size() != 0;
- mSurfacesChanged = false;
boolean obscured = false;
boolean blurring = false;
boolean dimming = false;
boolean covered = false;
- int tint = 0;
for (i=N-1; i>=0; i--) {
WindowState w = (WindowState)mWindows.get(i);
@@ -7558,9 +8017,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Update effect.
if (!obscured) {
- if (w.mSurface != null &&
- (attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
- holdScreen = w.mSession;
+ if (w.mSurface != null) {
+ if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
+ holdScreen = w.mSession;
+ }
+ if (w.mAttrs.screenBrightness >= 0 && screenBrightness < 0) {
+ screenBrightness = w.mAttrs.screenBrightness;
+ }
}
if (w.isFullscreenOpaque(dw, dh)) {
// This window completely covers everything behind it,
@@ -7619,6 +8082,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// the user.
duration *= DIM_DURATION_MULTIPLIER;
}
+ if (duration < 1) {
+ // Don't divide by zero
+ duration = 1;
+ }
mDimTargetAlpha = target;
mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha)
/ duration;
@@ -7673,7 +8140,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mDimCurrentAlpha += mDimDeltaPerMs
* (currentTime-mLastDimAnimTime);
boolean more = true;
- if (mDimDeltaPerMs > 0) {
+ if (mDisplayFrozen) {
+ // If the display is frozen, there is no reason to animate.
+ more = false;
+ } else if (mDimDeltaPerMs > 0) {
if (mDimCurrentAlpha > mDimTargetAlpha) {
more = false;
}
@@ -7767,6 +8237,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
i--;
WindowState win = mDestroySurface.get(i);
win.mDestroying = false;
+ if (mInputMethodWindow == win) {
+ mInputMethodWindow = null;
+ }
win.destroySurfaceLocked();
} while (i > 0);
mDestroySurface.clear();
@@ -7796,6 +8269,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
}
mQueue.setHoldScreenLocked(holdScreen != null);
+ if (screenBrightness < 0 || screenBrightness > 1.0f) {
+ mPowerManager.setScreenBrightnessOverride(-1);
+ } else {
+ mPowerManager.setScreenBrightnessOverride((int)
+ (screenBrightness * Power.BRIGHTNESS_ON));
+ }
if (holdScreen != mHoldingScreenOn) {
mHoldingScreenOn = holdScreen;
Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
@@ -7811,7 +8290,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
/**
- * Have the surface flinger show a surface, robustly dealing wit
+ * Have the surface flinger show a surface, robustly dealing with
* error conditions. In particular, if there is not enough memory
* to show the surface, then we will try to get rid of other surfaces
* in order to succeed.
@@ -7925,31 +8404,33 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (mCurrentFocus != newFocus) {
// This check makes sure that we don't already have the focus
// change message pending.
- if (mLastFocus == mCurrentFocus) {
- mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
- }
+ mH.removeMessages(H.REPORT_FOCUS_CHANGE);
+ mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
if (localLOGV) Log.v(
TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
mLosingFocus.remove(newFocus);
- if (newFocus != null) {
- mKeyWaiter.handleNewWindowLocked(newFocus);
- }
final WindowState imWindow = mInputMethodWindow;
if (newFocus != imWindow && oldFocus != imWindow) {
- moveInputMethodWindowsIfNeededLocked(
+ if (moveInputMethodWindowsIfNeededLocked(
mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
- mode != UPDATE_FOCUS_WILL_PLACE_SURFACES);
- mLayoutNeeded = true;
+ mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
+ mLayoutNeeded = true;
+ }
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
performLayoutLockedInner();
- } else if (mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) {
- mLayoutNeeded = true;
- performLayoutAndPlaceSurfacesLocked();
+ } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
+ // Client will do the layout, but we need to assign layers
+ // for handleNewWindowLocked() below.
+ assignLayersLocked();
}
}
+
+ if (newFocus != null && mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
+ mKeyWaiter.handleNewWindowLocked(newFocus);
+ }
return true;
}
return false;
@@ -8029,6 +8510,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return;
}
+ mScreenFrozenLock.acquire();
+
long now = SystemClock.uptimeMillis();
//Log.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
if (mFreezeGcPending != 0) {
@@ -8084,6 +8567,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mH.removeMessages(H.FORCE_GC);
mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
2000);
+
+ mScreenFrozenLock.release();
}
@Override
@@ -8218,13 +8703,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.println(" mSystemBooted=" + mSystemBooted
+ " mDisplayEnabled=" + mDisplayEnabled);
pw.println(" mLayoutNeeded=" + mLayoutNeeded
- + " mSurfacesChanged=" + mSurfacesChanged
+ " mBlurShown=" + mBlurShown);
pw.println(" mDimShown=" + mDimShown
+ " current=" + mDimCurrentAlpha
+ " target=" + mDimTargetAlpha
+ " delta=" + mDimDeltaPerMs
+ " lastAnimTime=" + mLastDimAnimTime);
+ pw.println(" mInputMethodAnimLayerAdjustment="
+ + mInputMethodAnimLayerAdjustment);
pw.println(" mDisplayFrozen=" + mDisplayFrozen
+ " mWindowsFreezingScreen=" + mWindowsFreezingScreen
+ " mAppsFreezingScreen=" + mAppsFreezingScreen);
@@ -8249,7 +8735,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ " mLastBinder=" + mKeyWaiter.mLastBinder);
pw.println(" mFinished=" + mKeyWaiter.mFinished
+ " mGotFirstWindow=" + mKeyWaiter.mGotFirstWindow
- + " mEventDispatching" + mKeyWaiter.mEventDispatching
+ + " mEventDispatching=" + mKeyWaiter.mEventDispatching
+ " mTimeToSwitch=" + mKeyWaiter.mTimeToSwitch);
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 361c7f7..9d720d1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -48,6 +48,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
@@ -96,6 +97,7 @@ import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
+import java.lang.IllegalStateException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
@@ -157,7 +159,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
static final int LOG_AM_CREATE_SERVICE = 30030;
static final int LOG_AM_DESTROY_SERVICE = 30031;
-
+ static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
+ static final int LOG_AM_DROP_PROCESS = 30033;
+ static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
+ static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
+ static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
+
static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
@@ -197,6 +204,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
*/
static final int LAUNCH_TIMEOUT = 10*1000;
+ // How long we wait for a launched process to attach to the activity manager
+ // before we decide it's never going to come up for real.
+ static final int PROC_START_TIMEOUT = 10*1000;
+
// How long we wait until giving up on the last activity telling us it
// is idle.
static final int IDLE_TIMEOUT = 10*1000;
@@ -252,6 +263,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final int HIDDEN_APP_MAX_ADJ;
static int HIDDEN_APP_MIN_ADJ;
+ // This is a process holding the home application -- we want to try
+ // avoiding killing it, even if it would normally be in the background,
+ // because the user interacts with it so much.
+ final int HOME_APP_ADJ;
+
// This is a process holding a secondary server -- killing it will not
// have much of an impact as far as the user is concerned. Value set in
// system/rootdir/init.rc on startup.
@@ -279,6 +295,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Corresponding memory levels for above adjustments.
final int EMPTY_APP_MEM;
final int HIDDEN_APP_MEM;
+ final int HOME_APP_MEM;
final int SECONDARY_SERVER_MEM;
final int VISIBLE_APP_MEM;
final int FOREGROUND_APP_MEM;
@@ -350,6 +367,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord mFocusedActivity = null;
/**
+ * This is the last activity that we put into the paused state. This is
+ * used to determine if we need to do an activity transition while sleeping,
+ * when we normally hold the top activity paused.
+ */
+ HistoryRecord mLastPausedActivity = null;
+
+ /**
* List of activities that are waiting for a new activity
* to become visible before completing whatever operation they are
* supposed to do.
@@ -469,6 +493,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
= new ArrayList<ProcessRecord>();
/**
+ * This is the process holding what we currently consider to be
+ * the "home" activity.
+ */
+ private ProcessRecord mHomeProcess;
+
+ /**
* List of running activities, sorted by recent usage.
* The first entry in the list is the least recently used.
* It contains HistoryRecord objects.
@@ -631,6 +661,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* any user id that can impact battery performance.
*/
final BatteryStatsService mBatteryStatsService;
+
+ /**
+ * information about component usage
+ */
+ final UsageStatsService mUsageStatsService;
/**
* Current configuration information. HistoryRecord objects are given
@@ -799,6 +834,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
static final int DESTROY_TIMEOUT_MSG = 17;
static final int SERVICE_ERROR_MSG = 18;
static final int RESUME_TOP_ACTIVITY_MSG = 19;
+ static final int PROC_START_TIMEOUT_MSG = 20;
AlertDialog mUidAlert;
@@ -840,17 +876,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
} break;
case SHOW_NOT_RESPONDING_MSG: {
- HashMap data = (HashMap) msg.obj;
- // This needs to be *un*synchronized to avoid deadlock.
- Checkin.logEvent(mContext.getContentResolver(),
- Checkin.Events.Tag.SYSTEM_APP_NOT_RESPONDING,
- (String)data.get("info"));
synchronized (ActivityManagerService.this) {
+ HashMap data = (HashMap) msg.obj;
ProcessRecord proc = (ProcessRecord)data.get("app");
if (proc != null && proc.anrDialog != null) {
Log.e(TAG, "App already has anr dialog: " + proc);
return;
}
+
+ broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID);
+
Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
mContext, proc, (HistoryRecord)data.get("activity"));
d.show();
@@ -981,6 +1018,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
resumeTopActivityLocked(null);
}
}
+ case PROC_START_TIMEOUT_MSG: {
+ ProcessRecord app = (ProcessRecord)msg.obj;
+ synchronized (ActivityManagerService.this) {
+ processStartTimedOutLocked(app);
+ }
+ }
}
}
};
@@ -1053,6 +1096,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
m.mLaunchingActivity.setReferenceCounted(false);
m.mBatteryStatsService.publish(context);
+ m.mUsageStatsService.publish(context);
synchronized (thr) {
thr.mReady = true;
@@ -1186,8 +1230,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
procs = service.mLRUProcesses;
}
}
- pw.println("Applications Memory Usage (kB):");
- dumpApplicationMemoryUsage(fd, pw, procs, " ");
+ dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
}
}
@@ -1224,6 +1267,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
systemDir, "batterystats.bin").toString());
mBatteryStatsService.getActiveStatistics().readLocked();
mBatteryStatsService.getActiveStatistics().writeLocked();
+
+ mUsageStatsService = new UsageStatsService( new File(
+ systemDir, "usagestats.bin").toString());
mConfiguration.makeDefault();
mProcessStats.init();
@@ -1238,6 +1284,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
SECONDARY_SERVER_ADJ =
Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
+ HOME_APP_ADJ =
+ Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
HIDDEN_APP_MIN_ADJ =
Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
CONTENT_PROVIDER_ADJ =
@@ -1251,6 +1299,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
SECONDARY_SERVER_MEM =
Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
+ HOME_APP_MEM =
+ Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
HIDDEN_APP_MEM =
Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
EMPTY_APP_MEM =
@@ -1519,9 +1569,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
System.identityHashCode(r),
r.task.taskId, r.shortComponentName);
}
+ if (r.isHomeActivity) {
+ mHomeProcess = app;
+ }
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
r.info, r.icicle, results, newIntents, !andResume,
isNextTransitionForward());
+ // Update usage stats for launched activity
+ updateUsageStats(r, true);
} catch (RemoteException e) {
if (r.launchFailed) {
// This is the second time we failed -- finish activity
@@ -1668,6 +1723,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (app.pid > 0 && app.pid != MY_PID) {
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
+ mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
app.pid = 0;
}
@@ -1760,6 +1816,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.removed = false;
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(pid, app);
+ Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
+ msg.obj = app;
+ mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
}
} else {
app.pid = 0;
@@ -1775,7 +1834,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- private final void startPausingLocked(boolean userLeaving) {
+ private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
if (mPausingActivity != null) {
RuntimeException e = new RuntimeException();
Log.e(TAG, "Trying to pause when pause is already pending for "
@@ -1791,6 +1850,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
mResumedActivity = null;
mPausingActivity = prev;
+ mLastPausedActivity = prev;
prev.state = ActivityState.PAUSING;
prev.task.touchActiveTime();
@@ -1804,13 +1864,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
prev.shortComponentName);
prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
prev.configChangeFlags);
+ updateUsageStats(prev, false);
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Log.w(TAG, "Exception thrown during pause", e);
mPausingActivity = null;
+ mLastPausedActivity = null;
}
} else {
mPausingActivity = null;
+ mLastPausedActivity = null;
}
// If we are not going to sleep, we want to ensure the device is
@@ -1827,9 +1890,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mPausingActivity != null) {
// Have the window manager pause its key dispatching until the new
- // activity has started...
- prev.pauseKeyDispatchingLocked();
-
+ // activity has started. If we're pausing the activity just because
+ // the screen is being turned off and the UI is sleeping, don't interrupt
+ // key dispatch; the same activity will pick it up again on wakeup.
+ if (!uiSleeping) {
+ prev.pauseKeyDispatchingLocked();
+ } else {
+ if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
+ }
+
// Schedule a pause timeout in case the app doesn't respond.
// We don't give it much time because this directly impacts the
// responsiveness seen by the user.
@@ -1848,6 +1917,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private final void completePauseLocked() {
HistoryRecord prev = mPausingActivity;
if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
+
if (prev != null) {
if (prev.finishing) {
if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
@@ -1966,7 +2036,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// First: if this is not the current activity being started, make
// sure it matches the current configuration.
if (r != starting && doThisProcess) {
- ensureActivityConfigurationLocked(r);
+ ensureActivityConfigurationLocked(r, 0);
}
if (r.app == null || r.app.thread == null) {
@@ -2085,6 +2155,14 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ensureActivitiesVisibleLocked(r, starting, null, configChanges);
}
}
+
+ private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
+ if (resumed) {
+ mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
+ } else {
+ mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
+ }
+ }
/**
* Ensure that the top activity in the stack is resumed.
@@ -2134,7 +2212,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityLocked(null, intent, null, null, 0, aInfo,
- null, null, 0, 0, 0, false);
+ null, null, 0, 0, 0, false, false);
}
}
return true;
@@ -2148,6 +2226,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return false;
}
+ // If we are sleeping, and there is no resumed activity, and the top
+ // activity is paused, well that is the state we want.
+ if (mSleeping && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
+ // Make sure we have executed any pending transitions, since there
+ // should be nothing left to do at this point.
+ mWindowManager.executeAppTransition();
+ return false;
+ }
+
// The activity may be waiting for stop, but that is no longer
// appropriate for it.
mStoppingActivities.remove(next);
@@ -2166,7 +2253,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// can be resumed...
if (mResumedActivity != null) {
if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
- startPausingLocked(userLeaving);
+ startPausingLocked(userLeaving, false);
return true;
}
@@ -2267,6 +2354,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Do over!
mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
}
+ mWindowManager.executeAppTransition();
return true;
}
@@ -2290,6 +2378,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
System.identityHashCode(next),
next.task.taskId, next.shortComponentName);
+ updateUsageStats(next, true);
next.app.thread.scheduleResumeActivity(next,
isNextTransitionForward());
@@ -2453,9 +2542,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// We don't want to reuse the previous starting preview if:
// (1) The current activity is in a different task.
if (prev.task != r.task) prev = null;
- // (2) The current activity is not the first in the task.
- else if (!prev.frontOfTask) prev = null;
- // (3) The current activity is already displayed.
+ // (2) The current activity is already displayed.
else if (prev.nowVisible) prev = null;
}
mWindowManager.setAppStartingWindow(
@@ -2537,6 +2624,40 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
/**
+ * Find the activity in the history stack within the given task. Returns
+ * the index within the history at which it's found, or < 0 if not found.
+ */
+ private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
+ int i = mHistory.size();
+ while (i > 0) {
+ i--;
+ HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
+ if (candidate.task.taskId != task) {
+ break;
+ }
+ if (candidate.realActivity.equals(r.realActivity)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Reorder the history stack so that the activity at the given index is
+ * brought to the front.
+ */
+ private final HistoryRecord moveActivityToFrontLocked(int where) {
+ HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
+ int top = mHistory.size();
+ HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
+ mHistory.add(top, newTop);
+ oldTop.frontOfTask = false;
+ newTop.frontOfTask = true;
+ return newTop;
+ }
+
+ /**
* Deliver a new Intent to an existing activity, so that its onNewIntent()
* method will be called at the proper time.
*/
@@ -2550,8 +2671,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.app.thread.scheduleNewIntent(ar, r);
sent = true;
} catch (Exception e) {
- Log.w(TAG,
- "Exception thrown sending new intent to " + r, e);
+ Log.w(TAG, "Exception thrown sending new intent to " + r, e);
}
}
if (!sent) {
@@ -2573,7 +2693,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Uri[] grantedUriPermissions,
int grantedMode, ActivityInfo aInfo, IBinder resultTo,
String resultWho, int requestCode,
- int callingPid, int callingUid, boolean onlyIfNeeded) {
+ int callingPid, int callingUid, boolean onlyIfNeeded,
+ boolean componentSpecified) {
Log.i(TAG, "Starting activity: " + intent);
HistoryRecord sourceRecord = null;
@@ -2688,7 +2809,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
intent, resolvedType, aInfo, mConfiguration,
- resultRecord, resultWho, requestCode);
+ resultRecord, resultWho, requestCode, componentSpecified);
r.startTime = SystemClock.uptimeMillis();
HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
@@ -2969,6 +3090,19 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
resumeTopActivityLocked(null);
return START_DELIVERED_TO_TOP;
}
+ } else if (!addingToTask &&
+ (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
+ // In this case, we are launching an activity in our own task
+ // that may already be running somewhere in the history, and
+ // we want to shuffle it to the front of the stack if so.
+ int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
+ if (where >= 0) {
+ HistoryRecord top = moveActivityToFrontLocked(where);
+ logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
+ deliverNewIntentLocked(top, r.intent);
+ resumeTopActivityLocked(null);
+ return START_DELIVERED_TO_TOP;
+ }
}
// An existing activity is starting this new activity, so we want
// to keep the new one in the same task as the one that is starting
@@ -3009,6 +3143,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
throw new IllegalArgumentException("File descriptors passed in Intent");
}
+ final boolean componentSpecified = intent.getComponent() != null;
+
// Don't modify the client's object!
intent = new Intent(intent);
@@ -3048,7 +3184,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int res = startActivityLocked(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, aInfo,
resultTo, resultWho, requestCode, -1, -1,
- onlyIfNeeded);
+ onlyIfNeeded, componentSpecified);
Binder.restoreCallingIdentity(origId);
return res;
}
@@ -3138,7 +3274,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// those are not yet exposed to user code, so there is no need.
int res = startActivityLocked(r.app.thread, intent,
r.resolvedType, null, 0, aInfo, resultTo, resultWho,
- requestCode, -1, r.launchedFromUid, false);
+ requestCode, -1, r.launchedFromUid, false, false);
Binder.restoreCallingIdentity(origId);
r.finishing = wasFinishing;
@@ -3152,6 +3288,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final int startActivityInPackage(int uid,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded) {
+ final boolean componentSpecified = intent.getComponent() != null;
+
// Don't modify the client's object!
intent = new Intent(intent);
@@ -3182,7 +3320,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized(this) {
return startActivityLocked(null, intent, resolvedType,
null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
- onlyIfNeeded);
+ onlyIfNeeded, componentSpecified);
}
}
@@ -3388,7 +3526,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mPausingActivity == null) {
if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
- startPausingLocked(false);
+ startPausingLocked(false, false);
}
} else if (r.state != ActivityState.PAUSING) {
@@ -3522,9 +3660,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.app.thread.scheduleSendResult(r, list);
return;
} catch (Exception e) {
- Log.w(TAG,
- "Exception thrown sending result to " + r,
- e);
+ Log.w(TAG, "Exception thrown sending result to " + r, e);
}
}
@@ -3710,8 +3846,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.configChangeFlags = 0;
if (!mLRUActivities.remove(r)) {
- Log.w(TAG, "Activity " + r
- + " being finished, but not in LRU list");
+ Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
}
return removedFromHistory;
@@ -3753,6 +3888,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
mPausingActivity = null;
}
+ if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
+ mLastPausedActivity = null;
+ }
// Remove this application's activities from active lists.
removeHistoryRecordsForAppLocked(mLRUActivities, app);
@@ -3958,9 +4096,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
info.append("\nCPU usage:\n");
info.append(processInfo);
}
- info.append("\n/proc/meminfo:\n");
- info.append(readFile("/proc/meminfo"));
-
Log.i(TAG, info.toString());
// The application is not responding. Dump as many thread traces as we can.
@@ -4012,7 +4147,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
msg.what = SHOW_NOT_RESPONDING_MSG;
msg.obj = map;
map.put("app", app);
- map.put("info", info.toString());
if (activity != null) {
map.put("activity", activity);
}
@@ -4142,21 +4276,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = ActivityThread.getPackageManager();
+ int pkgUid = -1;
synchronized(this) {
- int pkgUid = -1;
try {
pkgUid = pm.getPackageUid(packageName);
} catch (RemoteException e) {
}
if (pkgUid == -1) {
- Log.w(TAG, "Invalid packageName:"+packageName);
+ Log.w(TAG, "Invalid packageName:" + packageName);
return false;
}
if (uid == pkgUid || checkComponentPermission(
android.Manifest.permission.CLEAR_APP_USER_DATA,
pid, uid, -1)
== PackageManager.PERMISSION_GRANTED) {
- uninstallPackageLocked(packageName, pkgUid, false);
+ restartPackageLocked(packageName, pkgUid);
} else {
throw new SecurityException(pid+" does not have permission:"+
android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
@@ -4167,6 +4301,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
//clear application user data
pm.clearApplicationUserData(packageName, observer);
+ Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
+ Uri.fromParts("package", packageName, null));
+ intent.putExtra(Intent.EXTRA_UID, pkgUid);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID);
} catch (RemoteException e) {
}
} finally {
@@ -4188,25 +4328,48 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
long callingId = Binder.clearCallingIdentity();
try {
+ IPackageManager pm = ActivityThread.getPackageManager();
+ int pkgUid = -1;
synchronized(this) {
- uninstallPackageLocked(packageName, -1, false);
- broadcastIntentLocked(null, null,
- new Intent(Intent.ACTION_PACKAGE_RESTARTED,
- Uri.fromParts("package", packageName, null)),
- null, null, 0, null, null, null,
- false, false, MY_PID, Process.SYSTEM_UID);
+ try {
+ pkgUid = pm.getPackageUid(packageName);
+ } catch (RemoteException e) {
+ }
+ if (pkgUid == -1) {
+ Log.w(TAG, "Invalid packageName: " + packageName);
+ return;
+ }
+ restartPackageLocked(packageName, pkgUid);
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
+ private void restartPackageLocked(final String packageName, int uid) {
+ uninstallPackageLocked(packageName, uid, false);
+ Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
+ Uri.fromParts("package", packageName, null));
+ intent.putExtra(Intent.EXTRA_UID, uid);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID);
+ }
+
private final void uninstallPackageLocked(String name, int uid,
boolean callerWillRestart) {
if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
int i, N;
+ final String procNamePrefix = name + ":";
+ if (uid < 0) {
+ try {
+ uid = ActivityThread.getPackageManager().getPackageUid(name);
+ } catch (RemoteException e) {
+ }
+ }
+
Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
while (badApps.hasNext()) {
SparseArray<Long> ba = badApps.next();
@@ -4217,14 +4380,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
- final String procNamePrefix = name + ":";
- if (uid < 0) {
- try {
- uid = ActivityThread.getPackageManager().getPackageUid(name);
- } catch (RemoteException e) {
- }
- }
-
// Remove all processes this package may have touched: all with the
// same UID (except for the system or root user), and all whose name
// matches the package name.
@@ -4294,6 +4449,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int pid = app.pid;
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(pid);
+ mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
handleAppDiedLocked(app, true);
mLRUProcesses.remove(app);
@@ -4313,6 +4469,31 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return needRestart;
}
+ private final void processStartTimedOutLocked(ProcessRecord app) {
+ final int pid = app.pid;
+ boolean gone = false;
+ synchronized (mPidsSelfLocked) {
+ ProcessRecord knownApp = mPidsSelfLocked.get(pid);
+ if (knownApp != null && knownApp.thread == null) {
+ mPidsSelfLocked.remove(pid);
+ gone = true;
+ }
+ }
+
+ if (gone) {
+ Log.w(TAG, "Process " + app + " failed to attach");
+ mProcessNames.remove(app.processName, app.info.uid);
+ Process.killProcess(pid);
+ if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
+ Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
+ mPendingBroadcast = null;
+ scheduleBroadcastsLocked();
+ }
+ } else {
+ Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
+ }
+ }
+
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
@@ -4334,6 +4515,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (app == null) {
Log.w(TAG, "No pending application record for pid " + pid
+ " (IApplicationThread " + thread + "); dropping process");
+ EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
if (pid > 0 && pid != MY_PID) {
Process.killProcess(pid);
} else {
@@ -4375,6 +4557,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.foregroundServices = false;
app.debugging = false;
+ mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
+
List providers = generateApplicationProvidersLocked(app);
if (localLOGV) Log.v(
@@ -5523,9 +5707,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
outInfo.availMem = Process.getFreeMemory();
- outInfo.threshold = SECONDARY_SERVER_MEM;
+ outInfo.threshold = HOME_APP_MEM;
outInfo.lowMemory = outInfo.availMem <
- (SECONDARY_SERVER_MEM + ((HIDDEN_APP_MEM-SECONDARY_SERVER_MEM)/2));
+ (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
}
// =========================================================
@@ -6490,10 +6674,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (caller != null) {
r = getRecordForAppLocked(caller);
if (r == null) {
- throw new SecurityException(
- "Unable to find app for caller " + caller
- + " (pid=" + Binder.getCallingPid()
- + ") when getting content provider " + name);
+ throw new SecurityException(
+ "Unable to find app for caller " + caller
+ + " (pid=" + Binder.getCallingPid()
+ + ") when getting content provider " + name);
}
}
@@ -6650,6 +6834,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": launching app became null");
+ EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
+ cpi.applicationInfo.packageName,
+ cpi.applicationInfo.uid, name);
+ return null;
}
try {
cpr.wait();
@@ -6755,9 +6943,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ContentProviderRecord dst =
(ContentProviderRecord)r.pubProviders.get(src.info.name);
if (dst != null) {
- dst.provider = src.provider;
- dst.app = r;
-
mProvidersByClass.put(dst.info.name, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
@@ -6774,6 +6959,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
synchronized (dst) {
+ dst.provider = src.provider;
+ dst.app = r;
dst.notifyAll();
}
updateOomAdjLocked(r);
@@ -6904,7 +7091,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mPausingActivity == null) {
if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
- startPausingLocked(false);
+ startPausingLocked(false, true);
}
}
}
@@ -7226,6 +7413,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ public boolean testIsSystemReady() {
+ // no need to synchronize(this) just to read & return the value
+ return mSystemReady;
+ }
+
public void systemReady() {
// In the simulator, startRunning will never have been called, which
// normally sets a few crucial variables. Do it here instead.
@@ -7405,6 +7597,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// This process loses!
Log.w(TAG, "Process " + app.info.processName
+ " has crashed too many times: killing!");
+ EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
+ app.info.processName, app.info.uid);
killServicesLocked(app, false);
for (int i=mHistory.size()-1; i>=0; i--) {
HistoryRecord r = (HistoryRecord)mHistory.get(i);
@@ -7628,6 +7822,24 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ActivityManager.RunningAppProcessInfo currApp =
new ActivityManager.RunningAppProcessInfo(app.processName,
app.pid, app.getPackageList());
+ int adj = app.curAdj;
+ if (adj >= CONTENT_PROVIDER_ADJ) {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
+ } else if (adj >= HIDDEN_APP_MIN_ADJ) {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
+ currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
+ } else if (adj >= HOME_APP_ADJ) {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
+ currApp.lru = 0;
+ } else if (adj >= SECONDARY_SERVER_ADJ) {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
+ } else if (adj >= VISIBLE_APP_ADJ) {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+ } else {
+ currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+ }
+ //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
+ // + " lru=" + currApp.lru);
if (runList == null) {
runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
}
@@ -7679,6 +7891,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
pw.println(" mPausingActivity: " + mPausingActivity);
pw.println(" mResumedActivity: " + mResumedActivity);
pw.println(" mFocusedActivity: " + mFocusedActivity);
+ pw.println(" mLastPausedActivity: " + mLastPausedActivity);
if (mRecentTasks.size() > 0) {
pw.println(" ");
@@ -7816,6 +8029,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
pw.println(" ");
pw.println(" Total persistent processes: " + numPers);
+ pw.println(" mHomeProcess: " + mHomeProcess);
pw.println(" mConfiguration: " + mConfiguration);
pw.println(" mStartRunning=" + mStartRunning
+ " mSystemReady=" + mSystemReady
@@ -8176,28 +8390,53 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
- PrintWriter pw, List list, String prefix) {
+ PrintWriter pw, List list, String prefix, String[] args) {
+ final boolean isCheckinRequest = scanArgs(args, "-c");
+ long uptime = SystemClock.uptimeMillis();
+ long realtime = SystemClock.elapsedRealtime();
+
+ if (isCheckinRequest) {
+ // short checkin version
+ pw.println(uptime + "," + realtime);
+ pw.flush();
+ } else {
+ pw.println("Applications Memory Usage (kB):");
+ pw.println("Uptime: " + uptime + " Realtime: " + realtime);
+ }
for (int i = list.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = (ProcessRecord)list.get(i);
if (r.thread != null) {
- pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
- pw.flush();
-
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
+ if (!isCheckinRequest) {
+ pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
+ pw.flush();
+ }
try {
- data.writeFileDescriptor(fd);
- r.thread.asBinder().transact(IBinder.DUMP_TRANSACTION, data, reply, 0);
-
+ r.thread.asBinder().dump(fd, args);
} catch (RemoteException e) {
- pw.println("Got RemoteException!");
- pw.flush();
+ if (!isCheckinRequest) {
+ pw.println("Got RemoteException!");
+ pw.flush();
+ }
}
+ }
+ }
+ }
- data.recycle();
- reply.recycle();
+ /**
+ * Searches array of arguments for the specified string
+ * @param args array of argument strings
+ * @param value value to search for
+ * @return true if the value is contained in the array
+ */
+ private static boolean scanArgs(String[] args, String value) {
+ if (args != null) {
+ for (String arg : args) {
+ if (value.equals(arg)) {
+ return true;
+ }
}
}
+ return false;
}
private final int indexOfTokenLocked(IBinder token, boolean required) {
@@ -8295,6 +8534,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (sr.crashCount >= 2) {
Log.w(TAG, "Service crashed " + sr.crashCount
+ " times, stopping: " + sr);
+ EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
+ sr.crashCount, sr.shortName, app.pid);
bringDownServiceLocked(sr, true);
} else if (!allowRestart) {
bringDownServiceLocked(sr, true);
@@ -8313,7 +8554,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private final void removeDyingProviderLocked(ProcessRecord proc,
ContentProviderRecord cpr) {
- cpr.launchingApp = null;
+ synchronized (cpr) {
+ cpr.launchingApp = null;
+ cpr.notifyAll();
+ }
mProvidersByClass.remove(cpr.info.name);
String names[] = cpr.info.authority.split(";");
@@ -8395,6 +8639,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
break;
}
}
+ } else {
+ i = NL;
}
if (i >= NL) {
@@ -8467,8 +8713,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
mProcessesOnHold.remove(app);
+ if (app == mHomeProcess) {
+ mHomeProcess = null;
+ }
+
if (restart) {
- // We have component that still need to be running in the
+ // We have components that still need to be running in the
// process, so re-launch it.
mProcessNames.put(app.processName, app.info.uid, app);
startProcessLocked(app, "restart", app.processName);
@@ -8476,6 +8726,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Goodbye!
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
+ mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
app.pid = 0;
}
@@ -8818,6 +9069,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
Log.w(TAG, "Scheduling restart of crashed service "
+ r.shortName + " in " + r.restartDelay + "ms");
+ EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
+ r.shortName, r.restartDelay);
Message msg = Message.obtain();
msg.what = SERVICE_ERROR_MSG;
@@ -9120,6 +9373,36 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return 0;
}
+ public IBinder peekService(Intent service, String resolvedType) {
+ // Refuse possible leaked file descriptors
+ if (service != null && service.hasFileDescriptors() == true) {
+ throw new IllegalArgumentException("File descriptors passed in Intent");
+ }
+
+ IBinder ret = null;
+
+ synchronized(this) {
+ ServiceLookupResult r = findServiceLocked(service, resolvedType);
+
+ if (r != null) {
+ // r.record is null if findServiceLocked() failed the caller permission check
+ if (r.record == null) {
+ throw new SecurityException(
+ "Permission Denial: Accessing service " + r.record.name
+ + " from pid=" + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + r.permission);
+ }
+ IntentBindRecord ib = r.record.bindings.get(r.record.intent);
+ if (ib != null) {
+ ret = ib.binder;
+ }
+ }
+ }
+
+ return ret;
+ }
+
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) {
synchronized(this) {
@@ -9928,6 +10211,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized(this) {
+ if (!mSystemReady) {
+ // if the caller really truly claims to know what they're doing, go
+ // ahead and allow the broadcast without launching any receivers
+ int flags = intent.getFlags();
+ if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
+ intent = new Intent(intent);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
+ Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
+ + " before boot completion");
+ throw new IllegalStateException("Cannot broadcast before boot completed");
+ }
+ }
+
final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
@@ -10639,6 +10936,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// =========================================================
// CONFIGURATION
// =========================================================
+
+ public ConfigurationInfo getDeviceConfigurationInfo() {
+ ConfigurationInfo config = new ConfigurationInfo();
+ synchronized (this) {
+ config.reqTouchScreen = mConfiguration.touchscreen;
+ config.reqKeyboardType = mConfiguration.keyboard;
+ config.reqNavigation = mConfiguration.navigation;
+ if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
+ config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
+ }
+ if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
+ config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
+ }
+ }
+ return config;
+ }
public Configuration getConfiguration() {
Configuration ci;
@@ -10653,6 +10966,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
"updateConfiguration()");
synchronized(this) {
+ if (values == null && mWindowManager != null) {
+ // sentinel: fetch the current configuration from the window manager
+ values = mWindowManager.computeNewConfiguration();
+ }
+
final long origId = Binder.clearCallingIdentity();
updateConfigurationLocked(values, null);
Binder.restoreCallingIdentity(origId);
@@ -10718,7 +11036,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
if (starting != null) {
- kept = ensureActivityConfigurationLocked(starting);
+ kept = ensureActivityConfigurationLocked(starting, changes);
if (kept) {
// If this didn't result in the starting activity being
// destroyed, then we need to make sure at this point that all
@@ -10775,7 +11093,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* for whatever reason. Ensures the HistoryRecord is updated with the
* correct configuration and all other bookkeeping is handled.
*/
- private final boolean ensureActivityConfigurationLocked(HistoryRecord r) {
+ private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
+ int globalChanges) {
if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
// Short circuit: if the two configurations are the exact same
@@ -10822,7 +11141,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if ((changes&(~r.info.configChanges)) != 0) {
// Aha, the activity isn't handling the change, so DIE DIE DIE.
r.configChangeFlags |= changes;
- r.startFreezingScreenLocked(r.app, changes);
+ r.startFreezingScreenLocked(r.app, globalChanges);
if (r.app == null || r.app.thread == null) {
if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
destroyActivityLocked(r, true);
@@ -10903,9 +11222,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.isForeground = false;
- // Right now there are three interesting states: it is
- // either the foreground app, background with activities,
- // or background without activities.
+ // Determine the importance of the process, starting with most
+ // important to least, and assign an appropriate OOM adjustment.
int adj;
int N;
if (app == TOP_APP || app.instrumentationClass != null
@@ -10925,6 +11243,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} else if (app.foregroundServices || app.forcingToForeground != null) {
// The user is aware of this app, so make it visible.
adj = VISIBLE_APP_ADJ;
+ } else if (app == mHomeProcess) {
+ // This process is hosting what we currently consider to be the
+ // home app, so we don't want to let it go into the background.
+ adj = HOME_APP_ADJ;
} else if ((N=app.activities.size()) != 0) {
// This app is in the background with paused activities.
adj = hiddenAdj;
@@ -10940,7 +11262,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
adj = EMPTY_APP_ADJ;
}
- // By default, we use the computed adjusted. It may be changed if
+ // By default, we use the computed adjustment. It may be changed if
// there are applications dependent on our services or providers, but
// this gives us a baseline and makes sure we don't get into an
// infinite recursion.
@@ -11461,7 +11783,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// We can finish this one if we have its icicle saved and
// it is not persistent.
- if ((r.haveState || !r.stateNotNeeded)
+ if ((r.haveState || !r.stateNotNeeded) && !r.visible
&& r.stopped && !r.persistent && !r.finishing) {
final int origSize = mLRUActivities.size();
destroyActivityLocked(r, true);
@@ -11501,6 +11823,56 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ public boolean profileControl(String process, boolean start,
+ String path) throws RemoteException {
+
+ synchronized (this) {
+ // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
+ // its own permission.
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
+
+ ProcessRecord proc = null;
+ try {
+ int pid = Integer.parseInt(process);
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(pid);
+ }
+ } catch (NumberFormatException e) {
+ }
+
+ if (proc == null) {
+ HashMap<String, SparseArray<ProcessRecord>> all
+ = mProcessNames.getMap();
+ SparseArray<ProcessRecord> procs = all.get(process);
+ if (procs != null && procs.size() > 0) {
+ proc = procs.valueAt(0);
+ }
+ }
+
+ if (proc == null || proc.thread == null) {
+ throw new IllegalArgumentException("Unknown process: " + process);
+ }
+
+ boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
+ if (isSecure) {
+ if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ throw new SecurityException("Process not debuggable: " + proc);
+ }
+ }
+
+ try {
+ proc.thread.profilerControl(start, path);
+ return true;
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Process disappeared");
+ }
+ }
+ }
+
/** In this method we try to acquire our lock to make sure that we have not deadlocked */
public void monitor() {
synchronized (this) { }
diff --git a/services/java/com/android/server/am/BaseErrorDialog.java b/services/java/com/android/server/am/BaseErrorDialog.java
index 4f62f62..bed2768 100644
--- a/services/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/java/com/android/server/am/BaseErrorDialog.java
@@ -31,6 +31,8 @@ class BaseErrorDialog extends AlertDialog {
super(context, com.android.internal.R.style.Theme_Dialog_AppError);
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
getWindow().setTitle("Error Dialog");
setIcon(R.drawable.ic_dialog_alert);
}
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index bf1bc8c..27d0401 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -22,8 +22,10 @@ import com.android.internal.os.BatteryStatsImpl;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
+import android.os.Parcel;
import android.os.Process;
import android.os.ServiceManager;
+import android.util.PrintWriterPrinter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -58,14 +60,23 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
/**
* @return the current statistics object, which may be modified
- * to reflect events that affect battery usage.
+ * to reflect events that affect battery usage. You must lock the
+ * stats object before doing anything with it.
*/
public BatteryStatsImpl getActiveStatistics() {
return mStats;
}
- public BatteryStatsImpl getStatistics() {
- return mStats;
+ public byte[] getStatistics() {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.BATTERY_STATS, null);
+ //Log.i("foo", "SENDING BATTERY INFO:");
+ //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo"));
+ Parcel out = Parcel.obtain();
+ mStats.writeToParcel(out, 0);
+ byte[] data = out.marshall();
+ out.recycle();
+ return data;
}
public void noteStartWakelock(int uid, String name, int type) {
@@ -95,6 +106,48 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
mStats.getUidStatsLocked(uid).noteStopSensor(sensor);
}
}
+
+ public void noteStartGps(int uid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteStartGps(uid);
+ }
+ }
+
+ public void noteStopGps(int uid) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteStopGps(uid);
+ }
+ }
+
+ public void noteScreenOn() {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteScreenOnLocked();
+ }
+ }
+
+ public void noteScreenOff() {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteScreenOffLocked();
+ }
+ }
+
+ public void notePhoneOn() {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.notePhoneOnLocked();
+ }
+ }
+
+ public void notePhoneOff() {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.notePhoneOffLocked();
+ }
+ }
public boolean isOnBattery() {
return mStats.isOnBattery();
@@ -106,10 +159,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
}
public long getAwakeTimeBattery() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BATTERY_STATS, null);
return mStats.getAwakeTimeBattery();
}
public long getAwakeTimePlugged() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BATTERY_STATS, null);
return mStats.getAwakeTimePlugged();
}
@@ -117,14 +174,24 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
if (Binder.getCallingPid() == Process.myPid()) {
return;
}
- mContext.enforcePermission(android.Manifest.permission.BATTERY_STATS,
+ mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- synchronized (this) {
- mStats.dumpLocked(fd, pw, args);
+ synchronized (mStats) {
+ boolean isCheckin = false;
+ if (args != null) {
+ for (String arg : args) {
+ if ("-c".equals(arg)) {
+ isCheckin = true;
+ break;
+ }
+ }
+ }
+ if (isCheckin) mStats.dumpCheckinLocked(pw, args);
+ else mStats.dumpLocked(new PrintWriterPrinter(pw));
}
}
}
diff --git a/services/java/com/android/server/am/HistoryRecord.java b/services/java/com/android/server/am/HistoryRecord.java
index b370b1c..0f62471 100644
--- a/services/java/com/android/server/am/HistoryRecord.java
+++ b/services/java/com/android/server/am/HistoryRecord.java
@@ -23,6 +23,7 @@ import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.os.Bundle;
@@ -54,6 +55,8 @@ class HistoryRecord extends IApplicationToken.Stub {
final String taskAffinity; // as per ActivityInfo.taskAffinity
final boolean stateNotNeeded; // As per ActivityInfo.flags
final boolean fullscreen; // covers the full screen?
+ final boolean componentSpecified; // did caller specifiy an explicit component?
+ final boolean isHomeActivity; // do we consider this to be a home activity?
final String baseDir; // where activity source (resources etc) located
final String resDir; // where public activity source (public resources etc) located
final String dataDir; // where activity data should go
@@ -101,8 +104,8 @@ class HistoryRecord extends IApplicationToken.Stub {
pw.println(prefix + this);
pw.println(prefix + "packageName=" + packageName
+ " processName=" + processName);
- pw.println(prefix + "app=" + app);
- pw.println(prefix + "launchedFromUid=" + launchedFromUid);
+ pw.println(prefix + "launchedFromUid=" + launchedFromUid
+ + " app=" + app);
pw.println(prefix + intent);
pw.println(prefix + "frontOfTask=" + frontOfTask + " task=" + task);
pw.println(prefix + "taskAffinity=" + taskAffinity);
@@ -111,6 +114,9 @@ class HistoryRecord extends IApplicationToken.Stub {
pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
+ " icon=0x" + Integer.toHexString(icon)
+ " theme=0x" + Integer.toHexString(theme));
+ pw.println(prefix + "stateNotNeeded=" + stateNotNeeded
+ + " componentSpecified=" + componentSpecified
+ + " isHomeActivity=" + isHomeActivity);
pw.println(prefix + "configuration=" + configuration);
pw.println(prefix + "resultTo=" + resultTo
+ " resultWho=" + resultWho + " resultCode=" + requestCode);
@@ -139,13 +145,15 @@ class HistoryRecord extends IApplicationToken.Stub {
HistoryRecord(ActivityManagerService _service, ProcessRecord _caller,
int _launchedFromUid, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration,
- HistoryRecord _resultTo, String _resultWho, int _reqCode) {
+ HistoryRecord _resultTo, String _resultWho, int _reqCode,
+ boolean _componentSpecified) {
service = _service;
info = aInfo;
launchedFromUid = _launchedFromUid;
intent = _intent;
shortComponentName = _intent.getComponent().flattenToShortString();
resolvedType = _resolvedType;
+ componentSpecified = _componentSpecified;
configuration = _configuration;
resultTo = _resultTo;
resultWho = _resultWho;
@@ -184,6 +192,11 @@ class HistoryRecord extends IApplicationToken.Stub {
dataDir = aInfo.applicationInfo.dataDir;
nonLocalizedLabel = aInfo.nonLocalizedLabel;
labelRes = aInfo.labelRes;
+ if (nonLocalizedLabel == null && labelRes == 0) {
+ ApplicationInfo app = aInfo.applicationInfo;
+ nonLocalizedLabel = app.nonLocalizedLabel;
+ labelRes = app.labelRes;
+ }
icon = aInfo.getIconResource();
theme = aInfo.getThemeResource();
if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0
@@ -210,6 +223,29 @@ class HistoryRecord extends IApplicationToken.Stub {
&& !ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+ if (!_componentSpecified || _launchedFromUid == Process.myUid()
+ || _launchedFromUid == 0) {
+ // If we know the system has determined the component, then
+ // we can consider this to be a home activity...
+ if (Intent.ACTION_MAIN.equals(_intent.getAction()) &&
+ _intent.hasCategory(Intent.CATEGORY_HOME) &&
+ _intent.getCategories().size() == 1 &&
+ _intent.getData() == null &&
+ _intent.getType() == null &&
+ (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
+ !"android".equals(realActivity.getClassName())) {
+ // This sure looks like a home activity!
+ // Note the last check is so we don't count the resolver
+ // activity as being home... really, we don't care about
+ // doing anything special with something that comes from
+ // the core framework package.
+ isHomeActivity = true;
+ } else {
+ isHomeActivity = false;
+ }
+ } else {
+ isHomeActivity = false;
+ }
} else {
realActivity = null;
taskAffinity = null;
@@ -220,6 +256,7 @@ class HistoryRecord extends IApplicationToken.Stub {
processName = null;
packageName = null;
fullscreen = true;
+ isHomeActivity = false;
}
}
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
new file mode 100755
index 0000000..3922f39
--- /dev/null
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2006-2007 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.am;
+
+import com.android.internal.app.IUsageStats;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import com.android.internal.os.PkgUsageStats;
+import android.os.Parcel;
+import android.os.Process;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This service collects the statistics associated with usage
+ * of various components, like when a particular package is launched or
+ * paused and aggregates events like number of time a component is launched
+ * total duration of a component launch.
+ */
+public final class UsageStatsService extends IUsageStats.Stub {
+ public static final String SERVICE_NAME = "usagestats";
+ private static final boolean localLOGV = false;
+ private static final String TAG = "UsageStats";
+ static IUsageStats sService;
+ private Context mContext;
+ // structure used to maintain statistics since the last checkin.
+ final private Map<String, PkgUsageStatsExtended> mStats;
+ // Lock to update package stats. Methods suffixed by SLOCK should invoked with
+ // this lock held
+ final Object mStatsLock;
+ // Lock to write to file. Methods suffixed by FLOCK should invoked with
+ // this lock held.
+ final Object mFileLock;
+ // Order of locks is mFileLock followed by mStatsLock to avoid deadlocks
+ private String mResumedPkg;
+ private File mFile;
+ //private File mBackupFile;
+ private long mLastWriteRealTime;
+ private int _FILE_WRITE_INTERVAL = 30*60*1000; //ms
+ private static final String _PREFIX_DELIMIT=".";
+ private String mFilePrefix;
+ private Calendar mCal;
+ private static final int _MAX_NUM_FILES = 10;
+ private long mLastTime;
+
+ private class PkgUsageStatsExtended {
+ int mLaunchCount;
+ long mUsageTime;
+ long mPausedTime;
+ long mResumedTime;
+
+ PkgUsageStatsExtended() {
+ mLaunchCount = 0;
+ mUsageTime = 0;
+ }
+ void updateResume() {
+ mLaunchCount ++;
+ mResumedTime = SystemClock.elapsedRealtime();
+ }
+ void updatePause() {
+ mPausedTime = SystemClock.elapsedRealtime();
+ mUsageTime += (mPausedTime - mResumedTime);
+ }
+ void clear() {
+ mLaunchCount = 0;
+ mUsageTime = 0;
+ }
+ }
+
+ UsageStatsService(String fileName) {
+ mStats = new HashMap<String, PkgUsageStatsExtended>();
+ mStatsLock = new Object();
+ mFileLock = new Object();
+ mFilePrefix = fileName;
+ mCal = Calendar.getInstance();
+ // Update current stats which are binned by date
+ String uFileName = getCurrentDateStr(mFilePrefix);
+ mFile = new File(uFileName);
+ readStatsFromFile();
+ mLastWriteRealTime = SystemClock.elapsedRealtime();
+ mLastTime = new Date().getTime();
+ }
+
+ /*
+ * Utility method to convert date into string.
+ */
+ private String getCurrentDateStr(String prefix) {
+ mCal.setTime(new Date());
+ StringBuilder sb = new StringBuilder();
+ if (prefix != null) {
+ sb.append(prefix);
+ sb.append(".");
+ }
+ int mm = mCal.get(Calendar.MONTH) - Calendar.JANUARY +1;
+ if (mm < 10) {
+ sb.append("0");
+ }
+ sb.append(mm);
+ int dd = mCal.get(Calendar.DAY_OF_MONTH);
+ if (dd < 10) {
+ sb.append("0");
+ }
+ sb.append(dd);
+ sb.append(mCal.get(Calendar.YEAR));
+ return sb.toString();
+ }
+
+ private Parcel getParcelForFile(File file) throws IOException {
+ FileInputStream stream = new FileInputStream(file);
+ byte[] raw = readFully(stream);
+ Parcel in = Parcel.obtain();
+ in.unmarshall(raw, 0, raw.length);
+ in.setDataPosition(0);
+ stream.close();
+ return in;
+ }
+
+ private void readStatsFromFile() {
+ File newFile = mFile;
+ synchronized (mFileLock) {
+ try {
+ if (newFile.exists()) {
+ readStatsFLOCK(newFile);
+ } else {
+ // Check for file limit before creating a new file
+ checkFileLimitFLOCK();
+ newFile.createNewFile();
+ }
+ } catch (IOException e) {
+ Log.w(TAG,"Error : " + e + " reading data from file:" + newFile);
+ }
+ }
+ }
+
+ private void readStatsFLOCK(File file) throws IOException {
+ Parcel in = getParcelForFile(file);
+ while (in.dataAvail() > 0) {
+ String pkgName = in.readString();
+ PkgUsageStatsExtended pus = new PkgUsageStatsExtended();
+ pus.mLaunchCount = in.readInt();
+ pus.mUsageTime = in.readLong();
+ synchronized (mStatsLock) {
+ mStats.put(pkgName, pus);
+ }
+ }
+ }
+
+ private ArrayList<String> getUsageStatsFileListFLOCK() {
+ File dir = getUsageFilesDir();
+ if (dir == null) {
+ Log.w(TAG, "Couldnt find writable directory for usage stats file");
+ return null;
+ }
+ // Check if there are too many files in the system and delete older files
+ String fList[] = dir.list();
+ if (fList == null) {
+ return null;
+ }
+ File pre = new File(mFilePrefix);
+ String filePrefix = pre.getName();
+ // file name followed by dot
+ int prefixLen = filePrefix.length()+1;
+ ArrayList<String> fileList = new ArrayList<String>();
+ for (String file : fList) {
+ int index = file.indexOf(filePrefix);
+ if (index == -1) {
+ continue;
+ }
+ if (file.endsWith(".bak")) {
+ continue;
+ }
+ fileList.add(file);
+ }
+ return fileList;
+ }
+
+ private File getUsageFilesDir() {
+ if (mFilePrefix == null) {
+ return null;
+ }
+ File pre = new File(mFilePrefix);
+ return new File(pre.getParent());
+ }
+
+ private void checkFileLimitFLOCK() {
+ File dir = getUsageFilesDir();
+ if (dir == null) {
+ Log.w(TAG, "Couldnt find writable directory for usage stats file");
+ return;
+ }
+ // Get all usage stats output files
+ ArrayList<String> fileList = getUsageStatsFileListFLOCK();
+ if (fileList == null) {
+ // Strange but we dont have to delete any thing
+ return;
+ }
+ int count = fileList.size();
+ if (count <= _MAX_NUM_FILES) {
+ return;
+ }
+ // Sort files
+ Collections.sort(fileList);
+ count -= _MAX_NUM_FILES;
+ // Delete older files
+ for (int i = 0; i < count; i++) {
+ String fileName = fileList.get(i);
+ File file = new File(dir, fileName);
+ Log.i(TAG, "Deleting file : "+fileName);
+ file.delete();
+ }
+ }
+
+ private void writeStatsToFile() {
+ synchronized (mFileLock) {
+ long currTime = new Date().getTime();
+ boolean dayChanged = ((currTime - mLastTime) >= (24*60*60*1000));
+ long currRealTime = SystemClock.elapsedRealtime();
+ if (((currRealTime-mLastWriteRealTime) < _FILE_WRITE_INTERVAL) &&
+ (!dayChanged)) {
+ // wait till the next update
+ return;
+ }
+ // Get the most recent file
+ String todayStr = getCurrentDateStr(mFilePrefix);
+ // Copy current file to back up
+ File backupFile = new File(mFile.getPath() + ".bak");
+ mFile.renameTo(backupFile);
+ try {
+ checkFileLimitFLOCK();
+ mFile.createNewFile();
+ // Write mStats to file
+ writeStatsFLOCK();
+ mLastWriteRealTime = currRealTime;
+ mLastTime = currTime;
+ if (dayChanged) {
+ // clear stats
+ synchronized (mStats) {
+ mStats.clear();
+ }
+ mFile = new File(todayStr);
+ }
+ // Delete the backup file
+ if (backupFile != null) {
+ backupFile.delete();
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed writing stats to file:" + mFile);
+ if (backupFile != null) {
+ backupFile.renameTo(mFile);
+ }
+ }
+ }
+ }
+
+ private void writeStatsFLOCK() throws IOException {
+ FileOutputStream stream = new FileOutputStream(mFile);
+ Parcel out = Parcel.obtain();
+ writeStatsToParcelFLOCK(out);
+ stream.write(out.marshall());
+ out.recycle();
+ stream.flush();
+ stream.close();
+ }
+
+ private void writeStatsToParcelFLOCK(Parcel out) {
+ synchronized (mStatsLock) {
+ Set<String> keys = mStats.keySet();
+ for (String key : keys) {
+ PkgUsageStatsExtended pus = mStats.get(key);
+ out.writeString(key);
+ out.writeInt(pus.mLaunchCount);
+ out.writeLong(pus.mUsageTime);
+ }
+ }
+ }
+
+ public void publish(Context context) {
+ mContext = context;
+ ServiceManager.addService(SERVICE_NAME, asBinder());
+ }
+
+ public static IUsageStats getService() {
+ if (sService != null) {
+ return sService;
+ }
+ IBinder b = ServiceManager.getService(SERVICE_NAME);
+ sService = asInterface(b);
+ return sService;
+ }
+
+ public void noteResumeComponent(ComponentName componentName) {
+ enforceCallingPermission();
+ String pkgName;
+ if ((componentName == null) ||
+ ((pkgName = componentName.getPackageName()) == null)) {
+ return;
+ }
+ if ((mResumedPkg != null) && (mResumedPkg.equalsIgnoreCase(pkgName))) {
+ // Moving across activities in same package. just return
+ return;
+ }
+ if (localLOGV) Log.i(TAG, "started component:"+pkgName);
+ synchronized (mStatsLock) {
+ PkgUsageStatsExtended pus = mStats.get(pkgName);
+ if (pus == null) {
+ pus = new PkgUsageStatsExtended();
+ mStats.put(pkgName, pus);
+ }
+ pus.updateResume();
+ }
+ mResumedPkg = pkgName;
+ }
+
+ public void notePauseComponent(ComponentName componentName) {
+ enforceCallingPermission();
+ String pkgName;
+ if ((componentName == null) ||
+ ((pkgName = componentName.getPackageName()) == null)) {
+ return;
+ }
+ if ((mResumedPkg == null) || (!pkgName.equalsIgnoreCase(mResumedPkg))) {
+ Log.w(TAG, "Something wrong here, Didn't expect "+pkgName+" to be paused");
+ return;
+ }
+ if (localLOGV) Log.i(TAG, "paused component:"+pkgName);
+ synchronized (mStatsLock) {
+ PkgUsageStatsExtended pus = mStats.get(pkgName);
+ if (pus == null) {
+ // Weird some error here
+ Log.w(TAG, "No package stats for pkg:"+pkgName);
+ return;
+ }
+ pus.updatePause();
+ }
+ // Persist data to file
+ writeStatsToFile();
+ }
+
+ public void enforceCallingPermission() {
+ if (Binder.getCallingPid() == Process.myPid()) {
+ return;
+ }
+ mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
+ Binder.getCallingPid(), Binder.getCallingUid(), null);
+ }
+
+ public PkgUsageStats getPkgUsageStats(ComponentName componentName) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+ String pkgName;
+ if ((componentName == null) ||
+ ((pkgName = componentName.getPackageName()) == null)) {
+ return null;
+ }
+ synchronized (mStatsLock) {
+ PkgUsageStatsExtended pus = mStats.get(pkgName);
+ if (pus == null) {
+ return null;
+ }
+ return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime);
+ }
+ }
+
+ public PkgUsageStats[] getAllPkgUsageStats() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+ synchronized (mStatsLock) {
+ Set<String> keys = mStats.keySet();
+ int size = keys.size();
+ if (size <= 0) {
+ return null;
+ }
+ PkgUsageStats retArr[] = new PkgUsageStats[size];
+ int i = 0;
+ for (String key: keys) {
+ PkgUsageStatsExtended pus = mStats.get(key);
+ retArr[i] = new PkgUsageStats(key, pus.mLaunchCount, pus.mUsageTime);
+ i++;
+ }
+ return retArr;
+ }
+ }
+
+ static byte[] readFully(FileInputStream stream) throws java.io.IOException {
+ int pos = 0;
+ int avail = stream.available();
+ byte[] data = new byte[avail];
+ while (true) {
+ int amt = stream.read(data, pos, data.length-pos);
+ if (amt <= 0) {
+ return data;
+ }
+ pos += amt;
+ avail = stream.available();
+ if (avail > data.length-pos) {
+ byte[] newData = new byte[pos+avail];
+ System.arraycopy(data, 0, newData, 0, pos);
+ data = newData;
+ }
+ }
+ }
+
+ private void collectDumpInfoFLOCK(PrintWriter pw, String[] args) {
+ List<String> fileList = getUsageStatsFileListFLOCK();
+ if (fileList == null) {
+ return;
+ }
+ final boolean isCheckinRequest = scanArgs(args, "-c");
+ Collections.sort(fileList);
+ File usageFile = new File(mFilePrefix);
+ String dirName = usageFile.getParent();
+ File dir = new File(dirName);
+ String filePrefix = usageFile.getName();
+ // file name followed by dot
+ int prefixLen = filePrefix.length()+1;
+ String todayStr = getCurrentDateStr(null);
+ for (String file : fileList) {
+ File dFile = new File(dir, file);
+ String dateStr = file.substring(prefixLen);
+ try {
+ Parcel in = getParcelForFile(dFile);
+ collectDumpInfoFromParcelFLOCK(in, pw, dateStr, isCheckinRequest);
+ if (isCheckinRequest && !todayStr.equalsIgnoreCase(dateStr)) {
+ // Delete old file after collecting info only for checkin requests
+ dFile.delete();
+ }
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed with "+e+" when collecting dump info from file : " + file);
+ return;
+ } catch (IOException e) {
+ Log.w(TAG, "Failed with "+e+" when collecting dump info from file : "+file);
+ }
+ }
+ }
+
+ private void collectDumpInfoFromParcelFLOCK(Parcel in, PrintWriter pw,
+ String date, boolean isCheckinRequest) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Date:");
+ sb.append(date);
+ boolean first = true;
+ while (in.dataAvail() > 0) {
+ String pkgName = in.readString();
+ int launchCount = in.readInt();
+ long usageTime = in.readLong();
+ if (isCheckinRequest) {
+ if (!first) {
+ sb.append(",");
+ }
+ sb.append(pkgName);
+ sb.append(",");
+ sb.append(launchCount);
+ sb.append(",");
+ sb.append(usageTime);
+ sb.append("ms");
+ } else {
+ if (first) {
+ sb.append("\n");
+ }
+ sb.append("pkg=");
+ sb.append(pkgName);
+ sb.append(", launchCount=");
+ sb.append(launchCount);
+ sb.append(", usageTime=");
+ sb.append(usageTime);
+ sb.append(" ms\n");
+ }
+ first = false;
+ }
+ pw.write(sb.toString());
+ }
+
+ /**
+ * Searches array of arguments for the specified string
+ * @param args array of argument strings
+ * @param value value to search for
+ * @return true if the value is contained in the array
+ */
+ private static boolean scanArgs(String[] args, String value) {
+ if (args != null) {
+ for (String arg : args) {
+ if (value.equals(arg)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ /*
+ * The data persisted to file is parsed and the stats are computed.
+ */
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ synchronized (mFileLock) {
+ collectDumpInfoFLOCK(pw, args);
+ }
+ }
+
+}
diff --git a/services/java/com/android/server/status/AnimatedImageView.java b/services/java/com/android/server/status/AnimatedImageView.java
index 36492da..cd581c4 100644
--- a/services/java/com/android/server/status/AnimatedImageView.java
+++ b/services/java/com/android/server/status/AnimatedImageView.java
@@ -42,6 +42,7 @@ public class AnimatedImageView extends ImageView {
}
@Override
+ @android.view.RemotableViewMethod
public void setImageResource(int resid) {
super.setImageResource(resid);
updateAnim();
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 00ff7be..8433227 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -72,6 +72,11 @@ public class StatusBarPolicy {
private static final int EVENT_DATA_ACTIVITY = 3;
private static final int EVENT_BATTERY_CLOSE = 4;
+ // indices into mBatteryThresholds
+ private static final int BATTERY_THRESHOLD_CLOSE_WARNING = 0;
+ private static final int BATTERY_THRESHOLD_WARNING = 1;
+ private static final int BATTERY_THRESHOLD_EMPTY = 2;
+
private Context mContext;
private StatusBarService mService;
private Handler mHandler = new StatusBarHandler();
@@ -88,7 +93,7 @@ public class StatusBarPolicy {
private boolean mBatteryPlugged;
private int mBatteryLevel;
private int mBatteryThreshold = 0; // index into mBatteryThresholds
- private int[] mBatteryThresholds = new int[] { 15, -1 };
+ private int[] mBatteryThresholds = new int[] { 20, 15, -1 };
private AlertDialog mLowBatteryDialog;
private TextView mBatteryLevelTextView;
private View mBatteryView;
@@ -157,6 +162,7 @@ public class StatusBarPolicy {
private IconData mBluetoothData;
private int mBluetoothHeadsetState;
private int mBluetoothA2dpState;
+ private boolean mBluetoothEnabled;
// wifi
private static final int[] sWifiSignalImages = new int[] {
@@ -233,7 +239,7 @@ public class StatusBarPolicy {
}
else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) ||
action.equals(AudioManager.VIBRATE_SETTING_CHANGED_ACTION)) {
- updateVolume(intent);
+ updateVolume();
}
else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
updateSimState(intent);
@@ -286,7 +292,16 @@ public class StatusBarPolicy {
mBluetoothData = IconData.makeIcon("bluetooth",
null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0);
mBluetoothIcon = service.addIcon(mBluetoothData, null);
- updateBluetooth(null);
+ BluetoothDevice bluetooth =
+ (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ if (bluetooth != null) {
+ mBluetoothEnabled = bluetooth.isEnabled();
+ } else {
+ mBluetoothEnabled = false;
+ }
+ mBluetoothA2dpState = BluetoothA2dp.STATE_DISCONNECTED;
+ mBluetoothHeadsetState = BluetoothHeadset.STATE_DISCONNECTED;
+ mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
// Gps status
mGpsEnabledIconData = IconData.makeIcon("gps",
@@ -316,6 +331,7 @@ public class StatusBarPolicy {
null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0);
mVolumeIcon = service.addIcon(mVolumeData, null);
service.setIconVisibility(mVolumeIcon, false);
+ updateVolume();
IntentFilter filter = new IntentFilter();
@@ -419,9 +435,14 @@ public class StatusBarPolicy {
}
}
*/
+ if (false) {
+ Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level
+ + " mBatteryThreshold=" + mBatteryThreshold + " oldThreshold=" + oldThreshold);
+ }
if (!plugged
- && ((oldPlugged && level <= mBatteryThresholds[0])
- || (mBatteryThreshold > oldThreshold))) {
+ && ((oldPlugged && level < mBatteryThresholds[BATTERY_THRESHOLD_WARNING])
+ || (mBatteryThreshold > oldThreshold
+ && mBatteryThreshold > BATTERY_THRESHOLD_WARNING))) {
// Broadcast the low battery warning
mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW));
@@ -438,6 +459,13 @@ public class StatusBarPolicy {
mBatteryShowLowOnEndCall = true;
}
}
+ } else if (mBatteryThreshold == BATTERY_THRESHOLD_CLOSE_WARNING) {
+ if (SHOW_LOW_BATTERY_WARNING) {
+ if (mLowBatteryDialog != null) {
+ mLowBatteryDialog.dismiss();
+ mBatteryShowLowOnEndCall = false;
+ }
+ }
}
}
@@ -745,9 +773,7 @@ public class StatusBarPolicy {
}
}
- private final void updateVolume(Intent intent) {
- // This can be called from two different received intents, so don't use extras.
-
+ private final void updateVolume() {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
final int ringerMode = audioManager.getRingerMode();
final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
@@ -767,30 +793,17 @@ public class StatusBarPolicy {
}
private final void updateBluetooth(Intent intent) {
- boolean visible = false;
- if (intent == null) { // Initialize
- BluetoothDevice bluetooth =
- (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
- if (bluetooth != null) {
- visible = bluetooth.isEnabled();
- }
- mService.setIconVisibility(mBluetoothIcon, visible);
- return;
- }
-
int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
- String action = intent.getAction();
+ String action = intent.getAction();
if (action.equals(BluetoothIntent.DISABLED_ACTION)) {
- visible = false;
+ mBluetoothEnabled = false;
} else if (action.equals(BluetoothIntent.ENABLED_ACTION)) {
- visible = true;
+ mBluetoothEnabled = true;
} else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
- visible = true;
mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
BluetoothHeadset.STATE_ERROR);
} else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
- visible = true;
mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
BluetoothA2dp.STATE_DISCONNECTED);
} else {
@@ -805,7 +818,7 @@ public class StatusBarPolicy {
mBluetoothData.iconId = iconId;
mService.updateIcon(mBluetoothIcon, mBluetoothData, null);
- mService.setIconVisibility(mBluetoothIcon, visible);
+ mService.setIconVisibility(mBluetoothIcon, mBluetoothEnabled);
}
private final void updateWifi(Intent intent) {
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 3b6e354..5442e1d 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -27,6 +27,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
@@ -175,11 +176,11 @@ public class StatusBarService extends IStatusBar.Stub
WindowManager.LayoutParams mExpandedParams;
ScrollView mScrollView;
View mNotificationLinearLayout;
- View mOngoingTitle;
+ TextView mOngoingTitle;
LinearLayout mOngoingItems;
- View mLatestTitle;
+ TextView mLatestTitle;
LinearLayout mLatestItems;
- View mNoNotificationsTitle;
+ TextView mNoNotificationsTitle;
TextView mSpnLabel;
TextView mPlmnLabel;
TextView mClearButton;
@@ -269,11 +270,11 @@ public class StatusBarService extends IStatusBar.Stub
mExpandedDialog = new ExpandedDialog(context);
mExpandedView = expanded;
- mOngoingTitle = expanded.findViewById(R.id.ongoingTitle);
+ mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
- mLatestTitle = expanded.findViewById(R.id.latestTitle);
+ mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
- mNoNotificationsTitle = expanded.findViewById(R.id.noNotificationsTitle);
+ mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
mClearButton.setOnClickListener(mClearButtonListener);
mSpnLabel = (TextView)expanded.findViewById(R.id.spnLabel);
@@ -322,9 +323,11 @@ public class StatusBarService extends IStatusBar.Stub
}
public void systemReady() {
+ final StatusBarView view = mStatusBarView;
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
- 25,
+ view.getContext().getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height),
WindowManager.LayoutParams.TYPE_STATUS_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
@@ -333,7 +336,7 @@ public class StatusBarService extends IStatusBar.Stub
lp.setTitle("StatusBar");
lp.windowAnimations = R.style.Animation_StatusBar;
- WindowManagerImpl.getDefault().addView(mStatusBarView, lp);
+ WindowManagerImpl.getDefault().addView(view, lp);
}
// ================================================================================
@@ -1324,80 +1327,89 @@ public class StatusBarService extends IStatusBar.Stub
}
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump StatusBar from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
synchronized (mQueue) {
- pw.println("mExpanded=" + mExpanded
+ pw.println("Current Status Bar state:");
+ pw.println(" mExpanded=" + mExpanded
+ ", mExpandedVisible=" + mExpandedVisible);
- pw.println("mTicking=" + mTicking);
- pw.println("mTracking=" + mTracking);
- pw.println("mAnimating=" + mAnimating
+ pw.println(" mTicking=" + mTicking);
+ pw.println(" mTracking=" + mTracking);
+ pw.println(" mAnimating=" + mAnimating
+ ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel
+ ", mAnimAccel=" + mAnimAccel);
- pw.println("mCurAnimationTime=" + mCurAnimationTime
+ pw.println(" mCurAnimationTime=" + mCurAnimationTime
+ " mAnimLastTime=" + mAnimLastTime);
- pw.println("mDisplayHeight=" + mDisplayHeight
+ pw.println(" mDisplayHeight=" + mDisplayHeight
+ " mAnimatingReveal=" + mAnimatingReveal
+ " mViewDelta=" + mViewDelta);
- pw.println("mDisplayHeight=" + mDisplayHeight);
+ pw.println(" mDisplayHeight=" + mDisplayHeight);
final int N = mQueue.size();
- pw.println("mQueue.size=" + N);
+ pw.println(" mQueue.size=" + N);
for (int i=0; i<N; i++) {
PendingOp op = mQueue.get(i);
- pw.println(" [" + i + "] key=" + op.key + " code=" + op.code + " visible="
+ pw.println(" [" + i + "] key=" + op.key + " code=" + op.code + " visible="
+ op.visible);
- pw.println(" iconData=" + op.iconData);
- pw.println(" notificationData=" + op.notificationData);
+ pw.println(" iconData=" + op.iconData);
+ pw.println(" notificationData=" + op.notificationData);
}
- pw.println("mExpandedParams: " + mExpandedParams);
- pw.println("mExpandedView: " + viewInfo(mExpandedView));
- pw.println("mExpandedDialog: " + mExpandedDialog);
- pw.println("mTrackingParams: " + mTrackingParams);
- pw.println("mTrackingView: " + viewInfo(mTrackingView));
- pw.println("mOngoingTitle: " + viewInfo(mOngoingTitle));
- pw.println("mOngoingItems: " + viewInfo(mOngoingItems));
- pw.println("mLatestTitle: " + viewInfo(mLatestTitle));
- pw.println("mLatestItems: " + viewInfo(mLatestItems));
- pw.println("mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
- pw.println("mCloseView: " + viewInfo(mCloseView));
- pw.println("mTickerView: " + viewInfo(mTickerView));
- pw.println("mScrollView: " + viewInfo(mScrollView)
+ pw.println(" mExpandedParams: " + mExpandedParams);
+ pw.println(" mExpandedView: " + viewInfo(mExpandedView));
+ pw.println(" mExpandedDialog: " + mExpandedDialog);
+ pw.println(" mTrackingParams: " + mTrackingParams);
+ pw.println(" mTrackingView: " + viewInfo(mTrackingView));
+ pw.println(" mOngoingTitle: " + viewInfo(mOngoingTitle));
+ pw.println(" mOngoingItems: " + viewInfo(mOngoingItems));
+ pw.println(" mLatestTitle: " + viewInfo(mLatestTitle));
+ pw.println(" mLatestItems: " + viewInfo(mLatestItems));
+ pw.println(" mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle));
+ pw.println(" mCloseView: " + viewInfo(mCloseView));
+ pw.println(" mTickerView: " + viewInfo(mTickerView));
+ pw.println(" mScrollView: " + viewInfo(mScrollView)
+ " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout));
}
synchronized (mIconMap) {
final int N = mIconMap.size();
- pw.println("mIconMap.size=" + N);
+ pw.println(" mIconMap.size=" + N);
Set<IBinder> keys = mIconMap.keySet();
int i=0;
for (IBinder key: keys) {
StatusBarIcon icon = mIconMap.get(key);
- pw.println(" [" + i + "] key=" + key);
- pw.println(" data=" + icon.mData);
+ pw.println(" [" + i + "] key=" + key);
+ pw.println(" data=" + icon.mData);
i++;
}
}
synchronized (mNotificationData) {
int N = mNotificationData.ongoingCount();
- pw.println("ongoingCount.size=" + N);
+ pw.println(" ongoingCount.size=" + N);
for (int i=0; i<N; i++) {
StatusBarNotification n = mNotificationData.getOngoing(i);
- pw.println(" [" + i + "] key=" + n.key + " view=" + n.view);
- pw.println(" data=" + n.data);
+ pw.println(" [" + i + "] key=" + n.key + " view=" + n.view);
+ pw.println(" data=" + n.data);
}
N = mNotificationData.latestCount();
- pw.println("ongoingCount.size=" + N);
+ pw.println(" ongoingCount.size=" + N);
for (int i=0; i<N; i++) {
StatusBarNotification n = mNotificationData.getLatest(i);
- pw.println(" [" + i + "] key=" + n.key + " view=" + n.view);
- pw.println(" data=" + n.data);
+ pw.println(" [" + i + "] key=" + n.key + " view=" + n.view);
+ pw.println(" data=" + n.data);
}
}
synchronized (mDisableRecords) {
final int N = mDisableRecords.size();
- pw.println("mDisableRecords.size=" + N
+ pw.println(" mDisableRecords.size=" + N
+ " mDisabled=0x" + Integer.toHexString(mDisabled));
for (int i=0; i<N; i++) {
DisableRecord tok = mDisableRecords.get(i);
- pw.println(" [" + i + "] what=0x" + Integer.toHexString(tok.what)
+ pw.println(" [" + i + "] what=0x" + Integer.toHexString(tok.what)
+ " pkg=" + tok.pkg + " token=" + tok.token);
}
}
@@ -1693,6 +1705,9 @@ public class StatusBarService extends IStatusBar.Stub
*/
void updateResources() {
mClearButton.setText(mContext.getText(R.string.status_bar_clear_all_button));
+ mOngoingTitle.setText(mContext.getText(R.string.status_bar_ongoing_events_title));
+ mLatestTitle.setText(mContext.getText(R.string.status_bar_latest_events_title));
+ mNoNotificationsTitle.setText(mContext.getText(R.string.status_bar_no_notifications_title));
Log.d(TAG, "updateResources");
}
diff --git a/core/jni/server/Android.mk b/services/jni/Android.mk
index 2f48edf..2f48edf 100644
--- a/core/jni/server/Android.mk
+++ b/services/jni/Android.mk
diff --git a/core/jni/server/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp
index 0f37921..1d66fb1 100644
--- a/core/jni/server/com_android_server_AlarmManagerService.cpp
+++ b/services/jni/com_android_server_AlarmManagerService.cpp
@@ -52,12 +52,17 @@ static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jo
tz.tz_minuteswest = minswest;
tz.tz_dsttime = 0;
- int result = ioctl(fd, ANDROID_ALARM_SET_TIMEZONE, &tz);
+ int result = settimeofday(NULL, &tz);
if (result < 0) {
LOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
return -1;
+ } else {
+ LOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
}
+
return 0;
+#else
+ return -ENOSYS;
#endif
}
diff --git a/core/jni/server/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index 6636a97..6636a97 100644
--- a/core/jni/server/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
diff --git a/core/jni/server/com_android_server_HardwareService.cpp b/services/jni/com_android_server_HardwareService.cpp
index 224ab18..ac36348 100644
--- a/core/jni/server/com_android_server_HardwareService.cpp
+++ b/services/jni/com_android_server_HardwareService.cpp
@@ -28,21 +28,21 @@
namespace android
{
-static void on(JNIEnv *env, jobject clazz)
+static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms)
{
- // LOGI("on\n");
- vibrator_on();
+ // LOGI("vibratorOn\n");
+ vibrator_on(timeout_ms);
}
-static void off(JNIEnv *env, jobject clazz)
+static void vibratorOff(JNIEnv *env, jobject clazz)
{
- // LOGI("off\n");
+ // LOGI("vibratorOff\n");
vibrator_off();
}
static JNINativeMethod method_table[] = {
- { "on", "()V", (void*)on },
- { "off", "()V", (void*)off }
+ { "vibratorOn", "(J)V", (void*)vibratorOn },
+ { "vibratorOff", "()V", (void*)vibratorOff }
};
int register_android_os_Vibrator(JNIEnv *env)
diff --git a/core/jni/server/com_android_server_KeyInputQueue.cpp b/services/jni/com_android_server_KeyInputQueue.cpp
index 4e9ffb1..63830d5 100644
--- a/core/jni/server/com_android_server_KeyInputQueue.cpp
+++ b/services/jni/com_android_server_KeyInputQueue.cpp
@@ -205,6 +205,25 @@ android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz,
return st;
}
+static jboolean
+android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz,
+ jintArray keyCodes, jbooleanArray outFlags)
+{
+ jboolean ret = JNI_FALSE;
+
+ int32_t* codes = env->GetIntArrayElements(keyCodes, NULL);
+ uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL);
+ size_t numCodes = env->GetArrayLength(keyCodes);
+ if (numCodes == env->GetArrayLength(outFlags)) {
+ gLock.lock();
+ if (gHub != NULL) ret = gHub->hasKeys(numCodes, codes, flags);
+ gLock.unlock();
+ }
+
+ env->ReleaseBooleanArrayElements(outFlags, flags, 0);
+ env->ReleaseIntArrayElements(keyCodes, codes, 0);
+ return ret;
+}
// ----------------------------------------------------------------------------
@@ -233,6 +252,8 @@ static JNINativeMethod gInputMethods[] = {
(void*) android_server_KeyInputQueue_getKeycodeState },
{ "getKeycodeState", "(II)I",
(void*) android_server_KeyInputQueue_getKeycodeStateDevice },
+ { "hasKeys", "([I[Z)Z",
+ (void*) android_server_KeyInputQueue_hasKeys },
};
int register_android_server_KeyInputQueue(JNIEnv* env)
diff --git a/core/jni/server/com_android_server_SensorService.cpp b/services/jni/com_android_server_SensorService.cpp
index 695a8a3..695a8a3 100644
--- a/core/jni/server/com_android_server_SensorService.cpp
+++ b/services/jni/com_android_server_SensorService.cpp
diff --git a/core/jni/server/com_android_server_SystemServer.cpp b/services/jni/com_android_server_SystemServer.cpp
index ae29405..ae29405 100644
--- a/core/jni/server/com_android_server_SystemServer.cpp
+++ b/services/jni/com_android_server_SystemServer.cpp
diff --git a/core/jni/server/onload.cpp b/services/jni/onload.cpp
index 3d68cfb..3d68cfb 100644
--- a/core/jni/server/onload.cpp
+++ b/services/jni/onload.cpp
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 374a703..c5b1b73 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -252,10 +252,7 @@ public class TelephonyManager {
*/
public List<NeighboringCellInfo> getNeighboringCellInfo() {
try {
- ITelephony tel = getITelephony();
- if (tel != null) {
- return tel.getNeighboringCellInfo();
- }
+ return getITelephony().getNeighboringCellInfo();
} catch (RemoteException ex) {
}
return null;
@@ -683,7 +680,8 @@ public class TelephonyManager {
public void listen(PhoneStateListener listener, int events) {
String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
try {
- mRegistry.listen(pkgForDebug, listener.callback, events, true);
+ Boolean notifyNow = (getITelephony() != null);
+ mRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
} catch (RemoteException ex) {
// system process dead
}
diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java
index f79b0a0..c2e0165 100644
--- a/telephony/java/android/telephony/gsm/SmsMessage.java
+++ b/telephony/java/android/telephony/gsm/SmsMessage.java
@@ -467,7 +467,7 @@ public class SmsMessage {
* units remaining until the next message. int[3] is the encoding
* type that should be used for the message.
*/
- public static int[] calculateLength(String messageBody, boolean use7bitOnly) {
+ public static int[] calculateLength(CharSequence messageBody, boolean use7bitOnly) {
int ret[] = new int[4];
try {
@@ -502,6 +502,25 @@ public class SmsMessage {
return ret;
}
+ /**
+ * Calculates the number of SMS's required to encode the message body and
+ * the number of characters remaining until the next message, given the
+ * current encoding.
+ *
+ * @param messageBody the message to encode
+ * @param use7bitOnly if true, characters that are not part of the GSM
+ * alphabet are counted as a single space char. If false, a
+ * messageBody containing non-GSM alphabet characters is calculated
+ * for 16-bit encoding.
+ * @return an int[4] with int[0] being the number of SMS's required, int[1]
+ * the number of code units used, and int[2] is the number of code
+ * units remaining until the next message. int[3] is the encoding
+ * type that should be used for the message.
+ */
+ public static int[] calculateLength(String messageBody, boolean use7bitOnly) {
+ return calculateLength((CharSequence)messageBody, use7bitOnly);
+ }
+
/**
* Get an SMS-SUBMIT PDU for a destination address and a message
@@ -541,7 +560,12 @@ public class SmsMessage {
// TP-Data-Coding-Scheme
// Default encoding, uncompressed
- bo.write(0x00);
+ // To test writing messages to the SIM card, change this value 0x00 to 0x12, which
+ // means "bits 1 and 0 contain message class, and the class is 2". Note that this
+ // takes effect for the sender. In other words, messages sent by the phone with this
+ // change will end up on the receiver's SIM card. You can then send messages to
+ // yourself (on a phone with this change) and they'll end up on the SIM card.
+ bo.write(0x00);
// (no TP-Validity-Period)
diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java
index d53d4ab..d833810 100644
--- a/telephony/java/com/android/internal/telephony/Connection.java
+++ b/telephony/java/com/android/internal/telephony/Connection.java
@@ -37,7 +37,10 @@ public abstract class Connection
OUT_OF_SERVICE, /* out of service */
SIM_ERROR, /* No SIM, SIM locked, or other SIM error */
CALL_BARRED, /* call was blocked by call barrring */
- FDN_BLOCKED /* call was blocked by fixed dial number */
+ FDN_BLOCKED, /* call was blocked by fixed dial number */
+ CS_RESTRICTED, /* call was blocked by restricted all voice access */
+ CS_RESTRICTED_NORMAL,/* call was blocked by restricted normal voice access */
+ CS_RESTRICTED_EMERGENCY/* call was blocked by restricted emergency voice access */
}
Object userData;
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 4957366..2b4195b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -38,7 +38,7 @@ interface ITelephony {
void dial(String number);
/**
- * Place a call to the numer.
+ * Place a call to the specified number.
* @param number the number to be called.
*/
void call(String number);
@@ -73,6 +73,36 @@ interface ITelephony {
boolean endCall();
/**
+ * Answer the currently-ringing call.
+ *
+ * If there's already a current active call, that call will be
+ * automatically put on hold. If both lines are currently in use, the
+ * current active call will be ended.
+ *
+ * TODO: provide a flag to let the caller specify what policy to use
+ * if both lines are in use. (The current behavior is hardwired to
+ * "answer incoming, end ongoing", which is how the CALL button
+ * is specced to behave.)
+ *
+ * TODO: this should be a oneway call (especially since it's called
+ * directly from the key queue thread).
+ */
+ void answerRingingCall();
+
+ /**
+ * Silence the ringer if an incoming call is currently ringing.
+ * (If vibrating, stop the vibrator also.)
+ *
+ * It's safe to call this if the ringer has already been silenced, or
+ * even if there's no incoming call. (If so, this method will do nothing.)
+ *
+ * TODO: this should be a oneway call too (see above).
+ * (Actually *all* the methods here that return void can
+ * probably be oneway.)
+ */
+ void silenceRinger();
+
+ /**
* Check if we are in either an active or holding call
* @return true if the phone state is OFFHOOK.
*/
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 9a36bc1..05e61f2 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -138,8 +138,11 @@ public interface Phone {
static final String REASON_PDP_RESET = "pdpReset";
static final String REASON_VOICE_CALL_ENDED = "2GVoiceCallEnded";
static final String REASON_VOICE_CALL_STARTED = "2GVoiceCallStarted";
-
- // Used for band mode selction methods
+ static final String REASON_PS_RESTRICT_ENABLED = "psRestrictEnabled";
+ static final String REASON_PS_RESTRICT_DISABLED = "psRestrictDisabled";
+ static final String REASON_SIM_LOADED = "simLoaded";
+
+ // Used for band mode selection methods
static final int BM_UNSPECIFIED = 0; // selected by baseband automatically
static final int BM_EURO_BAND = 1; // GSM-900 / DCS-1800 / WCDMA-IMT-2000
static final int BM_US_BAND = 2; // GSM-850 / PCS-1900 / WCDMA-850 / WCDMA-PCS-1900
diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
new file mode 100644
index 0000000..2b70162
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
@@ -0,0 +1,227 @@
+/*
+ * 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.internal.telephony;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.PowerManager;
+import android.provider.Telephony.Sms.Intents;
+import android.util.Config;
+import android.util.Log;
+import com.android.internal.telephony.gsm.SimUtils;
+
+
+/**
+ * WAP push handler class.
+ *
+ * @hide
+ */
+public class WapPushOverSms {
+ private static final String LOG_TAG = "WAP PUSH";
+
+ private final Context mContext;
+ private WspTypeDecoder pduDecoder;
+ private PowerManager.WakeLock mWakeLock;
+
+ /**
+ * Hold the wake lock for 5 seconds, which should be enough time for
+ * any receiver(s) to grab its own wake lock.
+ */
+ private final int WAKE_LOCK_TIMEOUT = 5000;
+
+ public WapPushOverSms(Phone phone) {
+ mContext = phone.getContext();
+ createWakelock();
+ }
+
+ /**
+ * Dispatches inbound messages that are in the WAP PDU format. See
+ * wap-230-wsp-20010705-a section 8 for details on the WAP PDU format.
+ *
+ * @param pdu The WAP PDU, made up of one or more SMS PDUs
+ */
+ public void dispatchWapPdu(byte[] pdu) {
+
+ if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + SimUtils.bytesToHexString(pdu));
+
+ int index = 0;
+ int transactionId = pdu[index++] & 0xFF;
+ int pduType = pdu[index++] & 0xFF;
+ int headerLength = 0;
+
+ if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH) &&
+ (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
+ if (Config.LOGD) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
+ return;
+ }
+
+ pduDecoder = new WspTypeDecoder(pdu);
+
+ /**
+ * Parse HeaderLen(unsigned integer).
+ * From wap-230-wsp-20010705-a section 8.1.2
+ * The maximum size of a uintvar is 32 bits.
+ * So it will be encoded in no more than 5 octets.
+ */
+ if (pduDecoder.decodeUintvarInteger(index) == false) {
+ if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Length error.");
+ return;
+ }
+ headerLength = (int)pduDecoder.getValue32();
+ index += pduDecoder.getDecodedDataLength();
+
+ int headerStartIndex = index;
+
+ /**
+ * Parse Content-Type.
+ * From wap-230-wsp-20010705-a section 8.4.2.24
+ *
+ * Content-type-value = Constrained-media | Content-general-form
+ * Content-general-form = Value-length Media-type
+ * Media-type = (Well-known-media | Extension-Media) *(Parameter)
+ * Value-length = Short-length | (Length-quote Length)
+ * Short-length = <Any octet 0-30> (octet <= WAP_PDU_SHORT_LENGTH_MAX)
+ * Length-quote = <Octet 31> (WAP_PDU_LENGTH_QUOTE)
+ * Length = Uintvar-integer
+ */
+ if (pduDecoder.decodeContentType(index) == false) {
+ if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
+ return;
+ }
+ int binaryContentType;
+ String mimeType = pduDecoder.getValueString();
+ if (mimeType == null) {
+ binaryContentType = (int)pduDecoder.getValue32();
+ switch (binaryContentType) {
+ case WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_XML:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_WBXML:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_WBXML;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_PUSH_SI:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SI;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_PUSH_SL:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SL;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_MMS:
+ mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS;
+ break;
+ default:
+ if (Config.LOGD) {
+ Log.w(LOG_TAG,
+ "Received PDU. Unsupported Content-Type = " + binaryContentType);
+ }
+ return;
+ }
+ } else {
+ if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_XML;
+ } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_WBXML)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_WBXML;
+ } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SI)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_SI;
+ } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_SL)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_SL;
+ } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO;
+ } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS)) {
+ binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_MMS;
+ } else {
+ if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Unknown Content-Type = " + mimeType);
+ return;
+ }
+ }
+ index += pduDecoder.getDecodedDataLength();
+
+ int dataIndex = headerStartIndex + headerLength;
+ boolean dispatchedByApplication = false;
+ switch (binaryContentType) {
+ case WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO:
+ dispatchWapPdu_PushCO(pdu, transactionId, pduType);
+ dispatchedByApplication = true;
+ break;
+ case WspTypeDecoder.CONTENT_TYPE_B_MMS:
+ dispatchWapPdu_MMS(pdu, transactionId, pduType, dataIndex);
+ dispatchedByApplication = true;
+ break;
+ default:
+ break;
+ }
+ if (dispatchedByApplication == false) {
+ dispatchWapPdu_default(pdu, transactionId, pduType, mimeType, dataIndex);
+ }
+ }
+
+ private void dispatchWapPdu_default(
+ byte[] pdu, int transactionId, int pduType, String mimeType, int dataIndex) {
+ byte[] data;
+
+ data = new byte[pdu.length - dataIndex];
+ System.arraycopy(pdu, dataIndex, data, 0, data.length);
+
+ Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
+ intent.setType(mimeType);
+ intent.putExtra("transactionId", transactionId);
+ intent.putExtra("pduType", pduType);
+ intent.putExtra("data", data);
+
+ sendBroadcast(intent, "android.permission.RECEIVE_WAP_PUSH");
+ }
+
+ private void dispatchWapPdu_PushCO(byte[] pdu, int transactionId, int pduType) {
+ Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
+ intent.setType(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO);
+ intent.putExtra("transactionId", transactionId);
+ intent.putExtra("pduType", pduType);
+ intent.putExtra("data", pdu);
+
+ sendBroadcast(intent, "android.permission.RECEIVE_WAP_PUSH");
+ }
+
+ private void dispatchWapPdu_MMS(byte[] pdu, int transactionId, int pduType, int dataIndex) {
+ byte[] data;
+
+ data = new byte[pdu.length - dataIndex];
+ System.arraycopy(pdu, dataIndex, data, 0, data.length);
+
+ Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
+ intent.setType(WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS);
+ intent.putExtra("transactionId", transactionId);
+ intent.putExtra("pduType", pduType);
+ intent.putExtra("data", data);
+
+ sendBroadcast(intent, "android.permission.RECEIVE_MMS");
+ }
+
+ private void createWakelock() {
+ PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WapPushOverSms");
+ mWakeLock.setReferenceCounted(true);
+ }
+
+ private void sendBroadcast(Intent intent, String permission) {
+ // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
+ // receivers time to take their own wake locks.
+ mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
+ mContext.sendBroadcast(intent, permission);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
new file mode 100644
index 0000000..2984fa8
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java
@@ -0,0 +1,344 @@
+/*
+ * 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.internal.telephony;
+
+
+/**
+ * Implement the WSP data type decoder.
+ *
+ * @hide
+ */
+public class WspTypeDecoder {
+
+ private static final int WAP_PDU_SHORT_LENGTH_MAX = 30;
+ private static final int WAP_PDU_LENGTH_QUOTE = 31;
+
+ public static final int PDU_TYPE_PUSH = 0x06;
+ public static final int PDU_TYPE_CONFIRMED_PUSH = 0x07;
+
+ public static final int CONTENT_TYPE_B_DRM_RIGHTS_XML = 0x4a;
+ public static final int CONTENT_TYPE_B_DRM_RIGHTS_WBXML = 0x4b;
+ public static final int CONTENT_TYPE_B_PUSH_SI = 0x2e;
+ public static final int CONTENT_TYPE_B_PUSH_SL = 0x30;
+ public static final int CONTENT_TYPE_B_PUSH_CO = 0x32;
+ public static final int CONTENT_TYPE_B_MMS = 0x3e;
+
+ public static final String CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML =
+ "application/vnd.oma.drm.rights+xml";
+ public static final String CONTENT_MIME_TYPE_B_DRM_RIGHTS_WBXML =
+ "application/vnd.oma.drm.rights+wbxml";
+ public static final String CONTENT_MIME_TYPE_B_PUSH_SI = "application/vnd.wap.sic";
+ public static final String CONTENT_MIME_TYPE_B_PUSH_SL = "application/vnd.wap.slc";
+ public static final String CONTENT_MIME_TYPE_B_PUSH_CO = "application/vnd.wap.coc";
+ public static final String CONTENT_MIME_TYPE_B_MMS = "application/vnd.wap.mms-message";
+
+ public static final int PARAMETER_ID_X_WAP_APPLICATION_ID = 0x2f;
+
+
+ byte[] wspData;
+ int dataLength;
+ long unsigned32bit;
+ String stringValue;
+
+ public WspTypeDecoder(byte[] pdu) {
+ wspData = pdu;
+ }
+
+ /**
+ * Decode the "Text-string" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Text-string" in this pdu
+ *
+ * @return false when error(not a Text-string) occur
+ * return value can be retrieved by getValueString() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeTextString(int startIndex) {
+ int index = startIndex;
+ while (wspData[index] != 0) {
+ index++;
+ }
+ dataLength = index - startIndex + 1;
+ if (wspData[startIndex] == 127) {
+ stringValue = new String(wspData, startIndex+1, dataLength - 2);
+ } else {
+ stringValue = new String(wspData, startIndex, dataLength - 1);
+ }
+ return true;
+ }
+
+ /**
+ * Decode the "Short-integer" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Short-integer" in this pdu
+ *
+ * @return false when error(not a Short-integer) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeShortInteger(int startIndex) {
+ if ((wspData[startIndex] & 0x80) == 0) {
+ return false;
+ }
+ unsigned32bit = wspData[startIndex] & 0x7f;
+ dataLength = 1;
+ return true;
+ }
+
+ /**
+ * Decode the "Long-integer" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Long-integer" in this pdu
+ *
+ * @return false when error(not a Long-integer) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeLongInteger(int startIndex) {
+ int lengthMultiOctet = wspData[startIndex] & 0xff;
+
+ if (lengthMultiOctet > WAP_PDU_SHORT_LENGTH_MAX) {
+ return false;
+ }
+ unsigned32bit = 0;
+ for (int i=1; i<=lengthMultiOctet; i++) {
+ unsigned32bit = (unsigned32bit << 8) | (wspData[startIndex+i] & 0xff);
+ }
+ dataLength = 1+lengthMultiOctet;
+ return true;
+ }
+
+ /**
+ * Decode the "Integer-Value" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Integer-Value" in this pdu
+ *
+ * @return false when error(not a Integer-Value) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeIntegerValue(int startIndex) {
+ if (decodeShortInteger(startIndex) == true) {
+ return true;
+ }
+ return decodeLongInteger(startIndex);
+ }
+
+ /**
+ * Decode the "Uintvar-integer" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Uintvar-integer" in this pdu
+ *
+ * @return false when error(not a Uintvar-integer) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeUintvarInteger(int startIndex) {
+ int index = startIndex;
+
+ unsigned32bit = 0;
+ while ((wspData[index] & 0x80) != 0) {
+ if ((index - startIndex) >= 4) {
+ return false;
+ }
+ unsigned32bit = (unsigned32bit << 7) | (wspData[index] & 0x7f);
+ index++;
+ }
+ unsigned32bit = (unsigned32bit << 7) | (wspData[index] & 0x7f);
+ dataLength = index - startIndex + 1;
+ return true;
+ }
+
+ /**
+ * Decode the "Value-length" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Value-length" in this pdu
+ *
+ * @return false when error(not a Value-length) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeValueLength(int startIndex) {
+ if ((wspData[startIndex] & 0xff) > WAP_PDU_LENGTH_QUOTE) {
+ return false;
+ }
+ if (wspData[startIndex] < WAP_PDU_LENGTH_QUOTE) {
+ unsigned32bit = wspData[startIndex];
+ dataLength = 1;
+ } else {
+ decodeUintvarInteger(startIndex+1);
+ dataLength ++;
+ }
+ return true;
+ }
+
+ /**
+ * Decode the "Extension-media" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Extension-media" in this pdu
+ *
+ * @return false when error(not a Extension-media) occur
+ * return value can be retrieved by getValueString() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeExtensionMedia(int startIndex) {
+ int index = startIndex;
+ while (wspData[index] != 0) {
+ index++;
+ }
+ dataLength = index - startIndex + 1;
+ stringValue = new String(wspData, startIndex, dataLength - 1);
+ return true;
+ }
+
+ /**
+ * Decode the "Constrained-encoding" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Constrained-encoding" in this pdu
+ *
+ * @return false when error(not a Constrained-encoding) occur
+ * return value can be retrieved first by getValueString() and second by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeConstrainedEncoding(int startIndex) {
+ if (decodeShortInteger(startIndex) == true) {
+ stringValue = null;
+ return true;
+ }
+ return decodeExtensionMedia(startIndex);
+ }
+
+ /**
+ * Decode the "Content-type" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Content-type" in this pdu
+ *
+ * @return false when error(not a Content-type) occur
+ * return value can be retrieved first by getValueString() and second by getValue32()
+ * method length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeContentType(int startIndex) {
+ int mediaPrefixLength;
+ long mediaFieldLength;
+
+ if (decodeValueLength(startIndex) == false) {
+ return decodeConstrainedEncoding(startIndex);
+ }
+ mediaPrefixLength = getDecodedDataLength();
+ mediaFieldLength = getValue32();
+ if (decodeIntegerValue(startIndex + mediaPrefixLength) == true) {
+ dataLength += mediaPrefixLength;
+ stringValue = null;
+ return true;
+ }
+ if (decodeExtensionMedia(startIndex + mediaPrefixLength) == true) {
+ dataLength += mediaPrefixLength;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Decode the "Content length" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Content length" in this pdu
+ *
+ * @return false when error(not a Content length) occur
+ * return value can be retrieved by getValue32() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeContentLength(int startIndex) {
+ return decodeIntegerValue(startIndex);
+ }
+
+ /**
+ * Decode the "Content location" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "Content location" in this pdu
+ *
+ * @return false when error(not a Content location) occur
+ * return value can be retrieved by getValueString() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeContentLocation(int startIndex) {
+ return decodeTextString(startIndex);
+ }
+
+ /**
+ * Decode the "X-Wap-Application-Id" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "X-Wap-Application-Id" in this pdu
+ *
+ * @return false when error(not a X-Wap-Application-Id) occur
+ * return value can be retrieved first by getValueString() and second by getValue32()
+ * method length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeXWapApplicationId(int startIndex) {
+ if (decodeIntegerValue(startIndex) == true) {
+ stringValue = null;
+ return true;
+ }
+ return decodeTextString(startIndex);
+ }
+
+ /**
+ * Decode the "X-Wap-Content-URI" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "X-Wap-Content-URI" in this pdu
+ *
+ * @return false when error(not a X-Wap-Content-URI) occur
+ * return value can be retrieved by getValueString() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeXWapContentURI(int startIndex) {
+ return decodeTextString(startIndex);
+ }
+
+ /**
+ * Decode the "X-Wap-Initiator-URI" type for WSP pdu
+ *
+ * @param startIndex The starting position of the "X-Wap-Initiator-URI" in this pdu
+ *
+ * @return false when error(not a X-Wap-Initiator-URI) occur
+ * return value can be retrieved by getValueString() method
+ * length of data in pdu can be retrieved by getValue32() method
+ */
+ public boolean decodeXWapInitiatorURI(int startIndex) {
+ return decodeTextString(startIndex);
+ }
+
+ /**
+ * The data length of latest operation.
+ */
+ public int getDecodedDataLength() {
+ return dataLength;
+ }
+
+ /**
+ * The 32-bits result of latest operation.
+ */
+ public long getValue32() {
+ return unsigned32bit;
+ }
+
+ /**
+ * The String result of latest operation.
+ */
+ public String getValueString() {
+ return stringValue;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java b/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java
index 58a5bba..8e14b43 100644
--- a/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java
@@ -67,6 +67,8 @@ public abstract class BaseCommands implements CommandsInterface
protected Registrant mSimRefreshRegistrant;
/** Registrant for handling RING notifications */
protected Registrant mRingRegistrant;
+ /** Registrant for handling RESTRICTED STATE changed notification */
+ protected Registrant mRestrictedStateRegistrant;
public BaseCommands(Context context) {
mContext = context; // May be null (if so we won't log statistics)
@@ -279,6 +281,12 @@ public abstract class BaseCommands implements CommandsInterface
mRingRegistrant = new Registrant (h, what, obj);
}
+ public void
+ setOnRestrictedStateChanged(Handler h, int what, Object obj)
+ {
+ mRestrictedStateRegistrant = new Registrant (h, what, obj);
+ }
+
//***** Protected Methods
/**
* Store new RadioState and send notification based on the changes
diff --git a/telephony/java/com/android/internal/telephony/gsm/CallTracker.java b/telephony/java/com/android/internal/telephony/gsm/CallTracker.java
index afd11c4..2d716bb 100644
--- a/telephony/java/com/android/internal/telephony/gsm/CallTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/CallTracker.java
@@ -51,10 +51,7 @@ public final class CallTracker extends Handler
private static final boolean REPEAT_POLLING = false;
private static final boolean DBG_POLL = false;
-
- // Event Log Tags
- private static final int EVENT_LOG_CALL_DROP = 50106;
-
+
//***** Constants
static final int POLL_DELAY_MSEC = 250;
@@ -62,17 +59,17 @@ public final class CallTracker extends Handler
static final int MAX_CONNECTIONS_PER_CALL = 5; // only 5 connections allowed per call
//***** Instance Variables
-
+
GSMConnection connections[] = new GSMConnection[MAX_CONNECTIONS];
RegistrantList voiceCallEndedRegistrants = new RegistrantList();
RegistrantList voiceCallStartedRegistrants = new RegistrantList();
// connections dropped durin last poll
- ArrayList<GSMConnection> droppedDuringPoll
- = new ArrayList<GSMConnection>(MAX_CONNECTIONS);
+ ArrayList<GSMConnection> droppedDuringPoll
+ = new ArrayList<GSMConnection>(MAX_CONNECTIONS);
- GSMCall ringingCall = new GSMCall(this);
+ GSMCall ringingCall = new GSMCall(this);
// A call that is ringing or (call) waiting
GSMCall foregroundCall = new GSMCall(this);
GSMCall backgroundCall = new GSMCall(this);
@@ -172,13 +169,13 @@ public final class CallTracker extends Handler
// for the newly dialed connection
switchWaitingOrHoldingAndActive();
- // Fake local state so that
+ // Fake local state so that
// a) foregroundCall is empty for the newly dialed connection
// b) hasNonHangupStateChanged remains false in the
// next poll, so that we don't clear a failed dialing call
fakeHoldForegroundBeforeDial();
- }
-
+ }
+
if (foregroundCall.getState() != Call.State.IDLE) {
//we should have failed in !canDial() above before we get here
throw new CallStateException("cannot dial in current state");
@@ -194,22 +191,22 @@ public final class CallTracker extends Handler
pendingMO.cause = Connection.DisconnectCause.INVALID_NUMBER;
// handlePollCalls() will notice this call not present
- // and will mark it as dropped.
+ // and will mark it as dropped.
pollCallsWhenSafe();
} else {
// Always unmute when initiating a new call
setMute(false);
- cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());
+ cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());
}
updatePhoneState();
phone.notifyCallStateChanged();
-
+
return pendingMO;
}
-
+
Connection
dial (String dialString) throws CallStateException
{
@@ -222,7 +219,7 @@ public final class CallTracker extends Handler
// FIXME if SWITCH fails, should retry with ANSWER
// in case the active/holding call disappeared and this
// is no longer call waiting
-
+
if (ringingCall.getState() == Call.State.INCOMING) {
Log.i("phone", "acceptCall: incoming...");
// Always unmute when answering a new call
@@ -270,7 +267,7 @@ public final class CallTracker extends Handler
{
cm.explicitCallTransfer(obtainCompleteMessage(EVENT_ECT_RESULT));
}
-
+
void
clearDisconnected()
{
@@ -280,7 +277,7 @@ public final class CallTracker extends Handler
phone.notifyCallStateChanged();
}
- boolean
+ boolean
canConference()
{
return foregroundCall.getState() == Call.State.ACTIVE
@@ -312,13 +309,13 @@ public final class CallTracker extends Handler
}
//***** Private Instance Methods
-
+
private void
internalClearDisconnected()
{
ringingCall.clearDisconnected();
foregroundCall.clearDisconnected();
- backgroundCall.clearDisconnected();
+ backgroundCall.clearDisconnected();
}
/**
@@ -364,7 +361,7 @@ public final class CallTracker extends Handler
/**
* Obtain a complete message that indicates that this operation
* does not require polling of getCurrentCalls(). However, if other
- * operations that do need getCurrentCalls() are pending or are
+ * operations that do need getCurrentCalls() are pending or are
* scheduled while this operation is pending, the invocatoin
* of getCurrentCalls() will be postponed until this
* operation is also complete.
@@ -382,20 +379,20 @@ public final class CallTracker extends Handler
operationComplete()
{
pendingOperations--;
-
+
if (DBG_POLL) log("operationComplete: pendingOperations=" +
pendingOperations + ", needsPoll=" + needsPoll);
if (pendingOperations == 0 && needsPoll) {
lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
- cm.getCurrentCalls(lastRelevantPoll);
+ cm.getCurrentCalls(lastRelevantPoll);
} else if (pendingOperations < 0) {
// this should never happen
Log.e(LOG_TAG,"CallTracker.pendingOperations < 0");
pendingOperations = 0;
}
}
-
+
private void
pollCallsWhenSafe()
{
@@ -403,10 +400,10 @@ public final class CallTracker extends Handler
if (checkNoOperationsPending()) {
lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
- cm.getCurrentCalls(lastRelevantPoll);
+ cm.getCurrentCalls(lastRelevantPoll);
}
}
-
+
private void
pollCallsAfterDelay()
{
@@ -428,7 +425,7 @@ public final class CallTracker extends Handler
updatePhoneState()
{
Phone.State oldState = state;
-
+
if (ringingCall.isRinging()) {
state = Phone.State.RINGING;
} else if (pendingMO != null ||
@@ -436,7 +433,7 @@ public final class CallTracker extends Handler
state = Phone.State.OFFHOOK;
} else {
state = Phone.State.IDLE;
- }
+ }
if (state == Phone.State.IDLE && oldState != state) {
voiceCallEndedRegistrants.notifyRegistrants(
@@ -475,7 +472,7 @@ public final class CallTracker extends Handler
boolean needsPollDelay = false;
boolean unknownConnectionAppeared = false;
- for (int i = 0, curDC = 0, dcSize = polledCalls.size()
+ for (int i = 0, curDC = 0, dcSize = polledCalls.size()
; i < connections.length; i++) {
GSMConnection conn = connections[i];
DriverCall dc = null;
@@ -532,7 +529,7 @@ public final class CallTracker extends Handler
// which is neither a ringing call or one we created.
// Either we've crashed and re-attached to an existing
// call, or something else (eg, SIM) initiated the call.
-
+
Log.i(LOG_TAG,"Phantom call appeared " + dc);
// If it's a connected call, set the connect time so that
@@ -549,8 +546,8 @@ public final class CallTracker extends Handler
hasNonHangupStateChanged = true;
} else if (conn != null && dc == null) {
// Connection missing in CLCC response that we were
- // tracking.
- droppedDuringPoll.add(conn);
+ // tracking.
+ droppedDuringPoll.add(conn);
// Dropped connections are removed from the CallTracker
// list but kept in the GSMCall list
connections[i] = null;
@@ -558,7 +555,7 @@ public final class CallTracker extends Handler
// Connection in CLCC response does not match what
// we were tracking. Assume dropped call and new call
- droppedDuringPoll.add(conn);
+ droppedDuringPoll.add(conn);
connections[i] = new GSMConnection (phone.getContext(), dc, this, i);
if (connections[i].getCall() == ringingCall) {
@@ -594,11 +591,11 @@ public final class CallTracker extends Handler
// This is the first poll after an ATD.
// We expect the pending call to appear in the list
// If it does not, we land here
- if (pendingMO != null) {
- Log.d(LOG_TAG,"Pending MO dropped before poll fg state:"
+ if (pendingMO != null) {
+ Log.d(LOG_TAG,"Pending MO dropped before poll fg state:"
+ foregroundCall.getState());
- droppedDuringPoll.add(pendingMO);
+ droppedDuringPoll.add(pendingMO);
pendingMO = null;
hangupPendingMO = false;
}
@@ -619,7 +616,7 @@ public final class CallTracker extends Handler
if (conn.cause == Connection.DisconnectCause.LOCAL) {
cause = Connection.DisconnectCause.INCOMING_REJECTED;
} else {
- cause = Connection.DisconnectCause.INCOMING_MISSED;
+ cause = Connection.DisconnectCause.INCOMING_MISSED;
}
if (Phone.DEBUG_PHONE) {
@@ -690,7 +687,7 @@ public final class CallTracker extends Handler
dumpState()
{
List l;
-
+
Log.i(LOG_TAG,"Phone State:" + state);
Log.i(LOG_TAG,"Ringing call: " + ringingCall.toString());
@@ -722,7 +719,7 @@ public final class CallTracker extends Handler
hangup (GSMConnection conn) throws CallStateException
{
if (conn.owner != this) {
- throw new CallStateException ("Connection " + conn
+ throw new CallStateException ("Connection " + conn
+ "does not belong to CallTracker " + this);
}
@@ -731,14 +728,14 @@ public final class CallTracker extends Handler
// GSM index assigned yet
if (Phone.DEBUG_PHONE) log("hangup: set hangupPendingMO to true");
- hangupPendingMO = true;
+ hangupPendingMO = true;
} else {
- try {
+ try {
cm.hangupConnection (conn.getGSMIndex(), obtainCompleteMessage());
} catch (CallStateException ex) {
// Ignore "connection not found"
// Call may have hung up already
- Log.w(LOG_TAG,"CallTracker WARN: hangup() on absent connection "
+ Log.w(LOG_TAG,"CallTracker WARN: hangup() on absent connection "
+ conn);
}
}
@@ -750,16 +747,16 @@ public final class CallTracker extends Handler
separate (GSMConnection conn) throws CallStateException
{
if (conn.owner != this) {
- throw new CallStateException ("Connection " + conn
+ throw new CallStateException ("Connection " + conn
+ "does not belong to CallTracker " + this);
}
try {
- cm.separateConnection (conn.getGSMIndex(),
+ cm.separateConnection (conn.getGSMIndex(),
obtainCompleteMessage(EVENT_SEPARATE_RESULT));
} catch (CallStateException ex) {
// Ignore "connection not found"
// Call may have hung up already
- Log.w(LOG_TAG,"CallTracker WARN: separate() on absent connection "
+ Log.w(LOG_TAG,"CallTracker WARN: separate() on absent connection "
+ conn);
}
}
@@ -772,14 +769,14 @@ public final class CallTracker extends Handler
desiredMute = mute;
cm.setMute(desiredMute, null);
}
-
+
/*package*/ boolean
getMute()
{
return desiredMute;
}
-
+
//***** Called from GSMCall
/* package */ void
@@ -886,11 +883,11 @@ public final class CallTracker extends Handler
//****** Overridden from Handler
- public void
+ public void
handleMessage (Message msg)
{
AsyncResult ar;
-
+
switch (msg.what) {
case EVENT_POLL_CALLS_RESULT:
ar = (AsyncResult)msg.obj;
@@ -924,7 +921,7 @@ public final class CallTracker extends Handler
int causeCode;
ar = (AsyncResult)msg.obj;
- operationComplete();
+ operationComplete();
if (ar.exception != null) {
// An exception occurred...just treat the disconnect
@@ -936,7 +933,7 @@ public final class CallTracker extends Handler
causeCode = ((int[])ar.result)[0];
}
// Log the causeCode if its not normal
- if (causeCode == CallFailCause.NO_CIRCUIT_AVAIL ||
+ if (causeCode == CallFailCause.NO_CIRCUIT_AVAIL ||
causeCode == CallFailCause.TEMPORARY_FAILURE ||
causeCode == CallFailCause.SWITCHING_CONGESTION ||
causeCode == CallFailCause.CHANNEL_NOT_AVAIL ||
@@ -946,12 +943,12 @@ public final class CallTracker extends Handler
int cid = -1;
GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
if (loc != null) cid = loc.getCid();
-
- EventLog.List val = new EventLog.List(causeCode, cid,
+
+ EventLog.List val = new EventLog.List(causeCode, cid,
TelephonyManager.getDefault().getNetworkType());
- EventLog.writeEvent(EVENT_LOG_CALL_DROP, val);
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CALL_DROP, val);
}
-
+
for (int i = 0, s = droppedDuringPoll.size()
; i < s ; i++
) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java b/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java
index c7b08d2..7915798 100644
--- a/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java
@@ -283,6 +283,17 @@ public interface CommandsInterface
void setOnCallRing(Handler h, int what, Object obj);
/**
+ * Sets the handler for RESTRICTED_STATE changed notification,
+ * eg, for Domain Specific Access Control
+ * unlike the register* methods, there's only one signal strength handler
+ *
+ * AsyncResult.result is an int[1]
+ * response.obj.result[0] is a bitmask of RIL_RESTRICTED_STATE_* values
+ */
+
+ void setOnRestrictedStateChanged(Handler h, int what, Object obj);
+
+ /**
* Sets the handler for Supplementary Service Notifications.
* Unlike the register* methods, there's only one notification handler
*
diff --git a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java
index b0b8cdc..30b1be8 100644
--- a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java
@@ -16,11 +16,6 @@
package com.android.internal.telephony.gsm;
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE;
-import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_EDGE;
-import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_GPRS;
-import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_UMTS;
-import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_UNKNOWN;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -31,6 +26,8 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.INetStatService;
@@ -50,13 +47,10 @@ import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
-import android.util.EventLog.List;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.gsm.PdpConnection.PdpFailCause;
-import android.net.wifi.WifiManager;
-import android.net.NetworkInfo;
-
+
import java.io.IOException;
import java.util.ArrayList;
@@ -128,7 +122,8 @@ final class DataConnectionTracker extends Handler
Handler mDataConnectionTracker = null;
private ContentResolver mResolver;
- int txPkts, rxPkts, sentSinceLastRecv, netStatPollPeriod;
+ long txPkts, rxPkts, sentSinceLastRecv;
+ int netStatPollPeriod;
private int mNoRecvPollCount = 0;
private boolean mPingTestActive = false;
// Count of PDP reset attempts; reset when we see incoming,
@@ -161,7 +156,7 @@ final class DataConnectionTracker extends Handler
/** CID of active PDP */
int cidActive;
-
+
/** Currently requested APN type */
private String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
@@ -177,11 +172,14 @@ final class DataConnectionTracker extends Handler
private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
- // wifi connection status will be updated by sticky intent
+ /** wifi connection status will be updated by sticky intent */
private boolean mIsWifiConnected = false;
/** Intent sent when the reconnect alarm fires. */
private PendingIntent mReconnectIntent = null;
+
+ /** Is packet service restricted by network */
+ private boolean mIsPsRestricted = false;
//***** Constants
@@ -201,9 +199,9 @@ final class DataConnectionTracker extends Handler
private static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
/** Default ping deadline, in seconds. */
- private final int DEFAULT_PING_DEADLINE = 5;
+ private static final int DEFAULT_PING_DEADLINE = 5;
/** Default max failure count before attempting to network re-registration. */
- private final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
+ private static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
/**
* After detecting a potential connection problem, this is the max number
@@ -232,13 +230,6 @@ final class DataConnectionTracker extends Handler
private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
- //***** Tag IDs for EventLog
- private static final int EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED = 50101;
- private static final int EVENT_LOG_RADIO_RESET = 50102;
- private static final int EVENT_LOG_PDP_RESET = 50103;
- private static final int EVENT_LOG_REREGISTER_NETWORK = 50104;
- private static final int EVENT_LOG_RADIO_PDP_SETUP_FAIL = 50105;
-
//***** Event Codes
static final int EVENT_DATA_SETUP_COMPLETE = 1;
static final int EVENT_RADIO_AVAILABLE = 3;
@@ -261,6 +252,8 @@ final class DataConnectionTracker extends Handler
static final int EVENT_START_NETSTAT_POLL = 27;
static final int EVENT_START_RECOVERY = 28;
static final int EVENT_APN_CHANGED = 29;
+ static final int EVENT_PS_RESTRICT_ENABLED = 30;
+ static final int EVENT_PS_RESTRICT_DISABLED = 31;
BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
{
@@ -319,6 +312,8 @@ final class DataConnectionTracker extends Handler
phone.mSST.registerForGprsDetached(this, EVENT_GPRS_DETACHED, null);
phone.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null);
phone.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null);
+ phone.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null);
+ phone.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null);
this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat"));
@@ -486,6 +481,7 @@ final class DataConnectionTracker extends Handler
* 2. registered to gprs service
* 3. user doesn't explicitly disable data service
* 4. wifi is not on
+ * 5. packet service is not restricted
*
* @return false while no data connection if all above requirements are met.
*/
@@ -495,12 +491,13 @@ final class DataConnectionTracker extends Handler
if (phone.mSIMRecords.getRecordsLoaded() &&
phone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE &&
(!roaming || getDataOnRoamingEnabled()) &&
- !mIsWifiConnected ) {
+ !mIsWifiConnected &&
+ !mIsPsRestricted ) {
return (state == State.CONNECTED);
}
return true;
}
-
+
private boolean isApnTypeActive(String type) {
// TODO: to support simultaneous, mActiveApn can be a List instead.
return mActiveApn != null && mActiveApn.canHandleType(type);
@@ -537,7 +534,7 @@ final class DataConnectionTracker extends Handler
Log.d(LOG_TAG, "dataEnabled[DEFAULT_APN]=" + dataEnabled[APN_DEFAULT_ID] +
" dataEnabled[MMS_APN]=" + dataEnabled[APN_MMS_ID]);
}
-
+
/**
* Prevent mobile data connections from being established,
* or once again allow mobile data connections. If the state
@@ -571,6 +568,14 @@ final class DataConnectionTracker extends Handler
}
/**
+ * Simply tear down data connections due to radio off
+ * and don't setup again.
+ */
+ public void cleanConnectionBeforeRadioOff() {
+ cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF);
+ }
+
+ /**
* Report the current state of data connectivity (enabled or disabled) for
* the default APN.
* @return {@code false} if data connectivity has been explicitly disabled,
@@ -605,7 +610,7 @@ final class DataConnectionTracker extends Handler
//Retrieve the data roaming setting from the shared preferences.
public boolean getDataOnRoamingEnabled() {
try {
- return Settings.Secure.getInt(phone.getContext().getContentResolver(),
+ return Settings.Secure.getInt(phone.getContext().getContentResolver(),
Settings.Secure.DATA_ROAMING) > 0;
} catch (SettingNotFoundException snfe) {
return false;
@@ -636,7 +641,7 @@ final class DataConnectionTracker extends Handler
stopNetStatPoll();
phone.notifyDataConnection(Phone.REASON_GPRS_DETACHED);
}
-
+
private void onGprsAttached() {
if (state == State.CONNECTED) {
startNetStatPoll();
@@ -654,6 +659,8 @@ final class DataConnectionTracker extends Handler
{
if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason));
+ Log.d(LOG_TAG, "[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted);
+
if (phone.getSimulatedRadioControl() != null) {
// Assume data is connected on the simulator
// FIXME this can be improved
@@ -670,9 +677,9 @@ final class DataConnectionTracker extends Handler
if ((state == State.IDLE || state == State.SCANNING)
&& (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach)
&& phone.mSIMRecords.getRecordsLoaded()
- && ( phone.mSST.isConcurrentVoiceAndData() ||
- phone.getState() == Phone.State.IDLE )
- && isDataAllowed()) {
+ && phone.getState() == Phone.State.IDLE
+ && isDataAllowed()
+ && !mIsPsRestricted ) {
if (state == State.IDLE) {
waitingApns = buildWaitingApns();
@@ -699,7 +706,8 @@ final class DataConnectionTracker extends Handler
" phoneState=" + phone.getState() +
" dataEnabled=" + getAnyDataEnabled() +
" roaming=" + roaming +
- " dataOnRoamingEnable=" + getDataOnRoamingEnabled());
+ " dataOnRoamingEnable=" + getDataOnRoamingEnabled() +
+ " ps restricted=" + mIsPsRestricted);
return false;
}
}
@@ -746,7 +754,7 @@ final class DataConnectionTracker extends Handler
* IDLE before the code below runs. If we didn't check
* for that, future calls to trySetupData would fail,
* and we would never get out of the DISCONNECTING state.
- */
+ */
if (!tearDown) {
setState(State.IDLE);
phone.notifyDataConnection(reason);
@@ -888,6 +896,9 @@ final class DataConnectionTracker extends Handler
isConnected = (state != State.IDLE && state != State.FAILED);
+ // The "current" may no longer be valid. MMS depends on this to send properly.
+ phone.updateCurrentCarrierInProvider();
+
// TODO: It'd be nice to only do this if the changed entrie(s)
// match the current operator.
createAllApnList();
@@ -932,6 +943,16 @@ final class DataConnectionTracker extends Handler
Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting");
+ // Add an event log when the network drops PDP
+ int cid = -1;
+ GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
+ if (loc != null) cid = loc.getCid();
+
+ EventLog.List val = new EventLog.List(cid,
+ TelephonyManager.getDefault().getNetworkType());
+
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val);
+
cleanUpConnection(true, null);
return;
@@ -964,6 +985,16 @@ final class DataConnectionTracker extends Handler
Log.i(LOG_TAG, "PDP connection has dropped (active=false case). "
+ " Reconnecting");
+ // Log the network drop on the event log.
+ int cid = -1;
+ GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
+ if (loc != null) cid = loc.getCid();
+
+ EventLog.List val = new EventLog.List(cid,
+ TelephonyManager.getDefault().getNetworkType());
+
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val);
+
cleanUpConnection(true, null);
}
}
@@ -1040,14 +1071,14 @@ final class DataConnectionTracker extends Handler
if (state == State.CONNECTED) {
int maxPdpReset = Settings.Gservices.getInt(mResolver,
Settings.Gservices.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT,
- DEFAULT_MAX_PDP_RESET_FAIL);
+ DEFAULT_MAX_PDP_RESET_FAIL);
if (mPdpResetCount < maxPdpReset) {
mPdpResetCount++;
- EventLog.writeEvent(EVENT_LOG_PDP_RESET, sentSinceLastRecv);
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_RESET, sentSinceLastRecv);
cleanUpConnection(true, Phone.REASON_PDP_RESET);
} else {
mPdpResetCount = 0;
- EventLog.writeEvent(EVENT_LOG_REREGISTER_NETWORK, sentSinceLastRecv);
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_REREGISTER_NETWORK, sentSinceLastRecv);
phone.mSST.reRegisterNetwork(null);
}
// TODO: Add increasingly drastic recovery steps, eg,
@@ -1096,8 +1127,8 @@ final class DataConnectionTracker extends Handler
{
public void run() {
- int sent, received;
- int preTxPkts = -1, preRxPkts = -1;
+ long sent, received;
+ long preTxPkts = -1, preRxPkts = -1;
Activity newActivity;
@@ -1105,8 +1136,8 @@ final class DataConnectionTracker extends Handler
preRxPkts = rxPkts;
try {
- txPkts = netstat.getTxPackets();
- rxPkts = netstat.getRxPackets();
+ txPkts = netstat.getMobileTxPackets();
+ rxPkts = netstat.getMobileRxPackets();
} catch (RemoteException e) {
txPkts = 0;
rxPkts = 0;
@@ -1152,7 +1183,7 @@ final class DataConnectionTracker extends Handler
if (sentSinceLastRecv >= watchdogTrigger) {
// we already have NUMBER_SENT_PACKETS sent without ack
if (mNoRecvPollCount == 0) {
- EventLog.writeEvent(EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED,
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED,
sentSinceLastRecv);
}
@@ -1220,11 +1251,11 @@ final class DataConnectionTracker extends Handler
} catch (Exception e) {
Log.w(LOG_TAG, "exception trying to ping");
}
-
+
if (status == 0) {
// ping succeeded. False alarm. Reset netStatPoll.
// ("-1" for this event indicates a false alarm)
- EventLog.writeEvent(EVENT_LOG_PDP_RESET, -1);
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_RESET, -1);
mPdpResetCount = 0;
sendMessage(obtainMessage(EVENT_START_NETSTAT_POLL));
} else {
@@ -1249,6 +1280,24 @@ final class DataConnectionTracker extends Handler
return (shouldPost && cause != PdpConnection.PdpFailCause.UNKNOWN);
}
+ /**
+ * Return true if data connection need to be setup after disconnected due to
+ * reason.
+ *
+ * @param reason the reason why data is disconnected
+ * @return true if try setup data connection is need for this reason
+ */
+ private boolean retryAfterDisconnected(String reason) {
+ boolean retry = true;
+
+ if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
+ Phone.REASON_DATA_DISABLED.equals(reason) ||
+ Phone.REASON_PS_RESTRICT_ENABLED.equals(reason)) {
+ retry = false;
+ }
+ return retry;
+ }
+
private void reconnectAfterFail(PdpFailCause lastFailCauseCode, String reason) {
if (state == State.FAILED) {
Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for "
@@ -1301,7 +1350,7 @@ final class DataConnectionTracker extends Handler
if (state == State.FAILED) {
cleanUpConnection(false, null);
}
- sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
+ sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
break;
case EVENT_ENABLE_NEW_APN:
@@ -1312,6 +1361,10 @@ final class DataConnectionTracker extends Handler
break;
case EVENT_TRY_SETUP_DATA:
+ if (msg.obj instanceof String) {
+ reason = (String)msg.obj;
+ }
+
trySetupData(reason);
break;
@@ -1335,7 +1388,7 @@ final class DataConnectionTracker extends Handler
case EVENT_GPRS_ATTACHED:
onGprsAttached();
break;
-
+
case EVENT_ROAMING_ON:
if (getDataOnRoamingEnabled()) {
trySetupData(Phone.REASON_ROAMING_ON);
@@ -1410,7 +1463,7 @@ final class DataConnectionTracker extends Handler
SystemProperties.set("gsm.defaultpdpcontext.active", "false");
}
notifyDefaultData(reason);
-
+
// TODO: For simultaneous PDP support, we need to build another
// trigger another TRY_SETUP_DATA for the next APN type. (Note
// that the existing connection may service that type, in which
@@ -1421,7 +1474,7 @@ final class DataConnectionTracker extends Handler
if(DBG)
log("PDP setup failed " + cause);
// Log this failure to the Event Logs.
- if (cause == PdpConnection.PdpFailCause.BAD_APN ||
+ if (cause == PdpConnection.PdpFailCause.BAD_APN ||
cause == PdpConnection.PdpFailCause.BAD_PAP_SECRET ||
cause == PdpConnection.PdpFailCause.BARRED ||
cause == PdpConnection.PdpFailCause.RADIO_ERROR_RETRY ||
@@ -1431,12 +1484,12 @@ final class DataConnectionTracker extends Handler
int cid = -1;
GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
if (loc != null) cid = loc.getCid();
-
+
EventLog.List val = new EventLog.List(
- cause.ordinal(), cid,
- TelephonyManager.getDefault().getNetworkType());
- EventLog.writeEvent(EVENT_LOG_RADIO_PDP_SETUP_FAIL, val);
- }
+ cause.ordinal(), cid,
+ TelephonyManager.getDefault().getNetworkType());
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val);
+ }
// No try for permanent failure
if (cause.isPermanentFail()) {
notifyNoData(cause);
@@ -1450,7 +1503,10 @@ final class DataConnectionTracker extends Handler
} else {
// we still have more apns to try
setState(State.SCANNING);
- trySetupData(reason);
+ // Wait a bit before trying the next APN, so that
+ // we're not tying up the RIL command channel
+ sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason),
+ RECONNECT_DELAY_INITIAL_MILLIS);
}
} else {
startDelayedRetry(cause, reason);
@@ -1467,7 +1523,9 @@ final class DataConnectionTracker extends Handler
setState(State.IDLE);
phone.notifyDataConnection(reason);
mActiveApn = null;
- trySetupData(reason);
+ if ( retryAfterDisconnected(reason) ) {
+ trySetupData(reason);
+ }
break;
case EVENT_PDP_STATE_CHANGED:
@@ -1533,6 +1591,37 @@ final class DataConnectionTracker extends Handler
case EVENT_APN_CHANGED:
onApnChanged();
break;
+
+ case EVENT_PS_RESTRICT_ENABLED:
+ /**
+ * We don't need to explicitly to tear down the PDP context
+ * when PS restricted is enabled. The base band will deactive
+ * PDP context and notify us with PDP_CONTEXT_CHANGED.
+ * But we should stop the network polling and prevent reset PDP.
+ */
+ Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
+ stopNetStatPoll();
+ mIsPsRestricted = true;
+ break;
+
+ case EVENT_PS_RESTRICT_DISABLED:
+ /**
+ * When PS restrict is removed, we need setup PDP connection if
+ * PDP connection is down.
+ */
+ Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
+ mIsPsRestricted = false;
+ if (state == State.CONNECTED) {
+ startNetStatPoll();
+ } else {
+ if (state == State.FAILED) {
+ cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED);
+ nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ }
+ trySetupData(Phone.REASON_PS_RESTRICT_ENABLED);
+ }
+ break;
+
}
}
@@ -1575,7 +1664,7 @@ final class DataConnectionTracker extends Handler
if (cursor != null) {
if (cursor.getCount() > 0) {
allApns = createApnList(cursor);
- // TODO: Figure out where this fits in. This basically just
+ // TODO: Figure out where this fits in. This basically just
// writes the pap-secrets file. No longer tied to PdpConnection
// object. Not used on current platform (no ppp).
//PdpConnection pdp = pdpList.get(pdp_name);
@@ -1622,7 +1711,7 @@ final class DataConnectionTracker extends Handler
}
/**
- * Get next apn in waitingApns
+ * Get next apn in waitingApns
* @return the first apn found in waitingApns, null if none
*/
private ApnSetting getNextApn() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java b/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java
index 43930c1..70e9f62 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java
@@ -77,15 +77,15 @@ public class GSMConnection extends Connection {
private PowerManager.WakeLock mPartialWakeLock;
//***** Event Constants
-
static final int EVENT_DTMF_DONE = 1;
static final int EVENT_PAUSE_DONE = 2;
static final int EVENT_NEXT_POST_DIAL = 3;
-
+ static final int EVENT_WAKE_LOCK_TIMEOUT = 4;
+
//***** Constants
-
static final int PAUSE_DELAY_FIRST_MILLIS = 100;
static final int PAUSE_DELAY_MILLIS = 3 * 1000;
+ static final int WAKE_LOCK_TIMEOUT_MILLIS = 60*1000;
//***** Inner Classes
@@ -100,8 +100,10 @@ public class GSMConnection extends Connection {
case EVENT_DTMF_DONE:
case EVENT_PAUSE_DONE:
processNextPostDialChar();
- break;
-
+ break;
+ case EVENT_WAKE_LOCK_TIMEOUT:
+ releaseWakeLock();
+ break;
}
}
}
@@ -279,7 +281,7 @@ public class GSMConnection extends Connection {
return;
}
- postDialState = PostDialState.STARTED;
+ setPostDialState(PostDialState.STARTED);
processNextPostDialChar();
}
@@ -291,7 +293,7 @@ public class GSMConnection extends Connection {
return;
}
- postDialState = PostDialState.STARTED;
+ setPostDialState(PostDialState.STARTED);
if (false) {
boolean playedTone = false;
@@ -333,7 +335,7 @@ public class GSMConnection extends Connection {
public void cancelPostDial()
{
- postDialState = PostDialState.CANCELLED;
+ setPostDialState(PostDialState.CANCELLED);
}
/**
@@ -388,6 +390,16 @@ public class GSMConnection extends Connection {
return DisconnectCause.OUT_OF_SERVICE;
} else if (phone.getSimCard().getState() != GsmSimCard.State.READY) {
return DisconnectCause.SIM_ERROR;
+ } else if (causeCode == CallFailCause.ERROR_UNSPECIFIED) {
+ if (phone.mSST.rs.isCsRestricted()) {
+ return DisconnectCause.CS_RESTRICTED;
+ } else if (phone.mSST.rs.isCsEmergencyRestricted()) {
+ return DisconnectCause.CS_RESTRICTED_EMERGENCY;
+ } else if (phone.mSST.rs.isCsNormalRestricted()) {
+ return DisconnectCause.CS_RESTRICTED_NORMAL;
+ } else {
+ return DisconnectCause.NORMAL;
+ }
} else {
return DisconnectCause.NORMAL;
}
@@ -562,9 +574,9 @@ public class GSMConnection extends Connection {
PAUSE_DELAY_MILLIS);
}
} else if (c == PhoneNumberUtils.WAIT) {
- postDialState = PostDialState.WAIT;
+ setPostDialState(PostDialState.WAIT);
} else if (c == PhoneNumberUtils.WILD) {
- postDialState = PostDialState.WILD;
+ setPostDialState(PostDialState.WILD);
} else {
return false;
}
@@ -614,14 +626,14 @@ public class GSMConnection extends Connection {
if (postDialString == null ||
postDialString.length() <= nextPostDialChar) {
- postDialState = PostDialState.COMPLETE;
+ setPostDialState(PostDialState.COMPLETE);
// notifyMessage.arg1 is 0 on complete
c = 0;
} else {
boolean isValid;
- postDialState = PostDialState.STARTED;
+ setPostDialState(PostDialState.STARTED);
c = postDialString.charAt(nextPostDialChar++);
@@ -699,6 +711,26 @@ public class GSMConnection extends Connection {
}
}
+ /**
+ * Set post dial state and acquire wake lock while switching to "started"
+ * state, the wake lock will be released if state switches out of "started"
+ * state or after WAKE_LOCK_TIMEOUT_MILLIS.
+ * @param s new PostDialState
+ */
+ private void setPostDialState(PostDialState s) {
+ if (postDialState != PostDialState.STARTED
+ && s == PostDialState.STARTED) {
+ acquireWakeLock();
+ Message msg = h.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT);
+ h.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS);
+ } else if (postDialState == PostDialState.STARTED
+ && s != PostDialState.STARTED) {
+ h.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
+ releaseWakeLock();
+ }
+ postDialState = s;
+ }
+
private void
createWakeLock(Context context) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index f314944..f93c724 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -91,6 +91,8 @@ public class GSMPhone extends PhoneBase {
public static final String VM_NUMBER = "vm_number_key";
// Key used to read/write the SIM IMSI used for storing the voice mail
public static final String VM_SIM_IMSI = "vm_sim_imsi_key";
+ // Key used to read/write "disable DNS server check" pref (used for testing)
+ public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key";
//***** Instance Variables
@@ -108,6 +110,8 @@ public class GSMPhone extends PhoneBase {
SimPhoneBookInterfaceManager mSimPhoneBookIntManager;
SimSmsInterfaceManager mSimSmsIntManager;
PhoneSubInfo mSubInfo;
+ boolean mDnsCheckDisabled = false;
+
Registrant mPostDialHandler;
@@ -195,6 +199,9 @@ public class GSMPhone extends PhoneBase {
mCM.setOnCallRing(h, EVENT_CALL_RING, null);
mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null);
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+ mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);
+
if (false) {
try {
//debugSocket = new LocalServerSocket("com.android.internal.telephony.debug");
@@ -1151,6 +1158,26 @@ public class GSMPhone extends PhoneBase {
return mDataConnection.getAllPdps();
}
+ /**
+ * Disables the DNS check (i.e., allows "0.0.0.0").
+ * Useful for lab testing environment.
+ * @param b true disables the check, false enables.
+ */
+ public void disableDnsCheck(boolean b) {
+ mDnsCheckDisabled = b;
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
+ SharedPreferences.Editor editor = sp.edit();
+ editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b);
+ editor.commit();
+ }
+
+ /**
+ * Returns true if the DNS check is currently disabled.
+ */
+ public boolean isDnsCheckDisabled() {
+ return mDnsCheckDisabled;
+ }
+
public void updateServiceLocation(Message response) {
mSST.getLacAndCid(response);
}
@@ -1356,18 +1383,8 @@ public class GSMPhone extends PhoneBase {
break;
case EVENT_SIM_RECORDS_LOADED:
- mSIMRecords.getSIMOperatorNumeric();
-
- try {
- //set the current field the telephony provider according to
- //the SIM's operator
- Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
- ContentValues map = new ContentValues();
- map.put(Telephony.Carriers.NUMERIC, mSIMRecords.getSIMOperatorNumeric());
- mContext.getContentResolver().insert(uri, map);
- } catch (SQLException e) {
- Log.e(LOG_TAG, "Can't store current operator", e);
- }
+ updateCurrentCarrierInProvider();
+
// Check if this is a different SIM than the previous one. If so unset the
// voice mail number.
String imsi = getVmSimImsi();
@@ -1508,7 +1525,27 @@ public class GSMPhone extends PhoneBase {
}
}
}
-
+
+ /**
+ * Sets the "current" field in the telephony provider according to the SIM's operator
+ *
+ * @return true for success; false otherwise.
+ */
+ boolean updateCurrentCarrierInProvider() {
+ if (mSIMRecords != null) {
+ try {
+ Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
+ ContentValues map = new ContentValues();
+ map.put(Telephony.Carriers.NUMERIC, mSIMRecords.getSIMOperatorNumeric());
+ mContext.getContentResolver().insert(uri, map);
+ return true;
+ } catch (SQLException e) {
+ Log.e(LOG_TAG, "Can't store current operator", e);
+ }
+ }
+ return false;
+ }
+
/**
* Used to track the settings upon completion of the network change.
*/
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java
index 59a9422..df34897 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java
@@ -532,7 +532,7 @@ public class GsmAlphabet
* needed to represent this string. Counts unencodable char as 1 septet.
*/
public static int
- countGsmSeptets(String s)
+ countGsmSeptets(CharSequence s)
{
try {
return countGsmSeptets(s, false);
@@ -549,7 +549,7 @@ public class GsmAlphabet
* char. Otherwise, counts invalid char as 1 septet
*/
public static int
- countGsmSeptets(String s, boolean throwsException) throws EncodeException
+ countGsmSeptets(CharSequence s, boolean throwsException) throws EncodeException
{
int charIndex = 0;
int sz = s.length();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java b/telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java
index 0859806..a4cded9 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java
@@ -258,7 +258,7 @@ public final class GsmSimCard extends Handler implements SimCard {
}
public String getServiceProviderName () {
- return phone.mSIMRecords.getServiceProvideName();
+ return phone.mSIMRecords.getServiceProviderName();
}
//***** Handler implementation
diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java
index 8f6b22e..bb17cc4 100644
--- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java
+++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java
@@ -171,16 +171,16 @@ public final class MccTable
table.add(new MccEntry(202,"gr",2)); //Greece
table.add(new MccEntry(204,"nl",2,"Europe/Amsterdam")); //Netherlands (Kingdom of the)
table.add(new MccEntry(206,"be",2)); //Belgium
- table.add(new MccEntry(208,"fr",2)); //France
+ table.add(new MccEntry(208,"fr",2,"Europe/Paris","fr")); //France
table.add(new MccEntry(212,"mc",2)); //Monaco (Principality of)
table.add(new MccEntry(213,"ad",2)); //Andorra (Principality of)
- table.add(new MccEntry(214,"es",2)); //Spain
+ table.add(new MccEntry(214,"es",2,"Europe/Madrid","es")); //Spain
table.add(new MccEntry(216,"hu",2)); //Hungary (Republic of)
table.add(new MccEntry(218,"ba",2)); //Bosnia and Herzegovina
table.add(new MccEntry(219,"hr",2)); //Croatia (Republic of)
table.add(new MccEntry(220,"rs",2)); //Serbia and Montenegro
- table.add(new MccEntry(222,"it",2)); //Italy
- table.add(new MccEntry(225,"va",2)); //Vatican City State
+ table.add(new MccEntry(222,"it",2,"Europe/Rome","it")); //Italy
+ table.add(new MccEntry(225,"va",2,"Europe/Rome","it")); //Vatican City State
table.add(new MccEntry(226,"ro",2)); //Romania
table.add(new MccEntry(228,"ch",2)); //Switzerland (Confederation of)
table.add(new MccEntry(230,"cz",2,"Europe/Prague")); //Czech Republic
@@ -217,7 +217,7 @@ public final class MccTable
table.add(new MccEntry(290,"gl",2)); //Greenland (Denmark)
table.add(new MccEntry(292,"sm",2)); //San Marino (Republic of)
table.add(new MccEntry(293,"sl",2)); //Slovenia (Republic of)
- table.add(new MccEntry(294,"mk",2)); //The Former Yugoslav Republic of Macedonia
+ table.add(new MccEntry(294,"mk",2)); //The Former Yugoslav Republic of Macedonia
table.add(new MccEntry(295,"li",2)); //Liechtenstein (Principality of)
table.add(new MccEntry(302,"ca",2)); //Canada
table.add(new MccEntry(308,"pm",2)); //Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise)
@@ -283,8 +283,8 @@ public final class MccTable
table.add(new MccEntry(436,"tj",2)); //Tajikistan (Republic of)
table.add(new MccEntry(437,"kg",2)); //Kyrgyz Republic
table.add(new MccEntry(438,"tm",2)); //Turkmenistan
- table.add(new MccEntry(440,"jp",2)); //Japan
- table.add(new MccEntry(441,"jp",2)); //Japan
+ table.add(new MccEntry(440,"jp",2,"Asia/Tokyo","ja")); //Japan
+ table.add(new MccEntry(441,"jp",2,"Asia/Tokyo","ja")); //Japan
table.add(new MccEntry(450,"kr",2)); //Korea (Republic of)
table.add(new MccEntry(452,"vn",2)); //Viet Nam (Socialist Republic of)
table.add(new MccEntry(454,"hk",2)); //"Hong Kong, China"
diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
index 6428f70..66f8b72 100644
--- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
@@ -114,9 +114,6 @@ public class PdpConnection extends Handler {
private static final int EVENT_DEACTIVATE_DONE = 4;
private static final int EVENT_FORCE_RETRY = 5;
- //***** Tag IDs for EventLog
- private static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
-
//***** Instance Variables
private GSMPhone phone;
private String pdp_name;
@@ -301,7 +298,7 @@ public class PdpConnection extends Handler {
private void notifyDisconnect(Message msg) {
if (DBG) log("Notify PDP disconnect");
-
+
if (msg != null) {
AsyncResult.forMessage(msg);
msg.sendToTarget();
@@ -378,7 +375,7 @@ public class PdpConnection extends Handler {
if (ar.exception != null) {
Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception);
-
+
if (receivedDisconnectReq) {
// Don't bother reporting the error if there's already a
// pending disconnect request, since DataConnectionTracker
@@ -406,7 +403,7 @@ public class PdpConnection extends Handler {
} else {
String[] response = ((String[]) ar.result);
cid = Integer.parseInt(response[0]);
-
+
if (response.length > 2) {
interfaceName = response[1];
ipAddress = response[2];
@@ -420,7 +417,8 @@ public class PdpConnection extends Handler {
+ " DNS2=" + dnsServers[1]);
}
- if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])) {
+ if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
+ && !phone.isDnsCheckDisabled()) {
// Work around a race condition where QMI does not fill in DNS:
// Deactivate PDP and let DataConnectionTracker retry.
// Do not apply the race condition workaround for MMS APN
@@ -428,20 +426,21 @@ public class PdpConnection extends Handler {
// Otherwise, the default APN will not be restored anymore.
if (!apn.types[0].equals(Phone.APN_TYPE_MMS)
|| !isIpAddress(apn.mmsProxy)) {
- EventLog.writeEvent(EVENT_LOG_BAD_DNS_ADDRESS, dnsServers[0]);
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
+ dnsServers[0]);
phone.mCM.deactivateDefaultPDP(cid,
obtainMessage(EVENT_FORCE_RETRY));
break;
}
}
}
-
+
if (dataLink != null) {
dataLink.connect();
} else {
onLinkStateChanged(DataLink.LinkState.LINK_UP);
}
-
+
if (DBG) log("PDP setup on cid = " + cid);
}
}
@@ -463,7 +462,7 @@ public class PdpConnection extends Handler {
} else {
ar = (AsyncResult) msg.obj;
PdpFailCause cause = PdpFailCause.UNKNOWN;
-
+
if (ar.exception == null) {
int rilFailCause = ((int[]) (ar.result))[0];
cause = getFailCauseFromRequest(rilFailCause);
diff --git a/telephony/java/com/android/internal/telephony/gsm/RIL.java b/telephony/java/com/android/internal/telephony/gsm/RIL.java
index 8ec286a..8b10ed2 100644
--- a/telephony/java/com/android/internal/telephony/gsm/RIL.java
+++ b/telephony/java/com/android/internal/telephony/gsm/RIL.java
@@ -1980,6 +1980,7 @@ public final class RIL extends BaseCommands implements CommandsInterface
case RIL_UNSOL_SIM_SMS_STORAGE_FULL: ret = responseVoid(p); break;
case RIL_UNSOL_SIM_REFRESH: ret = responseInts(p); break;
case RIL_UNSOL_CALL_RING: ret = responseVoid(p); break;
+ case RIL_UNSOL_RESTRICTED_STATE_CHANGED: ret = responseInts(p); break;
default:
throw new RuntimeException("Unrecognized unsol response: " + response);
//break; (implied)
@@ -2170,6 +2171,13 @@ public final class RIL extends BaseCommands implements CommandsInterface
mRingRegistrant.notifyRegistrant();
}
break;
+
+ case RIL_UNSOL_RESTRICTED_STATE_CHANGED:
+ if (RILJ_LOGD) unsljLogvRet(response, ret);
+ if (mRestrictedStateRegistrant != null) {
+ mRestrictedStateRegistrant.notifyRegistrant(
+ new AsyncResult (null, ret, null));
+ }
}
}
@@ -2553,6 +2561,7 @@ public final class RIL extends BaseCommands implements CommandsInterface
case RIL_UNSOL_SIM_SMS_STORAGE_FULL: return "UNSOL_SIM_SMS_STORAGE_FULL";
case RIL_UNSOL_SIM_REFRESH: return "UNSOL_SIM_REFRESH";
case RIL_UNSOL_CALL_RING: return "UNSOL_CALL_RING";
+ case RIL_UNSOL_RESTRICTED_STATE_CHANGED: return "RIL_UNSOL_RESTRICTED_STATE_CHANGED";
default: return "<unknown reponse>";
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/RILConstants.java b/telephony/java/com/android/internal/telephony/gsm/RILConstants.java
index 0a8e192..4463b20 100644
--- a/telephony/java/com/android/internal/telephony/gsm/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/gsm/RILConstants.java
@@ -51,6 +51,32 @@ cat include/telephony/ril.h | \
int RIL_SIM_PIN = 3;
int RIL_SIM_PUK = 4;
int RIL_SIM_NETWORK_PERSONALIZATION = 5;
+
+ /**
+ * No restriction at all including voice/SMS/USSD/SS/AV64
+ * and packet data.
+ */
+ int RIL_RESTRICTED_STATE_NONE = 0x00;
+ /**
+ * Block emergency call due to restriction.
+ * But allow all normal voice/SMS/USSD/SS/AV64.
+ */
+ int RIL_RESTRICTED_STATE_CS_EMERGENCY = 0x01;
+ /**
+ * Block all normal voice/SMS/USSD/SS/AV64 due to restriction.
+ * Only Emergency call allowed.
+ */
+ int RIL_RESTRICTED_STATE_CS_NORMAL = 0x02;
+ /**
+ * Block all voice/SMS/USSD/SS/AV64
+ * including emergency call due to restriction.
+ */
+ int RIL_RESTRICTED_STATE_CS_ALL = 0x04;
+ /**
+ * Block packet data access due to restriction.
+ */
+ int RIL_RESTRICTED_STATE_PS_ALL = 0x10;
+
int RIL_REQUEST_GET_SIM_STATUS = 1;
int RIL_REQUEST_ENTER_SIM_PIN = 2;
int RIL_REQUEST_ENTER_SIM_PUK = 3;
@@ -147,4 +173,5 @@ cat include/telephony/ril.h | \
int RIL_UNSOL_SIM_SMS_STORAGE_FULL = 1016;
int RIL_UNSOL_SIM_REFRESH = 1017;
int RIL_UNSOL_CALL_RING = 1018;
+ int RIL_UNSOL_RESTRICTED_STATE_CHANGED = 1023;
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/RestrictedState.java b/telephony/java/com/android/internal/telephony/gsm/RestrictedState.java
new file mode 100644
index 0000000..d17f134
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/RestrictedState.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2006 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.internal.telephony.gsm;
+
+import android.telephony.ServiceState;
+
+public class RestrictedState {
+
+ /**
+ * Set true to block packet data access due to restriction
+ */
+ private boolean mPsRestricted;
+ /**
+ * Set true to block all normal voice/SMS/USSD/SS/AV64 due to restriction
+ */
+ private boolean mCsNormalRestricted;
+ /**
+ * Set true to block emergency call due to restriction
+ */
+ private boolean mCsEmergencyRestricted;
+
+ public RestrictedState() {
+ setPsRestricted(false);
+ setCsNormalRestricted(false);
+ setCsEmergencyRestricted(false);
+ }
+
+ /**
+ * @param csEmergencyRestricted the csEmergencyRestricted to set
+ */
+ public void setCsEmergencyRestricted(boolean csEmergencyRestricted) {
+ mCsEmergencyRestricted = csEmergencyRestricted;
+ }
+
+ /**
+ * @return the csEmergencyRestricted
+ */
+ public boolean isCsEmergencyRestricted() {
+ return mCsEmergencyRestricted;
+ }
+
+ /**
+ * @param csNormalRestricted the csNormalRestricted to set
+ */
+ public void setCsNormalRestricted(boolean csNormalRestricted) {
+ mCsNormalRestricted = csNormalRestricted;
+ }
+
+ /**
+ * @return the csNormalRestricted
+ */
+ public boolean isCsNormalRestricted() {
+ return mCsNormalRestricted;
+ }
+
+ /**
+ * @param psRestricted the psRestricted to set
+ */
+ public void setPsRestricted(boolean psRestricted) {
+ mPsRestricted = psRestricted;
+ }
+
+ /**
+ * @return the psRestricted
+ */
+ public boolean isPsRestricted() {
+ return mPsRestricted;
+ }
+
+ public boolean isCsRestricted() {
+ return mCsNormalRestricted && mCsEmergencyRestricted;
+ }
+
+ @Override
+ public boolean equals (Object o) {
+ RestrictedState s;
+
+ try {
+ s = (RestrictedState) o;
+ } catch (ClassCastException ex) {
+ return false;
+ }
+
+ if (o == null) {
+ return false;
+ }
+
+ return mPsRestricted == s.mPsRestricted
+ && mCsNormalRestricted == s.mCsNormalRestricted
+ && mCsEmergencyRestricted == s.mCsEmergencyRestricted;
+ }
+
+ @Override
+ public String toString() {
+ String csString = "none";
+
+ if (mCsEmergencyRestricted && mCsNormalRestricted) {
+ csString = "all";
+ } else if (mCsEmergencyRestricted && !mCsNormalRestricted) {
+ csString = "emergency";
+ } else if (!mCsEmergencyRestricted && mCsNormalRestricted) {
+ csString = "normal call";
+ }
+
+ return "Restricted State CS: " + csString + " PS:" + mPsRestricted;
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 75f56a3..a62f6cf 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -56,6 +56,7 @@ public final class SIMRecords extends Handler implements SimConstants
AdnRecordCache adnCache;
VoiceMailConstants mVmConfig;
+ SpnOverride mSpnOverride;
//***** Cached SIM State; cleared on channel close
@@ -167,6 +168,7 @@ public final class SIMRecords extends Handler implements SimConstants
adnCache = new AdnRecordCache(phone);
mVmConfig = new VoiceMailConstants();
+ mSpnOverride = new SpnOverride();
recordsRequested = false; // No load request is made till SIM ready
@@ -202,7 +204,6 @@ public final class SIMRecords extends Handler implements SimConstants
spnDisplayCondition = -1;
efMWIS = null;
efCPHS_MWI = null;
- spn = null;
spdiNetworks = null;
pnnHomeName = null;
@@ -284,7 +285,7 @@ public final class SIMRecords extends Handler implements SimConstants
* Return Service Provider Name stored in SIM
* @return null if SIM is not yet ready
*/
- public String getServiceProvideName()
+ String getServiceProviderName()
{
return spn;
}
@@ -1191,11 +1192,6 @@ public final class SIMRecords extends Handler implements SimConstants
SmsMessage message = SmsMessage.newFromCMT(
new String[] { "", pdu });
- Log.i("ENF", "message from " +
- message.getOriginatingAddress());
- Log.i("ENF", "message text " +
- message.getMessageBody());
-
phone.mSMS.dispatchMessage(message);
}
}
@@ -1226,11 +1222,6 @@ public final class SIMRecords extends Handler implements SimConstants
SmsMessage message = SmsMessage.newFromCMT(
new String[] { "", pdu });
- Log.i("ENF", "message from " +
- message.getOriginatingAddress());
- Log.i("ENF", "message text " +
- message.getMessageBody());
-
phone.mSMS.dispatchMessage(message);
// 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3
@@ -1267,10 +1258,11 @@ public final class SIMRecords extends Handler implements SimConstants
{
Log.d(LOG_TAG, "SIMRecords: record load complete");
+ String operator = getSIMOperatorNumeric();
+
// Some fields require more than one SIM record to set
- phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC,
- getSIMOperatorNumeric());
+ phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, operator);
if (imsi != null) {
phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY,
@@ -1281,7 +1273,8 @@ public final class SIMRecords extends Handler implements SimConstants
Log.e("SIM", "[SIMRecords] onAllRecordsLoaded: imsi is NULL!");
}
- setVoiceMailByCountry(getSIMOperatorNumeric());
+ setVoiceMailByCountry(operator);
+ setSpnFromConfig(operator);
recordsLoadedRegistrants.notifyRegistrants(
new AsyncResult(null, null, null));
@@ -1289,6 +1282,12 @@ public final class SIMRecords extends Handler implements SimConstants
SimCard.INTENT_VALUE_SIM_LOADED, null);
}
+ private void setSpnFromConfig(String carrier) {
+ if (mSpnOverride.containsCarrier(carrier)) {
+ spn = mSpnOverride.getSpn(carrier);
+ }
+ }
+
private void setVoiceMailByCountry (String spn) {
if (mVmConfig.containsCarrier(spn)) {
isVoiceMailFixed = true;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
index daf4b9c..5585524 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
@@ -32,11 +32,13 @@ import android.net.Uri;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
+import android.os.PowerManager;
import android.provider.Telephony;
import android.provider.Settings;
import android.provider.Telephony.Sms.Intents;
import android.telephony.gsm.SmsMessage;
import android.telephony.gsm.SmsManager;
+import com.android.internal.telephony.WapPushOverSms;
import android.telephony.ServiceState;
import android.util.Config;
import com.android.internal.util.HexDump;
@@ -62,37 +64,6 @@ final class SMSDispatcher extends Handler {
/** Default timeout for SMS sent query */
private static final int DEFAULT_SMS_TIMOUEOUT = 6000;
- private static final int WAP_PDU_TYPE_PUSH = 0x06;
-
- private static final int WAP_PDU_TYPE_CONFIRMED_PUSH = 0x07;
-
- private static final byte DRM_RIGHTS_XML = (byte)0xca;
-
- private static final String DRM_RIGHTS_XML_MIME_TYPE = "application/vnd.oma.drm.rights+xml";
-
- private static final byte DRM_RIGHTS_WBXML = (byte)0xcb;
-
- private static final String DRM_RIGHTS_WBXML_MIME_TYPE =
- "application/vnd.oma.drm.rights+wbxml";
-
- private static final byte WAP_SI_MIME_PORT = (byte)0xae;
-
- private static final String WAP_SI_MIME_TYPE = "application/vnd.wap.sic";
-
- private static final byte WAP_SL_MIME_PORT = (byte)0xb0;
-
- private static final String WAP_SL_MIME_TYPE = "application/vnd.wap.slc";
-
- private static final byte WAP_CO_MIME_PORT = (byte)0xb2;
-
- private static final String WAP_CO_MIME_TYPE = "application/vnd.wap.coc";
-
- private static final int WAP_PDU_SHORT_LENGTH_MAX = 30;
-
- private static final int WAP_PDU_LENGTH_QUOTE = 31;
-
- private static final String MMS_MIME_TYPE = "application/vnd.wap.mms-message";
-
private static final String[] RAW_PROJECTION = new String[] {
"pdu",
"sequence",
@@ -124,6 +95,8 @@ final class SMSDispatcher extends Handler {
private final GSMPhone mPhone;
+ private final WapPushOverSms mWapPush;
+
private final Context mContext;
private final ContentResolver mResolver;
@@ -135,7 +108,9 @@ final class SMSDispatcher extends Handler {
/** Maximum number of times to retry sending a failed SMS. */
private static final int MAX_SEND_RETRIES = 3;
/** Delay before next send attempt on a failed SMS, in milliseconds. */
- private static final int SEND_RETRY_DELAY = 2000; // ms
+ private static final int SEND_RETRY_DELAY = 2000;
+ /** single part SMS */
+ private static final int SINGLE_PART_SMS = 1;
/**
* Message reference for a CONCATENATED_8_BIT_REFERENCE or
@@ -148,6 +123,15 @@ final class SMSDispatcher extends Handler {
private SmsTracker mSTracker;
+ /** Wake lock to ensure device stays awake while dispatching the SMS intent. */
+ private PowerManager.WakeLock mWakeLock;
+
+ /**
+ * Hold the wake lock for 5 seconds, which should be enough time for
+ * any receiver(s) to grab its own wake lock.
+ */
+ private final int WAKE_LOCK_TIMEOUT = 5000;
+
/**
* Implement the per-application based SMS control, which only allows
* a limit on the number of SMS/MMS messages an app can send in checking
@@ -169,15 +153,23 @@ final class SMSDispatcher extends Handler {
mSmsStamp = new HashMap<String, ArrayList<Long>> ();
}
- boolean check(String appName) {
+ /**
+ * Check to see if an application allow to send new SMS messages
+ *
+ * @param appName is the application sending sms
+ * @param smsWaiting is the number of new sms wants to be sent
+ * @return true if application is allowed to send the requested number
+ * of new sms messages
+ */
+ boolean check(String appName, int smsWaiting) {
if (!mSmsStamp.containsKey(appName)) {
mSmsStamp.put(appName, new ArrayList<Long>());
}
- return isUnderLimit(mSmsStamp.get(appName));
+ return isUnderLimit(mSmsStamp.get(appName), smsWaiting);
}
- private boolean isUnderLimit(ArrayList<Long> sent) {
+ private boolean isUnderLimit(ArrayList<Long> sent, int smsWaiting) {
Long ct = System.currentTimeMillis();
Log.d(TAG, "SMS send size=" + sent.size() + "time=" + ct);
@@ -185,9 +177,11 @@ final class SMSDispatcher extends Handler {
while (sent.size() > 0 && (ct - sent.get(0)) > mCheckPeriod ) {
sent.remove(0);
}
-
- if (sent.size() < mMaxAllowed) {
- sent.add(ct);
+
+ if ( (sent.size() + smsWaiting) <= mMaxAllowed) {
+ for (int i = 0; i < smsWaiting; i++ ) {
+ sent.add(ct);
+ }
return true;
}
return false;
@@ -196,11 +190,14 @@ final class SMSDispatcher extends Handler {
SMSDispatcher(GSMPhone phone) {
mPhone = phone;
+ mWapPush = new WapPushOverSms(phone);
mContext = phone.getContext();
mResolver = mContext.getContentResolver();
mCm = phone.mCM;
mSTracker = null;
+ createWakelock();
+
int check_period = Settings.Gservices.getInt(mResolver,
Settings.Gservices.SMS_OUTGOING_CEHCK_INTERVAL_MS,
DEFAULT_SMS_CHECK_PERIOD);
@@ -290,14 +287,30 @@ final class SMSDispatcher extends Handler {
case EVENT_SEND_CONFIRMED_SMS:
if (mSTracker!=null) {
- Log.d(TAG, "Ready to send SMS again.");
- sendSms(mSTracker);
+ if (isMultipartTracker(mSTracker)) {
+ sendMultipartSms(mSTracker);
+ } else {
+ sendSms(mSTracker);
+ }
mSTracker = null;
}
break;
}
}
+ private void createWakelock() {
+ PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SMSDispatcher");
+ mWakeLock.setReferenceCounted(true);
+ }
+
+ private void sendBroadcast(Intent intent, String permission) {
+ // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
+ // receivers time to take their own wake locks.
+ mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
+ mContext.sendBroadcast(intent, permission);
+ }
+
/**
* Called when SIM_FULL message is received from the RIL. Notifies interested
* parties that SIM storage for SMS messages is full.
@@ -305,7 +318,7 @@ final class SMSDispatcher extends Handler {
private void handleSimFull() {
// broadcast SIM_FULL intent
Intent intent = new Intent(Intents.SIM_FULL_ACTION);
- mPhone.getContext().sendBroadcast(intent, "android.permission.RECEIVE_SMS");
+ sendBroadcast(intent, "android.permission.RECEIVE_SMS");
}
/**
@@ -434,6 +447,13 @@ final class SMSDispatcher extends Handler {
* @param sms the incoming message from the phone
*/
/* package */ void dispatchMessage(SmsMessage sms) {
+
+ // If sms is null, means there was a parsing error.
+ // TODO: Should NAK this.
+ if (sms == null) {
+ return;
+ }
+
boolean handled = false;
// Special case the message waiting indicator messages
@@ -476,35 +496,50 @@ final class SMSDispatcher extends Handler {
SmsHeader header = sms.getUserDataHeader();
if (header != null) {
for (SmsHeader.Element element : header.getElements()) {
- switch (element.getID()) {
- case SmsHeader.CONCATENATED_8_BIT_REFERENCE: {
- byte[] data = element.getData();
-
- referenceNumber = data[0] & 0xff;
- count = data[1] & 0xff;
- sequence = data[2] & 0xff;
-
- break;
- }
-
- case SmsHeader.CONCATENATED_16_BIT_REFERENCE: {
- byte[] data = element.getData();
-
- referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff);
- count = data[2] & 0xff;
- sequence = data[3] & 0xff;
-
- break;
- }
-
- case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: {
- byte[] data = element.getData();
-
- destPort = (data[0] & 0xff) << 8;
- destPort |= (data[1] & 0xff);
-
- break;
- }
+ try {
+ switch (element.getID()) {
+ case SmsHeader.CONCATENATED_8_BIT_REFERENCE: {
+ byte[] data = element.getData();
+
+ referenceNumber = data[0] & 0xff;
+ count = data[1] & 0xff;
+ sequence = data[2] & 0xff;
+
+ // Per TS 23.040, 9.2.3.24.1: If the count is zero, sequence
+ // is zero, or sequence > count, ignore the entire element
+ if (count == 0 || sequence == 0 || sequence > count) {
+ referenceNumber = -1;
+ }
+ break;
+ }
+
+ case SmsHeader.CONCATENATED_16_BIT_REFERENCE: {
+ byte[] data = element.getData();
+
+ referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff);
+ count = data[2] & 0xff;
+ sequence = data[3] & 0xff;
+
+ // Per TS 23.040, 9.2.3.24.8: If the count is zero, sequence
+ // is zero, or sequence > count, ignore the entire element
+ if (count == 0 || sequence == 0 || sequence > count) {
+ referenceNumber = -1;
+ }
+ break;
+ }
+
+ case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: {
+ byte[] data = element.getData();
+
+ destPort = (data[0] & 0xff) << 8;
+ destPort |= (data[1] & 0xff);
+
+ break;
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ Log.e(TAG, "Bad element in header", e);
+ return; // TODO: NACK the message or something, don't just discard.
}
}
}
@@ -516,7 +551,7 @@ final class SMSDispatcher extends Handler {
if (destPort != -1) {
if (destPort == SmsHeader.PORT_WAP_PUSH) {
- dispatchWapPdu(sms.getUserData());
+ mWapPush.dispatchWapPdu(sms.getUserData());
}
// The message was sent to a port, so concoct a URI for it
dispatchPortAddressedPdus(pdus, destPort);
@@ -599,7 +634,7 @@ final class SMSDispatcher extends Handler {
}
// Handle the PUSH
- dispatchWapPdu(output.toByteArray());
+ mWapPush.dispatchWapPdu(output.toByteArray());
break;
}
@@ -623,8 +658,7 @@ final class SMSDispatcher extends Handler {
private void dispatchPdus(byte[][] pdus) {
Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
intent.putExtra("pdus", pdus);
- mPhone.getContext().sendBroadcast(
- intent, "android.permission.RECEIVE_SMS");
+ sendBroadcast(intent, "android.permission.RECEIVE_SMS");
}
/**
@@ -637,130 +671,73 @@ final class SMSDispatcher extends Handler {
Uri uri = Uri.parse("sms://localhost:" + port);
Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri);
intent.putExtra("pdus", pdus);
- mPhone.getContext().sendBroadcast(
- intent, "android.permission.RECEIVE_SMS");
+ sendBroadcast(intent, "android.permission.RECEIVE_SMS");
}
+
/**
- * Dispatches inbound messages that are in the WAP PDU format. See
- * wap-230-wsp-20010705-a section 8 for details on the WAP PDU format.
+ * Send a multi-part text based SMS.
*
- * @param pdu The WAP PDU, made up of one or more SMS PDUs
+ * @param destinationAddress the address to send the message to
+ * @param scAddress is the service center address or null to use
+ * the current default SMSC
+ * @param parts an <code>ArrayList</code> of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code>
+ * <code>RESULT_ERROR_RADIO_OFF</code>
+ * <code>RESULT_ERROR_NULL_PDU</code>.
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applicaitons,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
*/
- private void dispatchWapPdu(byte[] pdu) {
- int index = 0;
- int transactionId = pdu[index++] & 0xFF;
- int pduType = pdu[index++] & 0xFF;
- int headerLength = 0;
-
- if ((pduType != WAP_PDU_TYPE_PUSH) &&
- (pduType != WAP_PDU_TYPE_CONFIRMED_PUSH)) {
- Log.w(TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
- return;
- }
-
- /**
- * Parse HeaderLen(unsigned integer).
- * From wap-230-wsp-20010705-a section 8.1.2
- * The maximum size of a uintvar is 32 bits.
- * So it will be encoded in no more than 5 octets.
- */
- int temp = 0;
- do {
- temp = pdu[index++];
- headerLength = headerLength << 7;
- headerLength |= temp & 0x7F;
- } while ((temp & 0x80) != 0);
-
- int headerStartIndex = index;
-
- /**
- * Parse Content-Type.
- * From wap-230-wsp-20010705-a section 8.4.2.24
- *
- * Content-type-value = Constrained-media | Content-general-form
- * Content-general-form = Value-length Media-type
- * Media-type = (Well-known-media | Extension-Media) *(Parameter)
- * Value-length = Short-length | (Length-quote Length)
- * Short-length = <Any octet 0-30> (octet <= WAP_PDU_SHORT_LENGTH_MAX)
- * Length-quote = <Octet 31> (WAP_PDU_LENGTH_QUOTE)
- * Length = Uintvar-integer
- */
- // Parse Value-length.
- if ((pdu[index] & 0xff) <= WAP_PDU_SHORT_LENGTH_MAX) {
- // Short-length.
- index++;
- } else if (pdu[index] == WAP_PDU_LENGTH_QUOTE) {
- // Skip Length-quote.
- index++;
- // Skip Length.
- // Now we assume 8bit is enough to store the content-type length.
- index++;
- }
- String mimeType;
- switch (pdu[headerStartIndex])
- {
- case DRM_RIGHTS_XML:
- mimeType = DRM_RIGHTS_XML_MIME_TYPE;
- break;
- case DRM_RIGHTS_WBXML:
- mimeType = DRM_RIGHTS_WBXML_MIME_TYPE;
- break;
- case WAP_SI_MIME_PORT:
- // application/vnd.wap.sic
- mimeType = WAP_SI_MIME_TYPE;
- break;
- case WAP_SL_MIME_PORT:
- mimeType = WAP_SL_MIME_TYPE;
- break;
- case WAP_CO_MIME_PORT:
- mimeType = WAP_CO_MIME_TYPE;
- break;
- default:
- int start = index;
+ void sendMultipartText(String destinationAddress, String scAddress, ArrayList<String> parts,
+ ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
- // Skip text-string.
- // Now we assume the mimetype is Extension-Media.
- while (pdu[index++] != '\0') {
- ;
+ PendingIntent sentIntent = null;
+
+
+ int ss = mPhone.getServiceState().getState();
+
+ if (ss == ServiceState.STATE_IN_SERVICE) {
+ // Only check SMS sending limit while in service
+ if (sentIntents != null && sentIntents.size() > 0) {
+ sentIntent = sentIntents.get(0);
+ }
+ String appName = getAppNameByIntent(sentIntent);
+ if ( !mCounter.check(appName, parts.size())) {
+ HashMap<String, Object> map = new HashMap<String, Object>();
+ map.put("destination", destinationAddress);
+ map.put("scaddress", scAddress);
+ map.put("parts", parts);
+ map.put("sentIntents", sentIntents);
+ map.put("deliveryIntents", deliveryIntents);
+
+ SmsTracker multipartParameter = new SmsTracker(map, null, null);
+
+ sendMessage(obtainMessage(EVENT_POST_ALERT, multipartParameter));
+ return;
}
- mimeType = new String(pdu, start, index-start-1);
- break;
- }
-
- // XXX Skip the remainder of the header for now
- int dataIndex = headerStartIndex + headerLength;
- byte[] data;
- if (pdu[headerStartIndex] == WAP_CO_MIME_PORT)
- {
- // because SMSDispatcher can't parse push headers "Content-Location" and
- // X-Wap-Content-URI, so pass the whole push to CO application.
- data = pdu;
- } else
- {
- data = new byte[pdu.length - dataIndex];
- System.arraycopy(pdu, dataIndex, data, 0, data.length);
- }
-
- // Notify listeners about the WAP PUSH
- Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION);
- intent.setType(mimeType);
- intent.putExtra("transactionId", transactionId);
- intent.putExtra("pduType", pduType);
- intent.putExtra("data", data);
-
- if (mimeType.equals(MMS_MIME_TYPE)) {
- mPhone.getContext().sendBroadcast(
- intent, "android.permission.RECEIVE_MMS");
- } else {
- mPhone.getContext().sendBroadcast(
- intent, "android.permission.RECEIVE_WAP_PUSH");
}
+
+ sendMultipartTextWithPermit(destinationAddress,
+ scAddress, parts, sentIntents, deliveryIntents);
}
/**
- * Send a multi-part text based SMS.
+ * Send a multi-part text based SMS which already passed SMS control check.
*
+ * It is the working function for sendMultipartText().
+ *
* @param destinationAddress the address to send the message to
* @param scAddress is the service center address or null to use
* the current default SMSC
@@ -774,17 +751,32 @@ final class SMSDispatcher extends Handler {
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
* <code>RESULT_ERROR_RADIO_OFF</code>
* <code>RESULT_ERROR_NULL_PDU</code>.
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applicaitons,
- * which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntents if not null, an <code>ArrayList</code> of
* <code>PendingIntent</code>s (one for each message part) that is
* broadcast when the corresponding message part has been delivered
* to the recipient. The raw pdu of the status report is in the
* extended data ("pdu").
*/
- void sendMultipartText(String destinationAddress, String scAddress, ArrayList<String> parts,
- ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
+ private void sendMultipartTextWithPermit(String destinationAddress,
+ String scAddress, ArrayList<String> parts,
+ ArrayList<PendingIntent> sentIntents,
+ ArrayList<PendingIntent> deliveryIntents) {
+
+ PendingIntent sentIntent = null;
+ PendingIntent deliveryIntent = null;
+
+ // check if in service
+ int ss = mPhone.getServiceState().getState();
+ if (ss != ServiceState.STATE_IN_SERVICE) {
+ for (int i = 0, count = parts.size(); i < count; i++) {
+ if (sentIntents != null && sentIntents.size() > i) {
+ sentIntent = sentIntents.get(i);
+ }
+ SmsTracker tracker = new SmsTracker(null, sentIntent, null);
+ handleNotInService(ss, tracker);
+ }
+ return;
+ }
int ref = ++sConcatenatedRef & 0xff;
@@ -796,9 +788,7 @@ final class SMSDispatcher extends Handler {
data[2] = (byte) (i + 1); // 1-based sequence
SmsHeader header = new SmsHeader();
header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data));
- PendingIntent sentIntent = null;
- PendingIntent deliveryIntent = null;
-
+
if (sentIntents != null && sentIntents.size() > i) {
sentIntent = sentIntents.get(i);
}
@@ -809,8 +799,14 @@ final class SMSDispatcher extends Handler {
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
parts.get(i), deliveryIntent != null, header.toByteArray());
- sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
- }
+ HashMap<String, Object> map = new HashMap<String, Object>();
+ map.put("smsc", pdus.encodedScAddress);
+ map.put("pdu", pdus.encodedMessage);
+
+ SmsTracker tracker = new SmsTracker(map, sentIntent,
+ deliveryIntent);
+ sendSms(tracker);
+ }
}
/**
@@ -856,7 +852,7 @@ final class SMSDispatcher extends Handler {
handleNotInService(ss, tracker);
} else {
String appName = getAppNameByIntent(sentIntent);
- if (mCounter.check(appName)) {
+ if (mCounter.check(appName, SINGLE_PART_SMS)) {
sendSms(tracker);
} else {
sendMessage(obtainMessage(EVENT_POST_ALERT, tracker));
@@ -913,6 +909,41 @@ final class SMSDispatcher extends Handler {
}
/**
+ * Send the multi-part SMS based on multipart Sms tracker
+ *
+ * @param tracker holds the multipart Sms tracker ready to be sent
+ */
+ private void sendMultipartSms (SmsTracker tracker) {
+ ArrayList<String> parts;
+ ArrayList<PendingIntent> sentIntents;
+ ArrayList<PendingIntent> deliveryIntents;
+
+ HashMap map = tracker.mData;
+
+ String destinationAddress = (String) map.get("destination");
+ String scAddress = (String) map.get("scaddress");
+
+ parts = (ArrayList<String>) map.get("parts");
+ sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
+ deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
+
+ sendMultipartTextWithPermit(destinationAddress,
+ scAddress, parts, sentIntents, deliveryIntents);
+
+ }
+
+ /**
+ * Check if a SmsTracker holds multi-part Sms
+ *
+ * @param tracker a SmsTracker could hold a multi-part Sms
+ * @return true for tracker holds Multi-parts Sms
+ */
+ private boolean isMultipartTracker (SmsTracker tracker) {
+ HashMap map = tracker.mData;
+ return ( map.get("parts") != null);
+ }
+
+ /**
* Keeps track of an SMS that has been sent to the RIL, until it it has
* successfully been sent, or we're done trying.
*
@@ -939,7 +970,7 @@ final class SMSDispatcher extends Handler {
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON1) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
Log.d(TAG, "click YES to send out sms");
sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS));
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
index d3a19c5..89ce506 100644
--- a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
@@ -23,9 +23,15 @@ import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERAT
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC;
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.TelephonyIntents;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.gsm.DataConnectionTracker.State;
+
import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -33,6 +39,7 @@ import android.database.ContentObserver;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
+import android.os.PowerManager;
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.SystemClock;
@@ -70,6 +77,9 @@ final class ServiceStateTracker extends Handler
static final int DATA_ACCESS_GPRS = 1;
static final int DATA_ACCESS_EDGE = 2;
static final int DATA_ACCESS_UMTS = 3;
+
+ static final int MAX_NUM_DATA_STATE_READS = 15;
+ static final int DATA_STATE_POLL_SLEEP_MS = 100;
//***** Instance Variables
@@ -81,6 +91,7 @@ final class ServiceStateTracker extends Handler
GsmCellLocation cellLoc;
GsmCellLocation newCellLoc;
int mPreferredNetworkType;
+ RestrictedState rs;
int rssi = 99; // signal strength 0-31, 99=unknown
// That's "received signal strength indication" fyi
@@ -113,6 +124,9 @@ final class ServiceStateTracker extends Handler
private RegistrantList gprsDetachedRegistrants = new RegistrantList();
private RegistrantList roamingOnRegistrants = new RegistrantList();
private RegistrantList roamingOffRegistrants = new RegistrantList();
+ private RegistrantList psRestrictEnabledRegistrants = new RegistrantList();
+ private RegistrantList psRestrictDisabledRegistrants = new RegistrantList();
+
// Sometimes we get the NITZ time before we know what country we are in.
// Keep the time zone information from the NITZ string so we can fix
@@ -122,7 +136,7 @@ final class ServiceStateTracker extends Handler
private boolean mZoneDst;
private long mZoneTime;
private boolean mGotCountryCode = false;
-
+
String mSavedTimeZone;
long mSavedTime;
long mSavedAtTime;
@@ -135,7 +149,15 @@ final class ServiceStateTracker extends Handler
private boolean mStartedGprsRegCheck = false;
// Already sent the event-log for no gprs register
private boolean mReportedGprsNoReg = false;
+
+ /**
+ * The Notification object given to the NotificationManager.
+ */
+ private Notification mNotification;
+ // Wake lock used while setting time of day.
+ private PowerManager.WakeLock mWakeLock;
+ private static final String WAKELOCK_TAG = "ServiceStateTracker";
// Keep track of SPN display rules, so we only broadcast intent if something changes.
private String curSpn = null;
@@ -153,8 +175,18 @@ final class ServiceStateTracker extends Handler
// waiting period before recheck gprs and voice registration
static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000;
- //***** Events
+ // notification 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
+
+ //***** Events
static final int EVENT_RADIO_STATE_CHANGED = 1;
static final int EVENT_NETWORK_STATE_CHANGED = 2;
static final int EVENT_GET_SIGNAL_STRENGTH = 3;
@@ -174,10 +206,7 @@ final class ServiceStateTracker extends Handler
static final int EVENT_SET_PREFERRED_NETWORK_TYPE = 20;
static final int EVENT_RESET_PREFERRED_NETWORK_TYPE = 21;
static final int EVENT_CHECK_REPORT_GPRS = 22;
-
- // Event Log Tags
- private static final int EVENT_LOG_CGREG_FAIL = 50107;
- private static final int EVENT_DATA_STATE_RADIO_OFF = 50108;
+ static final int EVENT_RESTRICTED_STATE_CHANGED = 23;
//***** Time Zones
@@ -209,7 +238,7 @@ final class ServiceStateTracker extends Handler
"tg", // Togo
"uk", // U.K
};
-
+
private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
@@ -217,8 +246,7 @@ final class ServiceStateTracker extends Handler
revertToNitz();
}
};
-
-
+
//***** Constructors
ServiceStateTracker(GSMPhone phone)
@@ -229,6 +257,11 @@ final class ServiceStateTracker extends Handler
newSS = new ServiceState();
cellLoc = new GsmCellLocation();
newCellLoc = new GsmCellLocation();
+ rs = new RestrictedState();
+
+ PowerManager powerManager =
+ (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
@@ -236,18 +269,18 @@ final class ServiceStateTracker extends Handler
cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
cm.setOnNITZTime(this, EVENT_NITZ_TIME, null);
cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
-
+ cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
cm.registerForSIMReady(this, EVENT_SIM_READY, null);
-
+
// system setting property AIRPLANE_MODE_ON is set in Settings.
int airplaneMode = Settings.System.getInt(
phone.getContext().getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 0);
- mDesiredPowerState = ! (airplaneMode > 0);
+ mDesiredPowerState = ! (airplaneMode > 0);
ContentResolver cr = phone.getContext().getContentResolver();
cr.registerContentObserver(
- Settings.System.getUriFor(Settings.System.AUTO_TIME), true,
+ Settings.System.getUriFor(Settings.System.AUTO_TIME), true,
mAutoTimeObserver);
setRssiDefaultValues();
mNeedToRegForSimLoaded = true;
@@ -259,8 +292,7 @@ final class ServiceStateTracker extends Handler
* @param what what code of message when delivered
* @param obj placed in Message.obj
*/
- /*protected*/ void
- registerForGprsAttached(Handler h, int what, Object obj) {
+ /*protected*/ void registerForGprsAttached(Handler h, int what, Object obj) {
Registrant r = new Registrant(h, what, obj);
gprsAttachedRegistrants.add(r);
@@ -272,7 +304,7 @@ final class ServiceStateTracker extends Handler
void registerForNetworkAttach(Handler h, int what, Object obj) {
Registrant r = new Registrant(h, what, obj);
networkAttachedRegistrants.add(r);
-
+
if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
r.notifyRegistrant();
}
@@ -283,8 +315,7 @@ final class ServiceStateTracker extends Handler
* @param what what code of message when delivered
* @param obj placed in Message.obj
*/
- /*protected*/ void
- registerForGprsDetached(Handler h, int what, Object obj) {
+ /*protected*/ void registerForGprsDetached(Handler h, int what, Object obj) {
Registrant r = new Registrant(h, what, obj);
gprsDetachedRegistrants.add(r);
@@ -341,6 +372,38 @@ final class ServiceStateTracker extends Handler
obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete));
}
+ /**
+ * Registration point for transition into packet service restricted zone.
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ void registerForPsRestrictedEnabled(Handler h, int what, Object obj) {
+ Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedEnabled ");
+ Registrant r = new Registrant(h, what, obj);
+ psRestrictEnabledRegistrants.add(r);
+
+ if (rs.isPsRestricted()) {
+ r.notifyRegistrant();
+ }
+ }
+
+ /**
+ * Registration point for transition out of packet service restricted zone.
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ void registerForPsRestrictedDisabled(Handler h, int what, Object obj) {
+ Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedDisabled ");
+ Registrant r = new Registrant(h, what, obj);
+ psRestrictDisabledRegistrants.add(r);
+
+ if (rs.isPsRestricted()) {
+ r.notifyRegistrant();
+ }
+ }
+
//***** Called from GSMPhone
public void
@@ -360,7 +423,7 @@ final class ServiceStateTracker extends Handler
/*package*/ void enableLocationUpdates() {
cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED));
}
-
+
/*package*/ void disableLocationUpdates() {
cm.setLocationUpdates(false, null);
}
@@ -407,7 +470,7 @@ final class ServiceStateTracker extends Handler
pollState();
break;
- case EVENT_GET_SIGNAL_STRENGTH:
+ case EVENT_GET_SIGNAL_STRENGTH:
// This callback is called when signal strength is polled
// all by itself
@@ -418,7 +481,7 @@ final class ServiceStateTracker extends Handler
ar = (AsyncResult) msg.obj;
onSignalStrengthResult(ar);
queueNextSignalStrengthPoll();
-
+
break;
case EVENT_GET_LOC_DONE:
@@ -503,7 +566,7 @@ final class ServiceStateTracker extends Handler
getLacAndCid(null);
}
break;
-
+
case EVENT_SET_PREFERRED_NETWORK_TYPE:
ar = (AsyncResult) msg.obj;
// Don't care the result, only use for dereg network (COPS=2)
@@ -548,11 +611,22 @@ final class ServiceStateTracker extends Handler
if (loc != null) cid = loc.getCid();
EventLog.List val = new EventLog.List(ss.getOperatorNumeric(), cid);
- EventLog.writeEvent(EVENT_LOG_CGREG_FAIL, val);
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CGREG_FAIL, val);
mReportedGprsNoReg = true;
}
mStartedGprsRegCheck = false;
break;
+
+ case EVENT_RESTRICTED_STATE_CHANGED:
+ // This is a notification from
+ // CommandsInterface.setOnRestrictedStateChanged
+
+ Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_RESTRICTED_STATE_CHANGED");
+
+ ar = (AsyncResult) msg.obj;
+
+ onRestrictedStateChanged(ar);
+ break;
}
}
@@ -561,7 +635,7 @@ final class ServiceStateTracker extends Handler
private void updateSpnDisplay() {
int rule = phone.mSIMRecords.getDisplayRule(ss.getOperatorNumeric());
- String spn = phone.mSIMRecords.getServiceProvideName();
+ String spn = phone.mSIMRecords.getServiceProviderName();
String plmn = ss.getOperatorAlphaLong();
if (rule != curSpnRule
@@ -598,7 +672,19 @@ final class ServiceStateTracker extends Handler
EventLog.List val = new EventLog.List(
dcTracker.getStateInString(),
(dcTracker.getAnyDataEnabled() ? 1 : 0) );
- EventLog.writeEvent(EVENT_DATA_STATE_RADIO_OFF, val);
+ EventLog.writeEvent(TelephonyEventLog.EVENT_DATA_STATE_RADIO_OFF, val);
+ }
+ dcTracker.cleanConnectionBeforeRadioOff();
+
+ // poll data state up to 15 times, with a 100ms delay
+ // totaling 1.5 sec. Normal data disable action will finish in 100ms.
+ for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) {
+ if (dcTracker.state != State.CONNECTED
+ && dcTracker.state != State.DISCONNECTING) {
+ Log.d(LOG_TAG, "Data shutdown complete.");
+ break;
+ }
+ SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS);
}
// If it's on and available and we want it off..
cm.setRadioPower(false, null);
@@ -689,7 +775,7 @@ final class ServiceStateTracker extends Handler
if (states.length > 0) {
try {
regState = Integer.parseInt(states[0]);
-
+
// states[3] (if present) is the current radio technology
if (states.length >= 4 && states[3] != null) {
type = Integer.parseInt(states[3]);
@@ -1038,7 +1124,7 @@ final class ServiceStateTracker extends Handler
break;
}
}
-
+
return guess;
}
@@ -1091,6 +1177,63 @@ final class ServiceStateTracker extends Handler
phone.notifySignalStrength();
}
}
+
+ /**
+ * Set restricted state based on the OnRestrictedStateChanged notification
+ * If any voice or packet restricted state changes, trigger a UI
+ * notification and notify registrants.
+ * @param ar an int value of RIL_RESTRICTED_STATE_*
+ */
+ private void onRestrictedStateChanged(AsyncResult ar)
+ {
+ Log.d(LOG_TAG, "[DSAC DEB] " + "onRestrictedStateChanged");
+ RestrictedState newRs = new RestrictedState();
+
+ Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at enter "+ rs);
+
+ if (ar.exception == null) {
+ int[] ints = (int[])ar.result;
+ int state = ints[0];
+
+ 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);
+
+ Log.d(LOG_TAG, "[DSAC DEB] " + "new rs "+ newRs);
+
+ if (!rs.isPsRestricted() && newRs.isPsRestricted()) {
+ psRestrictEnabledRegistrants.notifyRegistrants();
+ setNotification(PS_ENABLED, false);
+ } else if (rs.isPsRestricted() && !newRs.isPsRestricted()) {
+ psRestrictDisabledRegistrants.notifyRegistrants();
+ setNotification(PS_DISABLED, false);
+ }
+
+ 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);
+ }
+ if (!rs.isCsNormalRestricted() && newRs.isCsNormalRestricted()) {
+ setNotification(CS_NORMAL_ENABLED, false);
+ } else if (rs.isCsEmergencyRestricted() && !newRs.isCsEmergencyRestricted()) {
+ setNotification(CS_NORMAL_DISABLED, false);
+ }
+ }
+ rs = newRs;
+ }
+ Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at return "+ rs);
+ }
/** code is registration state 0-5 from TS 27.007 7.2 */
private int
@@ -1147,7 +1290,7 @@ final class ServiceStateTracker extends Handler
String simNumeric = SystemProperties.get(PROPERTY_SIM_OPERATOR_NUMERIC, "");
String operatorNumeric = s.getOperatorNumeric();
-
+
boolean equalsMcc = true;
try {
equalsMcc = simNumeric.substring(0, 3).
@@ -1329,49 +1472,56 @@ final class ServiceStateTracker extends Handler
}
saveNitzTimeZone(zone.getID());
}
-
+
String ignore = SystemProperties.get("gsm.ignore-nitz");
if (ignore != null && ignore.equals("yes")) {
Log.i(LOG_TAG, "NITZ: Not setting clock because gsm.ignore-nitz is set");
return;
}
- if (getAutoTime()) {
- long millisSinceNitzReceived
- = SystemClock.elapsedRealtime() - nitzReceiveTime;
-
- if (millisSinceNitzReceived < 0) {
- // Sanity check: something is wrong
- Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled "
- + "backwards since NITZ time was received, "
- + nitz);
- return;
+ try {
+ mWakeLock.acquire();
+
+ if (getAutoTime()) {
+ long millisSinceNitzReceived
+ = SystemClock.elapsedRealtime() - nitzReceiveTime;
+
+ if (millisSinceNitzReceived < 0) {
+ // Sanity check: something is wrong
+ Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled "
+ + "backwards since NITZ time was received, "
+ + nitz);
+ return;
+ }
+
+ if (millisSinceNitzReceived > Integer.MAX_VALUE) {
+ // If the time is this far off, something is wrong > 24 days!
+ Log.i(LOG_TAG, "NITZ: not setting time, processing has taken "
+ + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
+ + " days");
+ return;
+ }
+
+ // Note: with range checks above, cast to int is safe
+ c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
+
+ Log.i(LOG_TAG, "NITZ: Setting time of day to " + c.getTime()
+ + " NITZ receive delay(ms): " + millisSinceNitzReceived
+ + " gained(ms): "
+ + (c.getTimeInMillis() - System.currentTimeMillis())
+ + " from " + nitz);
+
+ setAndBroadcastNetworkSetTime(c.getTimeInMillis());
+ Log.i(LOG_TAG, "NITZ: after Setting time of day");
}
-
- if (millisSinceNitzReceived > Integer.MAX_VALUE) {
- // If the time is this far off, something is wrong > 24 days!
- Log.i(LOG_TAG, "NITZ: not setting time, processing has taken "
- + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
- + " days");
- return;
+ SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
+ saveNitzTime(c.getTimeInMillis());
+ if (Config.LOGV) {
+ long end = SystemClock.elapsedRealtime();
+ Log.v(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
}
-
- // Note: with range checks above, cast to int is safe
- c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
-
- Log.i(LOG_TAG, "NITZ: Setting time of day to " + c.getTime()
- + " NITZ receive delay(ms): " + millisSinceNitzReceived
- + " gained(ms): "
- + (c.getTimeInMillis() - System.currentTimeMillis())
- + " from " + nitz);
-
- setAndBroadcastNetworkSetTime(c.getTimeInMillis());
- }
- SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
- saveNitzTime(c.getTimeInMillis());
- if (Config.LOGV) {
- long end = SystemClock.elapsedRealtime();
- Log.v(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
+ } finally {
+ mWakeLock.release();
}
} catch (RuntimeException ex) {
Log.e(LOG_TAG, "NITZ: Parsing NITZ time " + nitz, ex);
@@ -1399,11 +1549,11 @@ final class ServiceStateTracker extends Handler
/**
* Set the timezone and send out a sticky broadcast so the system can
* determine if the timezone was set by the carrier.
- *
+ *
* @param zoneId timezone set by carrier
*/
private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
- AlarmManager alarm =
+ AlarmManager alarm =
(AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
alarm.setTimeZone(zoneId);
Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
@@ -1414,9 +1564,9 @@ final class ServiceStateTracker extends Handler
/**
* Set the time and Send out a sticky broadcast so the system can determine
* if the time was set by the carrier.
- *
+ *
* @param time time set by network
- */
+ */
private void setAndBroadcastNetworkSetTime(long time) {
SystemClock.setCurrentTimeMillis(time);
Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
@@ -1438,4 +1588,72 @@ final class ServiceStateTracker extends Handler
+ (SystemClock.elapsedRealtime() - mSavedAtTime));
}
}
+
+ /**
+ * 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) {
+
+ Log.d(LOG_TAG, "[DSAC DEB] " + "create notification " + notifyType);
+ mNotification = new Notification();
+ mNotification.when = System.currentTimeMillis();
+ mNotification.flags = Notification.FLAG_AUTO_CANCEL;
+ mNotification.icon = com.android.internal.R.drawable.icon_highlight_square;
+ Intent intent = new Intent();
+ mNotification.contentIntent = PendingIntent
+ .getActivity(phone.getContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+
+ // TODO
+ // should use getResources().getText(com.android.internal.R.)
+ CharSequence title = "Restricted State Changed";
+ CharSequence details = "";
+ switch (notifyType) {
+ case PS_ENABLED:
+ details = "Access Control blocks data service.";
+ break;
+ case PS_DISABLED:
+ details = "Access Control enables data service.";
+ break;
+ case CS_ENABLED:
+ details = "Access Control blocks all voice/sms service.";
+ 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.";
+ break;
+ }
+
+ Log.d(LOG_TAG, "[DSAC DEB] " + "put notification " + title + " / " +details);
+ mNotification.tickerText = title;
+ mNotification.setLatestEventInfo(phone.getContext(), title, details,
+ mNotification.contentIntent);
+
+ NotificationManager notificationManager = (NotificationManager)
+ phone.getContext().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);
+ }
+ notificationManager.notify(notifyType, mNotification);
+ }
+
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SpnOverride.java b/telephony/java/com/android/internal/telephony/gsm/SpnOverride.java
new file mode 100644
index 0000000..9ea30101
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/SpnOverride.java
@@ -0,0 +1,78 @@
+package com.android.internal.telephony.gsm;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.os.Environment;
+import android.util.Log;
+import android.util.Xml;
+
+import com.android.internal.util.XmlUtils;
+
+public class SpnOverride {
+ private HashMap<String, String> CarrierSpnMap;
+
+
+ static final String LOG_TAG = "GSM";
+ static final String PARTNER_SPN_OVERRIDE_PATH ="etc/spn-conf.xml";
+
+ SpnOverride () {
+ CarrierSpnMap = new HashMap<String, String>();
+ loadSpnOverrides();
+ }
+
+ boolean containsCarrier(String carrier) {
+ return CarrierSpnMap.containsKey(carrier);
+ }
+
+ String getSpn(String carrier) {
+ return CarrierSpnMap.get(carrier);
+ }
+
+ private void loadSpnOverrides() {
+ FileReader spnReader;
+
+ final File spnFile = new File(Environment.getRootDirectory(),
+ PARTNER_SPN_OVERRIDE_PATH);
+
+ try {
+ spnReader = new FileReader(spnFile);
+ } catch (FileNotFoundException e) {
+ Log.w(LOG_TAG, "Can't open " +
+ Environment.getRootDirectory() + "/" + PARTNER_SPN_OVERRIDE_PATH);
+ return;
+ }
+
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(spnReader);
+
+ XmlUtils.beginDocument(parser, "spnOverrides");
+
+ while (true) {
+ XmlUtils.nextElement(parser);
+
+ String name = parser.getName();
+ if (!"spnOverride".equals(name)) {
+ break;
+ }
+
+ String numeric = parser.getAttributeValue(null, "numeric");
+ String data = parser.getAttributeValue(null, "spn");
+
+ CarrierSpnMap.put(numeric, data);
+ }
+ } catch (XmlPullParserException e) {
+ Log.w(LOG_TAG, "Exception in spn-conf parser " + e);
+ } catch (IOException e) {
+ Log.w(LOG_TAG, "Exception in spn-conf parser " + e);
+ }
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/gsm/TelephonyEventLog.java b/telephony/java/com/android/internal/telephony/gsm/TelephonyEventLog.java
new file mode 100644
index 0000000..1e583f0
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/TelephonyEventLog.java
@@ -0,0 +1,33 @@
+/*
+ * 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.internal.telephony.gsm;
+
+/* This class contains the details related to Telephony Event Logging */
+public final class TelephonyEventLog {
+
+ /* Event log tags */
+ public static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
+ public static final int EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED = 50101;
+ public static final int EVENT_LOG_RADIO_RESET = 50102;
+ public static final int EVENT_LOG_PDP_RESET = 50103;
+ public static final int EVENT_LOG_REREGISTER_NETWORK = 50104;
+ public static final int EVENT_LOG_RADIO_PDP_SETUP_FAIL = 50105;
+ public static final int EVENT_LOG_CALL_DROP = 50106;
+ public static final int EVENT_LOG_CGREG_FAIL = 50107;
+ public static final int EVENT_DATA_STATE_RADIO_OFF = 50108;
+ public static final int EVENT_LOG_PDP_NETWORK_DROP = 50109;
+}
diff --git a/test-runner/android/test/InstrumentationTestRunner.java b/test-runner/android/test/InstrumentationTestRunner.java
index 8b8d472..f038612 100644
--- a/test-runner/android/test/InstrumentationTestRunner.java
+++ b/test-runner/android/test/InstrumentationTestRunner.java
@@ -148,6 +148,8 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
public static final String ARGUMENT_TEST_SIZE_PREDICATE = "size";
/** @hide */
public static final String ARGUMENT_INCLUDE_PERF = "perf";
+ /** @hide */
+ public static final String ARGUMENT_DELAY_MSEC = "delay_msec";
private static final String SMALL_SUITE = "small";
private static final String MEDIUM_SUITE = "medium";
@@ -249,6 +251,7 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
private String mPackageOfTests;
private boolean mCoverage;
private String mCoverageFilePath;
+ private int mDelayMsec;
@Override
public void onCreate(Bundle arguments) {
@@ -277,11 +280,18 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
logOnly = getBooleanArgument(arguments, ARGUMENT_LOG_ONLY);
mCoverage = getBooleanArgument(arguments, "coverage");
mCoverageFilePath = arguments.getString("coverageFile");
+
+ try {
+ Object delay = arguments.get(ARGUMENT_DELAY_MSEC); // Accept either string or int
+ if (delay != null) mDelayMsec = Integer.parseInt(delay.toString());
+ } catch (NumberFormatException e) {
+ Log.e(LOG_TAG, "Invalid delay_msec parameter", e);
+ }
}
-
+
TestSuiteBuilder testSuiteBuilder = new TestSuiteBuilder(getClass().getName(),
getTargetContext().getClassLoader());
-
+
if (testSizePredicate != null) {
testSuiteBuilder.addRequirements(testSizePredicate);
}
@@ -600,6 +610,18 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
} else {
mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "");
}
+
+ // The delay_msec parameter is normally used to provide buffers of idle time
+ // for power measurement purposes. To make sure there is a delay before and after
+ // every test in a suite, we delay *after* every test (see endTest below) and also
+ // delay *before* the first test. So, delay test1 delay test2 delay.
+
+ try {
+ if (mTestNum == 1) Thread.sleep(mDelayMsec);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
+
sendStatus(REPORT_VALUE_RESULT_START, mTestResult);
mTestResultCode = 0;
}
@@ -636,10 +658,15 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, ".");
}
sendStatus(mTestResultCode, mTestResult);
+
+ try { // Sleep after every test, if specified
+ Thread.sleep(mDelayMsec);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
}
// TODO report the end of the cycle
// TODO report runtime for each test
}
}
-
diff --git a/test-runner/android/test/ServiceTestCase.java b/test-runner/android/test/ServiceTestCase.java
index c53bf7d..fcb9d55 100644
--- a/test-runner/android/test/ServiceTestCase.java
+++ b/test-runner/android/test/ServiceTestCase.java
@@ -48,7 +48,7 @@ import java.util.Random;
* the test case will call onCreate(), and then call the corresponding entry point in your service.
* It will record any parameters or other support values necessary to support the lifecycle.</li>
* <li>After your test completes, the test case {@link #tearDown} function is
- * automatically called, and it will stop & destroy your service with the appropriate
+ * automatically called, and it will stop and destroy your service with the appropriate
* calls (depending on how your test invoked the service.)</li>
* </ul>
*
@@ -172,7 +172,7 @@ public abstract class ServiceTestCase<T extends Service> extends AndroidTestCase
* Return the communication channel to the service. May return null if
* clients can not bind to the service. The returned
* {@link android.os.IBinder} is usually for a complex interface
- * that has been <a href="{@docRoot}reference/aidl.html">described using
+ * that has been <a href="{@docRoot}guide/developing/tools/aidl.html">described using
* aidl</a>.
*
* Note: In order to test with this interface, your service must implement a getService()
diff --git a/test-runner/android/test/TestCaseUtil.java b/test-runner/android/test/TestCaseUtil.java
index 4109d9c..3ba9711 100644
--- a/test-runner/android/test/TestCaseUtil.java
+++ b/test-runner/android/test/TestCaseUtil.java
@@ -17,6 +17,7 @@
package android.test;
import com.google.android.collect.Lists;
+
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
@@ -26,7 +27,9 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Enumeration;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* @hide - This is part of a framework that is under development and should not be used for
@@ -48,10 +51,25 @@ public class TestCaseUtil {
}
public static List<? extends Test> getTests(Test test, boolean flatten) {
+ return getTests(test, flatten, new HashSet<Class<?>>());
+ }
+
+ private static List<? extends Test> getTests(Test test, boolean flatten,
+ Set<Class<?>> seen) {
List<Test> testCases = Lists.newArrayList();
if (test != null) {
- Test workingTest = invokeSuiteMethodIfPossible(test.getClass());
+ Test workingTest = null;
+ /*
+ * If we want to run a single TestCase method only, we must not
+ * invoke the suite() method, because we will run all test methods
+ * of the class then.
+ */
+ if (test instanceof TestCase &&
+ ((TestCase)test).getName() == null) {
+ workingTest = invokeSuiteMethodIfPossible(test.getClass(),
+ seen);
+ }
if (workingTest == null) {
workingTest = test;
}
@@ -62,7 +80,7 @@ public class TestCaseUtil {
while (enumeration.hasMoreElements()) {
Test childTest = (Test) enumeration.nextElement();
if (flatten) {
- testCases.addAll(getTests(childTest, flatten));
+ testCases.addAll(getTests(childTest, flatten, seen));
} else {
testCases.add(childTest);
}
@@ -74,11 +92,20 @@ public class TestCaseUtil {
return testCases;
}
- private static Test invokeSuiteMethodIfPossible(Class testClass) {
+ private static Test invokeSuiteMethodIfPossible(Class testClass,
+ Set<Class<?>> seen) {
try {
Method suiteMethod = testClass.getMethod(
BaseTestRunner.SUITE_METHODNAME, new Class[0]);
- if (Modifier.isStatic(suiteMethod.getModifiers())) {
+ /*
+ * Additional check necessary: If a TestCase contains a suite()
+ * method that returns a TestSuite including the TestCase itself,
+ * we need to stop the recursion. We use a set of classes to
+ * remember which classes' suite() methods were already invoked.
+ */
+ if (Modifier.isStatic(suiteMethod.getModifiers())
+ && !seen.contains(testClass)) {
+ seen.add(testClass);
try {
return (Test) suiteMethod.invoke(null, (Object[]) null);
} catch (InvocationTargetException e) {
@@ -128,7 +155,8 @@ public class TestCaseUtil {
public static TestSuite createTestSuite(Class<? extends Test> testClass)
throws InstantiationException, IllegalAccessException {
- Test test = invokeSuiteMethodIfPossible(testClass);
+ Test test = invokeSuiteMethodIfPossible(testClass,
+ new HashSet<Class<?>>());
if (test == null) {
return new TestSuite(testClass);
diff --git a/test-runner/android/test/TouchUtils.java b/test-runner/android/test/TouchUtils.java
index c4bca41..52d2ee8 100644
--- a/test-runner/android/test/TouchUtils.java
+++ b/test-runner/android/test/TouchUtils.java
@@ -73,7 +73,7 @@ public class TouchUtils {
*/
@Deprecated
public static void dragQuarterScreenUp(ActivityInstrumentationTestCase test) {
- dragQuarterScreenDown(test, test.getActivity());
+ dragQuarterScreenUp(test, test.getActivity());
}
/**
@@ -269,9 +269,9 @@ public class TouchUtils {
inst.waitForIdleSync();
eventTime = SystemClock.uptimeMillis();
- event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
- x + (ViewConfiguration.getTouchSlop() / 2.0f),
- y + (ViewConfiguration.getTouchSlop() / 2.0f), 0);
+ final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
+ event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
+ x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0);
inst.sendPointerSync(event);
inst.waitForIdleSync();
@@ -309,9 +309,9 @@ public class TouchUtils {
inst.waitForIdleSync();
eventTime = SystemClock.uptimeMillis();
+ final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_CANCEL,
- x + (ViewConfiguration.getTouchSlop() / 2.0f),
- y + (ViewConfiguration.getTouchSlop() / 2.0f), 0);
+ x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0);
inst.sendPointerSync(event);
inst.waitForIdleSync();
@@ -345,9 +345,9 @@ public class TouchUtils {
eventTime = SystemClock.uptimeMillis();
- event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
- x + (ViewConfiguration.getTouchSlop() / 2.0f),
- y + (ViewConfiguration.getTouchSlop() / 2.0f), 0);
+ final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
+ event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
+ x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0);
inst.sendPointerSync(event);
inst.waitForIdleSync();
@@ -405,9 +405,9 @@ public class TouchUtils {
inst.waitForIdleSync();
eventTime = SystemClock.uptimeMillis();
- event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
- x + ViewConfiguration.getTouchSlop() / 2,
- y + ViewConfiguration.getTouchSlop() / 2, 0);
+ final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
+ event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
+ x + touchSlop / 2, y + touchSlop / 2, 0);
inst.sendPointerSync(event);
inst.waitForIdleSync();
diff --git a/test-runner/android/test/mock/MockContentProvider.java b/test-runner/android/test/mock/MockContentProvider.java
index 9c00ecf..d04fc44 100644
--- a/test-runner/android/test/mock/MockContentProvider.java
+++ b/test-runner/android/test/mock/MockContentProvider.java
@@ -19,6 +19,7 @@ package android.test.mock;
import android.content.ContentValues;
import android.content.IContentProvider;
import android.content.ISyncAdapter;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.IBulkCursor;
@@ -82,6 +83,12 @@ public class MockContentProvider implements IContentProvider {
}
@SuppressWarnings("unused")
+ public AssetFileDescriptor openAssetFile(Uri uri, String mode)
+ throws FileNotFoundException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
+ @SuppressWarnings("unused")
public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
String sortOrder) throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java
index f131bf2..ea190e2 100644
--- a/test-runner/android/test/mock/MockPackageManager.java
+++ b/test-runner/android/test/mock/MockPackageManager.java
@@ -34,6 +34,7 @@ import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
@@ -56,6 +57,12 @@ public class MockPackageManager extends PackageManager {
}
@Override
+ public Intent getLaunchIntentForPackage(String packageName)
+ throws NameNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public int[] getPackageGids(String packageName) throws NameNotFoundException {
throw new UnsupportedOperationException();
}
@@ -393,4 +400,14 @@ public class MockPackageManager extends PackageManager {
List<ComponentName> outActivities, String packageName) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public String[] getSystemSharedLibraryNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isSafeMode() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/tests/AndroidTests/Android.mk b/tests/AndroidTests/Android.mk
index cf8ac94..f5e49d7 100644
--- a/tests/AndroidTests/Android.mk
+++ b/tests/AndroidTests/Android.mk
@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := eng tests
+LOCAL_MODULE_TAGS := tests
LOCAL_JAVA_LIBRARIES := framework-tests android.test.runner
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
index f126b8c..843d844 100644
--- a/tests/AndroidTests/AndroidManifest.xml
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -44,10 +44,10 @@
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_GSERVICES" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.android.unit_tests.permission.TEST_GRANTED" />
diff --git a/tests/AndroidTests/DisabledTestApp/Android.mk b/tests/AndroidTests/DisabledTestApp/Android.mk
index 814607d..a5daedf 100644
--- a/tests/AndroidTests/DisabledTestApp/Android.mk
+++ b/tests/AndroidTests/DisabledTestApp/Android.mk
@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := eng tests
+LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/tests/AndroidTests/EnabledTestApp/Android.mk b/tests/AndroidTests/EnabledTestApp/Android.mk
index 2de5c3b..4b986d3 100644
--- a/tests/AndroidTests/EnabledTestApp/Android.mk
+++ b/tests/AndroidTests/EnabledTestApp/Android.mk
@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := eng tests
+LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
index 6a9ac86..3daa8ab 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
@@ -44,7 +44,7 @@ import android.os.ServiceManager;
import android.os.StatFs;
public class AppCacheTest extends AndroidTestCase {
- private static final boolean localLOGV = true;
+ private static final boolean localLOGV = false;
public static final String TAG="AppCacheTest";
public final long MAX_WAIT_TIME=60*1000;
public final long WAIT_TIME_INCR=10*1000;
@@ -121,6 +121,7 @@ public class AppCacheTest extends AndroidTestCase {
}
@LargeTest
public void testFreeApplicationCacheAllFiles() throws Exception {
+ boolean TRACKING = true;
StatFs st = new StatFs("/data");
long blks1 = getFreeStorageBlks(st);
long availableMem = getFreeStorageSize(st);
@@ -128,11 +129,11 @@ public class AppCacheTest extends AndroidTestCase {
assertNotNull(cacheDir);
createTestFiles1(cacheDir, "testtmpdir", 5);
long blks2 = getFreeStorageBlks(st);
- if(localLOGV) Log.i(TAG, "blk1="+blks1+", blks2="+blks2);
+ if(localLOGV || TRACKING) Log.i(TAG, "blk1="+blks1+", blks2="+blks2);
//this should free up the test files that were created earlier
invokePMFreeApplicationCache(availableMem);
long blks3 = getFreeStorageBlks(st);
- if(localLOGV) Log.i(TAG, "blks3="+blks3);
+ if(localLOGV || TRACKING) Log.i(TAG, "blks3="+blks3);
verifyTestFiles1(cacheDir, "testtmpdir", 5);
}
@@ -593,6 +594,20 @@ public class AppCacheTest extends AndroidTestCase {
", cache="+stats.cacheSize);
}
+ @SmallTest
+ public void testGetSystemSharedLibraryNames() throws Exception {
+ try {
+ String[] sharedLibs = getPm().getSystemSharedLibraryNames();
+ if (localLOGV) {
+ for (String str : sharedLibs) {
+ Log.i(TAG, str);
+ }
+ }
+ } catch (RemoteException e) {
+ fail("Failed invoking getSystemSharedLibraryNames with exception:" + e);
+ }
+ }
+
class FreeStorageReceiver extends BroadcastReceiver {
public static final String ACTION_FREE = "com.android.unit_tests.testcallback";
private boolean doneFlag = false;
@@ -615,15 +630,16 @@ public class AppCacheTest extends AndroidTestCase {
@SmallTest
public void testFreeStorage() throws Exception {
+ boolean TRACKING = true;
StatFs st = new StatFs("/data");
long blks1 = getFreeStorageBlks(st);
- if(localLOGV) Log.i(TAG, "Available free blocks="+blks1);
+ if(localLOGV || TRACKING) Log.i(TAG, "Available free blocks="+blks1);
long availableMem = getFreeStorageSize(st);
File cacheDir = mContext.getCacheDir();
assertNotNull(cacheDir);
createTestFiles1(cacheDir, "testtmpdir", 5);
long blks2 = getFreeStorageBlks(st);
- if(localLOGV) Log.i(TAG, "Available blocks after writing test files in application cache="+blks2);
+ if(localLOGV || TRACKING) Log.i(TAG, "Available blocks after writing test files in application cache="+blks2);
// Create receiver and register it
FreeStorageReceiver receiver = new FreeStorageReceiver();
mContext.registerReceiver(receiver, new IntentFilter(FreeStorageReceiver.ACTION_FREE));
@@ -632,7 +648,7 @@ public class AppCacheTest extends AndroidTestCase {
// Invoke PackageManager api
invokePMFreeStorage(availableMem, receiver, pi);
long blks3 = getFreeStorageBlks(st);
- if(localLOGV) Log.i(TAG, "Available blocks after freeing cache"+blks3);
+ if(localLOGV || TRACKING) Log.i(TAG, "Available blocks after freeing cache"+blks3);
assertEquals(receiver.getResultCode(), 1);
mContext.unregisterReceiver(receiver);
// Verify result
diff --git a/tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java b/tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java
deleted file mode 100644
index 21fb94b..0000000
--- a/tests/AndroidTests/src/com/android/unit_tests/BluetoothTest.java
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * Copyright (C) 2007 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.unit_tests;
-
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothIntent;
-import android.bluetooth.BluetoothClass;
-import android.bluetooth.IBluetoothDeviceCallback;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.SystemProperties;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import junit.framework.Assert;
-
-import java.util.List;
-import java.util.HashSet;
-
-public class BluetoothTest extends AndroidTestCase {
- private static final String TAG = "BluetoothTest";
-
- @MediumTest
- public void testBluetoothSmokeTest() throws Exception {
-
- BluetoothDevice btDevice =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
-
- // TODO: Use a more reliable check to see if this product should
- // support Bluetooth - see bug 988521
- boolean shouldSupportBluetooth = SystemProperties.get("ro.kernel.qemu").equals("0");
-
- assertFalse(shouldSupportBluetooth && btDevice == null);
- if (!shouldSupportBluetooth) {
- Log.i(TAG, "Skipping test - this device does not have bluetooth.");
- return;
- }
-
- boolean bluetoothWasEnabled = btDevice.isEnabled();
-
- if (bluetoothWasEnabled) {
- Log.i(TAG, "Bluetooth already enabled");
- } else {
- Log.i(TAG, "Enabling Bluetooth...");
- btDevice.enable();
- Log.i(TAG, "Bluetooth enabled");
- }
- Assert.assertTrue(btDevice.isEnabled());
-
- String myAddress = btDevice.getAddress();
- Assert.assertTrue(myAddress != null);
- Log.i(TAG, "My Bluetooth Address is " + myAddress);
- Assert.assertFalse(myAddress.equals("00:00:00:00:00:00"));
-
- if (!bluetoothWasEnabled) {
- Log.i(TAG, "Disabling Bluetooth...");
- btDevice.disable();
- Log.i(TAG, "Bluetooth disabled");
- }
- }
-
- private boolean listenA2dp = false;
- private void listenA2dp() {
- if (!listenA2dp) {
- listenA2dp = true;
- getContext().registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE, -1);
- int oldState = intent.getIntExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, -1);
- Log.e(TAG, "A2DP INTENT: state = " + state + " oldState = " + oldState);
- }
- }, new IntentFilter(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION));
- }
- }
-
- @MediumTest
- public void testA2dpSmokeTest() throws Exception {
- listenA2dp();
-
- BluetoothA2dp a2dp = new BluetoothA2dp(getContext());
-
- List<String> sinks = a2dp.listConnectedSinks();
- Log.e(TAG, "listConnectedSinks()...");
- for (String sink : sinks) {
- Log.e(TAG, sink + " state = " + a2dp.getSinkState(sink));
- }
- }
-
- @MediumTest
- public void testA2dpConnect() throws Exception {
- listenA2dp();
- String address = SystemProperties.get("debug.a2dp.address", "<none>");
- BluetoothA2dp a2dp = new BluetoothA2dp(getContext());
- int result = a2dp.connectSink(address);
- Log.e(TAG, "connectSink(" + address + ") = " + result);
- }
-
- @MediumTest
- public void testA2dpDisconnect() throws Exception {
- listenA2dp();
- String address = SystemProperties.get("debug.a2dp.address", "<none>");
- BluetoothA2dp a2dp = new BluetoothA2dp(getContext());
- int result = a2dp.disconnectSink(address);
- Log.e(TAG, "disconnectSink(" + address + ") = " + result);
- }
-
- @MediumTest
- public void testBluetoothEnabled() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
-
- if (device.isEnabled()) {
- Log.i(TAG, "isEnabled() = yes");
- } else {
- Log.i(TAG, "isEnabled() = no");
- }
- }
-
- @MediumTest
- public void testEnableBluetooth() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- device.enable();
- }
-
- @MediumTest
- public void testEnableBluetoothWithCallback() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- if (!device.enable(mCallback)) {
- Log.e(TAG, "enable() failed");
- }
- }
-
- @MediumTest
- public void testDisableBluetooth() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- device.disable();
- }
-
- @LargeTest
- public void testDiscovery() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- if (device.isEnabled()) {
- getContext().registerReceiver((BroadcastReceiver)new TestDiscoveryReceiver(),
- new IntentFilter(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION));
- Log.i(TAG, "Starting discovery...");
- String result = device.startDiscovery() ? "true" : "false";
- Log.i(TAG, "startDiscovery() = " + result);
- }
- }
-
- @LargeTest
- public void testMultipleDiscovery() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- if (device.isEnabled()) {
- getContext().registerReceiver((BroadcastReceiver)new TestDiscoveryReceiver(),
- new IntentFilter(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION));
- String result;
- Log.i(TAG, "Starting multiple discovery...");
- for (int i = 0; i < 5; i++) {
- result = device.startDiscovery() ? "true" : "false";
- Log.i(TAG, "startDiscovery() = " + result);
- }
- }
- }
- private class TestDiscoveryReceiver extends BroadcastReceiver {
- @Override public void onReceive(Context context, Intent intent) {
- String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
- int deviceClass = intent.getIntExtra(BluetoothIntent.CLASS, -1);
- short rssi = intent.getShortExtra(BluetoothIntent.RSSI, (short)-1);
- Log.i(TAG, "Discovered Device: " + address + " " + deviceClass + " " + rssi);
- }
- }
-
- private IBluetoothDeviceCallback mCallback = new IBluetoothDeviceCallback.Stub() {
- public void onEnableResult(int res) {
- String result = "unknown";
- switch (res) {
- case BluetoothDevice.RESULT_SUCCESS:
- result = "success";
- break;
- case BluetoothDevice.RESULT_FAILURE:
- result = "FAILURE";
- break;
- }
- Log.i(TAG, "onEnableResult(" + result + ")");
- }
- public void onGetRemoteServiceChannelResult(String device, int channel) {}
- };
-
- @SmallTest
- public void testCreateBond() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- if (!device.createBond("01:23:45:67:89:AB")) {
- Log.e(TAG, "createBonding() failed");
- }
- }
-
- @SmallTest
- public void testIsPeriodicDiscovery() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- boolean ret = device.isPeriodicDiscovery();
- if (ret) {
- Log.i(TAG, "isPeriodicDiscovery() = TRUE");
- } else {
- Log.i(TAG, "isPeriodicDiscovery() = FALSE");
- }
- }
-
- @LargeTest
- public void testListBondings() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- String[] addresses = device.listBonds();
- if (addresses == null) {
- Log.i(TAG, "Bluetooth disabled");
- return;
- }
- for (String address : addresses) {
- String name = device.getRemoteName(address);
- Log.i(TAG, "BONDING: " + address + " (" + name + ")");
- }
- }
-
- @LargeTest
- public void testListAclConnections() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- String[] addresses = device.listAclConnections();
- if (addresses == null) {
- Log.i(TAG, "Bluetooth disabled");
- return;
- }
- for (String address : addresses) {
- String name = device.getRemoteName(address);
- Log.i(TAG, "CONNECTION: " + address + " (" + name + ")");
- }
- }
-
- @LargeTest
- public void testListRemoteDevices() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- String[] addresses = device.listRemoteDevices();
- if (addresses == null) {
- Log.i(TAG, "Bluetooth disabled");
- return;
- }
- for (String address : addresses) {
- String name = device.getRemoteName(address);
- Log.i(TAG, "KNOWN DEVICE: " + address + " (" + name + ")");
- }
- }
-
- @MediumTest
- public void testSetupBTIntentRecv() throws Exception {
- BluetoothDevice device =
- (BluetoothDevice)getContext().getSystemService(Context.BLUETOOTH_SERVICE);
- if (device == null) {
- Log.i(TAG, "Device not Bluetooth capable, skipping test");
- return;
- }
- if (device.isEnabled()) {
- IntentFilter filter = new IntentFilter(BluetoothIntent.ENABLED_ACTION);
- filter.addAction(BluetoothIntent.ENABLED_ACTION);
- filter.addAction(BluetoothIntent.DISABLED_ACTION);
- filter.addAction(BluetoothIntent.NAME_CHANGED_ACTION);
- filter.addAction(BluetoothIntent.MODE_CHANGED_ACTION);
- filter.addAction(BluetoothIntent.DISCOVERY_STARTED_ACTION);
- filter.addAction(BluetoothIntent.DISCOVERY_COMPLETED_ACTION);
- filter.addAction(BluetoothIntent.PAIRING_REQUEST_ACTION);
- filter.addAction(BluetoothIntent.PAIRING_CANCEL_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_DISCONNECT_REQUESTED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_NAME_FAILED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_ALIAS_CHANGED_ACTION);
- filter.addAction(BluetoothIntent.REMOTE_ALIAS_CLEARED_ACTION);
- filter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
- filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
- getContext().registerReceiver(
- (BroadcastReceiver)new BluetoothIntentReceiver(), filter);
- Log.i(TAG, "Listening for BLUETOOTH INTENTS....");
- } else {
- Log.e(TAG, "BT not enabled");
- }
- }
-
-
- private class BluetoothIntentReceiver extends BroadcastReceiver {
- @Override public void onReceive(Context context, Intent intent) {
- String msg = "";
-
- String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
- if (address != null) {
- msg += " address=" + address;
- }
-
- int deviceClass = intent.getIntExtra(BluetoothIntent.CLASS, BluetoothClass.ERROR);
- if (deviceClass != BluetoothClass.ERROR) {
- msg += " class=" + deviceClass;
- }
-
- int rssi = intent.getIntExtra(BluetoothIntent.RSSI, -1);
- if (rssi != -1) {
- msg += " rssi=" + rssi;
- }
-
- String name = intent.getStringExtra(BluetoothIntent.NAME);
- if (name != null) {
- msg += " name=" + name;
- }
-
- String alias = intent.getStringExtra(BluetoothIntent.ALIAS);
- if (alias != null) {
- msg += " alias=" + alias;
- }
-
- int mode = intent.getIntExtra(BluetoothIntent.MODE, -10);
- if (mode != -10) {
- msg += " mode=" + mode;
- }
-
- int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, -10);
- if (state != -10) {
- msg += " headset state=" + state;
- }
- Log.i(TAG, "BLUETOOTH INTENT: " + intent.getAction() + msg);
- }
- }
-
-
- private static final int[] ALL_SERVICE_CLASSES = new int[] {
- BluetoothClass.Service.LIMITED_DISCOVERABILITY,
- BluetoothClass.Service.POSITIONING,
- BluetoothClass.Service.NETWORKING,
- BluetoothClass.Service.RENDER,
- BluetoothClass.Service.CAPTURE,
- BluetoothClass.Service.OBJECT_TRANSFER,
- BluetoothClass.Service.AUDIO,
- BluetoothClass.Service.TELEPHONY,
- BluetoothClass.Service.INFORMATION
- };
- private void assertOnlyTheseServiceClassesAreSupported(int deviceClass, HashSet<Integer> serviceClasses) {
- for (int serviceClassType : ALL_SERVICE_CLASSES) {
- Assert.assertEquals(serviceClasses.contains(new Integer(serviceClassType)),
- BluetoothClass.Service.hasService(deviceClass, serviceClassType));
- }
- }
-
- @SmallTest
- public void testDeviceClass() throws Exception {
- // This test does not require bluetooth hardware
- int deviceClass;
- HashSet<Integer> serviceClasses;
-
- deviceClass = BluetoothClass.ERROR; // bogus class
- serviceClasses = new HashSet<Integer>();
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.ERROR, BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(BluetoothClass.ERROR, BluetoothClass.Device.getDevice(deviceClass));
-
- deviceClass = 0x10210C; // mac book pro
- serviceClasses = new HashSet<Integer>();
- serviceClasses.add(BluetoothClass.Service.OBJECT_TRANSFER);
- serviceClasses.add(BluetoothClass.Service.LIMITED_DISCOVERABILITY);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.COMPUTER,
- BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(0x10C, BluetoothClass.Device.getDevice(deviceClass));
-
- // mac book pro with some unused bits set. Expecting the same results
- deviceClass = 0xFF10210F;
- serviceClasses = new HashSet<Integer>();
- serviceClasses.add(BluetoothClass.Service.OBJECT_TRANSFER);
- serviceClasses.add(BluetoothClass.Service.LIMITED_DISCOVERABILITY);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.COMPUTER,
- BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(0x10C, BluetoothClass.Device.getDevice(deviceClass));
-
- deviceClass = 0x3E0100; // droid.corp.google.com
- serviceClasses = new HashSet<Integer>();
- serviceClasses.add(BluetoothClass.Service.AUDIO);
- serviceClasses.add(BluetoothClass.Service.OBJECT_TRANSFER);
- serviceClasses.add(BluetoothClass.Service.CAPTURE);
- serviceClasses.add(BluetoothClass.Service.RENDER);
- serviceClasses.add(BluetoothClass.Service.NETWORKING);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.COMPUTER,
- BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(0x100, BluetoothClass.Device.getDevice(deviceClass));
-
- deviceClass = 0x40020C; // Android
- serviceClasses = new HashSet<Integer>();
- serviceClasses.add(BluetoothClass.Service.TELEPHONY);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.PHONE, BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(0x20C, BluetoothClass.Device.getDevice(deviceClass));
-
- // Motorola T305 & Jabra BT125 & Jabra BT250V
- // This seems to be a very common headset & handsfree device code
- deviceClass = 0x200404;
- serviceClasses = new HashSet<Integer>();
- serviceClasses.add(BluetoothClass.Service.AUDIO);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.AUDIO_VIDEO,
- BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET,
- BluetoothClass.Device.getDevice(deviceClass));
-
- // Audi UHV 0128
- deviceClass = 0x200408;
- serviceClasses = new HashSet<Integer>();
- serviceClasses.add(BluetoothClass.Service.AUDIO);
- assertOnlyTheseServiceClassesAreSupported(deviceClass, serviceClasses);
- Assert.assertEquals(BluetoothClass.Device.Major.AUDIO_VIDEO,
- BluetoothClass.Device.Major.getDeviceMajor(deviceClass));
- Assert.assertEquals(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE,
- BluetoothClass.Device.getDevice(deviceClass));
- }
-}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/BuildTest.java b/tests/AndroidTests/src/com/android/unit_tests/BuildTest.java
index a8c51f4..dbfd0e7 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/BuildTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/BuildTest.java
@@ -55,6 +55,7 @@ public class BuildTest extends TestCase {
@SmallTest
public void testBuildFields() throws Exception {
assertNotEmpty("ID", Build.ID);
+ assertNotEmpty("DISPLAY", Build.DISPLAY);
assertNotEmpty("PRODUCT", Build.PRODUCT);
assertNotEmpty("DEVICE", Build.DEVICE);
assertNotEmpty("BOARD", Build.BOARD);
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CheckinProviderTest.java b/tests/AndroidTests/src/com/android/unit_tests/CheckinProviderTest.java
deleted file mode 100644
index f9a2ec0..0000000
--- a/tests/AndroidTests/src/com/android/unit_tests/CheckinProviderTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2006 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.unit_tests;
-
-import org.apache.commons.codec.binary.Base64;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.ContentUris;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.Checkin;
-import android.server.checkin.CheckinProvider;
-import android.server.data.BuildData;
-import android.server.data.CrashData;
-import android.server.data.ThrowableData;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.io.DataInputStream;
-import java.io.ByteArrayInputStream;
-
-/** Unit test for {@link CheckinProvider}. */
-public class CheckinProviderTest extends AndroidTestCase {
- @MediumTest
- public void testEventReport() {
- long start = System.currentTimeMillis();
- ContentResolver r = getContext().getContentResolver();
- Checkin.logEvent(r, Checkin.Events.Tag.TEST, "Test Value");
-
- Cursor c = r.query(Checkin.Events.CONTENT_URI,
- null,
- Checkin.Events.TAG + "=?",
- new String[] { Checkin.Events.Tag.TEST.toString() },
- null);
-
- long id = -1;
- while (c.moveToNext()) {
- String tag = c.getString(c.getColumnIndex(Checkin.Events.TAG));
- String value = c.getString(c.getColumnIndex(Checkin.Events.VALUE));
- long date = c.getLong(c.getColumnIndex(Checkin.Events.DATE));
- assertEquals(Checkin.Events.Tag.TEST.toString(), tag);
- if ("Test Value".equals(value) && date >= start) {
- assertTrue(id < 0);
- id = c.getInt(c.getColumnIndex(Checkin.Events._ID));
- }
- }
- assertTrue(id > 0);
-
- int rows = r.delete(ContentUris.withAppendedId(Checkin.Events.CONTENT_URI, id), null, null);
- assertEquals(1, rows);
- c.requery();
- while (c.moveToNext()) {
- long date = c.getLong(c.getColumnIndex(Checkin.Events.DATE));
- assertTrue(date < start); // Have deleted the only newer TEST.
- }
-
- c.close();
- }
-
- @MediumTest
- public void testStatsUpdate() {
- ContentResolver r = getContext().getContentResolver();
-
- // First, delete any existing data associated with the TEST tag.
- Uri uri = Checkin.updateStats(r, Checkin.Stats.Tag.TEST, 0, 0);
- assertNotNull(uri);
- assertEquals(1, r.delete(uri, null, null));
- assertFalse(r.query(uri, null, null, null, null).moveToNext());
-
- // Now, add a known quantity to the TEST tag.
- Uri u2 = Checkin.updateStats(r, Checkin.Stats.Tag.TEST, 1, 0.5);
- assertFalse(uri.equals(u2));
-
- Cursor c = r.query(u2, null, null, null, null);
- assertTrue(c.moveToNext());
- assertEquals(1, c.getInt(c.getColumnIndex(Checkin.Stats.COUNT)));
- assertEquals(0.5, c.getDouble(c.getColumnIndex(Checkin.Stats.SUM)));
- assertFalse(c.moveToNext()); // Only one.
-
- // Add another known quantity to TEST (should sum with the first).
- Uri u3 = Checkin.updateStats(r, Checkin.Stats.Tag.TEST, 2, 1.0);
- assertEquals(u2, u3);
- c.requery();
- assertTrue(c.moveToNext());
- assertEquals(3, c.getInt(c.getColumnIndex(Checkin.Stats.COUNT)));
- assertEquals(1.5, c.getDouble(c.getColumnIndex(Checkin.Stats.SUM)));
- assertFalse(c.moveToNext()); // Only one.
-
- // Now subtract the values; the whole row should disappear.
- Uri u4 = Checkin.updateStats(r, Checkin.Stats.Tag.TEST, -3, -1.5);
- assertNull(u4);
- c.requery();
- assertFalse(c.moveToNext()); // Row has been deleted.
- c.close();
- }
-
- @MediumTest
- public void testCrashReport() throws Exception {
- long start = System.currentTimeMillis();
- ContentResolver r = getContext().getContentResolver();
-
- // Log a test (fake) crash report.
- Checkin.reportCrash(r, new CrashData(
- "Test",
- "Test Activity",
- new BuildData("Test Build", "123", start),
- new ThrowableData(new RuntimeException("Test Exception"))));
-
-
- // Crashes aren't indexed; go through them all to find the one we added.
- Cursor c = r.query(Checkin.Crashes.CONTENT_URI, null, null, null, null);
-
- Uri uri = null;
- while (c.moveToNext()) {
- String coded = c.getString(c.getColumnIndex(Checkin.Crashes.DATA));
- byte[] bytes = Base64.decodeBase64(coded.getBytes());
- CrashData crash = new CrashData(
- new DataInputStream(new ByteArrayInputStream(bytes)));
-
- // Should be exactly one recently added "Test" crash.
- if (crash.getId().equals("Test") && crash.getTime() > start) {
- assertEquals("Test Activity", crash.getActivity());
- assertEquals("Test Build", crash.getBuildData().getFingerprint());
- assertEquals("Test Exception",
- crash.getThrowableData().getMessage());
-
- assertNull(uri);
- uri = ContentUris.withAppendedId(Checkin.Crashes.CONTENT_URI, c.getInt(c.getColumnIndex(Checkin.Crashes._ID)));
- }
- }
- assertNotNull(uri);
- c.close();
-
- // Update the "logs" column.
- ContentValues values = new ContentValues();
- values.put(Checkin.Crashes.LOGS, "Test Logs");
- assertEquals(1, r.update(uri, values, null, null));
-
- c = r.query(uri, null, null, null, null);
- assertTrue(c.moveToNext());
- String logs = c.getString(c.getColumnIndex(Checkin.Crashes.LOGS));
- assertEquals("Test Logs", logs);
- c.deleteRow();
- c.close();
-
- c.requery();
- assertFalse(c.moveToNext());
- c.close();
- }
-
- @MediumTest
- public void testPropertiesRestricted() throws Exception {
- ContentResolver r = getContext().getContentResolver();
-
- // The test app doesn't have the permission to access properties,
- // so any attempt to do so should fail.
- try {
- r.insert(Checkin.Properties.CONTENT_URI, new ContentValues());
- fail("SecurityException expected");
- } catch (SecurityException e) {
- // expected
- }
-
- try {
- r.query(Checkin.Properties.CONTENT_URI, null, null, null, null);
- fail("SecurityException expected");
- } catch (SecurityException e) {
- // expected
- }
- }
-}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java
index b004c93..d775dc2 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java
@@ -167,15 +167,6 @@ public class DatabaseGeneralTest extends TestCase implements PerformanceTestCase
c.close();
c = mDatabase.query("phones", null,
- "PHONE_NUMBERS_EQUAL(num, '+1 (617).555-1212p1234')", null, null, null, null);
- assertNotNull(c);
- assertEquals(1, c.getCount());
- c.moveToFirst();
- number = c.getString(c.getColumnIndexOrThrow("num"));
- assertEquals("+" + PHONE_NUMBER, number);
- c.close();
-
- c = mDatabase.query("phones", null,
"PHONE_NUMBERS_EQUAL(num, '" + PHONE_NUMBER + "')", null, null, null, null);
assertNotNull(c);
assertEquals(1, c.getCount());
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseLocaleTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseLocaleTest.java
index 0560c21..f07ca7c 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/DatabaseLocaleTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseLocaleTest.java
@@ -46,9 +46,13 @@ public class DatabaseLocaleTest extends TestCase {
protected void setUp() throws Exception {
super.setUp();
mDatabase = SQLiteDatabase.create(null);
- mDatabase.execSQL("CREATE TABLE test (data TEXT COLLATE LOCALIZED);");
+ mDatabase.execSQL(
+ "CREATE TABLE test (id INTEGER PRIMARY KEY, data TEXT COLLATE LOCALIZED);");
+ }
+
+ private void insertStrings() {
for (String s : STRINGS) {
- mDatabase.execSQL("INSERT INTO test VALUES('" + s + "');");
+ mDatabase.execSQL("INSERT INTO test (data) VALUES('" + s + "');");
}
}
@@ -75,12 +79,14 @@ public class DatabaseLocaleTest extends TestCase {
@MediumTest
public void testLocaleInsertOrder() throws Exception {
+ insertStrings();
String[] results = query("SELECT data FROM test");
MoreAsserts.assertEquals(STRINGS, results);
}
@MediumTest
public void testLocaleenUS() throws Exception {
+ insertStrings();
Log.i("LocaleTest", "about to call setLocale en_US");
mDatabase.setLocale(new Locale("en", "US"));
String[] results;
@@ -99,4 +105,25 @@ public class DatabaseLocaleTest extends TestCase {
STRINGS[5], // "dog"
});
}
-}
+
+ @SmallTest
+ public void testHoge() throws Exception {
+ Cursor cursor = null;
+ try {
+ String expectedString = new String(new int[] {0xFE000}, 0, 1);
+ mDatabase.execSQL("INSERT INTO test(id, data) VALUES(1, '" + expectedString + "')");
+ cursor = mDatabase.rawQuery("SELECT data FROM test WHERE id = 1", null);
+
+ assertNotNull(cursor);
+ assertTrue(cursor.moveToFirst());
+ String actualString = cursor.getString(0);
+ assertEquals(expectedString.length(), actualString.length());
+ for (int i = 0; i < expectedString.length(); i++) {
+ assertEquals((int)expectedString.charAt(i), (int)actualString.charAt(i));
+ }
+ assertEquals(expectedString, actualString);
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseLockTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseLockTest.java
new file mode 100644
index 0000000..bb821e3
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseLockTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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.unit_tests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import java.io.File;
+import java.util.concurrent.atomic.AtomicInteger;
+import android.test.AndroidTestCase;
+
+import junit.framework.TestCase;
+
+/*
+ * This is a series of unit tests for database locks.
+ */
+public class DatabaseLockTest extends AndroidTestCase {
+
+ private static final int NUM_ITERATIONS = 100;
+ private static final int SLEEP_TIME = 30;
+ private static final int MAX_ALLOWED_LATENCY_TIME = 30;
+ private SQLiteDatabase mDatabase;
+ private File mDatabaseFile;
+ private AtomicInteger mCounter = new AtomicInteger();
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ File parentDir = getContext().getFilesDir();
+ mDatabaseFile = new File(parentDir, "database_test.db");
+
+ if (mDatabaseFile.exists()) {
+ mDatabaseFile.delete();
+ }
+ mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+ assertNotNull(mDatabase);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mDatabase.close();
+ mDatabaseFile.delete();
+ super.tearDown();
+ }
+
+ /*
+ * testLockFairness() tests the fairness of prioritizing multiple threads
+ * attempting to access a database concurrently.
+ * This test is intended to verify that, when two threads are accessing the
+ * same database at the same time with the same prioritization, neither thread
+ * is locked out and prevented from accessing the database.
+ */
+ @LargeTest
+ public void testLockFairness() {
+ startDatabaseFairnessThread();
+ int previous = 0;
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ mDatabase.beginTransaction();
+ int val = mCounter.get();
+ if (i == 0) {
+ previous = val - i;
+ }
+ assertTrue(previous == (val - i));
+ try {
+ Thread.currentThread().sleep(SLEEP_TIME);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ mDatabase.endTransaction();
+ }
+ }
+
+ /*
+ * This function is to create the second thread for testLockFairness() test.
+ */
+ private void startDatabaseFairnessThread() {
+ Thread thread = new DatabaseFairnessThread();
+ thread.start();
+ }
+
+ private class DatabaseFairnessThread extends Thread {
+ @Override
+ public void run() {
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ mDatabase.beginTransaction();
+ int val = mCounter.incrementAndGet();
+ try {
+ Thread.currentThread().sleep(SLEEP_TIME);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ mDatabase.endTransaction();
+ }
+ }
+ }
+
+ /*
+ * testLockLatency() tests the latency of database locks.
+ * This test is intended to verify that, even when two threads are accessing
+ * the same database, the locking/unlocking of the database is done within an
+ * appropriate amount of time (MAX_ALLOWED_LATENCY_TIME).
+ */
+ @LargeTest
+ public void testLockLatency() {
+ startDatabaseLatencyThread();
+ int previous = 0;
+ long sumTime = 0;
+ long maxTime = 0;
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ long startTime = System.currentTimeMillis();
+ mDatabase.beginTransaction();
+ long endTime = System.currentTimeMillis();
+ long elapsedTime = endTime - startTime;
+ if (maxTime < elapsedTime) {
+ maxTime = elapsedTime;
+ }
+ sumTime += elapsedTime;
+ try {
+ Thread.currentThread().sleep(SLEEP_TIME);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ mDatabase.endTransaction();
+ }
+ long averageTime = sumTime/NUM_ITERATIONS;
+ Log.i("DatabaseLockLatency", "AverageTime: " + averageTime);
+ Log.i("DatabaseLockLatency", "MaxTime: " + maxTime);
+ assertTrue( (averageTime - SLEEP_TIME) <= MAX_ALLOWED_LATENCY_TIME);
+ }
+
+ /*
+ * This function is to create the second thread for testLockLatency() test.
+ */
+ private void startDatabaseLatencyThread() {
+ Thread thread = new DatabaseLatencyThread();
+ thread.start();
+ }
+
+ private class DatabaseLatencyThread extends Thread {
+ @Override
+ public void run() {
+ for (int i = 0; i < NUM_ITERATIONS; i++)
+ {
+ mDatabase.beginTransaction();
+ try {
+ Thread.currentThread().sleep(SLEEP_TIME);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ mDatabase.endTransaction();
+ }
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java
index 68b0b83..a7a1400 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java
@@ -27,6 +27,7 @@ public class DatabaseTests {
suite.addTestSuite(DatabaseStatementTest.class);
suite.addTestSuite(DatabaseLocaleTest.class);
suite.addTestSuite(CursorWindowTest.class);
+ suite.addTestSuite(DatabaseLockTest.class);
return suite;
}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DbSSLSessionCacheTest.java b/tests/AndroidTests/src/com/android/unit_tests/DbSSLSessionCacheTest.java
new file mode 100644
index 0000000..8d7d797
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/DbSSLSessionCacheTest.java
@@ -0,0 +1,259 @@
+/*
+ * 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.unit_tests;
+
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+import com.google.android.net.GoogleHttpClient;
+
+import com.android.internal.net.DbSSLSessionCache;
+import com.android.internal.net.DbSSLSessionCache.DatabaseHelper;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.Certificate;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import javax.security.cert.X509Certificate;
+
+/** Unit test for SSL session caching with {@link GoogleHttpClient}.
+ * Uses network resources.
+ */
+@Suppress
+public class DbSSLSessionCacheTest extends AndroidTestCase {
+
+ protected void setUp() throws Exception {
+ }
+
+ protected void tearDown() throws Exception {
+ }
+
+ /**
+ * We want to test the actual database write - the actual hooking into
+ * low-level SSL is tested.
+ */
+ @LargeTest
+ public void testSslCacheAdd() throws Exception {
+ // Let's verify the database has the rows.
+ // Use internal details of the implementation - could make the field
+ // visible for testing, but it's same.
+
+ // Use default database
+ DbSSLSessionCache cache = DbSSLSessionCache.getInstanceForPackage(getContext());
+ cache.clear();
+
+
+ makeRequestInNewContext("https://www.google.com");
+
+ // Verify the key was inserted
+ SQLiteOpenHelper helper = new DatabaseHelper(getContext());
+ Cursor query = null;
+ try {
+ query = helper.getReadableDatabase().query(DbSSLSessionCache.SSL_CACHE_TABLE,
+ new String[] {"hostport"}, null,
+ null, null, null, null);
+
+ assertTrue(query.moveToFirst()); // one row inserted
+ String hostPort = query.getString(0);
+ assertEquals(hostPort, "www.google.com:443");
+ } finally {
+ query.close();
+ }
+ }
+
+ @LargeTest
+ public void testExpire() throws Exception {
+ DatabaseHelper helper = new DatabaseHelper(getContext());
+ // clean up
+ DbSSLSessionCache cache = new DbSSLSessionCache(helper);
+ cache.clear();
+
+ long t0 = System.currentTimeMillis();
+ for (int i = 0; i < DbSSLSessionCache.MAX_CACHE_SIZE + 2; i++) {
+ final int port = i;
+ cache.putSessionData(new MockSession() {
+
+ public String getPeerHost() {
+ return "test.host.com";
+ }
+
+ public int getPeerPort() {
+ return port;
+ }
+ }, new byte[256]);
+ }
+ long t1 = System.currentTimeMillis();
+
+ System.err.println("Time to insert " +
+ (DbSSLSessionCache.MAX_CACHE_SIZE + 2) + " " + (t1 - t0));
+
+ // first entry should have port 1.
+ Cursor query = helper.getReadableDatabase().query(DbSSLSessionCache.SSL_CACHE_TABLE,
+ new String[] {"hostport", "session"}, null,
+ null, null, null, null);
+
+ int cnt = query.getCount();
+
+ assertTrue(query.moveToFirst()); // one row inserted
+ String hostPort = query.getString(0);
+ assertEquals("test.host.com:2", hostPort);
+ while (query.moveToNext()) {
+ hostPort = query.getString(0);
+ String session = query.getString(1);
+ }
+ long t2 = System.currentTimeMillis();
+ System.err.println("Time to load " + cnt + " " + (t2 - t1));
+
+ query.close();
+ }
+
+ private void makeRequestInNewContext(String url) throws IOException {
+ GoogleHttpClient client = new GoogleHttpClient(getContext(), "Test",
+ false /* no gzip */);
+
+ try {
+ // Note: we must test against a real server, because the connection
+ // gets established before the interceptor can crash the request.
+ HttpGet method = new HttpGet(url);
+ HttpResponse response = client.execute(method);
+ } finally {
+ client.close();
+ }
+ }
+
+ private static class MockSession implements SSLSession {
+
+ public String getPeerHost() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public int getPeerPort() {
+ throw new UnsupportedOperationException();
+ }
+
+
+
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public String getCipherSuite() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public long getCreationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public byte[] getId() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public String getProtocol() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public boolean isValid() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/HtmlTest.java b/tests/AndroidTests/src/com/android/unit_tests/HtmlTest.java
index 26a3ae0..27da4f1 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/HtmlTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/HtmlTest.java
@@ -61,6 +61,10 @@ public class HtmlTest extends TestCase {
s = new SpannableString("Hello world\n\n\nor something");
assertEquals(Html.toHtml(s), "<p>Hello world<br></p>\n<p>or something</p>\n");
+
+ assertEquals("foo\nbar", Html.fromHtml("foo<br>bar").toString());
+ assertEquals("foo\nbar", Html.fromHtml("foo<br>\nbar").toString());
+ assertEquals("foo\nbar", Html.fromHtml("foo<br>\n \nbar").toString());
}
@SmallTest
diff --git a/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java b/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java
index d184543..c436726 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java
@@ -131,20 +131,7 @@ public class MenuTest extends AndroidTestCase {
makeKeyEvent(KeyEvent.KEYCODE_A,
KeyEvent.META_SYM_ON)));
}
-
- @LargeTest
- public void testIsNotShortcutWithMultipleMetas() throws Exception {
- mMenu.setQwertyMode(true);
- mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
- Assert.assertFalse(mMenu.isShortcutKey(
- 'a',
- makeKeyEvent(KeyEvent.KEYCODE_A, KeyEvent.META_SYM_ON & KeyEvent.META_ALT_ON)));
- Assert.assertFalse(mMenu.isShortcutKey(
- 'a', makeKeyEvent(KeyEvent.KEYCODE_A, KeyEvent.META_SYM_ON)));
- Assert.assertFalse(mMenu.isShortcutKey(
- 'a', makeKeyEvent(KeyEvent.KEYCODE_A, KeyEvent.META_SHIFT_ON)));
- }
-
+
@SmallTest
public void testIsShortcutWithUpperCaseAlpha() throws Exception {
mMenu.setQwertyMode(true);
diff --git a/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTestSuite.java b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTestSuite.java
new file mode 100644
index 0000000..3462f97
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTestSuite.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2005 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.unit_tests;
+import android.test.FrameworkTests;
+import android.test.suitebuilder.TestSuiteBuilder;
+
+import junit.framework.TestSuite;
+import junit.framework.TestCase;
+
+public class NewDatabasePerformanceTestSuite extends TestSuite {
+ public static TestSuite suite() {
+ TestSuite suite =
+ new TestSuite(NewDatabasePerformanceTestSuite.class.getName());
+
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ Insert1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InsertIndexed1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ Select100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringComparison100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectIndex100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InnerJoin100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InnerJoinOneSide100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InnerJoinNoIndex100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectSubQIndex100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectIndexStringComparison100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectInteger100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectString100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectIntegerIndex100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectIndexString100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringStartsWith100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ DeleteIndexed1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ Delete1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ DeleteWhere1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ DeleteIndexWhere1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ UpdateIndexWhere1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ UpdateWhere1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InsertInteger10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InsertIntegerIndex10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InsertString10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InsertStringIndexed10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringStartsWith10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringIndexedStartsWith10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectInteger10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectIntegerIndexed10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringContains10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringIndexedContains10000.class);
+
+ return suite;
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTests.java
new file mode 100644
index 0000000..8644fbb
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTests.java
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.content.ContentValues;
+import android.database.sqlite.SQLiteDatabase;
+import android.test.PerformanceTestCase;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.util.Random;
+
+/**
+ * Database Performance Tests
+ *
+ */
+
+public class NewDatabasePerformanceTests {
+
+ // Edit this to change the test run times. The original is 100.
+ final static int kMultiplier = 1;
+
+ public static class PerformanceBase extends TestCase
+ implements PerformanceTestCase {
+ protected static final int CURRENT_DATABASE_VERSION = 42;
+ protected SQLiteDatabase mDatabase;
+ protected File mDatabaseFile;
+
+ public void setUp() {
+ mDatabaseFile = new File("/sdcard", "perf_database_test.db");
+ if (mDatabaseFile.exists()) {
+ mDatabaseFile.delete();
+ }
+ mDatabase =
+ SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(),
+ null);
+ assertTrue(mDatabase != null);
+ mDatabase.setVersion(CURRENT_DATABASE_VERSION);
+ }
+
+ public void tearDown() {
+ mDatabase.close();
+ mDatabaseFile.delete();
+ }
+
+ public boolean isPerformanceOnly() {
+ return true;
+ }
+
+ // These tests can only be run once.
+ public int startPerformance(Intermediates intermediates) {
+ return 0;
+ }
+
+ public String numberName(int number) {
+ String result = "";
+
+ if (number >= 1000) {
+ result += numberName((number / 1000)) + " thousand";
+ number = (number % 1000);
+
+ if (number > 0) result += " ";
+ }
+
+ if (number >= 100) {
+ result += ONES[(number / 100)] + " hundred";
+ number = (number % 100);
+
+ if (number > 0) result += " ";
+ }
+
+ if (number >= 20) {
+ result += TENS[(number / 10)];
+ number = (number % 10);
+
+ if (number > 0) result += " ";
+ }
+
+ if (number > 0) {
+ result += ONES[number];
+ }
+
+ return result;
+ }
+ }
+
+ /**
+ * Test 1000 inserts.
+ */
+
+ public static class Insert1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+
+ private String[] statements = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ statements[i] =
+ "INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')";
+ }
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.execSQL(statements[i]);
+ }
+ }
+ }
+
+ /**
+ * Test 1000 inserts into an indexed table.
+ */
+
+ public static class InsertIndexed1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+
+ private String[] statements = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ statements[i] =
+ "INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')";
+ }
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.execSQL(statements[i]);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs without an index
+ */
+
+ public static class Select100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on a string comparison
+ */
+
+ public static class SelectStringComparison100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ where[i] = "c LIKE '" + numberName(i) + "'";
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs with an index
+ */
+
+ public static class SelectIndex100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * INNER JOIN without an index
+ */
+
+ public static class InnerJoin100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"t1.a"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase
+ .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+ }
+
+ public void testRun() {
+ mDatabase.query("t1 INNER JOIN t2 ON t1.b = t2.b", COLUMNS, null,
+ null, null, null, null);
+ }
+ }
+
+ /**
+ * INNER JOIN without an index on one side
+ */
+
+ public static class InnerJoinOneSide100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"t1.a"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase
+ .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+ }
+
+ public void testRun() {
+ mDatabase.query("t1 INNER JOIN t2 ON t1.b = t2.b", COLUMNS, null,
+ null, null, null, null);
+ }
+ }
+
+ /**
+ * INNER JOIN without an index on one side
+ */
+
+ public static class InnerJoinNoIndex100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"t1.a"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase
+ .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+ }
+
+ public void testRun() {
+ mDatabase.query("t1 INNER JOIN t2 ON t1.c = t2.c", COLUMNS, null,
+ null, null, null, null);
+ }
+ }
+
+ /**
+ * 100 SELECTs with subqueries. Subquery is using an index
+ */
+
+ public static class SelectSubQIndex100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"t1.a"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase
+ .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ mDatabase.execSQL("CREATE INDEX i2b ON t2(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] =
+ "t1.b IN (SELECT t2.b FROM t2 WHERE t2.b >= " + lower
+ + " AND t2.b < " + upper + ")";
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on string comparison with Index
+ */
+
+ public static class SelectIndexStringComparison100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i3c ON t1(c)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ where[i] = "c LIKE '" + numberName(i) + "'";
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on integer
+ */
+
+ public static class SelectInteger100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"b"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on String
+ */
+
+ public static class SelectString100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"c"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on integer with index
+ */
+
+ public static class SelectIntegerIndex100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"b"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1b on t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on String with index
+ */
+
+ public static class SelectIndexString100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"c"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on String with starts with
+ */
+
+ public static class SelectStringStartsWith100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"c"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ where[i] = "c LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 1000 Deletes on an indexed table
+ */
+
+ public static class DeleteIndexed1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private static final String[] COLUMNS = {"c"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i3c ON t1(c)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.delete("t1", null, null);
+ }
+ }
+ }
+
+ /**
+ * 1000 Deletes
+ */
+
+ public static class Delete1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private static final String[] COLUMNS = {"c"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.delete("t1", null, null);
+ }
+ }
+ }
+
+ /**
+ * 1000 DELETE's without an index with where clause
+ */
+
+ public static class DeleteWhere1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.delete("t1", where[i], null);
+ }
+ }
+ }
+
+ /**
+ * 1000 DELETE's with an index with where clause
+ */
+
+ public static class DeleteIndexWhere1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.delete("t1", where[i], null);
+ }
+ }
+ }
+
+ /**
+ * 1000 update's with an index with where clause
+ */
+
+ public static class UpdateIndexWhere1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private String[] where = new String[SIZE];
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ ContentValues b = new ContentValues(1);
+ b.put("b", upper);
+ mValues[i] = b;
+
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.update("t1", mValues[i], where[i], null);
+ }
+ }
+ }
+
+ /**
+ * 1000 update's without an index with where clause
+ */
+
+ public static class UpdateWhere1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private String[] where = new String[SIZE];
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ ContentValues b = new ContentValues(1);
+ b.put("b", upper);
+ mValues[i] = b;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.update("t1", mValues[i], where[i], null);
+ }
+ }
+ }
+
+ /**
+ * 10000 inserts for an integer
+ */
+
+ public static class InsertInteger10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ ContentValues b = new ContentValues(1);
+ b.put("a", r);
+ mValues[i] = b;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.insert("t1", null, mValues[i]);
+ }
+ }
+ }
+
+ /**
+ * 10000 inserts for an integer -indexed table
+ */
+
+ public static class InsertIntegerIndex10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER)");
+ mDatabase.execSQL("CREATE INDEX i1a ON t1(a)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ ContentValues b = new ContentValues(1);
+ b.put("a", r);
+ mValues[i] = b;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.insert("t1", null, mValues[i]);
+ }
+ }
+ }
+
+ /**
+ * 10000 inserts for a String
+ */
+
+ public static class InsertString10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ ContentValues b = new ContentValues(1);
+ b.put("a", numberName(r));
+ mValues[i] = b;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.insert("t1", null, mValues[i]);
+ }
+ }
+ }
+
+ /**
+ * 10000 inserts for a String - indexed table
+ */
+
+ public static class InsertStringIndexed10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1a ON t1(a)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ ContentValues b = new ContentValues(1);
+ b.put("a", numberName(r));
+ mValues[i] = b;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.insert("t1", null, mValues[i]);
+ }
+ }
+ }
+
+
+ /**
+ * 10000 selects for a String -starts with
+ */
+
+ public static class SelectStringStartsWith10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t3.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t3 VALUES('"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ where[i] = "a LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 10000 selects for a String - indexed table -starts with
+ */
+
+ public static class SelectStringIndexedStartsWith10000 extends
+ PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t3.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i3a ON t3(a)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t3 VALUES('"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ where[i] = "a LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 10000 selects for an integer -
+ */
+
+ public static class SelectInteger10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t4.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t4(a INTEGER)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t4 VALUES(" + r + ")");
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "a >= " + lower + " AND a < " + upper;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t4", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 10000 selects for an integer -indexed table
+ */
+
+ public static class SelectIntegerIndexed10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t4.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t4(a INTEGER)");
+ mDatabase.execSQL("CREATE INDEX i4a ON t4(a)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t4 VALUES(" + r + ")");
+
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "a >= " + lower + " AND a < " + upper;
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t4", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+
+ /**
+ * 10000 selects for a String - contains 'e'
+ */
+
+ public static class SelectStringContains10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t3.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t3 VALUES('"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ where[i] = "a LIKE '*e*'";
+
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 10000 selects for a String - contains 'e'-indexed table
+ */
+
+ public static class SelectStringIndexedContains10000 extends
+ PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t3.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i3a ON t3(a)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t3 VALUES('"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ where[i] = "a LIKE '*e*'";
+
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ public static final String[] ONES =
+ {"zero", "one", "two", "three", "four", "five", "six", "seven",
+ "eight", "nine", "ten", "eleven", "twelve", "thirteen",
+ "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
+ "nineteen"};
+
+ public static final String[] TENS =
+ {"", "ten", "twenty", "thirty", "forty", "fifty", "sixty",
+ "seventy", "eighty", "ninety"};
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SSLClientSessionCacheFactoryTest.java b/tests/AndroidTests/src/com/android/unit_tests/SSLClientSessionCacheFactoryTest.java
new file mode 100644
index 0000000..5d7349f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SSLClientSessionCacheFactoryTest.java
@@ -0,0 +1,54 @@
+package com.android.unit_tests;
+
+import com.google.android.net.SSLClientSessionCacheFactory;
+import com.android.internal.net.DbSSLSessionCache;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+
+/**
+ * Unit test for {@link SSLClientSessionCacheFactory}.
+ */
+@MediumTest
+public final class SSLClientSessionCacheFactoryTest extends AndroidTestCase {
+
+ protected void tearDown() throws Exception {
+ setSslSessionCacheValue(getContext(), "");
+ super.tearDown();
+ }
+
+ private static void setSslSessionCacheValue(Context context, String value) {
+ ContentResolver resolver = context.getContentResolver();
+ Settings.Gservices.putString(resolver, Settings.Gservices.SSL_SESSION_CACHE, value);
+ }
+
+ private static SSLClientSessionCache getCache(Context context, String type) {
+ setSslSessionCacheValue(context, type);
+ return SSLClientSessionCacheFactory.getCache(context);
+ }
+
+ public void testGetDbCache() throws Exception {
+ Context context = getContext();
+ SSLClientSessionCache cache = getCache(context, "db");
+ assertNotNull(cache);
+ assertTrue(cache instanceof DbSSLSessionCache);
+ }
+
+ public void testGetFileCache() throws Exception {
+ Context context = getContext();
+ SSLClientSessionCache cache = getCache(context, "file");
+ assertNotNull(cache);
+ // yuck =)
+ assertEquals("org.apache.harmony.xnet.provider.jsse.FileClientSessionCache$Impl",
+ cache.getClass().getName());
+ }
+
+ public void testGetNoCache() throws Exception {
+ Context context = getContext();
+ SSLClientSessionCache cache = getCache(context, "none");
+ assertNull(cache);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java
index 8c1c91f..51e841c 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java
@@ -262,7 +262,7 @@ public class TextUtilsTest extends TestCase {
Map<String, String> fixes = Maps.newHashMap();
fixes.put("a", "<a@gmail.com>");
fixes.put("a b", "<ab@gmail.com>");
- fixes.put("a@b", "<a@gmail.com>");
+ fixes.put("a@b", "<a@b>");
for (Map.Entry<String, String> e : fixes.entrySet()) {
assertEquals(e.getValue(), validator.fixText(e.getKey()).toString());
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java
index d7d8c89..ab91761 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java
@@ -18,6 +18,8 @@ package com.android.unit_tests.activity;
import android.app.ActivityManager;
import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.content.res.Configuration;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.Suppress;
@@ -90,6 +92,24 @@ public class ActivityManagerTest extends AndroidTestCase {
// test: confirm our ANR'ing application shows up in the list
}
+ @SmallTest
+ public void testGetDeviceConfigurationInfo() throws Exception {
+ ConfigurationInfo config = mActivityManager.getDeviceConfigurationInfo();
+ assertNotNull(config);
+ // Validate values against configuration retrieved from resources
+ Configuration vconfig = mContext.getResources().getConfiguration();
+ assertNotNull(vconfig);
+ assertEquals(config.reqKeyboardType, vconfig.keyboard);
+ assertEquals(config.reqTouchScreen, vconfig.touchscreen);
+ assertEquals(config.reqNavigation, vconfig.navigation);
+ if (vconfig.navigation == Configuration.NAVIGATION_NONAV) {
+ assertNotNull(config.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV);
+ }
+ if (vconfig.keyboard != Configuration.KEYBOARD_UNDEFINED) {
+ assertNotNull(config.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD);
+ }
+ }
+
// If any entries in appear in the list, sanity check them against all running applications
private void checkErrorListSanity(List<ActivityManager.ProcessErrorStateInfo> errList) {
if (errList == null) return;
diff --git a/tests/CoreTests/android/Android.mk b/tests/CoreTests/android/Android.mk
index 3b80228..e6b5c45 100644
--- a/tests/CoreTests/android/Android.mk
+++ b/tests/CoreTests/android/Android.mk
@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := eng tests
+LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
$(call all-subdir-java-files)
diff --git a/tests/CoreTests/android/AndroidManifest.xml b/tests/CoreTests/android/AndroidManifest.xml
index 8c642f4..4809f844 100644
--- a/tests/CoreTests/android/AndroidManifest.xml
+++ b/tests/CoreTests/android/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
+ <uses-permission android:name="android.permission.BROADCAST_STICKY" />
<!-- location test permissions -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
diff --git a/tests/CoreTests/android/core/DatabaseSessionCache.java b/tests/CoreTests/android/core/DatabaseSessionCache.java
new file mode 100644
index 0000000..c344d9c
--- /dev/null
+++ b/tests/CoreTests/android/core/DatabaseSessionCache.java
@@ -0,0 +1,312 @@
+// Copyright 2009 The Android Open Source Project
+
+package android.core;
+
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+import android.content.ContentValues;
+import android.content.Context;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.net.ssl.SSLSession;
+
+/**
+ * Hook into harmony SSL cache to persist the SSL sessions.
+ *
+ * Current implementation is suitable for saving a small number of hosts -
+ * like google services. It can be extended with expiration and more features
+ * to support more hosts.
+ *
+ * {@hide}
+ */
+public class DatabaseSessionCache implements SSLClientSessionCache {
+ private static final String TAG = "SslSessionCache";
+ static DatabaseHelper sDefaultDatabaseHelper;
+
+ private DatabaseHelper mDatabaseHelper;
+
+ /**
+ * Table where sessions are stored.
+ */
+ public static final String SSL_CACHE_TABLE = "ssl_sessions";
+
+ private static final String SSL_CACHE_ID = "_id";
+
+ /**
+ * Key is host:port - port is not optional.
+ */
+ private static final String SSL_CACHE_HOSTPORT = "hostport";
+
+ /**
+ * Base64-encoded DER value of the session.
+ */
+ private static final String SSL_CACHE_SESSION = "session";
+
+ /**
+ * Time when the record was added - should be close to the time
+ * of the initial session negotiation.
+ */
+ private static final String SSL_CACHE_TIME_SEC = "time_sec";
+
+ public static final String DATABASE_NAME = "ssl_sessions.db";
+
+ public static final int DATABASE_VERSION = 1;
+
+ /** public for testing
+ */
+ public static final int SSL_CACHE_ID_COL = 0;
+ public static final int SSL_CACHE_HOSTPORT_COL = 1;
+ public static final int SSL_CACHE_SESSION_COL = 2;
+ public static final int SSL_CACHE_TIME_SEC_COL = 3;
+
+ private static final String SAVE_ON_ADD = "save_on_add";
+
+ static boolean sHookInitializationDone = false;
+
+ public static final int MAX_CACHE_SIZE = 256;
+
+ private static final Map<String, byte[]> mExternalCache =
+ new LinkedHashMap<String, byte[]>(MAX_CACHE_SIZE, 0.75f, true) {
+ @Override
+ public boolean removeEldestEntry(
+ Map.Entry<String, byte[]> eldest) {
+ boolean shouldDelete = this.size() > MAX_CACHE_SIZE;
+
+ // TODO: delete from DB
+ return shouldDelete;
+ }
+ };
+ static boolean mNeedsCacheLoad = true;
+
+ public static final String[] PROJECTION = new String[] {
+ SSL_CACHE_ID,
+ SSL_CACHE_HOSTPORT,
+ SSL_CACHE_SESSION,
+ SSL_CACHE_TIME_SEC
+ };
+
+ /**
+ * This class needs to be installed as a hook, if the security property
+ * is set. Getting the right classloader may be fun since we don't use
+ * Provider to get its classloader, but in android this is in same
+ * loader with AndroidHttpClient.
+ *
+ * This constructor will use the default database. You must
+ * call init() before to specify the context used for the database and
+ * check settings.
+ */
+ public DatabaseSessionCache() {
+ Log.v(TAG, "Instance created.");
+ // May be null if caching is disabled - no sessions will be persisted.
+ this.mDatabaseHelper = sDefaultDatabaseHelper;
+ }
+
+ /**
+ * Create a SslSessionCache instance, using the specified context to
+ * initialize the database.
+ *
+ * This constructor will use the default database - created the first
+ * time.
+ *
+ * @param activityContext
+ */
+ public DatabaseSessionCache(Context activityContext) {
+ // Static init - only one initialization will happen.
+ // Each SslSessionCache is using the same DB.
+ init(activityContext);
+ // May be null if caching is disabled - no sessions will be persisted.
+ this.mDatabaseHelper = sDefaultDatabaseHelper;
+ }
+
+ /**
+ * Create a SslSessionCache that uses a specific database.
+ *
+ * @param database
+ */
+ public DatabaseSessionCache(DatabaseHelper database) {
+ this.mDatabaseHelper = database;
+ }
+
+// public static boolean enabled(Context androidContext) {
+// String sslCache = Settings.Gservices.getString(androidContext.getContentResolver(),
+// Settings.Gservices.SSL_SESSION_CACHE);
+//
+// if (Log.isLoggable(TAG, Log.DEBUG)) {
+// Log.d(TAG, "enabled " + sslCache + " " + androidContext.getPackageName());
+// }
+//
+// return SAVE_ON_ADD.equals(sslCache);
+// }
+
+ /**
+ * You must call this method to enable SSL session caching for an app.
+ */
+ public synchronized static void init(Context activityContext) {
+ // It is possible that multiple provider will try to install this hook.
+ // We want a single db per VM.
+ if (sHookInitializationDone) {
+ return;
+ }
+
+
+// // More values can be added in future to provide different
+// // behaviours, like 'batch save'.
+// if (enabled(activityContext)) {
+ Context appContext = activityContext.getApplicationContext();
+ sDefaultDatabaseHelper = new DatabaseHelper(appContext);
+
+ // Set default SSLSocketFactory
+ // The property is defined in the javadocs for javax.net.SSLSocketFactory
+ // (no constant defined there)
+ // This should cover all code using SSLSocketFactory.getDefault(),
+ // including native http client and apache httpclient.
+ // MCS is using its own custom factory - will need special code.
+// Security.setProperty("ssl.SocketFactory.provider",
+// SslSocketFactoryWithCache.class.getName());
+// }
+
+ // Won't try again.
+ sHookInitializationDone = true;
+ }
+
+ public void putSessionData(SSLSession session, byte[] der) {
+ if (mDatabaseHelper == null) {
+ return;
+ }
+ if (mExternalCache.size() > MAX_CACHE_SIZE) {
+ // remove oldest.
+ Cursor byTime = mDatabaseHelper.getWritableDatabase().query(SSL_CACHE_TABLE,
+ PROJECTION, null, null, null, null, SSL_CACHE_TIME_SEC);
+ byTime.moveToFirst();
+ // TODO: can I do byTime.deleteRow() ?
+ String hostPort = byTime.getString(SSL_CACHE_HOSTPORT_COL);
+
+ mDatabaseHelper.getWritableDatabase().delete(SSL_CACHE_TABLE,
+ SSL_CACHE_HOSTPORT + "= ?" , new String[] { hostPort });
+ }
+ // Serialize native session to standard DER encoding
+ long t0 = System.currentTimeMillis();
+
+ String b64 = new String(Base64.encodeBase64(der));
+ String key = session.getPeerHost() + ":" + session.getPeerPort();
+
+ ContentValues values = new ContentValues();
+ values.put(SSL_CACHE_HOSTPORT, key);
+ values.put(SSL_CACHE_SESSION, b64);
+ values.put(SSL_CACHE_TIME_SEC, System.currentTimeMillis() / 1000);
+
+ synchronized (this.getClass()) {
+ mExternalCache.put(key, der);
+
+ try {
+ mDatabaseHelper.getWritableDatabase().insert(SSL_CACHE_TABLE, null /*nullColumnHack */ , values);
+ } catch(SQLException ex) {
+ // Ignore - nothing we can do to recover, and caller shouldn't
+ // be affected.
+ Log.w(TAG, "Ignoring SQL exception when caching session", ex);
+ }
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ long t1 = System.currentTimeMillis();
+ Log.d(TAG, "New SSL session " + session.getPeerHost() +
+ " DER len: " + der.length + " " + (t1 - t0));
+ }
+
+ }
+
+ public byte[] getSessionData(String host, int port) {
+ // Current (simple) implementation does a single lookup to DB, then saves
+ // all entries to the cache.
+
+ // This works for google services - i.e. small number of certs.
+ // If we extend this to all processes - we should hold a separate cache
+ // or do lookups to DB each time.
+ if (mDatabaseHelper == null) {
+ return null;
+ }
+ synchronized(this.getClass()) {
+ if (mNeedsCacheLoad) {
+ // Don't try to load again, if something is wrong on the first
+ // request it'll likely be wrong each time.
+ mNeedsCacheLoad = false;
+ long t0 = System.currentTimeMillis();
+
+ Cursor cur = null;
+ try {
+ cur = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE, PROJECTION, null,
+ null, null, null, null);
+ if (cur.moveToFirst()) {
+ do {
+ String hostPort = cur.getString(SSL_CACHE_HOSTPORT_COL);
+ String value = cur.getString(SSL_CACHE_SESSION_COL);
+
+ if (hostPort == null || value == null) {
+ continue;
+ }
+ // TODO: blob support ?
+ byte[] der = Base64.decodeBase64(value.getBytes());
+ mExternalCache.put(hostPort, der);
+ } while (cur.moveToNext());
+
+ }
+ } catch (SQLException ex) {
+ Log.d(TAG, "Error loading SSL cached entries ", ex);
+ } finally {
+ if (cur != null) {
+ cur.close();
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ long t1 = System.currentTimeMillis();
+ Log.d(TAG, "LOADED CACHED SSL " + (t1 - t0) + " ms");
+ }
+ }
+ }
+
+ String key = host + ":" + port;
+
+ return mExternalCache.get(key);
+ }
+ }
+
+ public byte[] getSessionData(byte[] id) {
+ // We support client side only - the cache will do nothing on client.
+ return null;
+ }
+
+ /** Visible for testing.
+ */
+ public static class DatabaseHelper extends SQLiteOpenHelper {
+
+ public DatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null /* factory */, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + SSL_CACHE_TABLE + " (" +
+ SSL_CACHE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+ SSL_CACHE_HOSTPORT + " TEXT UNIQUE ON CONFLICT REPLACE," +
+ SSL_CACHE_SESSION + " TEXT," +
+ SSL_CACHE_TIME_SEC + " INTEGER" +
+ ");");
+ db.execSQL("CREATE INDEX ssl_sessions_idx1 ON ssl_sessions (" +
+ SSL_CACHE_HOSTPORT + ");");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL("DROP TABLE IF EXISTS " + SSL_CACHE_TABLE );
+ onCreate(db);
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/tests/CoreTests/android/core/SSLPerformanceTest.java b/tests/CoreTests/android/core/SSLPerformanceTest.java
new file mode 100644
index 0000000..e2bd9c5
--- /dev/null
+++ b/tests/CoreTests/android/core/SSLPerformanceTest.java
@@ -0,0 +1,432 @@
+/*
+ * 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 android.core;
+
+import android.test.AndroidTestCase;
+import android.os.Debug;
+import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.impl.conn.SingleClientConnManager;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.HttpResponse;
+
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.security.cert.Certificate;
+import java.security.Principal;
+import java.security.KeyManagementException;
+import java.util.Arrays;
+
+public class SSLPerformanceTest extends AndroidTestCase {
+
+ static final byte[] SESSION_DATA = new byte[6000];
+ static {
+ for (int i = 0; i < SESSION_DATA.length; i++) {
+ SESSION_DATA[i] = (byte) i;
+ }
+ }
+
+ static final File dataDir = new File("/data/data/android.core/");
+ static final File filesDir = new File(dataDir, "files");
+ static final File dbDir = new File(dataDir, "databases");
+
+ static final String CACHE_DIR
+ = SSLPerformanceTest.class.getName() + "/cache";
+
+ static final int ITERATIONS = 10;
+
+ public void testCreateNewEmptyDatabase() {
+ deleteDatabase();
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+ cache.getSessionData("crazybob.org", 443);
+
+ stopwatch.stop();
+ }
+
+ public void testCreateNewEmptyDirectory() throws IOException {
+ deleteDirectory();
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ cache.getSessionData("crazybob.org", 443);
+
+ stopwatch.stop();
+ }
+
+ public void testOpenDatabaseWith10Sessions() {
+ deleteDatabase();
+
+ DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+ putSessionsIn(cache);
+ closeDatabase();
+
+ System.err.println("Size of ssl_sessions.db w/ 10 sessions: "
+ + new File(dbDir, "ssl_sessions.db").length());
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ cache = new DatabaseSessionCache(getContext());
+ cache.getSessionData("crazybob.org", 443);
+
+ stopwatch.stop();
+ }
+
+ public void testOpenDirectoryWith10Sessions() throws IOException {
+ deleteDirectory();
+
+ SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ putSessionsIn(cache);
+ closeDirectoryCache();
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ cache.getSessionData("crazybob.org", 443);
+
+ stopwatch.stop();
+ }
+
+ public void testGetSessionFromDatabase() {
+ deleteDatabase();
+
+ DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+ cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+ closeDatabase();
+
+ cache = new DatabaseSessionCache(getContext());
+ cache.getSessionData("crazybob.org", 443);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ byte[] sessionData = cache.getSessionData("foo", 443);
+
+ stopwatch.stop();
+
+ assertTrue(Arrays.equals(SESSION_DATA, sessionData));
+ }
+
+ public void testGetSessionFromDirectory() throws IOException {
+ deleteDirectory();
+
+ SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+ closeDirectoryCache();
+
+ cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ cache.getSessionData("crazybob.org", 443);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ byte[] sessionData = cache.getSessionData("foo", 443);
+
+ stopwatch.stop();
+
+ assertTrue(Arrays.equals(SESSION_DATA, sessionData));
+ }
+
+ public void testPutSessionIntoDatabase() {
+ deleteDatabase();
+
+ DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+ cache.getSessionData("crazybob.org", 443);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+
+ stopwatch.stop();
+ }
+
+ public void testPutSessionIntoDirectory() throws IOException {
+ deleteDirectory();
+
+ SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ cache.getSessionData("crazybob.org", 443);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+
+ stopwatch.stop();
+ }
+
+ public void testEngineInit() throws IOException, KeyManagementException {
+ Stopwatch stopwatch = new Stopwatch();
+
+ new SSLContextImpl().engineInit(null, null, null);
+
+ stopwatch.stop();
+ }
+
+ public void testWebRequestWithoutCache() throws IOException,
+ KeyManagementException {
+ SSLContextImpl sslContext = new SSLContextImpl();
+ sslContext.engineInit(null, null, null);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ getVerisignDotCom(sslContext);
+
+ stopwatch.stop();
+ }
+
+ public void testWebRequestWithFileCache() throws IOException,
+ KeyManagementException {
+ deleteDirectory();
+
+ SSLContextImpl sslContext = new SSLContextImpl();
+ sslContext.engineInit(null, null, null,
+ FileClientSessionCache.usingDirectory(getCacheDirectory()),
+ null);
+
+ // Make sure www.google.com is in the cache.
+ getVerisignDotCom(sslContext);
+
+ // Re-initialize so we hit the file cache.
+ sslContext.engineInit(null, null, null,
+ FileClientSessionCache.usingDirectory(getCacheDirectory()),
+ null);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ getVerisignDotCom(sslContext);
+
+ stopwatch.stop();
+ }
+
+ public void testWebRequestWithInMemoryCache() throws IOException,
+ KeyManagementException {
+ deleteDirectory();
+
+ SSLContextImpl sslContext = new SSLContextImpl();
+ sslContext.engineInit(null, null, null);
+
+ // Make sure www.google.com is in the cache.
+ getVerisignDotCom(sslContext);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ getVerisignDotCom(sslContext);
+
+ stopwatch.stop();
+ }
+
+ private void getVerisignDotCom(SSLContextImpl sslContext)
+ throws IOException {
+ SchemeRegistry schemeRegistry = new SchemeRegistry();
+ schemeRegistry.register(new Scheme("https",
+ new SSLSocketFactory(sslContext.engineGetSocketFactory()),
+ 443));
+
+ ClientConnectionManager manager =
+ new SingleClientConnManager(null, schemeRegistry);
+
+ new DefaultHttpClient(manager, null).execute(
+ new HttpGet("https://www.verisign.com"),
+ new ResponseHandler<Object>() {
+ public Object handleResponse(HttpResponse response)
+ throws ClientProtocolException, IOException {
+ return null;
+ }
+ });
+ }
+
+ private void putSessionsIn(SSLClientSessionCache cache) {
+ for (int i = 0; i < 10; i++) {
+ cache.putSessionData(new FakeSession("host" + i), SESSION_DATA);
+ }
+ }
+
+ private void deleteDatabase() {
+ closeDatabase();
+ if (!new File(dbDir, "ssl_sessions.db").delete()) {
+ System.err.println("Failed to delete database.");
+ }
+ }
+
+ private void closeDatabase() {
+ if (DatabaseSessionCache.sDefaultDatabaseHelper != null) {
+ DatabaseSessionCache.sDefaultDatabaseHelper.close();
+ }
+ DatabaseSessionCache.sDefaultDatabaseHelper = null;
+ DatabaseSessionCache.sHookInitializationDone = false;
+ DatabaseSessionCache.mNeedsCacheLoad = true;
+ }
+
+ private void deleteDirectory() {
+ closeDirectoryCache();
+
+ File dir = getCacheDirectory();
+ if (!dir.exists()) {
+ return;
+ }
+ for (File file : dir.listFiles()) {
+ file.delete();
+ }
+ if (!dir.delete()) {
+ System.err.println("Failed to delete directory.");
+ }
+ }
+
+ private void closeDirectoryCache() {
+ try {
+ Method reset = FileClientSessionCache.class
+ .getDeclaredMethod("reset");
+ reset.setAccessible(true);
+ reset.invoke(null);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private File getCacheDirectory() {
+ return new File(getContext().getFilesDir(), CACHE_DIR);
+ }
+
+ class Stopwatch {
+ {
+ Debug.startAllocCounting();
+ }
+ long start = System.nanoTime();
+
+ void stop() {
+ long elapsed = (System.nanoTime() - start) / 1000;
+ Debug.stopAllocCounting();
+ System.err.println(getName() + ": " + elapsed + "us, "
+ + Debug.getThreadAllocCount() + " allocations, "
+ + Debug.getThreadAllocSize() + " bytes");
+ }
+ }
+}
+
+class FakeSession implements SSLSession {
+ final String host;
+
+ FakeSession(String host) {
+ this.host = host;
+ }
+
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getCipherSuite() {
+ throw new UnsupportedOperationException();
+ }
+
+ public long getCreationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ public byte[] getId() {
+ return host.getBytes();
+ }
+
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Certificate[] getPeerCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getPeerHost() {
+ return host;
+ }
+
+ public int getPeerPort() {
+ return 443;
+ }
+
+ public Principal getPeerPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getProtocol() {
+ throw new UnsupportedOperationException();
+ }
+
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isValid() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/tests/CoreTests/android/core/SSLSocketTest.java b/tests/CoreTests/android/core/SSLSocketTest.java
index 922090a..088fa8c 100644
--- a/tests/CoreTests/android/core/SSLSocketTest.java
+++ b/tests/CoreTests/android/core/SSLSocketTest.java
@@ -19,9 +19,13 @@ package android.core;
import junit.framework.TestCase;
import org.apache.commons.codec.binary.Base64;
+import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -29,18 +33,28 @@ import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.KeyStore;
+import java.security.KeyManagementException;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.Random;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
+/**
+ * SSL integration tests that hit real servers.
+ */
public class SSLSocketTest extends TestCase {
private static SSLSocketFactory clientFactory =
@@ -61,13 +75,15 @@ public class SSLSocketTest extends TestCase {
* @param delay The delay after each request (in seconds).
* @throws IOException When a problem occurs.
*/
- private void fetch(String host, int port, boolean secure, String path,
- int outerLoop, int innerLoop, int delay, int timeout) throws IOException {
+ private void fetch(SSLSocketFactory socketFactory, String host, int port,
+ boolean secure, String path, int outerLoop, int innerLoop,
+ int delay, int timeout) throws IOException {
InetSocketAddress address = new InetSocketAddress(host, port);
for (int i = 0; i < outerLoop; i++) {
// Connect to the remote host
- Socket socket = secure ? clientFactory.createSocket() : new Socket();
+ Socket socket = secure ? socketFactory.createSocket()
+ : new Socket();
if (timeout >= 0) {
socket.setKeepAlive(true);
socket.setSoTimeout(timeout * 1000);
@@ -159,6 +175,16 @@ public class SSLSocketTest extends TestCase {
}
/**
+ * Invokes fetch() with the default socket factory.
+ */
+ private void fetch(String host, int port, boolean secure, String path,
+ int outerLoop, int innerLoop,
+ int delay, int timeout) throws IOException {
+ fetch(clientFactory, host, port, secure, path, outerLoop, innerLoop,
+ delay, timeout);
+ }
+
+ /**
* Does a single request for each of the hosts. Consumes the response.
*
* @throws IOException If a problem occurs.
@@ -619,13 +645,17 @@ public class SSLSocketTest extends TestCase {
public void run() {
try {
- KeyManager[] keyManagers = provideKeys ? getKeyManagers(SERVER_KEYS_BKS) : null;
- TrustManager[] trustManagers = new TrustManager[] { trustManager };
+ KeyManager[] keyManagers = provideKeys
+ ? getKeyManagers(SERVER_KEYS_BKS) : null;
+ TrustManager[] trustManagers = new TrustManager[] {
+ trustManager };
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
- SSLServerSocket serverSocket = (SSLServerSocket)sslContext.getServerSocketFactory().createServerSocket();
+ SSLServerSocket serverSocket
+ = (SSLServerSocket) sslContext.getServerSocketFactory()
+ .createServerSocket();
if (clientAuth == CLIENT_AUTH_WANTED) {
serverSocket.setWantClientAuth(true);
@@ -637,14 +667,15 @@ public class SSLSocketTest extends TestCase {
serverSocket.bind(new InetSocketAddress(port));
- SSLSocket clientSocket = (SSLSocket)serverSocket.accept();
+ SSLSocket clientSocket = (SSLSocket) serverSocket.accept();
InputStream stream = clientSocket.getInputStream();
for (int i = 0; i < 256; i++) {
int j = stream.read();
if (i != j) {
- throw new RuntimeException("Error reading socket, expected " + i + ", got " + j);
+ throw new RuntimeException("Error reading socket,"
+ + " expected " + i + ", got " + j);
}
}
@@ -690,13 +721,16 @@ public class SSLSocketTest extends TestCase {
public void run() {
try {
- KeyManager[] keyManagers = provideKeys ? getKeyManagers(CLIENT_KEYS_BKS) : null;
- TrustManager[] trustManagers = new TrustManager[] { trustManager };
+ KeyManager[] keyManagers = provideKeys
+ ? getKeyManagers(CLIENT_KEYS_BKS) : null;
+ TrustManager[] trustManagers = new TrustManager[] {
+ trustManager };
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
- SSLSocket socket = (SSLSocket)sslContext.getSocketFactory().createSocket();
+ SSLSocket socket = (SSLSocket) sslContext.getSocketFactory()
+ .createSocket();
socket.connect(new InetSocketAddress(port));
socket.startHandshake();
@@ -867,6 +901,189 @@ public class SSLSocketTest extends TestCase {
fail("SSL handshake should have failed.");
}
}
-
-
+
+ /**
+ * Tests our in-memory and persistent caching support.
+ */
+ public void testClientSessionCaching() throws IOException,
+ KeyManagementException {
+ SSLContextImpl context = new SSLContextImpl();
+
+ // Cache size = 2.
+ FakeClientSessionCache fakeCache = new FakeClientSessionCache();
+ context.engineInit(null, null, null, fakeCache, null);
+ SSLSocketFactory socketFactory = context.engineGetSocketFactory();
+ context.engineGetClientSessionContext().setSessionCacheSize(2);
+ makeRequests(socketFactory);
+ List<String> smallCacheOps = Arrays.asList(
+ "get www.fortify.net",
+ "put www.fortify.net",
+ "get www.paypal.com",
+ "put www.paypal.com",
+ "get www.yellownet.ch",
+ "put www.yellownet.ch",
+
+ // At this point, all in-memory cache requests should miss,
+ // but the sessions will still be in the persistent cache.
+ "get www.fortify.net",
+ "get www.paypal.com",
+ "get www.yellownet.ch"
+ );
+ assertEquals(smallCacheOps, fakeCache.ops);
+
+ // Cache size = 3.
+ fakeCache = new FakeClientSessionCache();
+ context.engineInit(null, null, null, fakeCache, null);
+ socketFactory = context.engineGetSocketFactory();
+ context.engineGetClientSessionContext().setSessionCacheSize(3);
+ makeRequests(socketFactory);
+ List<String> bigCacheOps = Arrays.asList(
+ "get www.fortify.net",
+ "put www.fortify.net",
+ "get www.paypal.com",
+ "put www.paypal.com",
+ "get www.yellownet.ch",
+ "put www.yellownet.ch"
+
+ // At this point, all results should be in the in-memory
+ // cache, and the persistent cache shouldn't be hit anymore.
+ );
+ assertEquals(bigCacheOps, fakeCache.ops);
+
+ // Cache size = 4.
+ fakeCache = new FakeClientSessionCache();
+ context.engineInit(null, null, null, fakeCache, null);
+ socketFactory = context.engineGetSocketFactory();
+ context.engineGetClientSessionContext().setSessionCacheSize(4);
+ makeRequests(socketFactory);
+ assertEquals(bigCacheOps, fakeCache.ops);
+ }
+
+ /**
+ * Executes sequence of requests twice using given socket factory.
+ */
+ private void makeRequests(SSLSocketFactory socketFactory)
+ throws IOException {
+ for (int i = 0; i < 2; i++) {
+ fetch(socketFactory, "www.fortify.net", 443, true, "/sslcheck.html",
+ 1, 1, 0, 60);
+ fetch(socketFactory, "www.paypal.com", 443, true, "/",
+ 1, 1, 0, 60);
+ fetch(socketFactory, "www.yellownet.ch", 443, true, "/",
+ 1, 1, 0, 60);
+ }
+ }
+
+ /**
+ * Fake in the sense that it doesn't actually persist anything.
+ */
+ static class FakeClientSessionCache implements SSLClientSessionCache {
+
+ List<String> ops = new ArrayList<String>();
+ Map<String, byte[]> sessions = new HashMap<String, byte[]>();
+
+ public byte[] getSessionData(String host, int port) {
+ ops.add("get " + host);
+ return sessions.get(host);
+ }
+
+ public void putSessionData(SSLSession session, byte[] sessionData) {
+ String host = session.getPeerHost();
+ System.err.println("length: " + sessionData.length);
+ ops.add("put " + host);
+ sessions.put(host, sessionData);
+ }
+ }
+
+ public void testFileBasedClientSessionCache() throws IOException,
+ KeyManagementException {
+ SSLContextImpl context = new SSLContextImpl();
+ String tmpDir = System.getProperty("java.io.tmpdir");
+ if (tmpDir == null) {
+ fail("Please set 'java.io.tmpdir' system property.");
+ }
+ File cacheDir = new File(tmpDir
+ + "/" + SSLSocketTest.class.getName() + "/cache");
+ deleteDir(cacheDir);
+ SSLClientSessionCache fileCache
+ = FileClientSessionCache.usingDirectory(cacheDir);
+ try {
+ ClientSessionCacheProxy cacheProxy
+ = new ClientSessionCacheProxy(fileCache);
+ context.engineInit(null, null, null, cacheProxy, null);
+ SSLSocketFactory socketFactory = context.engineGetSocketFactory();
+ context.engineGetClientSessionContext().setSessionCacheSize(1);
+ makeRequests(socketFactory);
+ List<String> expected = Arrays.asList(
+ "unsuccessful get www.fortify.net",
+ "put www.fortify.net",
+ "unsuccessful get www.paypal.com",
+ "put www.paypal.com",
+ "unsuccessful get www.yellownet.ch",
+ "put www.yellownet.ch",
+
+ // At this point, all in-memory cache requests should miss,
+ // but the sessions will still be in the persistent cache.
+ "successful get www.fortify.net",
+ "successful get www.paypal.com",
+ "successful get www.yellownet.ch"
+ );
+ assertEquals(expected, cacheProxy.ops);
+
+ // Try again now that file-based cache is populated.
+ fileCache = FileClientSessionCache.usingDirectory(cacheDir);
+ cacheProxy = new ClientSessionCacheProxy(fileCache);
+ context.engineInit(null, null, null, cacheProxy, null);
+ socketFactory = context.engineGetSocketFactory();
+ context.engineGetClientSessionContext().setSessionCacheSize(1);
+ makeRequests(socketFactory);
+ expected = Arrays.asList(
+ "successful get www.fortify.net",
+ "successful get www.paypal.com",
+ "successful get www.yellownet.ch",
+ "successful get www.fortify.net",
+ "successful get www.paypal.com",
+ "successful get www.yellownet.ch"
+ );
+ assertEquals(expected, cacheProxy.ops);
+ } finally {
+ deleteDir(cacheDir);
+ }
+ }
+
+ private static void deleteDir(File directory) {
+ if (!directory.exists()) {
+ return;
+ }
+ for (File file : directory.listFiles()) {
+ file.delete();
+ }
+ directory.delete();
+ }
+
+ static class ClientSessionCacheProxy implements SSLClientSessionCache {
+
+ final SSLClientSessionCache delegate;
+ final List<String> ops = new ArrayList<String>();
+
+ ClientSessionCacheProxy(SSLClientSessionCache delegate) {
+ this.delegate = delegate;
+ }
+
+ public byte[] getSessionData(String host, int port) {
+ byte[] sessionData = delegate.getSessionData(host, port);
+ ops.add((sessionData == null ? "unsuccessful" : "successful")
+ + " get " + host);
+ return sessionData;
+ }
+
+ public void putSessionData(SSLSession session, byte[] sessionData) {
+ delegate.putSessionData(session, sessionData);
+ ops.add("put " + session.getPeerHost());
+ }
+ }
+
+ public static void main(String[] args) throws KeyManagementException, IOException {
+ new SSLSocketTest().testFileBasedClientSessionCache();
+ }
}
diff --git a/tests/CoreTests/android/core/TestHandler.java b/tests/CoreTests/android/core/TestHandler.java
deleted file mode 100644
index 4ff2e6e..0000000
--- a/tests/CoreTests/android/core/TestHandler.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/* //device/java/android/com/android/tests/TestHandler.java
-**
-** Copyright 2007, 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 android.core;
-
-import com.android.internal.os.HandlerHelper;
-import android.os.HandlerInterface;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
-
-/**
- * Naive class that implements a getNextMessage()
- * by running a Handler in a new thread. <p>
- * <p/>
- * This class blocks the Handler thread when the getNextMessage() thread
- * is not in getNextMessage(). This allows the getNextMessage() thread to
- * inspect state that is otherwise unguarded and would otherwise be prone to
- * race conditions.<p>
- * <p/>
- * Please note that both threads are allowed to run unsynchronized until
- * the first message is posted to this handler.
- * <p/>
- * Please call hh.looper.quit() when done to clean this up
- */
-public class TestHandler implements Runnable, HandlerInterface {
- //***** Instance Variables
-
- public HandlerHelper hh;
- public Looper looper;
-
- Runnable setupRoutine;
- Message nextMessage;
- long failTimeoutMillis;
- boolean waitBeforeReturning = true;
-
- //***** Class Methods
-
- public static TestHandler create() {
- return create("TestHandler", null);
- }
-
- public static TestHandler create(String name) {
- return create(name, null);
- }
-
- public static TestHandler create(String name, Runnable doSetup) {
- TestHandler ret;
-
- ret = new TestHandler();
-
- ret.setupRoutine = doSetup;
-
- synchronized (ret) {
- new Thread(ret, name).start();
- while (ret.looper == null) {
- try {
- ret.wait();
- } catch (InterruptedException ex) {
- }
- }
- }
-
- return ret;
- }
-
- //***** Public Methods
-
- /**
- * Maximum time to wait for a message before failing
- * by throwing exception
- */
- public void setFailTimeoutMillis(long msec) {
- failTimeoutMillis = msec;
- }
-
- /**
- * Waits for the next message to be sent to this handler and returns it.
- * Blocks the Handler's looper thread until another call to getNextMessage()
- * is made
- */
-
- public Message getNextMessage() {
- Message ret;
-
- synchronized (this) {
- long time = SystemClock.uptimeMillis();
-
- waitBeforeReturning = false;
- this.notifyAll();
-
- try {
- while (nextMessage == null) {
- if (failTimeoutMillis > 0
- && ((SystemClock.uptimeMillis() - time)
- > failTimeoutMillis)) {
- throw new RuntimeException("Timeout exceeded exceeded");
- }
-
- try {
- this.wait(failTimeoutMillis);
- } catch (InterruptedException ex) {
- }
- }
- ret = nextMessage;
- nextMessage = null;
- } finally {
- waitBeforeReturning = true;
- }
- }
-
- return ret;
- }
-
- //***** Overridden from Runnable
-
- public void run() {
- Looper.prepare();
- hh = new HandlerHelper(this);
-
- if (setupRoutine != null) {
- setupRoutine.run();
- }
-
- synchronized (this) {
- looper = Looper.myLooper();
- this.notify();
- }
-
- Looper.loop();
- }
-
- //***** HandlerHelper implementation
-
- public void handleMessage(Message msg) {
- synchronized (this) {
- while (nextMessage != null) {
- try {
- this.wait();
- } catch (InterruptedException ex) {
- }
- }
-
- // msg will be recycled when this method returns.
- // so we need to make a copy of it.
- nextMessage = Message.obtain();
- nextMessage.copyFrom(msg);
- this.notifyAll();
-
- while (waitBeforeReturning) {
- try {
- this.wait();
- } catch (InterruptedException ex) {
- }
- }
- }
- }
-}
-
-
diff --git a/tests/CoreTests/android/location/LocationManagerProximityTest.java b/tests/CoreTests/android/location/LocationManagerProximityTest.java
index 5f62983..e1501e3 100644
--- a/tests/CoreTests/android/location/LocationManagerProximityTest.java
+++ b/tests/CoreTests/android/location/LocationManagerProximityTest.java
@@ -23,6 +23,7 @@ import android.content.IntentFilter;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
+import android.provider.Settings;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
@@ -33,8 +34,10 @@ import android.util.Log;
* TODO: add tests for more scenarios
*
* To run:
- * adb shell am instrument -e class com.google.android.mapstests.api.LocationProximityTest \
- * -w com.google.android.mapstests/.MapInstrumentationTestRunner
+ * adb shell am instrument -e class android.location.LocationManagerProximityTest \
+ * -w android.core/android.test.InstrumentationTestRunner
+ *
+ * This test requires that the "Allow mock locations" setting be enabled
*
*/
@MediumTest
@@ -46,8 +49,6 @@ public class LocationManagerProximityTest extends AndroidTestCase {
private LocationManager mLocationManager;
private PendingIntent mPendingIntent;
private TestIntentReceiver mIntentReceiver;
- private String mOriginalAllowedProviders;
- private int mOriginalMocksAllowed;
private static final String LOG_TAG = "LocationProximityTest";
@@ -60,27 +61,13 @@ public class LocationManagerProximityTest extends AndroidTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
-
- // allow mock locations
- mOriginalMocksAllowed =
- android.provider.Settings.Secure.getInt(getContext().getContentResolver(),
- android.provider.Settings.Secure.ALLOW_MOCK_LOCATION, 0);
-
- android.provider.Settings.Secure.putInt(getContext().getContentResolver(),
- android.provider.Settings.Secure.ALLOW_MOCK_LOCATION, 1);
-
- mOriginalAllowedProviders =
- android.provider.Settings.Secure.getString(
- getContext().getContentResolver(),
- android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
-
- // ensure 'only' the mock provider is enabled
- // need to do this so the proximity listener does not ignore the mock
- // updates in favor of gps updates
- android.provider.Settings.Secure.putString(
- getContext().getContentResolver(),
- android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- PROVIDER_NAME);
+
+ // test that mock locations are allowed so a more descriptive error message can be logged
+ if (Settings.Secure.getInt(getContext().getContentResolver(),
+ Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 0) {
+ fail("Mock locations are currently disabled in Settings - this test requires " +
+ "mock locations");
+ }
mLocationManager = (LocationManager) getContext().
getSystemService(Context.LOCATION_SERVICE);
@@ -109,18 +96,6 @@ public class LocationManagerProximityTest extends AndroidTestCase {
if (mIntentReceiver != null) {
getContext().unregisterReceiver(mIntentReceiver);
}
-
- android.provider.Settings.Secure.putInt(getContext().getContentResolver(),
- android.provider.Settings.Secure.ALLOW_MOCK_LOCATION, mOriginalMocksAllowed);
-
- if (mOriginalAllowedProviders != null) {
- // restore original settings
- android.provider.Settings.Secure.putString(
- getContext().getContentResolver(),
- android.provider.Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- mOriginalAllowedProviders);
- mLocationManager.updateProviders();
- }
}
/**
diff --git a/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java b/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java
index 359c902..d9afd54 100644
--- a/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java
+++ b/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java
@@ -89,6 +89,26 @@ public class InstrumentationTestRunnerTest extends TestCase {
}
+ public void testDelayParameter() throws Exception {
+ int delayMsec = 1000;
+ Bundle args = new Bundle();
+ args.putInt(InstrumentationTestRunner.ARGUMENT_DELAY_MSEC, delayMsec);
+ args.putString(InstrumentationTestRunner.ARGUMENT_TEST_CLASS,
+ PlaceHolderTest.class.getName() + "," +
+ PlaceHolderTest2.class.getName());
+ mInstrumentationTestRunner.onCreate(args);
+ Thread t = new Thread() { public void run() { mInstrumentationTestRunner.onStart(); } };
+
+ // Should delay three times: before, between, and after the two tests.
+ long beforeTest = System.currentTimeMillis();
+ t.start();
+ t.join();
+ assertTrue(System.currentTimeMillis() > beforeTest + delayMsec * 3);
+ assertTrue(mInstrumentationTestRunner.isStarted());
+ assertTrue(mInstrumentationTestRunner.isFinished());
+ assertTrue(mStubAndroidTestRunner.isRun());
+ }
+
private void assertContentsInOrder(List<TestDescriptor> actual, TestDescriptor... source) {
TestDescriptor[] clonedSource = source.clone();
assertEquals("Unexpected number of items.", clonedSource.length, actual.size());
@@ -217,6 +237,7 @@ public class InstrumentationTestRunnerTest extends TestCase {
}
public void runTest() {
+ super.runTest();
mRun = true;
}
}
diff --git a/tests/CoreTests/android/webkit/CookieTest.java b/tests/CoreTests/android/webkit/CookieTest.java
index 1c3d671..ea4422f 100644
--- a/tests/CoreTests/android/webkit/CookieTest.java
+++ b/tests/CoreTests/android/webkit/CookieTest.java
@@ -55,6 +55,11 @@ public class CookieTest extends AndroidTestCase {
mCookieManager.setCookie(url, "c=\"d;\"");
cookie = mCookieManager.getCookie(url);
assertTrue(cookie.equals("a=b; c=\"d;\""));
+
+ // empty
+ mCookieManager.setCookie(url, "; path=/");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie.equals("a=b; c=\"d;\""));
}
public void testDomain() {
diff --git a/tests/CoreTests/android/webkit/UrlInterceptRegistryTest.java b/tests/CoreTests/android/webkit/UrlInterceptRegistryTest.java
new file mode 100644
index 0000000..7504449
--- /dev/null
+++ b/tests/CoreTests/android/webkit/UrlInterceptRegistryTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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 android.webkit;
+
+import android.test.AndroidTestCase;
+import android.util.Log;
+import android.webkit.CacheManager.CacheResult;
+import android.webkit.PluginData;
+import android.webkit.UrlInterceptHandler;
+
+import java.util.LinkedList;
+import java.util.Map;
+
+public class UrlInterceptRegistryTest extends AndroidTestCase {
+
+ /**
+ * To run these tests: $ mmm
+ * frameworks/base/tests/CoreTests/android && adb remount && adb
+ * sync $ adb shell am instrument -w -e class \
+ * android.webkit.UrlInterceptRegistryTest \
+ * android.core/android.test.InstrumentationTestRunner
+ */
+
+ private static class MockUrlInterceptHandler implements UrlInterceptHandler {
+ private PluginData mData;
+ private String mUrl;
+
+ public MockUrlInterceptHandler(PluginData data, String url) {
+ mData = data;
+ mUrl = url;
+ }
+
+ public CacheResult service(String url, Map<String, String> headers) {
+ return null;
+ }
+
+ public PluginData getPluginData(String url,
+ Map<String,
+ String> headers) {
+ if (mUrl.equals(url)) {
+ return mData;
+ }
+
+ return null;
+ }
+ }
+
+ public void testGetPluginData() {
+ PluginData data = new PluginData(null, 0 , null, 200);
+ String url = new String("url1");
+ MockUrlInterceptHandler handler1 =
+ new MockUrlInterceptHandler(data, url);
+
+ data = new PluginData(null, 0 , null, 404);
+ url = new String("url2");
+ MockUrlInterceptHandler handler2 =
+ new MockUrlInterceptHandler(data, url);
+
+ assertTrue(UrlInterceptRegistry.registerHandler(handler1));
+ assertTrue(UrlInterceptRegistry.registerHandler(handler2));
+
+ data = UrlInterceptRegistry.getPluginData("url1", null);
+ assertTrue(data != null);
+ assertTrue(data.getStatusCode() == 200);
+
+ data = UrlInterceptRegistry.getPluginData("url2", null);
+ assertTrue(data != null);
+ assertTrue(data.getStatusCode() == 404);
+
+ assertTrue(UrlInterceptRegistry.unregisterHandler(handler1));
+ assertTrue(UrlInterceptRegistry.unregisterHandler(handler2));
+
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
index ec9b3ef..7107412 100644
--- a/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
@@ -9,19 +9,23 @@
*
* 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.
+ * WITHOUT WARRANTIES OR CONDITIONS OF GSMTestHandler.ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.telephony.gsm;
-import android.core.TestHandler;
import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.telephony.ServiceState;
import android.test.AndroidTestCase;
import android.test.PerformanceTestCase;
+import android.util.Log;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
@@ -29,15 +33,22 @@ import com.android.internal.telephony.Connection;
import com.android.internal.telephony.MmiCode;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.TestPhoneNotifier;
+import com.android.internal.telephony.gsm.CallFailCause;
+import com.android.internal.telephony.gsm.GSMPhone;
+import com.android.internal.telephony.gsm.GSMTestHandler;
+import com.android.internal.telephony.gsm.GsmMmiCode;
+import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.test.SimulatedCommands;
import com.android.internal.telephony.test.SimulatedRadioControl;
import java.util.List;
+
public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase {
private SimulatedRadioControl mRadioControl;
- private TestHandler mTestHandler;
private GSMPhone mGSMPhone;
+ private GSMTestHandler mGSMTestHandler;
+ private Handler mHandler;
private static final int EVENT_PHONE_STATE_CHANGED = 1;
private static final int EVENT_DISCONNECT = 2;
@@ -51,78 +62,65 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
private static final int EVENT_IN_SERVICE = 10;
private static final int SUPP_SERVICE_FAILED = 11;
private static final int SERVICE_STATE_CHANGED = 12;
-
- private static final int FAIL_TIMEOUT_MILLIS = 5 * 1000;
+ private static final int EVENT_OEM_RIL_MESSAGE = 13;
+ public static final int ANY_MESSAGE = -1;
@Override
protected void setUp() throws Exception {
super.setUp();
+ mGSMTestHandler = new GSMTestHandler(mContext);
+
+ mGSMTestHandler.start();
+ synchronized (mGSMTestHandler) {
+ do {
+ mGSMTestHandler.wait();
+ } while (mGSMTestHandler.getGSMPhone() == null);
+ }
+
+ mGSMPhone = mGSMTestHandler.getGSMPhone();
+ mRadioControl = mGSMTestHandler.getSimulatedCommands();
+
+ mHandler = mGSMTestHandler.getHandler();
+ mGSMPhone.registerForPhoneStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null);
+ mGSMPhone.registerForNewRingingConnection(mHandler, EVENT_RINGING, null);
+ mGSMPhone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
+
+ mGSMPhone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL, null);
- mTestHandler = TestHandler.create("GSMPhoneTest TestHandler",
- new Runnable() {
- public void run() {
- SimulatedCommands sc = new SimulatedCommands();
- mRadioControl = sc;
- mGSMPhone = new GSMPhone(
- mContext, sc,
- new TestPhoneNotifier(),
- true);
-
- }
- }
- );
-
- mTestHandler.setFailTimeoutMillis(FAIL_TIMEOUT_MILLIS);
- mGSMPhone.registerForPhoneStateChanged(mTestHandler.hh, EVENT_PHONE_STATE_CHANGED, null);
- mGSMPhone.registerForNewRingingConnection(mTestHandler.hh, EVENT_RINGING, null);
- mGSMPhone.registerForDisconnect(mTestHandler.hh, EVENT_DISCONNECT, null);
-
- mGSMPhone.setOnPostDialCharacter(mTestHandler.hh, EVENT_POST_DIAL, null);
-
- mGSMPhone.registerForSuppServiceNotification(mTestHandler.hh, EVENT_SSN, null);
- mGSMPhone.registerForMmiInitiate(mTestHandler.hh, EVENT_MMI_INITIATE, null);
- mGSMPhone.registerForMmiComplete(mTestHandler.hh, EVENT_MMI_COMPLETE, null);
- mGSMPhone.registerForSuppServiceFailed(mTestHandler.hh, SUPP_SERVICE_FAILED, null);
-
- mGSMPhone.registerForServiceStateChanged(mTestHandler.hh, SERVICE_STATE_CHANGED, null);
+ mGSMPhone.registerForSuppServiceNotification(mHandler, EVENT_SSN, null);
+ mGSMPhone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
+ mGSMPhone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
+ mGSMPhone.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null);
+
+ mGSMPhone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null);
// wait until we get phone in both voice and data service
Message msg;
ServiceState state;
+
do {
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != SERVICE_STATE_CHANGED);
- state = (ServiceState) ((AsyncResult) msg.obj).result;
+ msg = mGSMTestHandler.waitForMessage(SERVICE_STATE_CHANGED);
+ assertNotNull("Message Time Out", msg);
+ state = (ServiceState) ((AsyncResult) msg.obj).result;
} while (state.getState() != ServiceState.STATE_IN_SERVICE);
-
}
@Override
protected void tearDown() throws Exception {
- mGSMPhone.unregisterForPhoneStateChanged(mTestHandler.hh);
- mGSMPhone.unregisterForNewRingingConnection(mTestHandler.hh);
- mGSMPhone.unregisterForDisconnect(mTestHandler.hh);
- mGSMPhone.setOnPostDialCharacter(null, 0, null);
- mGSMPhone.unregisterForSuppServiceNotification(mTestHandler.hh);
- mGSMPhone.unregisterForMmiInitiate(mTestHandler.hh);
- mGSMPhone.unregisterForMmiComplete(mTestHandler.hh);
-
mRadioControl.shutdown();
- mTestHandler.hh.sendMessage(mTestHandler.hh.obtainMessage(EVENT_DONE));
-
- Message msg;
-
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_DONE);
-
- mTestHandler.looper.quit();
+ mGSMPhone.unregisterForPhoneStateChanged(mHandler);
+ mGSMPhone.unregisterForNewRingingConnection(mHandler);
+ mGSMPhone.unregisterForDisconnect(mHandler);
+ mGSMPhone.setOnPostDialCharacter(mHandler, 0, null);
+ mGSMPhone.unregisterForSuppServiceNotification(mHandler);
+ mGSMPhone.unregisterForMmiInitiate(mHandler);
+ mGSMPhone.unregisterForMmiComplete(mHandler);
mGSMPhone = null;
mRadioControl = null;
- mTestHandler = null;
+ mHandler = null;
+ mGSMTestHandler.cleanup();
super.tearDown();
}
@@ -136,7 +134,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
return false;
}
-
+
//This test is causing the emulator screen to turn off. I don't understand
//why, but I'm removing it until we can figure it out.
public void brokenTestGeneral() throws Exception {
@@ -167,19 +165,16 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_PHONE_STATE_CHANGED);
+ msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
assertEquals(Call.State.DIALING, mGSMPhone.getForegroundCall().getState());
assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting());
- /*
- do {
- th.getNextMessage();
- } while (phone.getForegroundCall().getConnections().size() == 0);
- */
+ /*do {
+ mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+ } while (mGSMPhone.getForegroundCall().getConnections().size() == 0);*/
assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
@@ -206,7 +201,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.progressConnectingCallState();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
}
while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING);
@@ -234,7 +229,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.progressConnectingCallState();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
@@ -259,9 +254,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// One disconnected connection
mGSMPhone.getForegroundCall().hangup();
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_DISCONNECT);
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.IDLE, mGSMPhone.getState());
assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
@@ -311,9 +305,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("18005551212");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_RINGING);
+ msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.RINGING, mGSMPhone.getState());
assertTrue(mGSMPhone.getRingingCall().isRinging());
@@ -347,7 +340,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.acceptCall();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getRingingCall().getConnections().size() == 1);
assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
@@ -382,10 +375,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
fail("unexpected ex");
}
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_DISCONNECT);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.IDLE, mGSMPhone.getState());
assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
@@ -444,7 +435,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("18005551212");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getRingingCall().getConnections().isEmpty());
assertEquals(Phone.State.RINGING, mGSMPhone.getState());
@@ -471,7 +462,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.rejectCall();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.IDLE);
assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
@@ -525,7 +516,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("18005551212");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getRingingCall().getConnections().isEmpty());
assertEquals(Phone.State.RINGING, mGSMPhone.getState());
@@ -539,7 +530,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerHangupForeground();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.IDLE);
assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause());
@@ -549,7 +540,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("18005551212");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.RINGING);
@@ -559,7 +550,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.acceptCall();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.OFFHOOK);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -569,7 +560,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.switchHoldingAndActive();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
@@ -580,7 +571,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.switchHoldingAndActive();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
}
while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING);
@@ -592,7 +583,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerHangupAll();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.IDLE);
assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
@@ -603,13 +594,13 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("18005551212");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.RINGING);
mGSMPhone.rejectCall();
do {
- msg = mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (msg.what != EVENT_DISCONNECT);
ar = (AsyncResult) msg.obj;
@@ -624,7 +615,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("18005551212");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.RINGING);
cn = mGSMPhone.getRingingCall().getEarliestConnection();
@@ -632,7 +623,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.acceptCall();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.OFFHOOK);
assertEquals(Connection.DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause());
@@ -647,7 +638,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
}
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState()
!= Call.State.DISCONNECTED);
@@ -661,7 +652,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.dial("+13125551212");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.OFFHOOK);
assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting());
@@ -672,7 +663,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// One ACTIVE call
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
@@ -682,7 +673,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("18005551212");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.RINGING);
assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
@@ -692,7 +683,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.acceptCall();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.OFFHOOK);
assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
@@ -706,7 +697,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.conference();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
@@ -720,7 +711,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.switchHoldingAndActive();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
}
while (mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING);
@@ -734,7 +725,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("18005558355");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.RINGING);
assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
@@ -750,7 +741,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.getBackgroundCall().hangup();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() != Call.State.DISCONNECTED);
assertEquals(Phone.State.RINGING, mGSMPhone.getState());
@@ -763,7 +754,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.rejectCall();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.IDLE);
assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
@@ -782,10 +773,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
Connection cn = mGSMPhone.dial("+13125551212");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_DISCONNECT);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.IDLE, mGSMPhone.getState());
assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause());
@@ -812,7 +801,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.dial("+13125551212");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
}
while (mGSMPhone.getForegroundCall().getState() != Call.State.DIALING);
@@ -820,10 +809,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.getForegroundCall().hangup();
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_DISCONNECT);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.IDLE, mGSMPhone.getState());
assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
@@ -833,13 +820,13 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.dial("+13125551212");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.OFFHOOK);
mRadioControl.progressConnectingCallState();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
}
while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING);
@@ -847,9 +834,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.getForegroundCall().hangup();
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_DISCONNECT);
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.IDLE, mGSMPhone.getState());
@@ -867,10 +853,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.resumeResponses();
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_DISCONNECT);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.IDLE, mGSMPhone.getState());
assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
@@ -883,13 +867,13 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.dial("+13125551212");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getConnections().isEmpty());
mRadioControl.shutdown();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
mGSMPhone.clearDisconnected();
} while (!mGSMPhone.getForegroundCall().getConnections().isEmpty());
}
@@ -902,7 +886,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
do {
mRadioControl.progressConnectingCallState();
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -912,9 +896,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("18005551212");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_RINGING);
+ msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.RINGING, mGSMPhone.getState());
assertTrue(mGSMPhone.getRingingCall().isRinging());
@@ -927,7 +910,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.handleInCallMmiCommands("0");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING);
assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
@@ -940,7 +923,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.switchHoldingAndActive();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
@@ -952,7 +935,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.handleInCallMmiCommands("0");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING);
assertEquals(Phone.State.IDLE, mGSMPhone.getState());
@@ -968,7 +951,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
do {
mRadioControl.progressConnectingCallState();
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -979,7 +962,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("18005551212");
do {
- msg = mTestHandler.getNextMessage();
+ msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+ assertNotNull("Message Time Out", msg);
} while (msg.what != EVENT_RINGING);
assertEquals(Phone.State.RINGING, mGSMPhone.getState());
@@ -994,7 +978,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.handleInCallMmiCommands("1");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING);
assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
@@ -1008,7 +992,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.switchHoldingAndActive();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
@@ -1019,7 +1003,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.handleInCallMmiCommands("1");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
@@ -1033,9 +1017,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("16505550100");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_RINGING);
+ msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.RINGING, mGSMPhone.getState());
assertTrue(mGSMPhone.getRingingCall().isRinging());
@@ -1048,7 +1031,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.handleInCallMmiCommands("12");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
assertEquals(Phone.State.RINGING, mGSMPhone.getState());
@@ -1060,7 +1043,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.acceptCall();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getState() != Phone.State.OFFHOOK);
assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
@@ -1075,7 +1058,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
do {
mRadioControl.progressConnectingCallState();
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE ||
mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING);
@@ -1086,20 +1069,20 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// have the gsm index of 2
// Simulate entering "11" followed by SEND: release the call with
- // gsm index equals to 1. This should not be allowed, and a
+ // gsm index equals to 1. This should not be allowed, and a
// Supplementary Service notification must be received.
mGSMPhone.handleInCallMmiCommands("11");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg != null && msg.what != SUPP_SERVICE_FAILED);
+
+ msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED);
+ assertNotNull("Message Time Out", msg);
assertFalse("IncallMmiCallWaiting: command should not work on holding call", msg == null);
-
+
// Simulate entering "12" followed by SEND: release the call with
// gsm index equals to 2.
mGSMPhone.handleInCallMmiCommands("12");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
@@ -1108,9 +1091,9 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// Simulate entering 1 followed by SEND: release all active calls
// (if any exist) and accepts the other (held or waiting) call.
mGSMPhone.handleInCallMmiCommands("1");
-
+
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
@@ -1124,7 +1107,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.handleInCallMmiCommands("11");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
@@ -1139,7 +1122,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
do {
mRadioControl.progressConnectingCallState();
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -1149,9 +1132,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerRing("18005551212");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_RINGING);
+ msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.RINGING, mGSMPhone.getState());
assertTrue(mGSMPhone.getRingingCall().isRinging());
@@ -1166,7 +1148,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.handleInCallMmiCommands("2");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING);
@@ -1184,9 +1166,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// swap the active and holding calls
mGSMPhone.handleInCallMmiCommands("2");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_PHONE_STATE_CHANGED);
+ msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED);
+ assertNotNull("Message Time Out", msg);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
assertEquals("13125551212",
@@ -1199,7 +1180,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.conference();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -1212,20 +1193,19 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// Simulate entering "23" followed by SEND: places all active call
// on hold except call 3. This should fail and a supplementary service
// failed notification should be received.
-
+
mGSMPhone.handleInCallMmiCommands("23");
-
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg != null && msg.what != SUPP_SERVICE_FAILED);
+
+ msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED);
+ assertNotNull("Message Time Out", msg);
assertFalse("IncallMmiCallHold: separate should have failed!", msg == null);
-
+
// Simulate entering "21" followed by SEND: places all active call
// on hold except call 1.
mGSMPhone.handleInCallMmiCommands("21");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -1242,7 +1222,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
do {
mRadioControl.progressConnectingCallState();
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -1253,7 +1233,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
do {
mRadioControl.progressConnectingCallState();
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -1262,7 +1242,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.handleInCallMmiCommands("3");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
@@ -1282,7 +1262,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
do {
mRadioControl.progressConnectingCallState();
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -1297,7 +1277,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
do {
mRadioControl.progressConnectingCallState();
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -1310,7 +1290,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.conference();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -1326,9 +1306,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// of 7
mRadioControl.triggerRing("18005551212");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_RINGING);
+ msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.RINGING, mGSMPhone.getState());
assertTrue(mGSMPhone.getRingingCall().isRinging());
@@ -1341,7 +1320,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.acceptCall();
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getRingingCall().getState() != Call.State.IDLE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -1354,7 +1333,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.handleInCallMmiCommands("17");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
@@ -1366,7 +1345,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.handleInCallMmiCommands("1");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
@@ -1375,7 +1354,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.handleInCallMmiCommands("16");
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
@@ -1389,53 +1368,44 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.dial("+13125551212,1234;5N8xx");
- do {
- msg = mTestHandler.getNextMessage();
- mRadioControl.progressConnectingToActive();
- } while (msg.what != EVENT_POST_DIAL);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
ar = (AsyncResult) (msg.obj);
cn = (Connection) (ar.result);
assertEquals(',', msg.arg1);
assertEquals("1234;5N8", cn.getRemainingPostDialString());
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals('1', msg.arg1);
ar = (AsyncResult) (msg.obj);
assertEquals(Connection.PostDialState.STARTED, ar.userObj);
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals('2', msg.arg1);
ar = (AsyncResult) (msg.obj);
assertEquals(Connection.PostDialState.STARTED, ar.userObj);
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals('3', msg.arg1);
ar = (AsyncResult) (msg.obj);
assertEquals(Connection.PostDialState.STARTED, ar.userObj);
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals('4', msg.arg1);
ar = (AsyncResult) (msg.obj);
assertEquals(Connection.PostDialState.STARTED, ar.userObj);
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals(';', msg.arg1);
ar = (AsyncResult) (msg.obj);
cn = (Connection) (ar.result);
@@ -1443,18 +1413,15 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
assertEquals(Connection.PostDialState.WAIT, ar.userObj);
cn.proceedAfterWaitChar();
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals('5', msg.arg1);
ar = (AsyncResult) (msg.obj);
assertEquals(Connection.PostDialState.STARTED, ar.userObj);
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
assertEquals('N', msg.arg1);
ar = (AsyncResult) (msg.obj);
cn = (Connection) (ar.result);
@@ -1462,27 +1429,22 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
assertEquals(Connection.PostDialState.WILD, ar.userObj);
cn.proceedAfterWildChar(",6;7");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
ar = (AsyncResult) (msg.obj);
cn = (Connection) (ar.result);
assertEquals(',', msg.arg1);
assertEquals("6;78", cn.getRemainingPostDialString());
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals('6', msg.arg1);
ar = (AsyncResult) (msg.obj);
assertEquals(Connection.PostDialState.STARTED, ar.userObj);
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals(';', msg.arg1);
ar = (AsyncResult) (msg.obj);
cn = (Connection) (ar.result);
@@ -1490,28 +1452,21 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
assertEquals(Connection.PostDialState.WAIT, ar.userObj);
cn.proceedAfterWaitChar();
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals('7', msg.arg1);
ar = (AsyncResult) (msg.obj);
assertEquals(Connection.PostDialState.STARTED, ar.userObj);
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals('8', msg.arg1);
ar = (AsyncResult) (msg.obj);
assertEquals(Connection.PostDialState.STARTED, ar.userObj);
// Bogus chars at end should be ignored
-
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals(0, msg.arg1);
ar = (AsyncResult) (msg.obj);
cn = (Connection) (ar.result);
@@ -1530,16 +1485,11 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.progressConnectingToActive();
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
assertEquals(',', msg.arg1);
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_POST_DIAL);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
assertEquals('N', msg.arg1);
ar = (AsyncResult) (msg.obj);
cn = (Connection) (ar.result);
@@ -1567,16 +1517,13 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// Normally these failure conditions would happen in DIALING
// not ALERTING
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (cn.getState() == Call.State.DIALING);
mRadioControl.triggerHangupAll();
-
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_DISCONNECT);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.IDLE, mGSMPhone.getState());
assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause());
@@ -1608,16 +1555,13 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// Normally these failure conditions would happen in DIALING
// not ALERTING
do {
- mTestHandler.getNextMessage();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
} while (cn.getState() == Call.State.DIALING);
mRadioControl.triggerHangupAll();
-
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_DISCONNECT);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
assertEquals(Phone.State.IDLE, mGSMPhone.getState());
assertEquals(Connection.DisconnectCause.BUSY, cn.getDisconnectCause());
@@ -1650,7 +1594,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// Normally these failure conditions would happen in DIALING
// not ALERTING
do {
- mTestHandler.getNextMessage();
+ msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+ assertNotNull("Message Time Out", msg);
} while (cn.getState() == Call.State.DIALING);
@@ -1659,7 +1604,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// Unlike the while loops above, this one waits
// for a "phone state changed" message back to "idle"
do {
- msg = mTestHandler.getNextMessage();
+ msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+ assertNotNull("Message Time Out", msg);
} while (!(msg.what == EVENT_PHONE_STATE_CHANGED
&& mGSMPhone.getState() == Phone.State.IDLE));
@@ -1696,10 +1642,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mRadioControl.triggerSsn(type, code);
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_SSN);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_SSN);
+ assertNotNull("Message Time Out", msg);
AsyncResult ar = (AsyncResult) msg.obj;
assertNull(ar.exception);
@@ -1714,7 +1658,7 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
public void testUssd() throws Exception {
// Quick hack to work around a race condition in this test:
// We may initiate a USSD MMI before GSMPhone receives its initial
- // EVENT_RADIO_OFF_OR_NOT_AVAILABLE event. When the phone sees this
+ // GSMTestHandler.EVENT_RADIO_OFF_OR_NOT_AVAILABLE event. When the phone sees this
// event, it will cancel the just issued USSD MMI, which we don't
// want. So sleep a little first.
try {
@@ -1735,10 +1679,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// Receive an incoming NOTIFY
mRadioControl.triggerIncomingUssd("0", "NOTIFY message");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_COMPLETE);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
ar = (AsyncResult) msg.obj;
mmi = (MmiCode) ar.result;
@@ -1746,29 +1688,23 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// Receive a REQUEST and send response
mRadioControl.triggerIncomingUssd("1", "REQUEST Message");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_COMPLETE);
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
ar = (AsyncResult) msg.obj;
mmi = (MmiCode) ar.result;
assertTrue(mmi.isUssdRequest());
mGSMPhone.sendUssdResponse("## TEST: TEST_GSMPhone responding...");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_INITIATE);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+ assertNotNull("Message Time Out", msg);
ar = (AsyncResult) msg.obj;
mmi = (MmiCode) ar.result;
GsmMmiCode gsmMmi = (GsmMmiCode) mmi;
assertTrue(gsmMmi.isPendingUSSD());
-
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_COMPLETE);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
ar = (AsyncResult) msg.obj;
mmi = (MmiCode) ar.result;
@@ -1777,19 +1713,16 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// Receive a REQUEST and cancel
mRadioControl.triggerIncomingUssd("1", "REQUEST Message");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_COMPLETE);
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
ar = (AsyncResult) msg.obj;
mmi = (MmiCode) ar.result;
assertTrue(mmi.isUssdRequest());
mmi.cancel();
-
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_COMPLETE);
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
ar = (AsyncResult) msg.obj;
mmi = (MmiCode) ar.result;
@@ -1808,13 +1741,11 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
mGSMPhone.dial("#646#");
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_INITIATE);
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+ assertNotNull("Message Time Out", msg);
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_COMPLETE);
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
ar = (AsyncResult) msg.obj;
mmi = (MmiCode) ar.result;
@@ -1842,13 +1773,11 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
assertTrue(mmi.isCancelable());
mmi.cancel();
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_INITIATE);
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+ assertNotNull("Message Time Out", msg);
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_COMPLETE);
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
AsyncResult ar = (AsyncResult) msg.obj;
mmi = (MmiCode) ar.result;
@@ -1867,11 +1796,10 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// null byte array
- mGSMPhone.invokeOemRilRequestRaw(null, mTestHandler.hh.obtainMessage(999));
+ mGSMPhone.invokeOemRilRequestRaw(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
- do {
- msg = mTestHandler.getNextMessage();
- } while (!(msg.what == 999));
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
ar = ((AsyncResult) msg.obj);
@@ -1880,11 +1808,10 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// empty byte array
- mGSMPhone.invokeOemRilRequestRaw(new byte[0], mTestHandler.hh.obtainMessage(999));
+ mGSMPhone.invokeOemRilRequestRaw(new byte[0], mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
- do {
- msg = mTestHandler.getNextMessage();
- } while (!(msg.what == 999));
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
ar = ((AsyncResult) msg.obj);
@@ -1894,11 +1821,10 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// byte array with data
mGSMPhone.invokeOemRilRequestRaw("Hello".getBytes("utf-8"),
- mTestHandler.hh.obtainMessage(999));
+ mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
- do {
- msg = mTestHandler.getNextMessage();
- } while (!(msg.what == 999));
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
ar = ((AsyncResult) msg.obj);
@@ -1907,11 +1833,10 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// null strings
- mGSMPhone.invokeOemRilRequestStrings(null, mTestHandler.hh.obtainMessage(999));
+ mGSMPhone.invokeOemRilRequestStrings(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
- do {
- msg = mTestHandler.getNextMessage();
- } while (!(msg.what == 999));
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
ar = ((AsyncResult) msg.obj);
@@ -1921,11 +1846,10 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
// empty byte array
mGSMPhone.invokeOemRilRequestStrings(new String[0],
- mTestHandler.hh.obtainMessage(999));
+ mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
- do {
- msg = mTestHandler.getNextMessage();
- } while (!(msg.what == 999));
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
ar = ((AsyncResult) msg.obj);
@@ -1938,11 +1862,10 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
s[0] = "Hello";
- mGSMPhone.invokeOemRilRequestStrings(s, mTestHandler.hh.obtainMessage(999));
+ mGSMPhone.invokeOemRilRequestStrings(s, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
- do {
- msg = mTestHandler.getNextMessage();
- } while (!(msg.what == 999));
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
ar = ((AsyncResult) msg.obj);
@@ -1976,21 +1899,15 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
private void runValidMmi(String dialString, boolean cancelable) throws CallStateException {
Connection c = mGSMPhone.dial(dialString);
assertNull(c);
-
- Message msg;
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_INITIATE);
-
+ Message msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+ assertNotNull("Message Time Out", msg);
// Should not be cancelable.
AsyncResult ar = (AsyncResult) msg.obj;
MmiCode mmi = (MmiCode) ar.result;
assertEquals(cancelable, mmi.isCancelable());
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_MMI_COMPLETE);
-
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
}
private void runValidMmiWithConnect(String dialString) throws CallStateException {
@@ -2006,11 +1923,8 @@ public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase
cn.hangup();
mRadioControl.resumeResponses();
+ assertNotNull(mGSMTestHandler.waitForMessage(EVENT_DISCONNECT));
- Message msg;
- do {
- msg = mTestHandler.getNextMessage();
- } while (msg.what != EVENT_DISCONNECT);
}
private void runNotMmi(String dialString) throws CallStateException {
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java b/tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java
new file mode 100644
index 0000000..fb8a5d9
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java
@@ -0,0 +1,118 @@
+/*
+ * 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.internal.telephony.gsm;
+
+import android.content.Context;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import com.android.internal.telephony.gsm.GSMPhone;
+import com.android.internal.telephony.test.SimulatedCommands;
+import com.android.internal.telephony.TestPhoneNotifier;
+
+/**
+ * This class creates a HandlerThread which waits for the various messages.
+ */
+public class GSMTestHandler extends HandlerThread implements Handler.Callback {
+
+ private Handler mHandler;
+ private Message mCurrentMessage;
+
+ private Boolean mMsgConsumed;
+ private SimulatedCommands sc;
+ private GSMPhone mGSMPhone;
+ private Context mContext;
+
+ private static final int FAIL_TIMEOUT_MILLIS = 5 * 1000;
+
+ public GSMTestHandler(Context context) {
+ super("GSMPhoneTest");
+ mMsgConsumed = false;
+ mContext = context;
+ }
+
+ @Override
+ protected void onLooperPrepared() {
+ sc = new SimulatedCommands();
+ mGSMPhone = new GSMPhone(mContext, sc, new TestPhoneNotifier(), true);
+ mHandler = new Handler(getLooper(), this);
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+
+ public boolean handleMessage(Message msg) {
+ synchronized (this) {
+ mCurrentMessage = msg;
+ this.notifyAll();
+ while(!mMsgConsumed) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) {}
+ }
+ mMsgConsumed = false;
+ }
+ return true;
+ }
+
+
+ public void cleanup() {
+ Looper looper = getLooper();
+ if (looper != null) looper.quit();
+ mHandler = null;
+ }
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ public SimulatedCommands getSimulatedCommands() {
+ return sc;
+ }
+
+ public GSMPhone getGSMPhone() {
+ return mGSMPhone;
+ }
+
+ public Message waitForMessage(int code) {
+ Message msg;
+ while(true) {
+ msg = null;
+ synchronized (this) {
+ try {
+ this.wait(FAIL_TIMEOUT_MILLIS);
+ } catch (InterruptedException e) {
+ }
+
+ // Check if timeout has occurred.
+ if (mCurrentMessage != null) {
+ // Consume the message
+ msg = Message.obtain();
+ msg.copyFrom(mCurrentMessage);
+ mCurrentMessage = null;
+ mMsgConsumed = true;
+ this.notifyAll();
+ }
+ }
+ if (msg == null || code == GSMPhoneTest.ANY_MESSAGE || msg.what == code) return msg;
+ }
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java
index 84974ef..6db230f 100644
--- a/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java
@@ -16,7 +16,6 @@
package com.android.internal.telephony.gsm;
-import android.core.TestHandler;
import android.test.suitebuilder.annotation.MediumTest;
import com.android.internal.telephony.TestPhoneNotifier;
import com.android.internal.telephony.test.SimulatedCommands;
@@ -38,24 +37,24 @@ public class SMSDispatcherTest extends AndroidTestCase {
Iterator<SmsHeader.Element> elements;
String[] lines = new String[2];
-
- lines[0] = "+CMT: ,158";
+
+ lines[0] = "+CMT: ,158";
lines[1] = "07914140279510F6440A8111110301003BF56080426101748A8C0B05040B"
+ "8423F000035502010106276170706C69636174696F6E2F766E642E776170"
+ "2E6D6D732D6D65737361676500AF848D0185B4848C8298524F347839776F"
+ "7547514D4141424C3641414141536741415A4B554141414141008D908918"
+ "802B31363530323438363137392F545950453D504C4D4E008A808E028000"
+ "88058103093A8083687474703A2F2F36";
-
+
sms = SmsMessage.newFromCMT(lines);
header = sms.getUserDataHeader();
assertNotNull(header);
assertNotNull(sms.getUserData());
-
+
elements = header.getElements().iterator();
assertNotNull(elements);
}
-
+
@MediumTest
public void testCMT2() throws Exception {
SmsMessage sms;
@@ -63,7 +62,7 @@ public class SMSDispatcherTest extends AndroidTestCase {
Iterator<SmsHeader.Element> elements;
String[] lines = new String[2];
-
+
lines[0] = "+CMT: ,77";
lines[1] = "07914140279510F6440A8111110301003BF56080426101848A3B0B05040B8423F"
@@ -75,7 +74,7 @@ public class SMSDispatcherTest extends AndroidTestCase {
System.out.println("header = " + header);
assertNotNull(header);
assertNotNull(sms.getUserData());
-
+
elements = header.getElements().iterator();
assertNotNull(elements);
}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java
index 53fdd51..db55bca 100644
--- a/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java
@@ -16,7 +16,6 @@
package com.android.internal.telephony.gsm;
-import android.core.TestHandler;
import android.os.ServiceManager;
import android.test.suitebuilder.annotation.Suppress;
@@ -48,21 +47,21 @@ public class SimPhoneBookTest extends TestCase {
AdnRecord originalAdn = null;
// We need to maintain the state of the SIM before and after the test.
// Since this test doesn't mock the SIM we try to get a valid ADN record,
- // for 3 tries and if this fails, we bail out.
+ // for 3 tries and if this fails, we bail out.
for (adnIndex = 3 ; adnIndex >= 1; adnIndex--) {
listIndex = adnIndex - 1; // listIndex is zero based.
originalAdn = adnRecordList.get(listIndex);
assertNotNull("Original Adn is Null.", originalAdn);
assertNotNull("Original Adn alpha tag is null.", originalAdn.getAlphaTag());
assertNotNull("Original Adn number is null.", originalAdn.getNumber());
-
- if (originalAdn.getNumber().length() > 0 &&
- originalAdn.getAlphaTag().length() > 0) {
+
+ if (originalAdn.getNumber().length() > 0 &&
+ originalAdn.getAlphaTag().length() > 0) {
break;
}
}
if (adnIndex == 0) return;
-
+
AdnRecord emptyAdn = new AdnRecord("", "");
AdnRecord firstAdn = new AdnRecord("John", "4085550101");
AdnRecord secondAdn = new AdnRecord("Andy", "6505550102");
diff --git a/tests/CoreTests/run_core_test.sh b/tests/CoreTests/run_core_test.sh
index 1fc3348..ffa31ed 100755
--- a/tests/CoreTests/run_core_test.sh
+++ b/tests/CoreTests/run_core_test.sh
@@ -1,4 +1,6 @@
framework=/system/framework
bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar:$framework/android.test.runner.jar
-adb shell exec dalvikvm -Xbootclasspath:$bpath -cp system/app/CoreTests.apk \
+adb shell exec dalvikvm -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=3001 \
+ -Xbootclasspath:$bpath -cp /data/app/android.core.apk \
+ -Djava.io.tmpdir=/sdcard/tmp \
com.android.internal.util.WithFramework junit.textui.TestRunner $*
diff --git a/tests/DpiTest/Android.mk b/tests/DpiTest/Android.mk
new file mode 100644
index 0000000..3596c39
--- /dev/null
+++ b/tests/DpiTest/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := DensityTest
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/DpiTest/AndroidManifest.xml b/tests/DpiTest/AndroidManifest.xml
new file mode 100644
index 0000000..f71cff2
--- /dev/null
+++ b/tests/DpiTest/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.test.dpi">
+ <application android:label="DpiTest">
+ <activity android:name="DpiTestActivity" android:label="DpiTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/DpiTest/res/drawable-120dpi/logo120dpi.png b/tests/DpiTest/res/drawable-120dpi/logo120dpi.png
new file mode 100644
index 0000000..46bbd5b
--- /dev/null
+++ b/tests/DpiTest/res/drawable-120dpi/logo120dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable-240dpi/logo240dpi.png b/tests/DpiTest/res/drawable-240dpi/logo240dpi.png
new file mode 100644
index 0000000..4d717a8
--- /dev/null
+++ b/tests/DpiTest/res/drawable-240dpi/logo240dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable/logo160dpi.png b/tests/DpiTest/res/drawable/logo160dpi.png
new file mode 100644
index 0000000..c23b2ce
--- /dev/null
+++ b/tests/DpiTest/res/drawable/logo160dpi.png
Binary files differ
diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
new file mode 100644
index 0000000..3759622
--- /dev/null
+++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
@@ -0,0 +1,167 @@
+/*
+ * 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.google.android.test.dpi;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.ScrollView;
+import android.view.View;
+import android.content.Context;
+
+public class DpiTestActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout root = new LinearLayout(this);
+ root.setOrientation(LinearLayout.VERTICAL);
+
+ LinearLayout layout = new LinearLayout(this);
+ addBitmapDrawable(layout, R.drawable.logo120dpi, true);
+ addBitmapDrawable(layout, R.drawable.logo160dpi, true);
+ addBitmapDrawable(layout, R.drawable.logo240dpi, true);
+ addLabelToRoot(root, "Prescaled bitmap in drawable");
+ addChildToRoot(root, layout);
+
+ layout = new LinearLayout(this);
+ addBitmapDrawable(layout, R.drawable.logo120dpi, false);
+ addBitmapDrawable(layout, R.drawable.logo160dpi, false);
+ addBitmapDrawable(layout, R.drawable.logo240dpi, false);
+ addLabelToRoot(root, "Autoscaled bitmap in drawable");
+ addChildToRoot(root, layout);
+
+ layout = new LinearLayout(this);
+ addResourceDrawable(layout, R.drawable.logo120dpi);
+ addResourceDrawable(layout, R.drawable.logo160dpi);
+ addResourceDrawable(layout, R.drawable.logo240dpi);
+ addLabelToRoot(root, "Prescaled resource drawable");
+ addChildToRoot(root, layout);
+
+ layout = new LinearLayout(this);
+ addCanvasBitmap(layout, R.drawable.logo120dpi, true);
+ addCanvasBitmap(layout, R.drawable.logo160dpi, true);
+ addCanvasBitmap(layout, R.drawable.logo240dpi, true);
+ addLabelToRoot(root, "Prescaled bitmap");
+ addChildToRoot(root, layout);
+
+ layout = new LinearLayout(this);
+ addCanvasBitmap(layout, R.drawable.logo120dpi, false);
+ addCanvasBitmap(layout, R.drawable.logo160dpi, false);
+ addCanvasBitmap(layout, R.drawable.logo240dpi, false);
+ addLabelToRoot(root, "Autoscaled bitmap");
+ addChildToRoot(root, layout);
+
+ setContentView(scrollWrap(root));
+ }
+
+ private View scrollWrap(View view) {
+ ScrollView scroller = new ScrollView(this);
+ scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.FILL_PARENT,
+ ScrollView.LayoutParams.FILL_PARENT));
+ return scroller;
+ }
+
+ private void addLabelToRoot(LinearLayout root, String text) {
+ TextView label = new TextView(this);
+ label.setText(text);
+ root.addView(label, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+ }
+
+ private void addChildToRoot(LinearLayout root, LinearLayout layout) {
+ root.addView(layout, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+ }
+
+ private void addBitmapDrawable(LinearLayout layout, int resource, boolean scale) {
+ Bitmap bitmap;
+ bitmap = loadAndPrintDpi(resource, scale);
+
+ View view = new View(this);
+
+ final BitmapDrawable d = new BitmapDrawable(bitmap);
+ if (!scale) d.setDensityScale(getResources().getDisplayMetrics());
+ view.setBackgroundDrawable(d);
+
+ view.setLayoutParams(new LinearLayout.LayoutParams(d.getIntrinsicWidth(),
+ d.getIntrinsicHeight()));
+ layout.addView(view);
+ }
+
+ private void addResourceDrawable(LinearLayout layout, int resource) {
+ View view = new View(this);
+
+ final Drawable d = getResources().getDrawable(resource);
+ view.setBackgroundDrawable(d);
+
+ view.setLayoutParams(new LinearLayout.LayoutParams(d.getIntrinsicWidth(),
+ d.getIntrinsicHeight()));
+ layout.addView(view);
+ }
+
+ private void addCanvasBitmap(LinearLayout layout, int resource, boolean scale) {
+ Bitmap bitmap;
+ bitmap = loadAndPrintDpi(resource, scale);
+
+ ScaledBitmapView view = new ScaledBitmapView(this, bitmap);
+
+ view.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+ layout.addView(view);
+ }
+
+ private Bitmap loadAndPrintDpi(int id, boolean scale) {
+ Bitmap bitmap;
+ if (scale) {
+ bitmap = BitmapFactory.decodeResource(getResources(), id);
+ } else {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inScaled = false;
+ bitmap = BitmapFactory.decodeResource(getResources(), id, opts);
+ }
+ return bitmap;
+ }
+
+ private class ScaledBitmapView extends View {
+ private Bitmap mBitmap;
+
+ public ScaledBitmapView(Context context, Bitmap bitmap) {
+ super(context);
+ mBitmap = bitmap;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ setMeasuredDimension(mBitmap.getScaledWidth(), mBitmap.getScaledHeight());
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null);
+ }
+ }
+}
diff --git a/tests/DumpRenderTree/AndroidManifest.xml b/tests/DumpRenderTree/AndroidManifest.xml
index 8e06cc8..17c44ad 100644
--- a/tests/DumpRenderTree/AndroidManifest.xml
+++ b/tests/DumpRenderTree/AndroidManifest.xml
@@ -23,7 +23,7 @@
<category android:name="android.intent.category.TEST" />
</intent-filter>
</activity>
- <activity android:name="HTMLHostActivity">
+ <activity android:name="TestShellActivity" android:launchMode="singleTop">
</activity>
</application>
diff --git a/tests/DumpRenderTree/results/layout_tests_crashed.txt b/tests/DumpRenderTree/results/layout_tests_crashed.txt
new file mode 100644
index 0000000..5a38ed8
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_crashed.txt
@@ -0,0 +1 @@
+/sdcard/android/layout_tests/fast/js/regexp-charclass-crash.html \ No newline at end of file
diff --git a/tests/DumpRenderTree/results/layout_tests_failed.txt b/tests/DumpRenderTree/results/layout_tests_failed.txt
new file mode 100644
index 0000000..3cec40d
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_failed.txt
@@ -0,0 +1,280 @@
+/sdcard/android/layout_tests/fast/replaced/image-map-bug16782.html : different length
+/sdcard/android/layout_tests/fast/replaced/table-percent-height.html : different length
+/sdcard/android/layout_tests/fast/replaced/image-map.html : different length
+/sdcard/android/layout_tests/fast/dynamic/paused-event-dispatch.html : @offset: 117
+/sdcard/android/layout_tests/fast/text/plain-text-line-breaks.html : different length
+/sdcard/android/layout_tests/fast/text/zero-width-characters.html : different length
+/sdcard/android/layout_tests/fast/text/reset-drag-on-mouse-down.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/encoding/invalid-xml.html : different length
+/sdcard/android/layout_tests/fast/encoding/char-decoding-mac.html : different length
+/sdcard/android/layout_tests/fast/encoding/frame-default-enc.html : @offset: 0
+/sdcard/android/layout_tests/fast/encoding/mailto-always-utf-8.html : different length
+/sdcard/android/layout_tests/fast/encoding/char-decoding.html : different length
+/sdcard/android/layout_tests/fast/encoding/url-host-name-non-ascii.html : different length
+/sdcard/android/layout_tests/fast/encoding/idn-security.html : different length
+/sdcard/android/layout_tests/fast/encoding/percent-escaping.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/encoding/xml-utf-8-default.xml : different length
+/sdcard/android/layout_tests/fast/encoding/char-encoding-mac.html : different length
+/sdcard/android/layout_tests/fast/encoding/charset-koi8-u.html : @offset: 147
+/sdcard/android/layout_tests/fast/encoding/preload-encoding.html : different length
+/sdcard/android/layout_tests/fast/workers/worker-location.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/workers/worker-constructor.html : different length
+/sdcard/android/layout_tests/fast/workers/worker-terminate.html : different length
+/sdcard/android/layout_tests/fast/workers/worker-gc.html : different length
+/sdcard/android/layout_tests/fast/workers/worker-navigator.html : different length
+/sdcard/android/layout_tests/fast/workers/worker-replace-global-constructor.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/workers/worker-replace-self.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/workers/worker-event-listener.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/overflow/scroll-vertical-not-horizontal.html : different length
+/sdcard/android/layout_tests/fast/events/onunload.html : different length
+/sdcard/android/layout_tests/fast/events/mouseup-outside-document.html : different length
+/sdcard/android/layout_tests/fast/events/offsetX-offsetY.html : different length
+/sdcard/android/layout_tests/fast/events/scroll-event-does-not-bubble.html : different length
+/sdcard/android/layout_tests/fast/events/mouseover-mouseout.html : different length
+/sdcard/android/layout_tests/fast/events/option-tab.html : different length
+/sdcard/android/layout_tests/fast/events/popup-blocking-click-in-iframe.html : different length
+/sdcard/android/layout_tests/fast/events/onchange-passwordfield.html : different length
+/sdcard/android/layout_tests/fast/events/drag-in-frames.html : different length
+/sdcard/android/layout_tests/fast/events/frame-tab-focus.html : different length
+/sdcard/android/layout_tests/fast/events/autoscroll-in-textfield.html : different length
+/sdcard/android/layout_tests/fast/events/arrow-navigation.html : different length
+/sdcard/android/layout_tests/fast/events/fire-scroll-event.html : different length
+/sdcard/android/layout_tests/fast/events/mouseclick-target-and-positioning.html : different length
+/sdcard/android/layout_tests/fast/events/keydown-keypress-focus-change.html : @offset: 172
+/sdcard/android/layout_tests/fast/events/input-image-scrolled-x-y.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/dblclick-addEventListener.html : different length
+/sdcard/android/layout_tests/fast/events/frame-programmatic-focus.html : different length
+/sdcard/android/layout_tests/fast/events/related-target.html : different length
+/sdcard/android/layout_tests/fast/events/content-changed-during-drop.html : different length
+/sdcard/android/layout_tests/fast/events/onload-fires-twice.html : different length
+/sdcard/android/layout_tests/fast/events/autoscroll-with-non-scrollable-parent.html : different length
+/sdcard/android/layout_tests/fast/events/window-events-capture.html : different length
+/sdcard/android/layout_tests/fast/events/onchange-click-hang.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/onload-webkit-before-webcore.html : @offset: 105
+/sdcard/android/layout_tests/fast/events/window-events-bubble2.html : different length
+/sdcard/android/layout_tests/fast/events/js-keyboard-event-creation.html : different length
+/sdcard/android/layout_tests/fast/events/event-view-toString.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/onchange-select-popup.html : different length
+/sdcard/android/layout_tests/fast/events/access-key-self-destruct.html : different length
+/sdcard/android/layout_tests/fast/events/scrollbar-double-click.html : different length
+/sdcard/android/layout_tests/fast/events/onunload-clears-onbeforeunload.html : different length
+/sdcard/android/layout_tests/fast/events/tabindex-focus-chain.html : @offset: 0
+/sdcard/android/layout_tests/fast/events/capture-on-target.html : different length
+/sdcard/android/layout_tests/fast/events/window-events-bubble.html : different length
+/sdcard/android/layout_tests/fast/events/mouseup-from-button2.html : different length
+/sdcard/android/layout_tests/fast/events/frame-click-focus.html : different length
+/sdcard/android/layout_tests/fast/events/mouseout-on-window.html : different length
+/sdcard/android/layout_tests/fast/events/keypress-insert-tab.html : @offset: 85
+/sdcard/android/layout_tests/fast/events/mouseout-dead-subframe.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/iframe-object-onload.html : different length
+/sdcard/android/layout_tests/fast/events/onunload-not-on-body.html : different length
+/sdcard/android/layout_tests/fast/events/mousemove-after-drag-over-scrollbar.html : different length
+/sdcard/android/layout_tests/fast/events/contextmenu-scrolled-page-with-frame.html : different length
+/sdcard/android/layout_tests/fast/events/key-events-in-input-button.html : different length
+/sdcard/android/layout_tests/fast/events/arrow-keys-on-body.html : different length
+/sdcard/android/layout_tests/fast/events/ondragenter.html : different length
+/sdcard/android/layout_tests/fast/events/scroll-to-anchor-in-overflow-hidden.html : different length
+/sdcard/android/layout_tests/fast/events/autoscroll-nonscrollable-iframe-in-scrollable-div.html : different length
+/sdcard/android/layout_tests/fast/events/keypress-focus-change.html : different length
+/sdcard/android/layout_tests/fast/events/key-events-in-input-text.html : different length
+/sdcard/android/layout_tests/fast/events/drag-outside-window.html : @offset: 20
+/sdcard/android/layout_tests/fast/events/selectstart-during-autoscroll.html : different length
+/sdcard/android/layout_tests/fast/events/click-count.html : different length
+/sdcard/android/layout_tests/fast/events/onchange-searchfield.html : different length
+/sdcard/android/layout_tests/fast/events/special-key-events-in-input-text.html : different length
+/sdcard/android/layout_tests/fast/events/keydown-keypress-preventDefault.html : @offset: 228
+/sdcard/android/layout_tests/fast/events/mouse-click-events.html : different length
+/sdcard/android/layout_tests/fast/events/onsearch-enter.html : different length
+/sdcard/android/layout_tests/fast/events/mouseover-mouseout2.html : different length
+/sdcard/android/layout_tests/fast/events/open-window-from-another-frame.html : different length
+/sdcard/android/layout_tests/fast/events/init-events.html : different length
+/sdcard/android/layout_tests/fast/events/onchange-textfield.html : different length
+/sdcard/android/layout_tests/fast/events/onclick-list-marker.html : different length
+/sdcard/android/layout_tests/fast/events/anchor-image-scrolled-x-y.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/html/tab-order.html : @offset: 246
+/sdcard/android/layout_tests/fast/js/exception-sequencing-binops.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/recursion-limit-equal.html : different length
+/sdcard/android/layout_tests/fast/js/exception-sequencing-binops2.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/math-transforms.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/try-catch-crash.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/navigator-mimeTypes-length.html : different length
+/sdcard/android/layout_tests/fast/js/global-constructors.html : different length
+/sdcard/android/layout_tests/fast/js/uncaught-exception-line-number.html : different length
+/sdcard/android/layout_tests/fast/js/exceptions-thrown-in-callbacks.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/toString-and-valueOf-override.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/exception-sequencing.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/exception-codegen-crash.html : different length
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/activeElement.html : different length
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/hasFocus.html : different length
+/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/listbox-select-reset.html : different length
+/sdcard/android/layout_tests/fast/dom/Element/offsetLeft-offsetTop-body-quirk.html : different length
+/sdcard/android/layout_tests/fast/dom/DOMException/XPathException.html : different length
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/010.xml : different length
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/011.xml : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-resize-and-move-arguments.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-function-name-getter-precedence.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-xy-properties.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/console-functions.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-screen-properties.html : @offset: 65
+/sdcard/android/layout_tests/fast/dom/Window/window-properties.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/Window/window-onFocus.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/new-window-opener.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/Window/window-open-pending-url.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/setting-properties-on-closed-window.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/Window/dom-access-from-closure-window.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-resize.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-custom-prototype.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/dom-access-from-closure-iframe.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/Plug-ins.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/get-set-properties.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-scroll-arguments.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-early-properties.html : different length
+/sdcard/android/layout_tests/fast/dom/StyleSheet/ownerNode-lifetime-2.html : different length
+/sdcard/android/layout_tests/fast/dom/dom-constructors.html : different length
+/sdcard/android/layout_tests/fast/dom/assign-to-window-status.html : different length
+/sdcard/android/layout_tests/fast/dom/gc-8.html : different length
+/sdcard/android/layout_tests/fast/dom/object-embed-plugin-scripting.html : different length
+/sdcard/android/layout_tests/fast/dom/gc-9.html : different length
+/sdcard/android/layout_tests/fast/dom/NamedNodeMap-setNamedItem-crash.html : different length
+/sdcard/android/layout_tests/fast/dom/wrapper-classes.html : different length
+/sdcard/android/layout_tests/fast/dom/select-selectedIndex.html : different length
+/sdcard/android/layout_tests/fast/dom/document-width-height-force-layout.html : @offset: 142
+/sdcard/android/layout_tests/fast/dom/client-width-height.html : @offset: 119
+/sdcard/android/layout_tests/fast/dom/clone-node-form-elements-with-attr.html : different length
+/sdcard/android/layout_tests/fast/dom/dom-add-optionelement.html : different length
+/sdcard/android/layout_tests/fast/dom/location-assign.html : different length
+/sdcard/android/layout_tests/fast/dom/javascript-backslash.html : different length
+/sdcard/android/layout_tests/fast/dom/global-constructors.html : different length
+/sdcard/android/layout_tests/fast/dom/client-width-height-quirks.html : @offset: 115
+/sdcard/android/layout_tests/fast/dom/javascript-url-crash-function.html : different length
+/sdcard/android/layout_tests/fast/dom/location-hash.html : different length
+/sdcard/android/layout_tests/fast/dom/constructors-cached.html : different length
+/sdcard/android/layout_tests/fast/dom/documenturi-can-hold-arbitrary-string.html : different length
+/sdcard/android/layout_tests/fast/dom/documenturi-not-affected-by-base-tag.html : different length
+/sdcard/android/layout_tests/fast/dom/open-and-close-by-DOM.html : different length
+/sdcard/android/layout_tests/fast/dom/document_write_params.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/tabindex-clamp.html : different length
+/sdcard/android/layout_tests/fast/dom/constructors-cached-navigate.html : different length
+/sdcard/android/layout_tests/fast/dom/frame-loading-via-document-write.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/ImageDocument-image-deletion.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-text-plain.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/advanced-get.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-text-plain-latin-1.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-multipart-form-data.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-always-utf-8.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-append-query.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items-x-www-form-urlencoded.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-overwrite-query.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-x-www-form-urlencoded.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items-text-plain.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-text-plain.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-text-plain-with-accept-charset.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-text-plain.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/advanced-put.html : different length
+/sdcard/android/layout_tests/fast/forms/listbox-typeahead-scroll.html : different length
+/sdcard/android/layout_tests/fast/forms/select-empty-list.html : different length
+/sdcard/android/layout_tests/fast/forms/select-accesskey.html : different length
+/sdcard/android/layout_tests/fast/forms/focus2.html : different length
+/sdcard/android/layout_tests/fast/forms/password-doubleclick-selection.html : different length
+/sdcard/android/layout_tests/fast/forms/textfield-inside-anchor.html : different length
+/sdcard/android/layout_tests/fast/forms/input-maxlength.html : different length
+/sdcard/android/layout_tests/fast/forms/input-text-option-delete.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/selection-functions.html : @offset: 306
+/sdcard/android/layout_tests/fast/forms/textfield-to-password-on-focus.html : different length
+/sdcard/android/layout_tests/fast/forms/focus-selection-textarea.html : different length
+/sdcard/android/layout_tests/fast/forms/enter-clicks-buttons.html : different length
+/sdcard/android/layout_tests/fast/forms/menulist-no-renderer-onmousedown.html : different length
+/sdcard/android/layout_tests/fast/forms/select-display-none-style-resolve.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/radio_checked_name.html : @offset: 303
+/sdcard/android/layout_tests/fast/forms/select-double-onchange.html : different length
+/sdcard/android/layout_tests/fast/forms/button-enter-click.html : different length
+/sdcard/android/layout_tests/fast/forms/11423.html : different length
+/sdcard/android/layout_tests/fast/forms/search-click-in-placeholder.html : @offset: 1
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-003.html : @offset: 51
+/sdcard/android/layout_tests/fast/forms/search-hidden-cancel-button.html : different length
+/sdcard/android/layout_tests/fast/forms/willvalidate-004.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-paste-newline.html : different length
+/sdcard/android/layout_tests/fast/forms/drag-into-textarea.html : different length
+/sdcard/android/layout_tests/fast/forms/onselect-textfield.html : different length
+/sdcard/android/layout_tests/fast/forms/input-implicit-length-limit.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/form-and-frame-interaction-retains-values.html : different length
+/sdcard/android/layout_tests/fast/forms/input-appearance-focus.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/slider-transformed.html : different length
+/sdcard/android/layout_tests/fast/forms/listbox-select-all.html : different length
+/sdcard/android/layout_tests/fast/forms/textfield-onchange-deletion.html : different length
+/sdcard/android/layout_tests/fast/forms/focus-control-to-page.html : different length
+/sdcard/android/layout_tests/fast/forms/select-type-ahead-non-latin.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-no-scroll-on-blur.html : @offset: 79
+/sdcard/android/layout_tests/fast/forms/focus-selection-input.html : different length
+/sdcard/android/layout_tests/fast/forms/listbox-onchange.html : different length
+/sdcard/android/layout_tests/fast/forms/button-spacebar-click.html : different length
+/sdcard/android/layout_tests/fast/forms/search-event-delay.html : different length
+/sdcard/android/layout_tests/fast/forms/search-cancel-button-mouseup.html : different length
+/sdcard/android/layout_tests/fast/forms/select-enter-key.html : different length
+/sdcard/android/layout_tests/fast/forms/drag-out-of-textarea.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-hard-linewrap.html : different length
+/sdcard/android/layout_tests/fast/forms/input-type-change-in-onfocus-keyboard.html : different length
+/sdcard/android/layout_tests/fast/forms/dragging-to-disabled-file-input.html : different length
+/sdcard/android/layout_tests/fast/forms/input-radio-checked-tab.html : @offset: 115
+/sdcard/android/layout_tests/fast/forms/plaintext-mode-1.html : different length
+/sdcard/android/layout_tests/fast/forms/option-in-optgroup-removal.html : different length
+/sdcard/android/layout_tests/fast/forms/search-display-none-cancel-button.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/check-box-enter-key.html : different length
+/sdcard/android/layout_tests/fast/forms/input-select-on-click.html : different length
+/sdcard/android/layout_tests/fast/forms/button-state-restore.html : different length
+/sdcard/android/layout_tests/fast/forms/access-key.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-scrolled-endline-caret.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-type-spaces.html : different length
+/sdcard/android/layout_tests/fast/forms/slider-mouse-events.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-selection-preservation.html : different length
+/sdcard/android/layout_tests/fast/forms/slider-onchange-event.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-appearance-wrap.html : different length
+/sdcard/android/layout_tests/fast/forms/onselect-textarea.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-initial-caret-position.html : different length
+/sdcard/android/layout_tests/fast/forms/listbox-selection.html : different length
+/sdcard/android/layout_tests/fast/css/variables/color-hex-test.html : different length
+/sdcard/android/layout_tests/fast/css/dashboard-region-parser.html : different length
+/sdcard/android/layout_tests/fast/css/hover-affects-child.html : different length
+/sdcard/android/layout_tests/fast/css/html-attr-case-sensitivity.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/css/computed-style.html : different length
+/sdcard/android/layout_tests/fast/css/getComputedStyle-transform.html : different length
+/sdcard/android/layout_tests/fast/css/computed-style-without-renderer.html : different length
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-iframe.html : @offset: 0
+/sdcard/android/layout_tests/fast/parser/external-entities.xml : different length
+/sdcard/android/layout_tests/fast/parser/script-tag-with-trailing-slash.html : different length
+/sdcard/android/layout_tests/fast/parser/comment-in-iframe.html : @offset: 0
+/sdcard/android/layout_tests/fast/parser/xml-declaration-missing-ending-mark.html : different length
+/sdcard/android/layout_tests/fast/parser/entity-end-script-tag.html : different length
+/sdcard/android/layout_tests/fast/parser/tabindex-parsing.html : different length
+/sdcard/android/layout_tests/fast/history/subframe-is-visited.html : different length
+/sdcard/android/layout_tests/fast/history/window-open.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/history/go-back-to-changed-name.html : different length
+/sdcard/android/layout_tests/fast/loader/cancel-load-during-port-block-timer.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/loader/local-iFrame-source-from-local.html : different length
+/sdcard/android/layout_tests/fast/loader/null-request-after-willSendRequest.html : different length
+/sdcard/android/layout_tests/fast/loader/stop-provisional-loads.html : different length
+/sdcard/android/layout_tests/fast/loader/xmlhttprequest-missing-file-exception.html : different length
+/sdcard/android/layout_tests/fast/loader/onunload-form-submit-crash-2.html : different length
+/sdcard/android/layout_tests/fast/loader/plain-text-document.html : different length
+/sdcard/android/layout_tests/fast/loader/onunload-form-submit-crash.html : different length
+/sdcard/android/layout_tests/fast/loader/local-image-from-local.html : different length
+/sdcard/android/layout_tests/fast/loader/local-CSS-from-local.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/loader/local-JavaScript-from-local.html : different length
+/sdcard/android/layout_tests/fast/loader/data-url-encoding-svg.html : different length
+/sdcard/android/layout_tests/fast/loader/opaque-base-url.html : @offset: 129
+/sdcard/android/layout_tests/fast/canvas/canvas-alphaImageData-behavior.html : different length
+/sdcard/android/layout_tests/fast/canvas/pointInPath.html : different length
+/sdcard/android/layout_tests/fast/canvas/toDataURL-supportedTypes.html : different length
+/sdcard/android/layout_tests/fast/canvas/canvas-getImageData.html : different length
+/sdcard/android/layout_tests/fast/canvas/canvas-longlived-context.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/canvas/canvas-save-restore-with-path.html : different length
+/sdcard/android/layout_tests/fast/canvas/set-colors.html : different length
+/sdcard/android/layout_tests/fast/frames/viewsource-empty-attribute-value.html : different length
+/sdcard/android/layout_tests/fast/frames/frame-deep-nested-resize.html : different length
+/sdcard/android/layout_tests/fast/frames/iframe-window-focus.html : different length
+/sdcard/android/layout_tests/fast/frames/frameElement-widthheight.html : different length
+/sdcard/android/layout_tests/fast/frames/removal-before-attach-crash.html : different length
+/sdcard/android/layout_tests/fast/frames/frame-js-url-clientWidth.html : different length
diff --git a/tests/DumpRenderTree/results/layout_tests_nontext.txt b/tests/DumpRenderTree/results/layout_tests_nontext.txt
new file mode 100644
index 0000000..c9e166c
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_nontext.txt
@@ -0,0 +1,1753 @@
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-05.html
+/sdcard/android/layout_tests/fast/media/mq-grid-02.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-02.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-09.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-03.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-02.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-04.html
+/sdcard/android/layout_tests/fast/media/mq-min-pixel-ratio.html
+/sdcard/android/layout_tests/fast/media/implicit-media-all.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-01.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-03.html
+/sdcard/android/layout_tests/fast/media/viewport-media-query.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-05.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-01.html
+/sdcard/android/layout_tests/fast/media/mq-transition.html
+/sdcard/android/layout_tests/fast/media/mq-transform-04.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-05.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-except-02.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-02.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-03.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-06.html
+/sdcard/android/layout_tests/fast/media/mq-valueless.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-03.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-01.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-03.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-04.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-05.html
+/sdcard/android/layout_tests/fast/media/mq-animation.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-02.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-04.html
+/sdcard/android/layout_tests/fast/media/media-type-syntax-01.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-06.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-02.html
+/sdcard/android/layout_tests/fast/media/mq-transform-01.html
+/sdcard/android/layout_tests/fast/media/monochrome.html
+/sdcard/android/layout_tests/fast/media/mq-pixel-ratio.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-except-03.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-03.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-04.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-07.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-04.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-01.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-02.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-04.html
+/sdcard/android/layout_tests/fast/media/mq-max-pixel-ratio.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-01.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-03.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-05.html
+/sdcard/android/layout_tests/fast/media/media-type-syntax-02.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-03.html
+/sdcard/android/layout_tests/fast/media/mq-transform-02.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-01.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-04.html
+/sdcard/android/layout_tests/fast/media/mq-grid-01.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-01.html
+/sdcard/android/layout_tests/fast/media/mq-min-constraint.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-08.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-05.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-02.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-01.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-03.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-forward-syntax.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-02.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-04.html
+/sdcard/android/layout_tests/fast/media/mq-transform-03.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-04.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-except-01.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-02.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-radio.html
+/sdcard/android/layout_tests/fast/replaced/object-align-hspace-vspace.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-menulist.html
+/sdcard/android/layout_tests/fast/replaced/selection-rect.html
+/sdcard/android/layout_tests/fast/replaced/image-sizing.html
+/sdcard/android/layout_tests/fast/replaced/minheight-pxs.html
+/sdcard/android/layout_tests/fast/replaced/maxheight-pxs.html
+/sdcard/android/layout_tests/fast/replaced/inline-box-wrapper-handover.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-searchfield.html
+/sdcard/android/layout_tests/fast/replaced/selection-rect-transform.html
+/sdcard/android/layout_tests/fast/replaced/pdf-as-image.html
+/sdcard/android/layout_tests/fast/replaced/replaced-breaking-mixture.html
+/sdcard/android/layout_tests/fast/replaced/minwidth-pxs.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-textarea.html
+/sdcard/android/layout_tests/fast/replaced/maxwidth-pxs.html
+/sdcard/android/layout_tests/fast/replaced/max-width-percent.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-percentage-height.html
+/sdcard/android/layout_tests/fast/replaced/002.html
+/sdcard/android/layout_tests/fast/replaced/004.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-checkbox.html
+/sdcard/android/layout_tests/fast/replaced/applet-disabled-positioned.html
+/sdcard/android/layout_tests/fast/replaced/006.html
+/sdcard/android/layout_tests/fast/replaced/008.html
+/sdcard/android/layout_tests/fast/replaced/percent-height-in-anonymous-block-widget.html
+/sdcard/android/layout_tests/fast/replaced/minheight-percent.html
+/sdcard/android/layout_tests/fast/replaced/maxheight-percent.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-with-auto-width-and-left-and-right.html
+/sdcard/android/layout_tests/fast/replaced/minwidth-percent.html
+/sdcard/android/layout_tests/fast/replaced/maxwidth-percent.html
+/sdcard/android/layout_tests/fast/replaced/applet-rendering-java-disabled.html
+/sdcard/android/layout_tests/fast/replaced/selection-rect-in-table-cell.html
+/sdcard/android/layout_tests/fast/replaced/percent-height-in-anonymous-block.html
+/sdcard/android/layout_tests/fast/replaced/three-selects-break.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-button.html
+/sdcard/android/layout_tests/fast/replaced/image-tag.html
+/sdcard/android/layout_tests/fast/replaced/image-onload.html
+/sdcard/android/layout_tests/fast/replaced/image-resize-width.html
+/sdcard/android/layout_tests/fast/replaced/absolute-image-sizing.html
+/sdcard/android/layout_tests/fast/replaced/replaced-breaking.html
+/sdcard/android/layout_tests/fast/replaced/001.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-image.html
+/sdcard/android/layout_tests/fast/replaced/image-solid-color-with-alpha.html
+/sdcard/android/layout_tests/fast/replaced/003.html
+/sdcard/android/layout_tests/fast/replaced/replaced-child-of-absolute-with-auto-height.html
+/sdcard/android/layout_tests/fast/replaced/005.html
+/sdcard/android/layout_tests/fast/replaced/007.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-with-auto-height-and-top-and-bottom.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-textfield.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-percentage-width.html
+/sdcard/android/layout_tests/fast/dynamic/positioned-movement-with-positioned-children.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-table-cell-height.html
+/sdcard/android/layout_tests/fast/dynamic/move-node-with-selection.html
+/sdcard/android/layout_tests/fast/dynamic/create-renderer-for-whitespace-only-text.html
+/sdcard/android/layout_tests/fast/dynamic/outerHTML-doc.html
+/sdcard/android/layout_tests/fast/dynamic/floating-to-positioned-2.html
+/sdcard/android/layout_tests/fast/dynamic/012.html
+/sdcard/android/layout_tests/fast/dynamic/004.html
+/sdcard/android/layout_tests/fast/dynamic/008.html
+/sdcard/android/layout_tests/fast/dynamic/float-no-longer-overhanging.html
+/sdcard/android/layout_tests/fast/dynamic/float-withdrawal-2.html
+/sdcard/android/layout_tests/fast/dynamic/float-in-trailing-whitespace-after-last-line-break.html
+/sdcard/android/layout_tests/fast/dynamic/selection-highlight-adjust.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-no-common-root-static-y.html
+/sdcard/android/layout_tests/fast/dynamic/genContentDestroyChildren.html
+/sdcard/android/layout_tests/fast/dynamic/001.html
+/sdcard/android/layout_tests/fast/dynamic/link-href-change.html
+/sdcard/android/layout_tests/fast/dynamic/013.html
+/sdcard/android/layout_tests/fast/dynamic/005.html
+/sdcard/android/layout_tests/fast/dynamic/009.html
+/sdcard/android/layout_tests/fast/dynamic/float-withdrawal.html
+/sdcard/android/layout_tests/fast/dynamic/anonymous-block-layer-lost.html
+/sdcard/android/layout_tests/fast/dynamic/layer-hit-test-crash.html
+/sdcard/android/layout_tests/fast/dynamic/view-overflow.html
+/sdcard/android/layout_tests/fast/dynamic/010.html
+/sdcard/android/layout_tests/fast/dynamic/002.html
+/sdcard/android/layout_tests/fast/dynamic/014.html
+/sdcard/android/layout_tests/fast/dynamic/006.html
+/sdcard/android/layout_tests/fast/dynamic/flash-replacement-test.html
+/sdcard/android/layout_tests/fast/dynamic/insert-before-table-part-in-continuation.html
+/sdcard/android/layout_tests/fast/dynamic/staticY.html
+/sdcard/android/layout_tests/fast/dynamic/anonymous-block-orphaned-lines.html
+/sdcard/android/layout_tests/fast/dynamic/noninlinebadness.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-parent-static-y.html
+/sdcard/android/layout_tests/fast/dynamic/outerHTML-img.html
+/sdcard/android/layout_tests/fast/dynamic/staticY-marking-parents-regression.html
+/sdcard/android/layout_tests/fast/dynamic/floating-to-positioned.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-boundary-percent-height.html
+/sdcard/android/layout_tests/fast/dynamic/011.html
+/sdcard/android/layout_tests/fast/dynamic/containing-block-change.html
+/sdcard/android/layout_tests/fast/dynamic/015.html
+/sdcard/android/layout_tests/fast/dynamic/007.html
+/sdcard/android/layout_tests/fast/text/firstline/001.html
+/sdcard/android/layout_tests/fast/text/firstline/002.html
+/sdcard/android/layout_tests/fast/text/firstline/003.html
+/sdcard/android/layout_tests/fast/text/international/wrap-CJK-001.html
+/sdcard/android/layout_tests/fast/text/international/bidi-listbox-atsui.html
+/sdcard/android/layout_tests/fast/text/international/hindi-spacing.html
+/sdcard/android/layout_tests/fast/text/international/thai-line-breaks.html
+/sdcard/android/layout_tests/fast/text/international/bidi-neutral-run.html
+/sdcard/android/layout_tests/fast/text/international/bidi-L2-run-reordering.html
+/sdcard/android/layout_tests/fast/text/international/bidi-override.html
+/sdcard/android/layout_tests/fast/text/international/bidi-innertext.html
+/sdcard/android/layout_tests/fast/text/international/bidi-european-terminators.html
+/sdcard/android/layout_tests/fast/text/international/bidi-listbox.html
+/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-formatting-characters.html
+/sdcard/android/layout_tests/fast/text/international/bidi-AN-after-L.html
+/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-CSS.html
+/sdcard/android/layout_tests/fast/text/international/bidi-control-chars-treated-as-ZWS.html
+/sdcard/android/layout_tests/fast/text/international/rtl-caret.html
+/sdcard/android/layout_tests/fast/text/international/bidi-neutral-directionality-paragraph-start.html
+/sdcard/android/layout_tests/fast/text/international/bidi-AN-after-empty-run.html
+/sdcard/android/layout_tests/fast/text/international/001.html
+/sdcard/android/layout_tests/fast/text/international/002.html
+/sdcard/android/layout_tests/fast/text/international/bidi-ignored-for-first-child-inline.html
+/sdcard/android/layout_tests/fast/text/international/bidi-explicit-embedding.html
+/sdcard/android/layout_tests/fast/text/international/003.html
+/sdcard/android/layout_tests/fast/text/international/rtl-white-space-pre-wrap.html
+/sdcard/android/layout_tests/fast/text/international/bidi-layout-across-linebreak.html
+/sdcard/android/layout_tests/fast/text/international/bidi-CS-after-AN.html
+/sdcard/android/layout_tests/fast/text/international/bidi-menulist.html
+/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-HTML.html
+/sdcard/android/layout_tests/fast/text/international/complex-character-based-fallback.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-overflow-selection.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-newline-box-test.html
+/sdcard/android/layout_tests/fast/text/whitespace/span-in-word-space-causes-overflow.html
+/sdcard/android/layout_tests/fast/text/whitespace/nowrap-clear-float.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-line-test.html
+/sdcard/android/layout_tests/fast/text/whitespace/010.html
+/sdcard/android/layout_tests/fast/text/whitespace/020.html
+/sdcard/android/layout_tests/fast/text/whitespace/002.html
+/sdcard/android/layout_tests/fast/text/whitespace/030.html
+/sdcard/android/layout_tests/fast/text/whitespace/012.html
+/sdcard/android/layout_tests/fast/text/whitespace/022.html
+/sdcard/android/layout_tests/fast/text/whitespace/004.html
+/sdcard/android/layout_tests/fast/text/whitespace/014.html
+/sdcard/android/layout_tests/fast/text/whitespace/024.html
+/sdcard/android/layout_tests/fast/text/whitespace/006.html
+/sdcard/android/layout_tests/fast/text/whitespace/016.html
+/sdcard/android/layout_tests/fast/text/whitespace/008.html
+/sdcard/android/layout_tests/fast/text/whitespace/026.html
+/sdcard/android/layout_tests/fast/text/whitespace/018.html
+/sdcard/android/layout_tests/fast/text/whitespace/028.html
+/sdcard/android/layout_tests/fast/text/whitespace/normal-after-nowrap-breaking.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-break-word.html
+/sdcard/android/layout_tests/fast/text/whitespace/nbsp-mode-and-linewraps.html
+/sdcard/android/layout_tests/fast/text/whitespace/001.html
+/sdcard/android/layout_tests/fast/text/whitespace/011.html
+/sdcard/android/layout_tests/fast/text/whitespace/tab-character-basics.html
+/sdcard/android/layout_tests/fast/text/whitespace/003.html
+/sdcard/android/layout_tests/fast/text/whitespace/021.html
+/sdcard/android/layout_tests/fast/text/whitespace/013.html
+/sdcard/android/layout_tests/fast/text/whitespace/005.html
+/sdcard/android/layout_tests/fast/text/whitespace/023.html
+/sdcard/android/layout_tests/fast/text/whitespace/015.html
+/sdcard/android/layout_tests/fast/text/whitespace/025.html
+/sdcard/android/layout_tests/fast/text/whitespace/007.html
+/sdcard/android/layout_tests/fast/text/whitespace/017.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-spaces-after-newline.html
+/sdcard/android/layout_tests/fast/text/whitespace/027.html
+/sdcard/android/layout_tests/fast/text/whitespace/009.html
+/sdcard/android/layout_tests/fast/text/whitespace/019.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-last-char.html
+/sdcard/android/layout_tests/fast/text/whitespace/029.html
+/sdcard/android/layout_tests/fast/text/basic/001.html
+/sdcard/android/layout_tests/fast/text/basic/002.html
+/sdcard/android/layout_tests/fast/text/basic/011.html
+/sdcard/android/layout_tests/fast/text/basic/generic-family-changes.html
+/sdcard/android/layout_tests/fast/text/basic/003.html
+/sdcard/android/layout_tests/fast/text/basic/012.html
+/sdcard/android/layout_tests/fast/text/basic/004.html
+/sdcard/android/layout_tests/fast/text/basic/013.html
+/sdcard/android/layout_tests/fast/text/basic/005.html
+/sdcard/android/layout_tests/fast/text/basic/014.html
+/sdcard/android/layout_tests/fast/text/basic/006.html
+/sdcard/android/layout_tests/fast/text/basic/015.html
+/sdcard/android/layout_tests/fast/text/basic/007.html
+/sdcard/android/layout_tests/fast/text/basic/008.html
+/sdcard/android/layout_tests/fast/text/basic/009.html
+/sdcard/android/layout_tests/fast/text/basic/generic-family-reset.html
+/sdcard/android/layout_tests/fast/text/in-rendered-text-rtl.html
+/sdcard/android/layout_tests/fast/text/selection-painted-separately.html
+/sdcard/android/layout_tests/fast/text/bidi-embedding-pop-and-push-same.html
+/sdcard/android/layout_tests/fast/text/wbr-in-pre-crash.html
+/sdcard/android/layout_tests/fast/text/atsui-spacing-features.html
+/sdcard/android/layout_tests/fast/text/textIteratorNilRenderer.html
+/sdcard/android/layout_tests/fast/text/drawBidiText.html
+/sdcard/android/layout_tests/fast/text/selection-hard-linebreak.html
+/sdcard/android/layout_tests/fast/text/word-break.html
+/sdcard/android/layout_tests/fast/text/font-initial.html
+/sdcard/android/layout_tests/fast/text/break-word.html
+/sdcard/android/layout_tests/fast/text/stroking.html
+/sdcard/android/layout_tests/fast/text/midword-break-hang.html
+/sdcard/android/layout_tests/fast/text/atsui-partial-selection.html
+/sdcard/android/layout_tests/fast/text/embed-at-end-of-pre-wrap-line.html
+/sdcard/android/layout_tests/fast/text/atsui-multiple-renderers.html
+/sdcard/android/layout_tests/fast/text/apply-start-width-after-skipped-text.html
+/sdcard/android/layout_tests/fast/text/capitalize-preserve-nbsp.html
+/sdcard/android/layout_tests/fast/text/updateNewFont.html
+/sdcard/android/layout_tests/fast/text/atsui-rtl-override-selection.html
+/sdcard/android/layout_tests/fast/text/align-center-rtl-spill.html
+/sdcard/android/layout_tests/fast/text/wbr.html
+/sdcard/android/layout_tests/fast/text/cg-vs-atsui.html
+/sdcard/android/layout_tests/fast/text/monospace-width-cache.html
+/sdcard/android/layout_tests/fast/text/soft-hyphen-2.html
+/sdcard/android/layout_tests/fast/text/justified-selection.html
+/sdcard/android/layout_tests/fast/text/atsui-pointtooffset-calls-cg.html
+/sdcard/android/layout_tests/fast/text/atsui-kerning-and-ligatures.html
+/sdcard/android/layout_tests/fast/text/wbr-pre.html
+/sdcard/android/layout_tests/fast/text/capitalize-boundaries.html
+/sdcard/android/layout_tests/fast/text/trailing-white-space.html
+/sdcard/android/layout_tests/fast/text/capitalize-empty-generated-string.html
+/sdcard/android/layout_tests/fast/text/stripNullFromText.html
+/sdcard/android/layout_tests/fast/text/letter-spacing-negative-opacity.html
+/sdcard/android/layout_tests/fast/text/atsui-small-caps-punctuation-size.html
+/sdcard/android/layout_tests/fast/text/word-break-soft-hyphen.html
+/sdcard/android/layout_tests/fast/text/fixed-pitch-control-characters.html
+/sdcard/android/layout_tests/fast/text/cg-fallback-bolding.html
+/sdcard/android/layout_tests/fast/text/line-breaks-after-white-space.html
+/sdcard/android/layout_tests/fast/text/soft-hyphen-3.html
+/sdcard/android/layout_tests/fast/text/wide-zero-width-space.html
+/sdcard/android/layout_tests/fast/text/should-use-atsui.html
+/sdcard/android/layout_tests/fast/text/justified-selection-at-edge.html
+/sdcard/android/layout_tests/fast/text/trailing-white-space-2.html
+/sdcard/android/layout_tests/fast/text/word-break-run-rounding.html
+/sdcard/android/layout_tests/fast/text/softHyphen.html
+/sdcard/android/layout_tests/fast/text/delete-hard-break-character.html
+/sdcard/android/layout_tests/fast/text/line-breaks.html
+/sdcard/android/layout_tests/fast/text/wbr-styled.html
+/sdcard/android/layout_tests/fast/text/large-text-composed-char.html
+/sdcard/android/layout_tests/fast/text/shadow-no-blur.html
+/sdcard/android/layout_tests/fast/text/reset-emptyRun.html
+/sdcard/android/layout_tests/fast/text/word-space.html
+/sdcard/android/layout_tests/fast/text/midword-break-after-breakable-char.html
+/sdcard/android/layout_tests/fast/text/stroking-decorations.html
+/sdcard/android/layout_tests/fast/encoding/utf-16-little-endian.html
+/sdcard/android/layout_tests/fast/encoding/denormalised-voiced-japanese-chars.html
+/sdcard/android/layout_tests/fast/encoding/utf-16-no-bom.xml
+/sdcard/android/layout_tests/fast/encoding/utf-16-big-endian.html
+/sdcard/android/layout_tests/fast/encoding/xmacroman-encoding-test.html
+/sdcard/android/layout_tests/fast/encoding/invalid-UTF-8.html
+/sdcard/android/layout_tests/fast/multicol/negativeColumnWidth.html
+/sdcard/android/layout_tests/fast/multicol/column-rules.html
+/sdcard/android/layout_tests/fast/multicol/zeroColumnCount.html
+/sdcard/android/layout_tests/fast/multicol/columns-shorthand-parsing.html
+/sdcard/android/layout_tests/fast/multicol/float-multicol.html
+/sdcard/android/layout_tests/fast/doctypes/001.html
+/sdcard/android/layout_tests/fast/doctypes/002.html
+/sdcard/android/layout_tests/fast/doctypes/003.html
+/sdcard/android/layout_tests/fast/doctypes/004.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-row-group-to-inline.html
+/sdcard/android/layout_tests/fast/css-generated-content/spellingToolTip-assert.html
+/sdcard/android/layout_tests/fast/css-generated-content/no-openclose-quote.html
+/sdcard/android/layout_tests/fast/css-generated-content/before-with-first-letter.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-row-group-with-before.html
+/sdcard/android/layout_tests/fast/css-generated-content/010.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-with-before.html
+/sdcard/android/layout_tests/fast/css-generated-content/002.html
+/sdcard/android/layout_tests/fast/css-generated-content/012.html
+/sdcard/android/layout_tests/fast/css-generated-content/004.html
+/sdcard/android/layout_tests/fast/css-generated-content/014.html
+/sdcard/android/layout_tests/fast/css-generated-content/016.html
+/sdcard/android/layout_tests/fast/css-generated-content/008.html
+/sdcard/android/layout_tests/fast/css-generated-content/after-order.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-cell-before-content.html
+/sdcard/android/layout_tests/fast/css-generated-content/visibleContentHiddenParent.html
+/sdcard/android/layout_tests/fast/css-generated-content/inline-display-types.html
+/sdcard/android/layout_tests/fast/css-generated-content/positioned-background-hit-test-crash.html
+/sdcard/android/layout_tests/fast/css-generated-content/001.html
+/sdcard/android/layout_tests/fast/css-generated-content/011.html
+/sdcard/android/layout_tests/fast/css-generated-content/003.html
+/sdcard/android/layout_tests/fast/css-generated-content/013.html
+/sdcard/android/layout_tests/fast/css-generated-content/005.html
+/sdcard/android/layout_tests/fast/css-generated-content/hover-style-change.html
+/sdcard/android/layout_tests/fast/css-generated-content/absolute-position-inside-inline.html
+/sdcard/android/layout_tests/fast/css-generated-content/015.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-row-with-before.html
+/sdcard/android/layout_tests/fast/css-generated-content/007.html
+/sdcard/android/layout_tests/fast/css-generated-content/009.html
+/sdcard/android/layout_tests/fast/css-generated-content/wbr-with-before-content.html
+/sdcard/android/layout_tests/fast/workers/stress-js-execution.html : has expected results
+/sdcard/android/layout_tests/fast/lists/decimal-leading-zero.html
+/sdcard/android/layout_tests/fast/lists/ol-display-types.html
+/sdcard/android/layout_tests/fast/lists/li-style-alpha-huge-value-crash.html
+/sdcard/android/layout_tests/fast/lists/ol-start-dynamic.html
+/sdcard/android/layout_tests/fast/lists/numeric-markers-outside-list.html
+/sdcard/android/layout_tests/fast/lists/marker-image-error.html
+/sdcard/android/layout_tests/fast/lists/marker-before-empty-inline.html
+/sdcard/android/layout_tests/fast/lists/scrolled-marker-paint.html
+/sdcard/android/layout_tests/fast/lists/li-values.html
+/sdcard/android/layout_tests/fast/lists/002.html
+/sdcard/android/layout_tests/fast/lists/dynamic-marker-crash.html
+/sdcard/android/layout_tests/fast/lists/list-item-line-height.html
+/sdcard/android/layout_tests/fast/lists/004.html
+/sdcard/android/layout_tests/fast/lists/drag-into-marker.html
+/sdcard/android/layout_tests/fast/lists/list-style-none-crash.html
+/sdcard/android/layout_tests/fast/lists/alpha-list-wrap.html
+/sdcard/android/layout_tests/fast/lists/006.html
+/sdcard/android/layout_tests/fast/lists/008.html
+/sdcard/android/layout_tests/fast/lists/inlineBoxWrapperNullCheck.html
+/sdcard/android/layout_tests/fast/lists/w3-list-styles.html
+/sdcard/android/layout_tests/fast/lists/item-not-in-list-line-wrapping.html
+/sdcard/android/layout_tests/fast/lists/olstart.html
+/sdcard/android/layout_tests/fast/lists/big-list-marker.html
+/sdcard/android/layout_tests/fast/lists/markers-in-selection.html
+/sdcard/android/layout_tests/fast/lists/list-style-type-dynamic-change.html
+/sdcard/android/layout_tests/fast/lists/001.html
+/sdcard/android/layout_tests/fast/lists/ordered-list-with-no-ol-tag.html
+/sdcard/android/layout_tests/fast/lists/003.html
+/sdcard/android/layout_tests/fast/lists/005.html
+/sdcard/android/layout_tests/fast/lists/li-br.html
+/sdcard/android/layout_tests/fast/lists/007.html
+/sdcard/android/layout_tests/fast/lists/009.html
+/sdcard/android/layout_tests/fast/transforms/transform-overflow.html
+/sdcard/android/layout_tests/fast/transforms/transforms-with-opacity.html
+/sdcard/android/layout_tests/fast/transforms/transformed-caret.html
+/sdcard/android/layout_tests/fast/transforms/matrix-01.html
+/sdcard/android/layout_tests/fast/transforms/transform-positioned-ancestor.html
+/sdcard/android/layout_tests/fast/transforms/matrix-02.html
+/sdcard/android/layout_tests/fast/transforms/skew-with-unitless-zero.html
+/sdcard/android/layout_tests/fast/transforms/overflow-with-transform.html
+/sdcard/android/layout_tests/fast/transforms/transformed-document-element.html
+/sdcard/android/layout_tests/fast/transforms/shadows.html
+/sdcard/android/layout_tests/fast/transforms/transformed-focused-text-input.html
+/sdcard/android/layout_tests/fast/transforms/diamond.html
+/sdcard/android/layout_tests/fast/transforms/identity-matrix.html
+/sdcard/android/layout_tests/fast/innerHTML/001.html
+/sdcard/android/layout_tests/fast/innerHTML/002.html
+/sdcard/android/layout_tests/fast/innerHTML/003.html
+/sdcard/android/layout_tests/fast/innerHTML/006.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDouble01.html
+/sdcard/android/layout_tests/fast/borders/block-mask-overlay-image.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid03.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDouble03.html
+/sdcard/android/layout_tests/fast/borders/border-color-inherit.html
+/sdcard/android/layout_tests/fast/borders/svg-as-border-image-2.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusInvalidColor.html
+/sdcard/android/layout_tests/fast/borders/border-image-scale-transform.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDotted02.html
+/sdcard/android/layout_tests/fast/borders/border-fit.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusArcs01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDashed01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDashed03.html
+/sdcard/android/layout_tests/fast/borders/fieldsetBorderRadius.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusAllStylesAllCorners.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusGroove01.html
+/sdcard/android/layout_tests/fast/borders/border-image-omit-right-slice.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDouble02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid02.html
+/sdcard/android/layout_tests/fast/borders/outline-offset-min-assert.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid04.html
+/sdcard/android/layout_tests/fast/borders/border-radius-huge-assert.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusInset01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDotted01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusOutset01.html
+/sdcard/android/layout_tests/fast/borders/svg-as-border-image.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDotted03.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDashed02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusRidge01.html
+/sdcard/android/layout_tests/fast/borders/border-image-rotate-transform.html
+/sdcard/android/layout_tests/fast/borders/inline-mask-overlay-image.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusGroove02.html
+/sdcard/android/layout_tests/fast/borders/border-image-01.html
+/sdcard/android/layout_tests/fast/selectors/175a.html
+/sdcard/android/layout_tests/fast/selectors/155c.html
+/sdcard/android/layout_tests/fast/selectors/059.html
+/sdcard/android/layout_tests/fast/selectors/066b.html
+/sdcard/android/layout_tests/fast/selectors/168.html
+/sdcard/android/layout_tests/fast/selectors/177a.html
+/sdcard/android/layout_tests/fast/selectors/087b.html
+/sdcard/android/layout_tests/fast/selectors/020.html
+/sdcard/android/layout_tests/fast/selectors/012.html
+/sdcard/android/layout_tests/fast/selectors/040.html
+/sdcard/android/layout_tests/fast/selectors/004.html
+/sdcard/android/layout_tests/fast/selectors/032.html
+/sdcard/android/layout_tests/fast/selectors/060.html
+/sdcard/android/layout_tests/fast/selectors/016.html
+/sdcard/android/layout_tests/fast/selectors/044.html
+/sdcard/android/layout_tests/fast/selectors/008.html
+/sdcard/android/layout_tests/fast/selectors/072.html
+/sdcard/android/layout_tests/fast/selectors/lang-inheritance.html : has expected results
+/sdcard/android/layout_tests/fast/selectors/064.html
+/sdcard/android/layout_tests/fast/selectors/056.html
+/sdcard/android/layout_tests/fast/selectors/018b.html
+/sdcard/android/layout_tests/fast/selectors/090b.html
+/sdcard/android/layout_tests/fast/selectors/045c.html
+/sdcard/android/layout_tests/fast/selectors/170d.html
+/sdcard/android/layout_tests/fast/selectors/157.html
+/sdcard/android/layout_tests/fast/selectors/039b.html
+/sdcard/android/layout_tests/fast/selectors/156b.html
+/sdcard/android/layout_tests/fast/selectors/175b.html
+/sdcard/android/layout_tests/fast/selectors/155d.html
+/sdcard/android/layout_tests/fast/selectors/167a.html
+/sdcard/android/layout_tests/fast/selectors/169.html
+/sdcard/android/layout_tests/fast/selectors/077b.html
+/sdcard/android/layout_tests/fast/selectors/177b.html
+/sdcard/android/layout_tests/fast/selectors/169a.html
+/sdcard/android/layout_tests/fast/selectors/lang-vs-xml-lang.html : has expected results
+/sdcard/android/layout_tests/fast/selectors/lang-inheritance2.html : has expected results
+/sdcard/android/layout_tests/fast/selectors/001.html
+/sdcard/android/layout_tests/fast/selectors/021.html
+/sdcard/android/layout_tests/fast/selectors/unqualified-hover-quirks.html
+/sdcard/android/layout_tests/fast/selectors/013.html
+/sdcard/android/layout_tests/fast/selectors/041.html
+/sdcard/android/layout_tests/fast/selectors/021b.html
+/sdcard/android/layout_tests/fast/selectors/005.html
+/sdcard/android/layout_tests/fast/selectors/061.html
+/sdcard/android/layout_tests/fast/selectors/170.html
+/sdcard/android/layout_tests/fast/selectors/017.html
+/sdcard/android/layout_tests/fast/selectors/170a.html
+/sdcard/android/layout_tests/fast/selectors/009.html
+/sdcard/android/layout_tests/fast/selectors/045.html
+/sdcard/android/layout_tests/fast/selectors/154.html
+/sdcard/android/layout_tests/fast/selectors/044b.html
+/sdcard/android/layout_tests/fast/selectors/065.html
+/sdcard/android/layout_tests/fast/selectors/155a.html
+/sdcard/android/layout_tests/fast/selectors/166.html
+/sdcard/android/layout_tests/fast/selectors/158.html
+/sdcard/android/layout_tests/fast/selectors/077.html
+/sdcard/android/layout_tests/fast/selectors/175c.html
+/sdcard/android/layout_tests/fast/selectors/089.html
+/sdcard/android/layout_tests/fast/selectors/088b.html
+/sdcard/android/layout_tests/fast/selectors/nondeterministic-combinators.html
+/sdcard/android/layout_tests/fast/selectors/unqualified-hover-strict.html
+/sdcard/android/layout_tests/fast/selectors/010.html
+/sdcard/android/layout_tests/fast/selectors/002.html
+/sdcard/android/layout_tests/fast/selectors/014.html
+/sdcard/android/layout_tests/fast/selectors/042.html
+/sdcard/android/layout_tests/fast/selectors/006.html
+/sdcard/android/layout_tests/fast/selectors/034.html
+/sdcard/android/layout_tests/fast/selectors/062.html
+/sdcard/android/layout_tests/fast/selectors/007a.html
+/sdcard/android/layout_tests/fast/selectors/054.html
+/sdcard/android/layout_tests/fast/selectors/018.html
+/sdcard/android/layout_tests/fast/selectors/046.html
+/sdcard/android/layout_tests/fast/selectors/170b.html
+/sdcard/android/layout_tests/fast/selectors/072b.html
+/sdcard/android/layout_tests/fast/selectors/044c.html
+/sdcard/android/layout_tests/fast/selectors/038.html
+/sdcard/android/layout_tests/fast/selectors/155.html
+/sdcard/android/layout_tests/fast/selectors/066.html
+/sdcard/android/layout_tests/fast/selectors/058.html
+/sdcard/android/layout_tests/fast/selectors/155b.html
+/sdcard/android/layout_tests/fast/selectors/166a.html
+/sdcard/android/layout_tests/fast/selectors/167.html
+/sdcard/android/layout_tests/fast/selectors/159.html
+/sdcard/android/layout_tests/fast/selectors/168a.html
+/sdcard/android/layout_tests/fast/selectors/078b.html
+/sdcard/android/layout_tests/fast/selectors/011.html
+/sdcard/android/layout_tests/fast/selectors/003.html
+/sdcard/android/layout_tests/fast/selectors/015.html
+/sdcard/android/layout_tests/fast/selectors/043.html
+/sdcard/android/layout_tests/fast/selectors/160.html
+/sdcard/android/layout_tests/fast/selectors/063.html
+/sdcard/android/layout_tests/fast/selectors/043b.html
+/sdcard/android/layout_tests/fast/selectors/007b.html
+/sdcard/android/layout_tests/fast/selectors/027.html
+/sdcard/android/layout_tests/fast/selectors/019.html
+/sdcard/android/layout_tests/fast/selectors/083.html
+/sdcard/android/layout_tests/fast/selectors/045b.html
+/sdcard/android/layout_tests/fast/selectors/170c.html
+/sdcard/android/layout_tests/fast/selectors/044d.html
+/sdcard/android/layout_tests/fast/selectors/039.html
+/sdcard/android/layout_tests/fast/overflow/overflow-focus-ring.html
+/sdcard/android/layout_tests/fast/overflow/overflow-x-y.html
+/sdcard/android/layout_tests/fast/overflow/overflow-text-hit-testing.html
+/sdcard/android/layout_tests/fast/overflow/unreachable-overflow-rtl-bug.html
+/sdcard/android/layout_tests/fast/overflow/overflow-auto-position-absolute.html
+/sdcard/android/layout_tests/fast/overflow/scrollRevealButton.html
+/sdcard/android/layout_tests/fast/overflow/overflow-rtl-inline-scrollbar.html
+/sdcard/android/layout_tests/fast/overflow/002.html
+/sdcard/android/layout_tests/fast/overflow/overflow-rtl.html
+/sdcard/android/layout_tests/fast/overflow/004.html
+/sdcard/android/layout_tests/fast/overflow/006.html
+/sdcard/android/layout_tests/fast/overflow/scrollbar-position-update.html
+/sdcard/android/layout_tests/fast/overflow/008.html
+/sdcard/android/layout_tests/fast/overflow/scroll-nested-positioned-layer-in-overflow.html
+/sdcard/android/layout_tests/fast/overflow/image-selection-highlight.html
+/sdcard/android/layout_tests/fast/overflow/childFocusRingClip.html
+/sdcard/android/layout_tests/fast/overflow/dynamic-hidden.html
+/sdcard/android/layout_tests/fast/overflow/position-relative.html
+/sdcard/android/layout_tests/fast/overflow/clip-rects-fixed-ancestor.html
+/sdcard/android/layout_tests/fast/overflow/overflow_hidden.html
+/sdcard/android/layout_tests/fast/overflow/infiniteRecursionGuard.html
+/sdcard/android/layout_tests/fast/overflow/float-in-relpositioned.html
+/sdcard/android/layout_tests/fast/overflow/table-overflow-float.html
+/sdcard/android/layout_tests/fast/overflow/unreachable-content-test.html
+/sdcard/android/layout_tests/fast/overflow/003.xml
+/sdcard/android/layout_tests/fast/overflow/overflow-auto-table.html
+/sdcard/android/layout_tests/fast/overflow/infiniteRecursion.html
+/sdcard/android/layout_tests/fast/overflow/001.html
+/sdcard/android/layout_tests/fast/overflow/hit-test-overflow-controls.html
+/sdcard/android/layout_tests/fast/overflow/005.html
+/sdcard/android/layout_tests/fast/overflow/007.html
+/sdcard/android/layout_tests/fast/overflow/hidden-scrollbar-resize.html
+/sdcard/android/layout_tests/fast/events/autoscroll.html
+/sdcard/android/layout_tests/fast/events/5056619.html
+/sdcard/android/layout_tests/fast/events/attempt-scroll-with-no-scrollbars.html : has expected results
+/sdcard/android/layout_tests/fast/events/updateLayoutForHitTest.html
+/sdcard/android/layout_tests/fast/events/label-focus.html
+/sdcard/android/layout_tests/fast/events/context-onmousedown-event.html : has expected results
+/sdcard/android/layout_tests/fast/events/onsubmit-bubbling.html : has expected results
+/sdcard/android/layout_tests/fast/events/onloadFrameCrash.html
+/sdcard/android/layout_tests/fast/events/event-listener-on-link.html
+/sdcard/android/layout_tests/fast/events/keydown-1.html
+/sdcard/android/layout_tests/fast/events/onload-re-entry.html
+/sdcard/android/layout_tests/fast/events/standalone-image-drag-to-editable.html
+/sdcard/android/layout_tests/fast/events/pointer-events.html : has expected results
+/sdcard/android/layout_tests/fast/events/pointer-events-2.html : has expected results
+/sdcard/android/layout_tests/fast/events/nested-window-event.html : has expected results
+/sdcard/android/layout_tests/fast/events/focusingUnloadedFrame.html
+/sdcard/android/layout_tests/fast/events/event-sender-mouse-moved.html
+/sdcard/android/layout_tests/fast/events/mouseout-dead-node.html
+/sdcard/android/layout_tests/fast/events/reveal-link-when-focused.html
+/sdcard/android/layout_tests/fast/html/keygen.html
+/sdcard/android/layout_tests/fast/html/link-rel-stylesheet.html
+/sdcard/android/layout_tests/fast/html/listing.html
+/sdcard/android/layout_tests/fast/html/marquee-scroll.html
+/sdcard/android/layout_tests/fast/images/svg-as-tiled-background.html
+/sdcard/android/layout_tests/fast/images/svg-as-background.html
+/sdcard/android/layout_tests/fast/images/svg-as-image.html
+/sdcard/android/layout_tests/fast/images/pdf-as-image-landscape.html
+/sdcard/android/layout_tests/fast/images/pdf-as-tiled-background.html
+/sdcard/android/layout_tests/fast/images/object-image.html
+/sdcard/android/layout_tests/fast/images/pdf-as-background.html
+/sdcard/android/layout_tests/fast/images/svg-as-relative-image.html
+/sdcard/android/layout_tests/fast/images/imagemap-case.html
+/sdcard/android/layout_tests/fast/images/pdf-as-image.html
+/sdcard/android/layout_tests/fast/images/image-map-anchor-children.html
+/sdcard/android/layout_tests/fast/images/embed-image.html
+/sdcard/android/layout_tests/fast/images/animated-svg-as-image.html
+/sdcard/android/layout_tests/fast/images/image-in-map.html
+/sdcard/android/layout_tests/fast/images/animated-gif-with-offsets.html
+/sdcard/android/layout_tests/fast/images/favicon-as-image.html
+/sdcard/android/layout_tests/fast/images/svg-width-100p-as-background.html
+/sdcard/android/layout_tests/fast/inline-block/14498-positionForCoordinates.html
+/sdcard/android/layout_tests/fast/inline-block/001.html
+/sdcard/android/layout_tests/fast/inline-block/002.html
+/sdcard/android/layout_tests/fast/inline-block/003.html
+/sdcard/android/layout_tests/fast/inline-block/004.html
+/sdcard/android/layout_tests/fast/inline-block/005.html
+/sdcard/android/layout_tests/fast/inline-block/contenteditable-baseline.html
+/sdcard/android/layout_tests/fast/inline-block/006.html
+/sdcard/android/layout_tests/fast/inline-block/inline-block-vertical-align.html
+/sdcard/android/layout_tests/fast/inline-block/tricky-baseline.html
+/sdcard/android/layout_tests/fast/inline-block/overflow-clip.html
+/sdcard/android/layout_tests/fast/inspector/matchedrules.html
+/sdcard/android/layout_tests/fast/inspector/style.html
+/sdcard/android/layout_tests/fast/flexbox/001.html
+/sdcard/android/layout_tests/fast/flexbox/010.html
+/sdcard/android/layout_tests/fast/flexbox/020.html
+/sdcard/android/layout_tests/fast/flexbox/002.html
+/sdcard/android/layout_tests/fast/flexbox/011.html
+/sdcard/android/layout_tests/fast/flexbox/021.html
+/sdcard/android/layout_tests/fast/flexbox/003.html
+/sdcard/android/layout_tests/fast/flexbox/012.html
+/sdcard/android/layout_tests/fast/flexbox/022.html
+/sdcard/android/layout_tests/fast/flexbox/004.html
+/sdcard/android/layout_tests/fast/flexbox/013.html
+/sdcard/android/layout_tests/fast/flexbox/023.html
+/sdcard/android/layout_tests/fast/flexbox/005.html
+/sdcard/android/layout_tests/fast/flexbox/014.html
+/sdcard/android/layout_tests/fast/flexbox/015.html
+/sdcard/android/layout_tests/fast/flexbox/006.html
+/sdcard/android/layout_tests/fast/flexbox/024.html
+/sdcard/android/layout_tests/fast/flexbox/016.html
+/sdcard/android/layout_tests/fast/flexbox/007.html
+/sdcard/android/layout_tests/fast/flexbox/025.html
+/sdcard/android/layout_tests/fast/flexbox/008.html
+/sdcard/android/layout_tests/fast/flexbox/017.html
+/sdcard/android/layout_tests/fast/flexbox/026.html
+/sdcard/android/layout_tests/fast/flexbox/009.html
+/sdcard/android/layout_tests/fast/flexbox/018.html
+/sdcard/android/layout_tests/fast/flexbox/019.html
+/sdcard/android/layout_tests/fast/flexbox/flex-hang.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-style-end-tag-1.html
+/sdcard/android/layout_tests/fast/tokenizer/002.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-title-end-tag-2.html
+/sdcard/android/layout_tests/fast/tokenizer/script-after-frameset.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-style-end-tag-2.html
+/sdcard/android/layout_tests/fast/tokenizer/external-script-document-write.html
+/sdcard/android/layout_tests/fast/tokenizer/script_extra_close.html
+/sdcard/android/layout_tests/fast/tokenizer/001.html
+/sdcard/android/layout_tests/fast/tokenizer/003.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-title-end-tag-1.html
+/sdcard/android/layout_tests/fast/tokenizer/external-script-document-write_2.html
+/sdcard/android/layout_tests/fast/box-shadow/border-radius-big.html
+/sdcard/android/layout_tests/fast/box-shadow/basic-shadows.html
+/sdcard/android/layout_tests/fast/js/exception-linenums-in-html-3.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/001.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/002.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/003.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/004.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/005.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/006.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/007.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/008.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/009.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/001.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/002.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/003.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/004.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/005.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/006.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/007.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/001.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/002.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/003.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/004.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/005.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/006.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/007.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/008.html
+/sdcard/android/layout_tests/fast/inline/continuation-outlines-with-layers.html
+/sdcard/android/layout_tests/fast/inline/inline-padding-disables-text-quirk.html
+/sdcard/android/layout_tests/fast/inline/emptyInlinesWithinLists.html
+/sdcard/android/layout_tests/fast/inline/drawStyledEmptyInlines.html
+/sdcard/android/layout_tests/fast/inline/drawStyledEmptyInlinesWithWS.html
+/sdcard/android/layout_tests/fast/inline/positionedLifetime.html
+/sdcard/android/layout_tests/fast/inline/dirtyLinesForInline.html
+/sdcard/android/layout_tests/fast/inline/001.html
+/sdcard/android/layout_tests/fast/inline/002.html
+/sdcard/android/layout_tests/fast/inline/inline-text-quirk-bpm.html
+/sdcard/android/layout_tests/fast/inline/inline-borders-with-bidi-override.html
+/sdcard/android/layout_tests/fast/inline/styledEmptyInlinesWithBRs.html
+/sdcard/android/layout_tests/fast/inline/continuation-outlines.html
+/sdcard/android/layout_tests/fast/inline/outline-continuations.html
+/sdcard/android/layout_tests/fast/inline/br-text-decoration.html
+/sdcard/android/layout_tests/fast/inline/percentage-margins.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/colSpan.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/createCaption.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/frameless-location-bugzilla10837.html
+/sdcard/android/layout_tests/fast/dom/Document/early-document-access.html : has expected results
+/sdcard/android/layout_tests/fast/dom/Element/null-offset-parent.html
+/sdcard/android/layout_tests/fast/dom/Element/class-attribute-whitespace.html
+/sdcard/android/layout_tests/fast/dom/HTMLLinkElement/pending-stylesheet-count.html
+/sdcard/android/layout_tests/fast/dom/HTMLStyleElement/insert-parser-generated.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-image-alt-text.html
+/sdcard/android/layout_tests/fast/dom/Window/timeout-released-on-close.html : has expected results
+/sdcard/android/layout_tests/fast/dom/Window/open-existing-pop-up-blocking.html
+/sdcard/android/layout_tests/fast/dom/Window/global-opener-function.html : has expected results
+/sdcard/android/layout_tests/fast/dom/Window/window-property-shadowing.html : has expected results
+/sdcard/android/layout_tests/fast/dom/Window/closure-access-after-navigation-window.html : has expected results
+/sdcard/android/layout_tests/fast/dom/Window/remove-timeout-crash.html : has expected results
+/sdcard/android/layout_tests/fast/dom/Window/window-special-properties.html : has expected results
+/sdcard/android/layout_tests/fast/dom/Window/timeout-callback-scope.html : has expected results
+/sdcard/android/layout_tests/fast/dom/Window/window-property-shadowing-name.html : has expected results
+/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/vspace-hspace-as-number.html
+/sdcard/android/layout_tests/fast/dom/HTMLElement/bdo.html
+/sdcard/android/layout_tests/fast/dom/Range/surroundContents-1.html
+/sdcard/android/layout_tests/fast/dom/Range/create-contextual-fragment.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead1.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead2.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead3.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead4.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead5.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/head-link-style-href-check.html
+/sdcard/android/layout_tests/fast/dom/HTMLTextAreaElement/reset-textarea.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-alt-text.html
+/sdcard/android/layout_tests/fast/dom/dom-parse-serialize.html
+/sdcard/android/layout_tests/fast/dom/focus-contenteditable.html
+/sdcard/android/layout_tests/fast/dom/jsDevicePixelRatio.html
+/sdcard/android/layout_tests/fast/dom/isindex-001.html
+/sdcard/android/layout_tests/fast/dom/css-cached-import-rule.html
+/sdcard/android/layout_tests/fast/dom/dom-parse-serialize-display.html
+/sdcard/android/layout_tests/fast/dom/css-rule-functions.html
+/sdcard/android/layout_tests/fast/dom/createDocumentType.html
+/sdcard/android/layout_tests/fast/dom/clientWidthAfterDocumentIsRemoved.html
+/sdcard/android/layout_tests/fast/dom/css-inline-style-important.html
+/sdcard/android/layout_tests/fast/dom/replaceChild.html
+/sdcard/android/layout_tests/fast/dom/anchor-text.html
+/sdcard/android/layout_tests/fast/dom/importNodeHTML.html
+/sdcard/android/layout_tests/fast/dom/gc-10.html
+/sdcard/android/layout_tests/fast/dom/inner-text.html
+/sdcard/android/layout_tests/fast/dom/isindex-002.html
+/sdcard/android/layout_tests/fast/dom/outerText.html
+/sdcard/android/layout_tests/fast/dom/setAttributeNS.html : has expected results
+/sdcard/android/layout_tests/fast/dom/anchor-toString.html : has expected results
+/sdcard/android/layout_tests/fast/dom/documenturi-affects-relative-paths.html : has expected results
+/sdcard/android/layout_tests/fast/dom/setAttribute-using-initial-input-value.html : has expected results
+/sdcard/android/layout_tests/fast/dom/blur-contenteditable.html
+/sdcard/android/layout_tests/fast/dom/setPrimitiveValue.html
+/sdcard/android/layout_tests/fast/dom/delete-contents.html
+/sdcard/android/layout_tests/fast/dom/children-nodes.html
+/sdcard/android/layout_tests/fast/dom/css-mediarule-deleteRule-update.html
+/sdcard/android/layout_tests/fast/dom/attr_dead_doc.html
+/sdcard/android/layout_tests/fast/dom/clone-contents-0-end-offset.html
+/sdcard/android/layout_tests/fast/dom/comment-not-documentElement.html
+/sdcard/android/layout_tests/fast/dom/clone-node-dynamic-style.html
+/sdcard/android/layout_tests/fast/dom/css-mediarule-insertRule-update.html
+/sdcard/android/layout_tests/fast/dom/set-frame-src-while-running-script-in-frame.html : has expected results
+/sdcard/android/layout_tests/fast/dom/stripNullFromTextNodes.html
+/sdcard/android/layout_tests/fast/dom/null-document-location-put-crash.html : has expected results
+/sdcard/android/layout_tests/fast/dom/document-scripts.html : has expected results
+/sdcard/android/layout_tests/fast/invalid/test-case-tr-th-td-should-not-close-dl-list.html : has expected results
+/sdcard/android/layout_tests/fast/invalid/table-inside-stray-table-content.html
+/sdcard/android/layout_tests/fast/invalid/010.html
+/sdcard/android/layout_tests/fast/invalid/002.html
+/sdcard/android/layout_tests/fast/invalid/012.html
+/sdcard/android/layout_tests/fast/invalid/004.html
+/sdcard/android/layout_tests/fast/invalid/014.html
+/sdcard/android/layout_tests/fast/invalid/006.html
+/sdcard/android/layout_tests/fast/invalid/016.html
+/sdcard/android/layout_tests/fast/invalid/008.html
+/sdcard/android/layout_tests/fast/invalid/018.html
+/sdcard/android/layout_tests/fast/invalid/junk-data.xml
+/sdcard/android/layout_tests/fast/invalid/missing-dl-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/td-inside-object.html
+/sdcard/android/layout_tests/fast/invalid/table-residual-style-crash.html
+/sdcard/android/layout_tests/fast/invalid/missing-font-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/missing-dt-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/020.xml
+/sdcard/android/layout_tests/fast/invalid/001.html
+/sdcard/android/layout_tests/fast/invalid/nestedh3s.html
+/sdcard/android/layout_tests/fast/invalid/011.html
+/sdcard/android/layout_tests/fast/invalid/003.html
+/sdcard/android/layout_tests/fast/invalid/021.html
+/sdcard/android/layout_tests/fast/invalid/013.html
+/sdcard/android/layout_tests/fast/invalid/005.html
+/sdcard/android/layout_tests/fast/invalid/015.html
+/sdcard/android/layout_tests/fast/invalid/007.html
+/sdcard/android/layout_tests/fast/invalid/residual-style.html
+/sdcard/android/layout_tests/fast/invalid/017.html
+/sdcard/android/layout_tests/fast/invalid/009.html
+/sdcard/android/layout_tests/fast/invalid/missing-address-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/019.html
+/sdcard/android/layout_tests/fast/forms/input-width.html
+/sdcard/android/layout_tests/fast/forms/select-item-background-clip.html
+/sdcard/android/layout_tests/fast/forms/radio-nested-labels.html
+/sdcard/android/layout_tests/fast/forms/thumbslider-crash.html
+/sdcard/android/layout_tests/fast/forms/input-first-letter.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-preventDefault.html
+/sdcard/android/layout_tests/fast/forms/plaintext-mode-2.html
+/sdcard/android/layout_tests/fast/forms/input-double-click-selection-gap-bug.html
+/sdcard/android/layout_tests/fast/forms/preserveFormDuringResidualStyle.html
+/sdcard/android/layout_tests/fast/forms/select-change-popup-to-listbox.html
+/sdcard/android/layout_tests/fast/forms/input-text-maxlength.html
+/sdcard/android/layout_tests/fast/forms/blankbuttons.html
+/sdcard/android/layout_tests/fast/forms/password-placeholder-text-security.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label05.html
+/sdcard/android/layout_tests/fast/forms/visual-hebrew-text-field.html
+/sdcard/android/layout_tests/fast/forms/textarea-trailing-newline.html : has expected results
+/sdcard/android/layout_tests/fast/forms/legend-access-key.html : has expected results
+/sdcard/android/layout_tests/fast/forms/textfield-overflow.html
+/sdcard/android/layout_tests/fast/forms/005.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label02.html
+/sdcard/android/layout_tests/fast/forms/file-input-disabled.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-visibility.html
+/sdcard/android/layout_tests/fast/forms/select-disabled-appearance.html
+/sdcard/android/layout_tests/fast/forms/input-type-change2.html
+/sdcard/android/layout_tests/fast/forms/select-block-background.html
+/sdcard/android/layout_tests/fast/forms/file-input-direction.html
+/sdcard/android/layout_tests/fast/forms/select-visual-hebrew.html
+/sdcard/android/layout_tests/fast/forms/select-change-listbox-size.html
+/sdcard/android/layout_tests/fast/forms/002.html
+/sdcard/android/layout_tests/fast/forms/textarea-align.html
+/sdcard/android/layout_tests/fast/forms/control-restrict-line-height.html
+/sdcard/android/layout_tests/fast/forms/textAreaLineHeight.html
+/sdcard/android/layout_tests/fast/forms/button-generated-content.html
+/sdcard/android/layout_tests/fast/forms/option-text-clip.html
+/sdcard/android/layout_tests/fast/forms/textfield-drag-into-disabled.html
+/sdcard/android/layout_tests/fast/forms/input-text-paste-maxlength.html
+/sdcard/android/layout_tests/fast/forms/tabs-with-modifiers.html : has expected results
+/sdcard/android/layout_tests/fast/forms/saved-state-adoptNode-crash.html : has expected results
+/sdcard/android/layout_tests/fast/forms/input-readonly-autoscroll.html
+/sdcard/android/layout_tests/fast/forms/thumbslider-no-parent-slider.html
+/sdcard/android/layout_tests/fast/forms/textfield-outline.html
+/sdcard/android/layout_tests/fast/forms/button-text-transform.html
+/sdcard/android/layout_tests/fast/forms/radio-check-click-and-drag.html : has expected results
+/sdcard/android/layout_tests/fast/forms/textarea-scroll-height.html
+/sdcard/android/layout_tests/fast/forms/button-table-styles.html
+/sdcard/android/layout_tests/fast/forms/textarea-setinnerhtml.html
+/sdcard/android/layout_tests/fast/forms/input-align.html
+/sdcard/android/layout_tests/fast/forms/box-shadow-override.html
+/sdcard/android/layout_tests/fast/forms/button-cannot-be-nested.html
+/sdcard/android/layout_tests/fast/forms/input-type-change.html
+/sdcard/android/layout_tests/fast/forms/checkbox-radio-onchange.html
+/sdcard/android/layout_tests/fast/forms/input-spaces.html
+/sdcard/android/layout_tests/fast/forms/dragging-to-file-input.html : has expected results
+/sdcard/android/layout_tests/fast/forms/menulist-option-wrap.html
+/sdcard/android/layout_tests/fast/forms/float-before-fieldset.html
+/sdcard/android/layout_tests/fast/forms/radio_checked.html
+/sdcard/android/layout_tests/fast/forms/minWidthPercent.html
+/sdcard/android/layout_tests/fast/forms/form-post-urlencoded.html : has expected results
+/sdcard/android/layout_tests/fast/forms/input-value.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label06.html
+/sdcard/android/layout_tests/fast/forms/placeholder-pseudo-style.html
+/sdcard/android/layout_tests/fast/forms/menulist-width-change.html
+/sdcard/android/layout_tests/fast/forms/option-strip-whitespace.html
+/sdcard/android/layout_tests/fast/forms/input-text-drag-down.html
+/sdcard/android/layout_tests/fast/forms/select-selected.html
+/sdcard/android/layout_tests/fast/forms/006.html
+/sdcard/android/layout_tests/fast/forms/control-clip-overflow.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-default-bkcolor.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label03.html
+/sdcard/android/layout_tests/fast/forms/003.html
+/sdcard/android/layout_tests/fast/forms/button-default-title.html
+/sdcard/android/layout_tests/fast/forms/hidden-listbox.html
+/sdcard/android/layout_tests/fast/forms/input-no-renderer.html
+/sdcard/android/layout_tests/fast/forms/input-text-click-outside.html
+/sdcard/android/layout_tests/fast/forms/input-baseline.html
+/sdcard/android/layout_tests/fast/forms/targeted-frame-submission.html
+/sdcard/android/layout_tests/fast/forms/input-table.html
+/sdcard/android/layout_tests/fast/forms/select-change-listbox-to-popup.html
+/sdcard/android/layout_tests/fast/forms/select-align.html
+/sdcard/android/layout_tests/fast/forms/radio_checked_dynamic.html
+/sdcard/android/layout_tests/fast/forms/select-writing-direction-natural.html
+/sdcard/android/layout_tests/fast/forms/hidden-input-file.html
+/sdcard/android/layout_tests/fast/forms/menulist-deselect-update.html
+/sdcard/android/layout_tests/fast/forms/button-sizes.html
+/sdcard/android/layout_tests/fast/forms/slider-thumb-stylability.html
+/sdcard/android/layout_tests/fast/forms/input-readonly-dimmed.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-width.html
+/sdcard/android/layout_tests/fast/forms/listbox-scrollbar-incremental-load.html
+/sdcard/android/layout_tests/fast/forms/password-placeholder.html
+/sdcard/android/layout_tests/fast/forms/select-list-box-with-height.html
+/sdcard/android/layout_tests/fast/forms/button-align.html
+/sdcard/android/layout_tests/fast/forms/textarea-rows-cols.html
+/sdcard/android/layout_tests/fast/forms/listbox-deselect-scroll.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-readonly.html
+/sdcard/android/layout_tests/fast/forms/select-initial-position.html
+/sdcard/android/layout_tests/fast/forms/menulist-no-overflow.html
+/sdcard/android/layout_tests/fast/forms/formmove2.html
+/sdcard/android/layout_tests/fast/forms/placeholder-set-attribute.html
+/sdcard/android/layout_tests/fast/forms/radio-attr-order.html
+/sdcard/android/layout_tests/fast/forms/input-disabled-color.html
+/sdcard/android/layout_tests/fast/forms/fieldset-align.html
+/sdcard/android/layout_tests/fast/forms/select-baseline.html
+/sdcard/android/layout_tests/fast/forms/input-text-word-wrap.html
+/sdcard/android/layout_tests/fast/forms/stuff-on-my-optgroup.html
+/sdcard/android/layout_tests/fast/forms/listbox-selection-2.html
+/sdcard/android/layout_tests/fast/forms/input-readonly-empty.html
+/sdcard/android/layout_tests/fast/forms/input-align-image.html
+/sdcard/android/layout_tests/fast/forms/input-selection-hidden.html : has expected results
+/sdcard/android/layout_tests/fast/forms/option-index.html
+/sdcard/android/layout_tests/fast/forms/indeterminate.html
+/sdcard/android/layout_tests/fast/forms/negativeLineHeight.html
+/sdcard/android/layout_tests/fast/forms/007.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label04.html
+/sdcard/android/layout_tests/fast/forms/select-style.html
+/sdcard/android/layout_tests/fast/forms/select-size.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-disabled.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-height.html
+/sdcard/android/layout_tests/fast/forms/004.html
+/sdcard/android/layout_tests/fast/forms/menulist-separator-painting.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label01.html
+/sdcard/android/layout_tests/fast/forms/fieldset-with-float.html
+/sdcard/android/layout_tests/fast/forms/search-placeholder-value-changed.html
+/sdcard/android/layout_tests/fast/forms/input-field-text-truncated.html
+/sdcard/android/layout_tests/fast/forms/floating-textfield-relayout.html
+/sdcard/android/layout_tests/fast/forms/add-remove-form-elements-stress-test.html : has expected results
+/sdcard/android/layout_tests/fast/forms/button-inner-block-reuse.html
+/sdcard/android/layout_tests/fast/forms/input-type-text-min-width.html
+/sdcard/android/layout_tests/fast/forms/onchange-enter-submit.html : has expected results
+/sdcard/android/layout_tests/fast/forms/slider-thumb-shared-style.html
+/sdcard/android/layout_tests/fast/forms/option-script.html
+/sdcard/android/layout_tests/fast/forms/input-paste-undo.html
+/sdcard/android/layout_tests/fast/forms/input-text-click-inside.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-selection.html
+/sdcard/android/layout_tests/fast/forms/button-white-space.html
+/sdcard/android/layout_tests/fast/forms/menulist-narrow-width.html
+/sdcard/android/layout_tests/fast/forms/slider-padding.html
+/sdcard/android/layout_tests/fast/forms/menulist-restrict-line-height.html
+/sdcard/android/layout_tests/fast/forms/textarea-width.html
+/sdcard/android/layout_tests/fast/forms/input-text-double-click.html
+/sdcard/android/layout_tests/fast/forms/button-submit.html
+/sdcard/android/layout_tests/fast/forms/disabled-select-change-index.html
+/sdcard/android/layout_tests/fast/forms/formmove3.html
+/sdcard/android/layout_tests/fast/forms/listbox-width-change.html
+/sdcard/android/layout_tests/fast/forms/input-text-self-emptying-click.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-bkcolor.html
+/sdcard/android/layout_tests/fast/forms/button-positioned.html
+/sdcard/android/layout_tests/fast/forms/search-transformed.html
+/sdcard/android/layout_tests/fast/forms/image-border.html
+/sdcard/android/layout_tests/fast/forms/encoding-test.html
+/sdcard/android/layout_tests/fast/forms/input-type-change-in-onfocus-mouse.html : has expected results
+/sdcard/android/layout_tests/fast/compact/001.html
+/sdcard/android/layout_tests/fast/compact/002.html
+/sdcard/android/layout_tests/fast/compact/003.html
+/sdcard/android/layout_tests/fast/clip/nestedTransparencyClip.html
+/sdcard/android/layout_tests/fast/clip/outline-overflowClip.html
+/sdcard/android/layout_tests/fast/clip/001.html
+/sdcard/android/layout_tests/fast/clip/010.html
+/sdcard/android/layout_tests/fast/clip/002.html
+/sdcard/android/layout_tests/fast/clip/011.html
+/sdcard/android/layout_tests/fast/clip/003.html
+/sdcard/android/layout_tests/fast/clip/012.html
+/sdcard/android/layout_tests/fast/clip/004.html
+/sdcard/android/layout_tests/fast/clip/013.html
+/sdcard/android/layout_tests/fast/clip/005.html
+/sdcard/android/layout_tests/fast/clip/014.html
+/sdcard/android/layout_tests/fast/clip/006.html
+/sdcard/android/layout_tests/fast/clip/015.html
+/sdcard/android/layout_tests/fast/clip/007.html
+/sdcard/android/layout_tests/fast/clip/016.html
+/sdcard/android/layout_tests/fast/clip/008.html
+/sdcard/android/layout_tests/fast/clip/017.html
+/sdcard/android/layout_tests/fast/clip/009.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/001.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/002.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/003.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/004.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/equal-precedence-resolution.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/rtl-border-collapsing.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/border-collapsing-head-foot.html
+/sdcard/android/layout_tests/fast/table/fixed-nested.html
+/sdcard/android/layout_tests/fast/table/frame-and-rules.html
+/sdcard/android/layout_tests/fast/table/empty-table-percent-height.html
+/sdcard/android/layout_tests/fast/table/100-percent-cell-width.html
+/sdcard/android/layout_tests/fast/table/stale-grid-crash.html
+/sdcard/android/layout_tests/fast/table/div-as-col-span.html
+/sdcard/android/layout_tests/fast/table/nobr.html
+/sdcard/android/layout_tests/fast/table/012.html
+/sdcard/android/layout_tests/fast/table/040.html
+/sdcard/android/layout_tests/fast/table/growCellForImageQuirk.html
+/sdcard/android/layout_tests/fast/table/024.html
+/sdcard/android/layout_tests/fast/table/cell-pref-width-invalidation.html
+/sdcard/android/layout_tests/fast/table/008.html
+/sdcard/android/layout_tests/fast/table/036.html
+/sdcard/android/layout_tests/fast/table/nested-percent-height-table.html
+/sdcard/android/layout_tests/fast/table/rules-attr-dynchange1.html
+/sdcard/android/layout_tests/fast/table/wide-column.html
+/sdcard/android/layout_tests/fast/table/fixed-with-auto-with-colspan.html
+/sdcard/android/layout_tests/fast/table/percent-heights.html
+/sdcard/android/layout_tests/fast/table/021.html
+/sdcard/android/layout_tests/fast/table/colspanMinWidth.html
+/sdcard/android/layout_tests/fast/table/005.html
+/sdcard/android/layout_tests/fast/table/033.html
+/sdcard/android/layout_tests/fast/table/017.html
+/sdcard/android/layout_tests/fast/table/floatingTablePaintBackground.html
+/sdcard/android/layout_tests/fast/table/029.html
+/sdcard/android/layout_tests/fast/table/cell-absolute-child.html
+/sdcard/android/layout_tests/fast/table/click-near-anonymous-table.html
+/sdcard/android/layout_tests/fast/table/auto-with-percent-height.html
+/sdcard/android/layout_tests/fast/table/insert-before-anonymous-ancestors.html
+/sdcard/android/layout_tests/fast/table/append-cells2.html
+/sdcard/android/layout_tests/fast/table/unused-percent-heights.html
+/sdcard/android/layout_tests/fast/table/max-width-integer-overflow.html
+/sdcard/android/layout_tests/fast/table/vertical-align-baseline-readjust.html
+/sdcard/android/layout_tests/fast/table/empty-row-crash.html
+/sdcard/android/layout_tests/fast/table/002.html
+/sdcard/android/layout_tests/fast/table/030.html
+/sdcard/android/layout_tests/fast/table/cell-width-auto.html
+/sdcard/android/layout_tests/fast/table/014.html
+/sdcard/android/layout_tests/fast/table/037.xml
+/sdcard/android/layout_tests/fast/table/large-width.html
+/sdcard/android/layout_tests/fast/table/026.html
+/sdcard/android/layout_tests/fast/table/unbreakable-images-quirk.html
+/sdcard/android/layout_tests/fast/table/038.html
+/sdcard/android/layout_tests/fast/table/dynamic-cellpadding.html
+/sdcard/android/layout_tests/fast/table/generated-caption.html
+/sdcard/android/layout_tests/fast/table/empty-cells.html
+/sdcard/android/layout_tests/fast/table/add-before-anonymous-child.html
+/sdcard/android/layout_tests/fast/table/011.html
+/sdcard/android/layout_tests/fast/table/table-display-types-strict.html
+/sdcard/android/layout_tests/fast/table/023.html
+/sdcard/android/layout_tests/fast/table/007.html
+/sdcard/android/layout_tests/fast/table/cellindex.html
+/sdcard/android/layout_tests/fast/table/035.html
+/sdcard/android/layout_tests/fast/table/colgroup-spanning-groups-rules.html
+/sdcard/android/layout_tests/fast/table/insert-row-before-form.html
+/sdcard/android/layout_tests/fast/table/rowspan-paint-order.html
+/sdcard/android/layout_tests/fast/table/rtl-cell-display-none-assert.html
+/sdcard/android/layout_tests/fast/table/insert-cell-before-form.html
+/sdcard/android/layout_tests/fast/table/replaced-percent-height.html
+/sdcard/android/layout_tests/fast/table/text-field-baseline.html
+/sdcard/android/layout_tests/fast/table/table-display-types.html
+/sdcard/android/layout_tests/fast/table/table-hspace-align-center.html
+/sdcard/android/layout_tests/fast/table/caption-relayout.html
+/sdcard/android/layout_tests/fast/table/020.html
+/sdcard/android/layout_tests/fast/table/fixed-table-non-cell-in-row.html
+/sdcard/android/layout_tests/fast/table/004.html
+/sdcard/android/layout_tests/fast/table/032.html
+/sdcard/android/layout_tests/fast/table/row-height-recalc.html
+/sdcard/android/layout_tests/fast/table/016.html
+/sdcard/android/layout_tests/fast/table/absolute-table-at-bottom.html
+/sdcard/android/layout_tests/fast/table/028.html
+/sdcard/android/layout_tests/fast/table/spanOverlapRepaint.html
+/sdcard/android/layout_tests/fast/table/invisible-cell-background.html
+/sdcard/android/layout_tests/fast/table/vertical-align-baseline.html
+/sdcard/android/layout_tests/fast/table/wide-colspan.html
+/sdcard/android/layout_tests/fast/table/rowindex.html
+/sdcard/android/layout_tests/fast/table/001.html
+/sdcard/android/layout_tests/fast/table/remove-td-display-none.html
+/sdcard/android/layout_tests/fast/table/013.html
+/sdcard/android/layout_tests/fast/table/041.html
+/sdcard/android/layout_tests/fast/table/colgroup-preceded-by-caption.html
+/sdcard/android/layout_tests/fast/table/025.html
+/sdcard/android/layout_tests/fast/table/giantCellspacing.html
+/sdcard/android/layout_tests/fast/table/009.html
+/sdcard/android/layout_tests/fast/table/edge-offsets.html
+/sdcard/android/layout_tests/fast/table/giantRowspan.html
+/sdcard/android/layout_tests/fast/table/010.html
+/sdcard/android/layout_tests/fast/table/inline-form-assert.html
+/sdcard/android/layout_tests/fast/table/overflowHidden.html
+/sdcard/android/layout_tests/fast/table/rules-attr-dynchange2.html
+/sdcard/android/layout_tests/fast/table/height-percent-test.html
+/sdcard/android/layout_tests/fast/table/multiple-percent-height-rows.html
+/sdcard/android/layout_tests/fast/table/giantRowspan2.html
+/sdcard/android/layout_tests/fast/table/tableInsideCaption.html
+/sdcard/android/layout_tests/fast/table/022.html
+/sdcard/android/layout_tests/fast/table/006.html
+/sdcard/android/layout_tests/fast/table/034.html
+/sdcard/android/layout_tests/fast/table/append-cells.html
+/sdcard/android/layout_tests/fast/table/018.html
+/sdcard/android/layout_tests/fast/table/percent-widths-stretch.html
+/sdcard/android/layout_tests/fast/table/prepend-in-anonymous-table.html
+/sdcard/android/layout_tests/fast/table/floating-th.html
+/sdcard/android/layout_tests/fast/table/empty-section-crash.html
+/sdcard/android/layout_tests/fast/table/form-with-table-style.html
+/sdcard/android/layout_tests/fast/table/003.html
+/sdcard/android/layout_tests/fast/table/031.html
+/sdcard/android/layout_tests/fast/table/015.html
+/sdcard/android/layout_tests/fast/table/027.html
+/sdcard/android/layout_tests/fast/table/039.html
+/sdcard/android/layout_tests/fast/css/counters/invalidate-cached-counter-node.html
+/sdcard/android/layout_tests/fast/css/counters/counter-text-security.html
+/sdcard/android/layout_tests/fast/css/counters/counter-text-transform.html
+/sdcard/android/layout_tests/fast/css/variables/multiple-term-test.html
+/sdcard/android/layout_tests/fast/css/variables/colors-test.html
+/sdcard/android/layout_tests/fast/css/variables/font-test.html
+/sdcard/android/layout_tests/fast/css/variables/multiple-blocks-test.html
+/sdcard/android/layout_tests/fast/css/variables/misplaced-variables-test.html
+/sdcard/android/layout_tests/fast/css/variables/invalid-variable-test.html
+/sdcard/android/layout_tests/fast/css/variables/misplaced-import-test.html
+/sdcard/android/layout_tests/fast/css/variables/import-test.html
+/sdcard/android/layout_tests/fast/css/variables/inline-style-test.html
+/sdcard/android/layout_tests/fast/css/variables/declaration-block-test.html
+/sdcard/android/layout_tests/fast/css/variables/margin-test.html
+/sdcard/android/layout_tests/fast/css/variables/set-variable-test.html
+/sdcard/android/layout_tests/fast/css/variables/override-test.html
+/sdcard/android/layout_tests/fast/css/variables/remove-variable-test.html
+/sdcard/android/layout_tests/fast/css/variables/variable-iteration-test.html
+/sdcard/android/layout_tests/fast/css/variables/image-test.html
+/sdcard/android/layout_tests/fast/css/variables/block-cycle-test.html
+/sdcard/android/layout_tests/fast/css/variables/shorthand-test.html
+/sdcard/android/layout_tests/fast/css/variables/print-test.html
+/sdcard/android/layout_tests/fast/css/namespaces/001.xml
+/sdcard/android/layout_tests/fast/css/namespaces/002.xml
+/sdcard/android/layout_tests/fast/css/namespaces/003.xml
+/sdcard/android/layout_tests/fast/css/namespaces/004.xml
+/sdcard/android/layout_tests/fast/css/namespaces/005.xml
+/sdcard/android/layout_tests/fast/css/namespaces/006.xml
+/sdcard/android/layout_tests/fast/css/namespaces/007.xml
+/sdcard/android/layout_tests/fast/css/font-face-in-media-rule.html
+/sdcard/android/layout_tests/fast/css/font-face-default-font.html
+/sdcard/android/layout_tests/fast/css/first-letter-float-after-float.html
+/sdcard/android/layout_tests/fast/css/invalidation-errors-2.html
+/sdcard/android/layout_tests/fast/css/line-height-negative.html
+/sdcard/android/layout_tests/fast/css/only-child-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/008.html
+/sdcard/android/layout_tests/fast/css/first-of-type-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/ZeroOpacityLayers2.html
+/sdcard/android/layout_tests/fast/css/target-fragment-match.html
+/sdcard/android/layout_tests/fast/css/marginComputedStyle.html
+/sdcard/android/layout_tests/fast/css/live-cssrules.html
+/sdcard/android/layout_tests/fast/css/zoom-font-size.html
+/sdcard/android/layout_tests/fast/css/005.html
+/sdcard/android/layout_tests/fast/css/first-letter-hover.html
+/sdcard/android/layout_tests/fast/css/color-quirk.html
+/sdcard/android/layout_tests/fast/css/resize-corner-tracking-transformed.html
+/sdcard/android/layout_tests/fast/css/selector-set-attribute.html
+/sdcard/android/layout_tests/fast/css/attribute-selector-empty-value.html
+/sdcard/android/layout_tests/fast/css/line-height-overflow.html
+/sdcard/android/layout_tests/fast/css/002.html
+/sdcard/android/layout_tests/fast/css/empty-generated-content.html
+/sdcard/android/layout_tests/fast/css/background-image-with-baseurl.html
+/sdcard/android/layout_tests/fast/css/border-radius-outline-offset.html
+/sdcard/android/layout_tests/fast/css/hsla-color.html
+/sdcard/android/layout_tests/fast/css/first-letter-skip-out-of-flow.html
+/sdcard/android/layout_tests/fast/css/font-face-multiple-remote-sources.html
+/sdcard/android/layout_tests/fast/css/hover-subselector.html
+/sdcard/android/layout_tests/fast/css/text-align.html : has expected results
+/sdcard/android/layout_tests/fast/css/margin-bottom-form-element-strict.html
+/sdcard/android/layout_tests/fast/css/shadow-multiple.html
+/sdcard/android/layout_tests/fast/css/import_with_baseurl.html
+/sdcard/android/layout_tests/fast/css/list-outline.html
+/sdcard/android/layout_tests/fast/css/apple-prefix.html
+/sdcard/android/layout_tests/fast/css/line-height.html
+/sdcard/android/layout_tests/fast/css/first-letter-visibility.html
+/sdcard/android/layout_tests/fast/css/acid2.html
+/sdcard/android/layout_tests/fast/css/font_property_normal.html
+/sdcard/android/layout_tests/fast/css/css-imports.html
+/sdcard/android/layout_tests/fast/css/last-of-type-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/last-child-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/visibility-hit-test.html
+/sdcard/android/layout_tests/fast/css/absolute-poition-in-rtl-parent.html
+/sdcard/android/layout_tests/fast/css/content-dynamic.html
+/sdcard/android/layout_tests/fast/css/acid2-pixel.html
+/sdcard/android/layout_tests/fast/css/transition-color-unspecified.html
+/sdcard/android/layout_tests/fast/css/table-text-align-strict.html
+/sdcard/android/layout_tests/fast/css/transform-default-parameter.html
+/sdcard/android/layout_tests/fast/css/contentImage.html
+/sdcard/android/layout_tests/fast/css/value-list-out-of-bounds-crash.html
+/sdcard/android/layout_tests/fast/css/color-strict.html
+/sdcard/android/layout_tests/fast/css/ignore-text-zoom.html
+/sdcard/android/layout_tests/fast/css/max-height-none.html
+/sdcard/android/layout_tests/fast/css/invalidation-errors-3.html
+/sdcard/android/layout_tests/fast/css/empty-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/begin-end-contain-selector-empty-value.html
+/sdcard/android/layout_tests/fast/css/find-next-layer.html
+/sdcard/android/layout_tests/fast/css/contentDiv.html
+/sdcard/android/layout_tests/fast/css/invalid-pseudo-classes.html
+/sdcard/android/layout_tests/fast/css/disabled-author-styles.html
+/sdcard/android/layout_tests/fast/css/text-security.html
+/sdcard/android/layout_tests/fast/css/font-weight-1.html
+/sdcard/android/layout_tests/fast/css/margin-bottom-form-element-quirk.html
+/sdcard/android/layout_tests/fast/css/font-shorthand-weight-only.html
+/sdcard/android/layout_tests/fast/css/006.html
+/sdcard/android/layout_tests/fast/css/fieldset-display-row.html
+/sdcard/android/layout_tests/fast/css/border-height.html
+/sdcard/android/layout_tests/fast/css/css2-system-fonts.html
+/sdcard/android/layout_tests/fast/css/imageTileOpacity.html
+/sdcard/android/layout_tests/fast/css/font-face-remote.html
+/sdcard/android/layout_tests/fast/css/003.html
+/sdcard/android/layout_tests/fast/css/error-in-last-decl.html
+/sdcard/android/layout_tests/fast/css/zoom-property-parsing.html
+/sdcard/android/layout_tests/fast/css/style-outside-head.html
+/sdcard/android/layout_tests/fast/css/first-letter-capitalized.html
+/sdcard/android/layout_tests/fast/css/word-space-extra.html
+/sdcard/android/layout_tests/fast/css/first-letter-float.html
+/sdcard/android/layout_tests/fast/css/simple-selector-chain-parsing.html
+/sdcard/android/layout_tests/fast/css/xml-stylesheet-pi-not-in-prolog.xml
+/sdcard/android/layout_tests/fast/css/continuationCrash.html
+/sdcard/android/layout_tests/fast/css/vertical-align-lengths.html
+/sdcard/android/layout_tests/fast/css/first-child-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/getFloatValueForUnit.html
+/sdcard/android/layout_tests/fast/css/first-letter-detach.html
+/sdcard/android/layout_tests/fast/css/line-height-font-order.html
+/sdcard/android/layout_tests/fast/css/font-face-unicode-range.html
+/sdcard/android/layout_tests/fast/css/layerZOrderCrash.html
+/sdcard/android/layout_tests/fast/css/007.html
+/sdcard/android/layout_tests/fast/css/import-rule-regression-11590.html
+/sdcard/android/layout_tests/fast/css/last-child-style-sharing.html
+/sdcard/android/layout_tests/fast/css/css3-modsel-22.html
+/sdcard/android/layout_tests/fast/css/ex-after-font-variant.html
+/sdcard/android/layout_tests/fast/css/quirk-orphaned-units.html
+/sdcard/android/layout_tests/fast/css/outline-auto-location.html
+/sdcard/android/layout_tests/fast/css/margin-top-bottom-dynamic.html
+/sdcard/android/layout_tests/fast/css/font-face-descriptor-multiple-values.html
+/sdcard/android/layout_tests/fast/css/empty-body-test.html
+/sdcard/android/layout_tests/fast/css/link-outside-head.html
+/sdcard/android/layout_tests/fast/css/font-size-negative.html
+/sdcard/android/layout_tests/fast/css/position-negative-top-margin.html
+/sdcard/android/layout_tests/fast/css/invalid-percentage-property.html : has expected results
+/sdcard/android/layout_tests/fast/css/ZeroOpacityLayers.html
+/sdcard/android/layout_tests/fast/css/only-of-type-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/004.html
+/sdcard/android/layout_tests/fast/css/rtl-ordering.html
+/sdcard/android/layout_tests/fast/css/affected-by-hover-after-style-change.html
+/sdcard/android/layout_tests/fast/css/resize-corner-tracking.html
+/sdcard/android/layout_tests/fast/css/background-shorthand-invalid-url.html
+/sdcard/android/layout_tests/fast/css/invalidation-errors.html
+/sdcard/android/layout_tests/fast/css/MarqueeLayoutTest.html
+/sdcard/android/layout_tests/fast/css/textCapitalizeEdgeCases.html
+/sdcard/android/layout_tests/fast/css/001.html
+/sdcard/android/layout_tests/fast/css/hsl-color.html
+/sdcard/android/layout_tests/fast/css/first-letter-recalculation.html
+/sdcard/android/layout_tests/fast/css/inline-properties-important.html
+/sdcard/android/layout_tests/fast/css/dynamic-sibling-selector.html
+/sdcard/android/layout_tests/fast/css/table-text-align-quirk.html
+/sdcard/android/layout_tests/fast/css/outline-auto-empty-rects.html
+/sdcard/android/layout_tests/fast/css/font-face-multiple-faces.html
+/sdcard/android/layout_tests/fast/css/rgb-float.html
+/sdcard/android/layout_tests/fast/css/pendingStylesheetFontSize.html
+/sdcard/android/layout_tests/fast/css/contentDivWithChildren.html
+/sdcard/android/layout_tests/fast/css/universal-hover-quirk.html
+/sdcard/android/layout_tests/fast/css/css3-nth-child.html
+/sdcard/android/layout_tests/fast/css/style-parsed-outside-head.html
+/sdcard/android/layout_tests/fast/css/percentage-non-integer.html
+/sdcard/android/layout_tests/fast/css/negative-nth-child.html
+/sdcard/android/layout_tests/fast/box-sizing/panels-one.html
+/sdcard/android/layout_tests/fast/box-sizing/percentage-height.html
+/sdcard/android/layout_tests/fast/box-sizing/box-sizing.html
+/sdcard/android/layout_tests/fast/box-sizing/panels-two.html
+/sdcard/android/layout_tests/fast/block/basic/minheight.html
+/sdcard/android/layout_tests/fast/block/basic/min-pref-width-nowrap-floats.html
+/sdcard/android/layout_tests/fast/block/basic/fieldset-stretch-to-legend.html
+/sdcard/android/layout_tests/fast/block/basic/white-space-pre-wraps.html
+/sdcard/android/layout_tests/fast/block/basic/adding-near-anonymous-block.html
+/sdcard/android/layout_tests/fast/block/basic/quirk-percent-height-grandchild.html
+/sdcard/android/layout_tests/fast/block/basic/001.html
+/sdcard/android/layout_tests/fast/block/basic/010.html
+/sdcard/android/layout_tests/fast/block/basic/quirk-height.html
+/sdcard/android/layout_tests/fast/block/basic/020.html
+/sdcard/android/layout_tests/fast/block/basic/002.html
+/sdcard/android/layout_tests/fast/block/basic/011.html
+/sdcard/android/layout_tests/fast/block/basic/text-indent-rtl.html
+/sdcard/android/layout_tests/fast/block/basic/021.html
+/sdcard/android/layout_tests/fast/block/basic/003.html
+/sdcard/android/layout_tests/fast/block/basic/012.html
+/sdcard/android/layout_tests/fast/block/basic/013.html
+/sdcard/android/layout_tests/fast/block/basic/004.html
+/sdcard/android/layout_tests/fast/block/basic/014.html
+/sdcard/android/layout_tests/fast/block/basic/005.html
+/sdcard/android/layout_tests/fast/block/basic/015.html
+/sdcard/android/layout_tests/fast/block/basic/006.html
+/sdcard/android/layout_tests/fast/block/basic/016.html
+/sdcard/android/layout_tests/fast/block/basic/007.html
+/sdcard/android/layout_tests/fast/block/basic/008.html
+/sdcard/android/layout_tests/fast/block/basic/009.html
+/sdcard/android/layout_tests/fast/block/basic/018.html
+/sdcard/android/layout_tests/fast/block/basic/019.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/001.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/002.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/003.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/004.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/005.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/006.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/007.html
+/sdcard/android/layout_tests/fast/block/positioning/059.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-short-rtl.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-short-ltr.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-replaced-float.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-positioned-overconstrained.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl-2.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr-2.html
+/sdcard/android/layout_tests/fast/block/positioning/020.html
+/sdcard/android/layout_tests/fast/block/positioning/012.html
+/sdcard/android/layout_tests/fast/block/positioning/004.html
+/sdcard/android/layout_tests/fast/block/positioning/040.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-position-direction-strict.html
+/sdcard/android/layout_tests/fast/block/positioning/032.html
+/sdcard/android/layout_tests/fast/block/positioning/024.html
+/sdcard/android/layout_tests/fast/block/positioning/060.html
+/sdcard/android/layout_tests/fast/block/positioning/052.html
+/sdcard/android/layout_tests/fast/block/positioning/016.html
+/sdcard/android/layout_tests/fast/block/positioning/044.html
+/sdcard/android/layout_tests/fast/block/positioning/008.html
+/sdcard/android/layout_tests/fast/block/positioning/036.html
+/sdcard/android/layout_tests/fast/block/positioning/028.html
+/sdcard/android/layout_tests/fast/block/positioning/056.html
+/sdcard/android/layout_tests/fast/block/positioning/048.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-position-direction-quirk.html
+/sdcard/android/layout_tests/fast/block/positioning/replaced-inside-fixed-top-bottom.html
+/sdcard/android/layout_tests/fast/block/positioning/pref-width-change.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr-3.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl-3.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl.html
+/sdcard/android/layout_tests/fast/block/positioning/001.html
+/sdcard/android/layout_tests/fast/block/positioning/021.html
+/sdcard/android/layout_tests/fast/block/positioning/013.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-block.html
+/sdcard/android/layout_tests/fast/block/positioning/005.html
+/sdcard/android/layout_tests/fast/block/positioning/041.html
+/sdcard/android/layout_tests/fast/block/positioning/033.html
+/sdcard/android/layout_tests/fast/block/positioning/025.html
+/sdcard/android/layout_tests/fast/block/positioning/061.html
+/sdcard/android/layout_tests/fast/block/positioning/017.html
+/sdcard/android/layout_tests/fast/block/positioning/053.html
+/sdcard/android/layout_tests/fast/block/positioning/009.html
+/sdcard/android/layout_tests/fast/block/positioning/045.html
+/sdcard/android/layout_tests/fast/block/positioning/037.html
+/sdcard/android/layout_tests/fast/block/positioning/029.html
+/sdcard/android/layout_tests/fast/block/positioning/057.html
+/sdcard/android/layout_tests/fast/block/positioning/049.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-with-html-border-quirks.html
+/sdcard/android/layout_tests/fast/block/positioning/leftmargin-topmargin.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-length-of-neg-666666.html
+/sdcard/android/layout_tests/fast/block/positioning/complex-percentage-height.html
+/sdcard/android/layout_tests/fast/block/positioning/auto-height-with-top-and-bottom.html
+/sdcard/android/layout_tests/fast/block/positioning/010.html
+/sdcard/android/layout_tests/fast/block/positioning/002.html
+/sdcard/android/layout_tests/fast/block/positioning/030.html
+/sdcard/android/layout_tests/fast/block/positioning/relayout-on-position-change.html
+/sdcard/android/layout_tests/fast/block/positioning/022.html
+/sdcard/android/layout_tests/fast/block/positioning/padding-percent.html
+/sdcard/android/layout_tests/fast/block/positioning/014.html
+/sdcard/android/layout_tests/fast/block/positioning/050.html
+/sdcard/android/layout_tests/fast/block/positioning/006.html
+/sdcard/android/layout_tests/fast/block/positioning/042.html
+/sdcard/android/layout_tests/fast/block/positioning/034.html
+/sdcard/android/layout_tests/fast/block/positioning/offsetLeft-offsetTop-borders.html
+/sdcard/android/layout_tests/fast/block/positioning/062.html
+/sdcard/android/layout_tests/fast/block/positioning/026.html
+/sdcard/android/layout_tests/fast/block/positioning/054.html
+/sdcard/android/layout_tests/fast/block/positioning/018.html
+/sdcard/android/layout_tests/fast/block/positioning/046.html
+/sdcard/android/layout_tests/fast/block/positioning/abs-inside-inline-rel.html
+/sdcard/android/layout_tests/fast/block/positioning/038.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-with-html-border-strict.html
+/sdcard/android/layout_tests/fast/block/positioning/058.html
+/sdcard/android/layout_tests/fast/block/positioning/negative-right-pos.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overconstrained.html
+/sdcard/android/layout_tests/fast/block/positioning/child-of-absolute-with-auto-height.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-replaced.html
+/sdcard/android/layout_tests/fast/block/positioning/height-change.html
+/sdcard/android/layout_tests/fast/block/positioning/window-height-change.html
+/sdcard/android/layout_tests/fast/block/positioning/011.html
+/sdcard/android/layout_tests/fast/block/positioning/003.html
+/sdcard/android/layout_tests/fast/block/positioning/move-with-auto-width.html
+/sdcard/android/layout_tests/fast/block/positioning/031.html
+/sdcard/android/layout_tests/fast/block/positioning/023.html
+/sdcard/android/layout_tests/fast/block/positioning/051.html
+/sdcard/android/layout_tests/fast/block/positioning/015.html
+/sdcard/android/layout_tests/fast/block/positioning/043.html
+/sdcard/android/layout_tests/fast/block/positioning/007.html
+/sdcard/android/layout_tests/fast/block/positioning/035.html
+/sdcard/android/layout_tests/fast/block/positioning/027.html
+/sdcard/android/layout_tests/fast/block/positioning/055.html
+/sdcard/android/layout_tests/fast/block/positioning/019.html
+/sdcard/android/layout_tests/fast/block/positioning/047.html
+/sdcard/android/layout_tests/fast/block/positioning/039.html
+/sdcard/android/layout_tests/fast/block/positioning/inline-block-relposition.html
+/sdcard/android/layout_tests/fast/block/float/vertical-move-relayout.html
+/sdcard/android/layout_tests/fast/block/float/tableshifting.html
+/sdcard/android/layout_tests/fast/block/float/table-relayout.html
+/sdcard/android/layout_tests/fast/block/float/br-with-clear-2.html
+/sdcard/android/layout_tests/fast/block/float/020.html
+/sdcard/android/layout_tests/fast/block/float/012.html
+/sdcard/android/layout_tests/fast/block/float/004.html
+/sdcard/android/layout_tests/fast/block/float/032.html
+/sdcard/android/layout_tests/fast/block/float/024.html
+/sdcard/android/layout_tests/fast/block/float/016.html
+/sdcard/android/layout_tests/fast/block/float/008.html
+/sdcard/android/layout_tests/fast/block/float/028.html
+/sdcard/android/layout_tests/fast/block/float/shrink-to-fit-width.html
+/sdcard/android/layout_tests/fast/block/float/clamped-right-float.html
+/sdcard/android/layout_tests/fast/block/float/independent-align-positioning.html
+/sdcard/android/layout_tests/fast/block/float/float-on-zero-height-line.html
+/sdcard/android/layout_tests/fast/block/float/nowrap-clear-min-width.html
+/sdcard/android/layout_tests/fast/block/float/overhanging-after-height-decrease-offsets.html
+/sdcard/android/layout_tests/fast/block/float/001.html
+/sdcard/android/layout_tests/fast/block/float/021.html
+/sdcard/android/layout_tests/fast/block/float/013.html
+/sdcard/android/layout_tests/fast/block/float/nopaint-after-layer-destruction2.html
+/sdcard/android/layout_tests/fast/block/float/005.html
+/sdcard/android/layout_tests/fast/block/float/033.html
+/sdcard/android/layout_tests/fast/block/float/025.html
+/sdcard/android/layout_tests/fast/block/float/017.html
+/sdcard/android/layout_tests/fast/block/float/009.html
+/sdcard/android/layout_tests/fast/block/float/float-in-float-hit-testing.html
+/sdcard/android/layout_tests/fast/block/float/029.html
+/sdcard/android/layout_tests/fast/block/float/4145535Crash.html
+/sdcard/android/layout_tests/fast/block/float/editable-text-overlapping-float.html
+/sdcard/android/layout_tests/fast/block/float/nestedAnonymousBlocks.html
+/sdcard/android/layout_tests/fast/block/float/intruding-painted-twice.html
+/sdcard/android/layout_tests/fast/block/float/010.html
+/sdcard/android/layout_tests/fast/block/float/002.html
+/sdcard/android/layout_tests/fast/block/float/dynamic-unfloat-pref-width.html
+/sdcard/android/layout_tests/fast/block/float/marquee-shrink-to-avoid-floats.html
+/sdcard/android/layout_tests/fast/block/float/030.html
+/sdcard/android/layout_tests/fast/block/float/022.html
+/sdcard/android/layout_tests/fast/block/float/014.html
+/sdcard/android/layout_tests/fast/block/float/006.html
+/sdcard/android/layout_tests/fast/block/float/034.html
+/sdcard/android/layout_tests/fast/block/float/relative-painted-twice.html
+/sdcard/android/layout_tests/fast/block/float/026.html
+/sdcard/android/layout_tests/fast/block/float/018.html
+/sdcard/android/layout_tests/fast/block/float/width-update-after-clear.html
+/sdcard/android/layout_tests/fast/block/float/nopaint-after-layer-destruction.html
+/sdcard/android/layout_tests/fast/block/float/float-in-float-painting.html
+/sdcard/android/layout_tests/fast/block/float/overhanging-after-height-decrease.html
+/sdcard/android/layout_tests/fast/block/float/float-avoidance.html
+/sdcard/android/layout_tests/fast/block/float/narrow-after-wide.html
+/sdcard/android/layout_tests/fast/block/float/multiple-float-positioning.html
+/sdcard/android/layout_tests/fast/block/float/br-with-clear.html
+/sdcard/android/layout_tests/fast/block/float/011.html
+/sdcard/android/layout_tests/fast/block/float/negative-margin-clear.html
+/sdcard/android/layout_tests/fast/block/float/003.html
+/sdcard/android/layout_tests/fast/block/float/031.html
+/sdcard/android/layout_tests/fast/block/float/023.html
+/sdcard/android/layout_tests/fast/block/float/015.html
+/sdcard/android/layout_tests/fast/block/float/007.html
+/sdcard/android/layout_tests/fast/block/float/035.html
+/sdcard/android/layout_tests/fast/block/float/027.html
+/sdcard/android/layout_tests/fast/block/float/019.html
+/sdcard/android/layout_tests/fast/block/float/nestedAnonymousBlocks2.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/059.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/empty-clear-blocks.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/010.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/negative-margins.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/002.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/020.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/101.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/030.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/012.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/040.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/022.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/004.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/103.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/032.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/006.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/042.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/016.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/034.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/062.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/044.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/026.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/018.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/028.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/056.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/038.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/058.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/100.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/001.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/011.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/102.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/021.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/003.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/031.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/005.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/041.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/104.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/033.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/015.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/025.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/043.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/035.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/017.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/027.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/045.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/063.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/037.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/019.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/055.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/029.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/039.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/057.html
+/sdcard/android/layout_tests/fast/runin/001.html
+/sdcard/android/layout_tests/fast/runin/002.html
+/sdcard/android/layout_tests/fast/parser/title-error-test.html
+/sdcard/android/layout_tests/fast/parser/comments.html
+/sdcard/android/layout_tests/fast/parser/fonts.html
+/sdcard/android/layout_tests/fast/parser/comment-in-style.html
+/sdcard/android/layout_tests/fast/parser/comment-in-script.html
+/sdcard/android/layout_tests/fast/parser/broken-comments-vs-parsing-mode.html
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-style.html
+/sdcard/android/layout_tests/fast/parser/xhtml-alternate-entities.xml
+/sdcard/android/layout_tests/fast/parser/nofoo-tags-inside-paragraph.html
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-textarea.html
+/sdcard/android/layout_tests/fast/parser/bad-xml-slash.html
+/sdcard/android/layout_tests/fast/parser/001.html
+/sdcard/android/layout_tests/fast/parser/open-comment-in-textarea.html
+/sdcard/android/layout_tests/fast/parser/tabs-in-scripts.html
+/sdcard/android/layout_tests/fast/parser/external-entities-in-xslt.xml : has expected results
+/sdcard/android/layout_tests/fast/parser/parseCommentsInTitles.html
+/sdcard/android/layout_tests/fast/parser/remove-block-in-residual-style.html
+/sdcard/android/layout_tests/fast/parser/open-comment-in-style.html
+/sdcard/android/layout_tests/fast/parser/document-write-option.html
+/sdcard/android/layout_tests/fast/parser/style-script-head-test.html
+/sdcard/android/layout_tests/fast/parser/comment-in-textarea.html
+/sdcard/android/layout_tests/fast/layers/zindex-ridonkulous.html
+/sdcard/android/layout_tests/fast/layers/positioned-inside-root-with-margins.html
+/sdcard/android/layout_tests/fast/layers/layer-visibility-sublayer.html
+/sdcard/android/layout_tests/fast/layers/opacity-outline.html
+/sdcard/android/layout_tests/fast/layers/add-layer-with-nested-stacking.html
+/sdcard/android/layout_tests/fast/layers/layer-content-visibility-change.html
+/sdcard/android/layout_tests/fast/layers/zindex-inherit.html
+/sdcard/android/layout_tests/fast/layers/layer-visibility.html
+/sdcard/android/layout_tests/fast/layers/remove-layer-with-nested-stacking.html
+/sdcard/android/layout_tests/fast/layers/opacity-transforms.html
+/sdcard/android/layout_tests/fast/layers/overflow-scroll-auto-switch.html
+/sdcard/android/layout_tests/fast/layers/scroll-rect-to-visible.html
+/sdcard/android/layout_tests/fast/layers/opacity-stacking.html
+/sdcard/android/layout_tests/fast/history/clicked-link-is-visited.html
+/sdcard/android/layout_tests/fast/history/history_reload.html : has expected results
+/sdcard/android/layout_tests/fast/backgrounds/repeat/mask-negative-offset-repeat.html
+/sdcard/android/layout_tests/fast/backgrounds/repeat/negative-offset-repeat.html
+/sdcard/android/layout_tests/fast/backgrounds/repeat/negative-offset-repeat-transformed.html
+/sdcard/android/layout_tests/fast/backgrounds/repeat/noRepeatCorrectClip.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize02.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize11.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize03.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize12.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize04.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize13.html
+/sdcard/android/layout_tests/fast/backgrounds/size/zero.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize05.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize14.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize06.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize15.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize07.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize16.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize17.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize08.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize09.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize18.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize19.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize10.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize01.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-2.html
+/sdcard/android/layout_tests/fast/backgrounds/background-origin-root-element.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-3.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-4.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-5.html
+/sdcard/android/layout_tests/fast/backgrounds/background-position-1.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-6.html
+/sdcard/android/layout_tests/fast/backgrounds/opacity-on-document-element.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-mask.html
+/sdcard/android/layout_tests/fast/backgrounds/solid-color-context-restore.html
+/sdcard/android/layout_tests/fast/backgrounds/mask-composite.html
+/sdcard/android/layout_tests/fast/backgrounds/animated-svg-as-background.html
+/sdcard/android/layout_tests/fast/backgrounds/001.html
+/sdcard/android/layout_tests/fast/backgrounds/animated-gif-as-background.html
+/sdcard/android/layout_tests/fast/backgrounds/background-position-rounding.html
+/sdcard/android/layout_tests/fast/backgrounds/bgCompositeCopy.html
+/sdcard/android/layout_tests/fast/backgrounds/background-inherit-color-bug.html
+/sdcard/android/layout_tests/fast/backgrounds/animated-svg-as-mask.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-1.html
+/sdcard/android/layout_tests/fast/repaint/reflection-redraw.html
+/sdcard/android/layout_tests/fast/repaint/layer-full-repaint.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-clip.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-clip-3.html
+/sdcard/android/layout_tests/fast/repaint/layer-outline-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/layer-hide-when-needs-layout.html
+/sdcard/android/layout_tests/fast/repaint/layer-outline.html
+/sdcard/android/layout_tests/fast/repaint/list-marker-2.html
+/sdcard/android/layout_tests/fast/repaint/table-section-overflow.html
+/sdcard/android/layout_tests/fast/repaint/body-background-image.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-strict-vertical.html
+/sdcard/android/layout_tests/fast/repaint/inline-outline-repaint.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-4.html
+/sdcard/android/layout_tests/fast/repaint/change-transform.html
+/sdcard/android/layout_tests/fast/repaint/fixed.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-8.html
+/sdcard/android/layout_tests/fast/repaint/erase-overflow.html
+/sdcard/android/layout_tests/fast/repaint/outline-child-repaint.html
+/sdcard/android/layout_tests/fast/repaint/float-overflow.html
+/sdcard/android/layout_tests/fast/repaint/containing-block-position-change.html
+/sdcard/android/layout_tests/fast/repaint/text-selection-rect-in-overflow.html
+/sdcard/android/layout_tests/fast/repaint/flexible-box-overflow-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/table-cell-move.html
+/sdcard/android/layout_tests/fast/repaint/transform-absolute-child.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-10.html
+/sdcard/android/layout_tests/fast/repaint/float-move-during-layout.html
+/sdcard/android/layout_tests/fast/repaint/overflow-clip-subtree-layout.html
+/sdcard/android/layout_tests/fast/repaint/invisible-objects.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-strict-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/focus-layers.html
+/sdcard/android/layout_tests/fast/repaint/inline-color-change.html
+/sdcard/android/layout_tests/fast/repaint/table-col-background.html
+/sdcard/android/layout_tests/fast/repaint/selection-after-remove.html
+/sdcard/android/layout_tests/fast/repaint/dynamic-table-vertical-alignment-change.html
+/sdcard/android/layout_tests/fast/repaint/flexible-box-overflow.html
+/sdcard/android/layout_tests/fast/repaint/table-two-pass-layout-overpaint.html
+/sdcard/android/layout_tests/fast/repaint/overflow-into-content.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-vertical.html
+/sdcard/android/layout_tests/fast/repaint/border-repaint-glitch.html
+/sdcard/android/layout_tests/fast/repaint/continuation-after-outline.html
+/sdcard/android/layout_tests/fast/repaint/intermediate-layout-position.html
+/sdcard/android/layout_tests/fast/repaint/table-section-repaint.html
+/sdcard/android/layout_tests/fast/repaint/clipped-relative.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-1.html
+/sdcard/android/layout_tests/fast/repaint/backgroundSizeRepaint.html
+/sdcard/android/layout_tests/fast/repaint/box-shadow-dynamic.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-5.html
+/sdcard/android/layout_tests/fast/repaint/text-shadow-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/caret-outside-block.html
+/sdcard/android/layout_tests/fast/repaint/renderer-destruction-by-invalidateSelection-crash.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-9.html
+/sdcard/android/layout_tests/fast/repaint/transform-repaint-descendants.html
+/sdcard/android/layout_tests/fast/repaint/layout-state-relative.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/border-fit-lines.html
+/sdcard/android/layout_tests/fast/repaint/repaint-resized-overflow.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-3509.html
+/sdcard/android/layout_tests/fast/repaint/inline-block-overflow.html
+/sdcard/android/layout_tests/fast/repaint/button-spurious-layout-hint.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-6278.html
+/sdcard/android/layout_tests/fast/repaint/box-shadow-v.html
+/sdcard/android/layout_tests/fast/repaint/delete-into-nested-block.html
+/sdcard/android/layout_tests/fast/repaint/float-overflow-right.html
+/sdcard/android/layout_tests/fast/repaint/table-cell-collapsed-border.html
+/sdcard/android/layout_tests/fast/repaint/selection-after-delete.html
+/sdcard/android/layout_tests/fast/repaint/lines-with-layout-delta.html
+/sdcard/android/layout_tests/fast/repaint/layout-state-only-positioned.html
+/sdcard/android/layout_tests/fast/repaint/table-extra-bottom-grow.html
+/sdcard/android/layout_tests/fast/repaint/transform-relative-position.html
+/sdcard/android/layout_tests/fast/repaint/selection-gap-overflow-scroll.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-skipped.html
+/sdcard/android/layout_tests/fast/repaint/line-overflow.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-2.html
+/sdcard/android/layout_tests/fast/repaint/table-row.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-6.html
+/sdcard/android/layout_tests/fast/repaint/table-outer-border.html
+/sdcard/android/layout_tests/fast/repaint/overflow-scroll-delete.html
+/sdcard/android/layout_tests/fast/repaint/layer-visibility.html
+/sdcard/android/layout_tests/fast/repaint/border-radius-repaint.html
+/sdcard/android/layout_tests/fast/repaint/table-collapsed-border.html
+/sdcard/android/layout_tests/fast/repaint/transform-translate.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-7235.html
+/sdcard/android/layout_tests/fast/repaint/4776765.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-6473.html
+/sdcard/android/layout_tests/fast/repaint/intermediate-layout-position-clip.html
+/sdcard/android/layout_tests/fast/repaint/focus-ring.html
+/sdcard/android/layout_tests/fast/repaint/table-cell-vertical-overflow.html
+/sdcard/android/layout_tests/fast/repaint/create-layer-repaint.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-clip-2.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-6388.html
+/sdcard/android/layout_tests/fast/repaint/overflow-outline-repaint.html
+/sdcard/android/layout_tests/fast/repaint/content-into-overflow.html
+/sdcard/android/layout_tests/fast/repaint/static-to-positioned.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-5699.html
+/sdcard/android/layout_tests/fast/repaint/transform-absolute-in-positioned-container.html
+/sdcard/android/layout_tests/fast/repaint/outline-repaint-glitch.html
+/sdcard/android/layout_tests/fast/repaint/overflow-delete-line.html
+/sdcard/android/layout_tests/fast/repaint/transform-disable-layoutstate.html
+/sdcard/android/layout_tests/fast/repaint/list-marker.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-3.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-7.html
+/sdcard/android/layout_tests/fast/repaint/outline-inset.html
+/sdcard/android/layout_tests/fast/repaint/box-shadow-h.html
+/sdcard/android/layout_tests/fast/repaint/4774354.html
+/sdcard/android/layout_tests/fast/repaint/clip-with-layout-delta.html
+/sdcard/android/layout_tests/fast/repaint/control-clip.html
+/sdcard/android/layout_tests/fast/repaint/selected-replaced.html
+/sdcard/android/layout_tests/fast/repaint/text-selection-rect-in-overflow-2.html
+/sdcard/android/layout_tests/fast/repaint/make-children-non-inline.html
+/sdcard/android/layout_tests/fast/repaint/text-shadow.html
+/sdcard/android/layout_tests/fast/repaint/outline-shrinking.html
+/sdcard/android/layout_tests/fast/repaint/layer-child-outline.html
+/sdcard/android/layout_tests/fast/loader/start-load-in-unload.html
+/sdcard/android/layout_tests/fast/loader/text-document-wrapping.html
+/sdcard/android/layout_tests/fast/canvas/fillrect-gradient-zero-stops.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transforms-during-path.html
+/sdcard/android/layout_tests/fast/canvas/drawImage.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-7.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-non-invertible.html : has expected results
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-4.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-infinity.html : has expected results
+/sdcard/android/layout_tests/fast/canvas/canvas-text-baseline.html
+/sdcard/android/layout_tests/fast/canvas/canvas-as-image-incremental-repaint.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-1.html
+/sdcard/android/layout_tests/fast/canvas/canvas-size-change-after-layout.html
+/sdcard/android/layout_tests/fast/canvas/canvas-resize-reset.html
+/sdcard/android/layout_tests/fast/canvas/canvas-bg.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-skewed.html : has expected results
+/sdcard/android/layout_tests/fast/canvas/zero-size-fill-rect.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-6.html
+/sdcard/android/layout_tests/fast/canvas/patternfill-repeat.html
+/sdcard/android/layout_tests/fast/canvas/image-object-in-canvas.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-3.html
+/sdcard/android/layout_tests/fast/canvas/canvas-composite.html
+/sdcard/android/layout_tests/fast/canvas/gradient-add-second-start-end-stop.html
+/sdcard/android/layout_tests/fast/canvas/quadraticCurveTo.xml
+/sdcard/android/layout_tests/fast/canvas/fill-stroke-clip-reset-path.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-nan.html : has expected results
+/sdcard/android/layout_tests/fast/canvas/canvas-text-alignment.html
+/sdcard/android/layout_tests/fast/canvas/canvas-incremental-repaint.html
+/sdcard/android/layout_tests/fast/canvas/canvasDrawingIntoSelf.html
+/sdcard/android/layout_tests/fast/canvas/canvas-as-image.html
+/sdcard/android/layout_tests/fast/canvas/canvas-before-css.html
+/sdcard/android/layout_tests/fast/canvas/canvas-incremental-repaint-2.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-identity.html : has expected results
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-5.html
+/sdcard/android/layout_tests/fast/canvas/fillrect_gradient.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-multiply.html : has expected results
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-2.html
+/sdcard/android/layout_tests/fast/frames/contentWindow_Frame.html
+/sdcard/android/layout_tests/fast/frames/onlyCommentInIFrame.html
+/sdcard/android/layout_tests/fast/frames/frame-src-attribute.html
+/sdcard/android/layout_tests/fast/frames/frameElement-frame.html
+/sdcard/android/layout_tests/fast/frames/empty-cols-attribute.html
+/sdcard/android/layout_tests/fast/frames/iframe-scrolling-attribute.html
+/sdcard/android/layout_tests/fast/frames/inline-object-inside-frameset.html
+/sdcard/android/layout_tests/fast/frames/valid.html
+/sdcard/android/layout_tests/fast/frames/no-frame-borders.html
+/sdcard/android/layout_tests/fast/frames/empty-frame-src.html
+/sdcard/android/layout_tests/fast/frames/calculate-round.html
+/sdcard/android/layout_tests/fast/frames/frame-navigation.html
+/sdcard/android/layout_tests/fast/frames/001.html
+/sdcard/android/layout_tests/fast/frames/invalid.html
+/sdcard/android/layout_tests/fast/frames/frameset-style-recalc.html
+/sdcard/android/layout_tests/fast/frames/viewsource-attribute.html
+/sdcard/android/layout_tests/fast/frames/002.html
+/sdcard/android/layout_tests/fast/frames/calculate-relative.html
+/sdcard/android/layout_tests/fast/frames/calculate-order.html
+/sdcard/android/layout_tests/fast/frames/calculate-percentage.html
+/sdcard/android/layout_tests/fast/frames/iframe-text-contents.html
+/sdcard/android/layout_tests/fast/frames/frame-scrolling-attribute.html
+/sdcard/android/layout_tests/fast/frames/contentWindow_iFrame.html
+/sdcard/android/layout_tests/fast/frames/frame-length-fractional.html : has expected results
+/sdcard/android/layout_tests/fast/frames/calculate-fixed.html
+/sdcard/android/layout_tests/fast/frames/frame-element-name.html
+/sdcard/android/layout_tests/fast/frames/frame-set-whitespace-attributes.html
+/sdcard/android/layout_tests/fast/frames/iframe-with-frameborder.html
+/sdcard/android/layout_tests/fast/frames/frameElement-iframe.html
+/sdcard/android/layout_tests/fast/frames/iframe-name-and-id.html : has expected results
+/sdcard/android/layout_tests/fast/reflections/inline-crash.html
+/sdcard/android/layout_tests/fast/reflections/reflection-nesting.html
+/sdcard/android/layout_tests/fast/reflections/reflection-overflow-hidden.html
+/sdcard/android/layout_tests/fast/reflections/table-cell.html
+/sdcard/android/layout_tests/fast/reflections/reflection-direction.html
diff --git a/tests/DumpRenderTree/results/layout_tests_passed.txt b/tests/DumpRenderTree/results/layout_tests_passed.txt
new file mode 100644
index 0000000..fbceabd
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_passed.txt
@@ -0,0 +1,1046 @@
+/sdcard/android/layout_tests/fast/replaced/object-param-no-name.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-common-root.html
+/sdcard/android/layout_tests/fast/dynamic/hovered-detach.html
+/sdcard/android/layout_tests/fast/dynamic/insertAdjacentHTML.html
+/sdcard/android/layout_tests/fast/dynamic/style-access-late-stylesheet-load.html
+/sdcard/android/layout_tests/fast/dynamic/insertAdjacentText.html
+/sdcard/android/layout_tests/fast/dynamic/insertAdjacentHTML-allowed-parents.html
+/sdcard/android/layout_tests/fast/dynamic/checkbox-selection-crash.html
+/sdcard/android/layout_tests/fast/dynamic/outerHTML-no-element.html
+/sdcard/android/layout_tests/fast/dynamic/5872671.html
+/sdcard/android/layout_tests/fast/dynamic/ancestor-to-absolute.html
+/sdcard/android/layout_tests/fast/dynamic/float-remove-above-line.html
+/sdcard/android/layout_tests/fast/dynamic/recursive-layout.html
+/sdcard/android/layout_tests/fast/dynamic/inline-to-block-crash.html
+/sdcard/android/layout_tests/fast/text/find-backwards.html
+/sdcard/android/layout_tests/fast/text/large-text-composed-char-dos.html
+/sdcard/android/layout_tests/fast/text/find-case-folding.html
+/sdcard/android/layout_tests/fast/text/line-breaks-after-ideographic-comma-or-full-stop.html
+/sdcard/android/layout_tests/fast/encoding/gbk/chinese.html
+/sdcard/android/layout_tests/fast/encoding/gbk/x-euc-cn.html
+/sdcard/android/layout_tests/fast/encoding/gbk/gb_2312-80.html
+/sdcard/android/layout_tests/fast/encoding/gbk/cn-gb.html
+/sdcard/android/layout_tests/fast/encoding/gbk/csgb2312.html
+/sdcard/android/layout_tests/fast/encoding/gbk/iso-ir-58.html
+/sdcard/android/layout_tests/fast/encoding/gbk/csgb231280.html
+/sdcard/android/layout_tests/fast/encoding/gbk/gb2312.html
+/sdcard/android/layout_tests/fast/encoding/gbk/gbk.html
+/sdcard/android/layout_tests/fast/encoding/gbk/x-gbk.html
+/sdcard/android/layout_tests/fast/encoding/gbk/EUC-CN.html
+/sdcard/android/layout_tests/fast/encoding/gbk/close-gbk-converter.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/hebrew.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/csISO88598I.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8-e.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8-i.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/logical.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/iso-ir-138.html
+/sdcard/android/layout_tests/fast/encoding/charset-invalid.html
+/sdcard/android/layout_tests/fast/encoding/hanarei-blog32-fc2-com.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-tags-in-attributes.html
+/sdcard/android/layout_tests/fast/encoding/decoder-allow-null-chars.html
+/sdcard/android/layout_tests/fast/encoding/charset-utf16.html
+/sdcard/android/layout_tests/fast/encoding/css-charset-dom.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml-4.html
+/sdcard/android/layout_tests/fast/encoding/char-encoding.html
+/sdcard/android/layout_tests/fast/encoding/css-link-charset.html
+/sdcard/android/layout_tests/fast/encoding/latin1-winlatin.html
+/sdcard/android/layout_tests/fast/encoding/no-charset-on-dynamic-script-load.html
+/sdcard/android/layout_tests/fast/encoding/high-bit-latin1.html
+/sdcard/android/layout_tests/fast/encoding/utf-32-little-endian-bom.html
+/sdcard/android/layout_tests/fast/encoding/bandai-co-jp-releases.html
+/sdcard/android/layout_tests/fast/encoding/utf-32-big-endian-bom.html
+/sdcard/android/layout_tests/fast/encoding/bom-in-content.html
+/sdcard/android/layout_tests/fast/encoding/bom-in-content-utf16.html
+/sdcard/android/layout_tests/fast/encoding/namespace-tolerance.html
+/sdcard/android/layout_tests/fast/encoding/css-charset-evil.html
+/sdcard/android/layout_tests/fast/encoding/css-charset.html
+/sdcard/android/layout_tests/fast/encoding/misplaced-xml-declaration.html
+/sdcard/android/layout_tests/fast/encoding/charset-xuser-defined.html
+/sdcard/android/layout_tests/fast/encoding/xml-charset-utf16.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml-2.html
+/sdcard/android/layout_tests/fast/encoding/floraexpress-ru.html
+/sdcard/android/layout_tests/fast/encoding/charset-cp1251.html
+/sdcard/android/layout_tests/fast/encoding/utf-32-little-endian-nobom.xml
+/sdcard/android/layout_tests/fast/encoding/charset-unicode.html
+/sdcard/android/layout_tests/fast/encoding/meta-charset.html
+/sdcard/android/layout_tests/fast/encoding/utf-32-big-endian-nobom.xml
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml-3.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml.html
+/sdcard/android/layout_tests/fast/encoding/tag-in-title.html
+/sdcard/android/layout_tests/fast/encoding/yahoo-mail.html
+/sdcard/android/layout_tests/fast/encoding/ahram-org-eg.html
+/sdcard/android/layout_tests/fast/encoding/noscript-in-head.html
+/sdcard/android/layout_tests/fast/encoding/script-in-head.html
+/sdcard/android/layout_tests/fast/encoding/css-cached-bom.html
+/sdcard/android/layout_tests/fast/encoding/mispositioned-meta.html
+/sdcard/android/layout_tests/fast/multicol/gap-non-negative.html
+/sdcard/android/layout_tests/fast/multicol/content-height-zero-crash.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-at-end.html
+/sdcard/android/layout_tests/fast/doctypes/005-case-preserving.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-in-element.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-after-comment.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-parsing.html
+/sdcard/android/layout_tests/fast/doctypes/html-doctype.html
+/sdcard/android/layout_tests/fast/cookies/local-file-can-set-cookies.html
+/sdcard/android/layout_tests/fast/css-generated-content/empty-content-with-float-crash.html
+/sdcard/android/layout_tests/fast/css-generated-content/reset-content-to-initial.html
+/sdcard/android/layout_tests/fast/transforms/container-transform-crash.html
+/sdcard/android/layout_tests/fast/leaks/001.html
+/sdcard/android/layout_tests/fast/leaks/002.html
+/sdcard/android/layout_tests/fast/innerHTML/innerHTML-custom-tag.html
+/sdcard/android/layout_tests/fast/innerHTML/additional-inline-style.html
+/sdcard/android/layout_tests/fast/innerHTML/005.html
+/sdcard/android/layout_tests/fast/innerHTML/javascript-url.html
+/sdcard/android/layout_tests/fast/innerHTML/innerHTML-case.html
+/sdcard/android/layout_tests/fast/overflow/onscroll-layer-self-destruct.html
+/sdcard/android/layout_tests/fast/overflow/generated-content-crash.html
+/sdcard/android/layout_tests/fast/events/dispatch-to-handle-event.html
+/sdcard/android/layout_tests/fast/events/onload-after-document-close-with-subresource.html
+/sdcard/android/layout_tests/fast/events/dispatchEvent-crash.html
+/sdcard/android/layout_tests/fast/events/programmatic-check-no-change-event.html
+/sdcard/android/layout_tests/fast/events/onunload-body-property.html
+/sdcard/android/layout_tests/fast/events/init-event-after-dispatch.html
+/sdcard/android/layout_tests/fast/events/delayed-style-mutation-event-crash.html
+/sdcard/android/layout_tests/fast/events/anchor-empty-focus.html
+/sdcard/android/layout_tests/fast/events/no-blur-on-page-leave.html
+/sdcard/android/layout_tests/fast/events/onload-name-collision.html
+/sdcard/android/layout_tests/fast/events/div-focus.html
+/sdcard/android/layout_tests/fast/events/overflow-events.html
+/sdcard/android/layout_tests/fast/events/create-document-crash-on-attach-event.html
+/sdcard/android/layout_tests/fast/events/no-blur-on-enter-button.html
+/sdcard/android/layout_tests/fast/events/keypress-removed-node.html
+/sdcard/android/layout_tests/fast/events/shadow-boundary-crossing.html
+/sdcard/android/layout_tests/fast/events/submit-reset-nested-bubble.html
+/sdcard/android/layout_tests/fast/events/nested-event-remove-node-crash.html
+/sdcard/android/layout_tests/fast/events/mousedown_in_scrollbar.html
+/sdcard/android/layout_tests/fast/events/window-load-capture.html
+/sdcard/android/layout_tests/fast/events/event-instanceof.html
+/sdcard/android/layout_tests/fast/events/event-creation.html
+/sdcard/android/layout_tests/fast/events/caller-access-from-event-listener.html
+/sdcard/android/layout_tests/fast/events/stopPropagation-submit.html
+/sdcard/android/layout_tests/fast/events/remove-event-listener.html
+/sdcard/android/layout_tests/fast/events/mouseup-outside-button.html
+/sdcard/android/layout_tests/fast/events/no-window-load.html
+/sdcard/android/layout_tests/fast/events/event-listener-html-non-html-confusion.html
+/sdcard/android/layout_tests/fast/events/onerror-bubbling.html
+/sdcard/android/layout_tests/fast/events/keydown-remove-frame.html
+/sdcard/android/layout_tests/fast/events/event-targets.html
+/sdcard/android/layout_tests/fast/events/space-scroll-event.html
+/sdcard/android/layout_tests/fast/events/onload-after-document-close-no-subresource.html
+/sdcard/android/layout_tests/fast/events/stopPropagation-checkbox.html
+/sdcard/android/layout_tests/fast/events/tab-crash-with-image-map.html
+/sdcard/android/layout_tests/fast/events/simulated-key-state.html
+/sdcard/android/layout_tests/fast/events/init-event-null-view.html
+/sdcard/android/layout_tests/fast/events/resize-subframe.html
+/sdcard/android/layout_tests/fast/events/onunload-window-property.html
+/sdcard/android/layout_tests/fast/html/empty-fragment-id-goto-top.html
+/sdcard/android/layout_tests/fast/html/script-allowed-types-languages.html
+/sdcard/android/layout_tests/fast/html/xhtml-serialize.html
+/sdcard/android/layout_tests/fast/html/body-offset-properties.html
+/sdcard/android/layout_tests/fast/images/animated-background-image-crash.html
+/sdcard/android/layout_tests/fast/images/border.html
+/sdcard/android/layout_tests/fast/images/load-img-with-empty-src.html
+/sdcard/android/layout_tests/fast/images/image-empty-data.html
+/sdcard/android/layout_tests/fast/images/text-content-crash-2.html
+/sdcard/android/layout_tests/fast/images/text-content-crash.html
+/sdcard/android/layout_tests/fast/inspector/cssURLQuotes.html
+/sdcard/android/layout_tests/fast/flexbox/inline-children-crash.html
+/sdcard/android/layout_tests/fast/tokenizer/nested-cached-scripts.html
+/sdcard/android/layout_tests/fast/tokenizer/image-empty-crash.html
+/sdcard/android/layout_tests/fast/tokenizer/lessthan-terminates-tags-and-attrs.html
+/sdcard/android/layout_tests/fast/tokenizer/ignore-tags-in-iframe.html
+/sdcard/android/layout_tests/fast/tokenizer/write-partial-entity.html
+/sdcard/android/layout_tests/fast/tokenizer/external-script-document-open.html
+/sdcard/android/layout_tests/fast/tokenizer/004.html
+/sdcard/android/layout_tests/fast/tokenizer/write-inline-script-open.html
+/sdcard/android/layout_tests/fast/tokenizer/write-external-script-open.html
+/sdcard/android/layout_tests/fast/tokenizer/doctype-search-reset.html
+/sdcard/android/layout_tests/fast/tokenizer/nested-multiple-scripts.html
+/sdcard/android/layout_tests/fast/tokenizer/nested-cached-scripts-and-stylesheet.html
+/sdcard/android/layout_tests/fast/tokenizer/ampersand-in-special-tag.html
+/sdcard/android/layout_tests/fast/tokenizer/write-unclosed-script.html
+/sdcard/android/layout_tests/fast/tokenizer/badscript.html
+/sdcard/android/layout_tests/fast/regex/quantified-assertions.html
+/sdcard/android/layout_tests/fast/regex/non-pattern-characters.html
+/sdcard/android/layout_tests/fast/regex/slow.html
+/sdcard/android/layout_tests/fast/regex/malformed-escapes.html
+/sdcard/android/layout_tests/fast/regex/early-acid3-86.html
+/sdcard/android/layout_tests/fast/regex/test1.html
+/sdcard/android/layout_tests/fast/regex/alternative-length-miscalculation.html
+/sdcard/android/layout_tests/fast/regex/test4.html
+/sdcard/android/layout_tests/fast/regex/non-capturing-backtracking.html
+/sdcard/android/layout_tests/fast/js/pic/cached-single-entry-transition.html
+/sdcard/android/layout_tests/fast/js/pic/cached-prototype-setter.html
+/sdcard/android/layout_tests/fast/js/pic/get-empty-string.html
+/sdcard/android/layout_tests/fast/js/pic/get-set-proxy-object.html
+/sdcard/android/layout_tests/fast/js/pic/rehash-poisons-structure.html
+/sdcard/android/layout_tests/fast/js/pic/cached-array-length-access.html
+/sdcard/android/layout_tests/fast/js/pic/cached-prototype-then-immediate.html
+/sdcard/android/layout_tests/fast/js/pic/cached-getter-setter.html
+/sdcard/android/layout_tests/fast/js/pic/cached-getter-dictionary-and-proto.html
+/sdcard/android/layout_tests/fast/js/pic/delete-global-object.html
+/sdcard/android/layout_tests/fast/js/pic/cached-deleted-properties.html
+/sdcard/android/layout_tests/fast/js/pic/dictionary-prototype.html
+/sdcard/android/layout_tests/fast/js/bitwise-and-on-undefined.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-eval-inside-closure.html
+/sdcard/android/layout_tests/fast/js/string_replace.html
+/sdcard/android/layout_tests/fast/js/ignored-result-ref-crash.html
+/sdcard/android/layout_tests/fast/js/function-toString-object-literals.html
+/sdcard/android/layout_tests/fast/js/numeric-conversion.html
+/sdcard/android/layout_tests/fast/js/select-options-remove.html
+/sdcard/android/layout_tests/fast/js/array-tostring-ignore-separator.html
+/sdcard/android/layout_tests/fast/js/number-toExponential.html
+/sdcard/android/layout_tests/fast/js/direct-entry-to-function-code.html
+/sdcard/android/layout_tests/fast/js/vardecl-preserve-vardecl.html
+/sdcard/android/layout_tests/fast/js/unexpected-constant-crash.html
+/sdcard/android/layout_tests/fast/js/var-shadows-arg-gc-crash.html
+/sdcard/android/layout_tests/fast/js/arguments-bad-index.html
+/sdcard/android/layout_tests/fast/js/resize-array-assign.html
+/sdcard/android/layout_tests/fast/js/number-toString.html
+/sdcard/android/layout_tests/fast/js/this-non-object-proto.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-new.html
+/sdcard/android/layout_tests/fast/js/cyclic-proto.html
+/sdcard/android/layout_tests/fast/js/vardecl-preserve-arguments.html
+/sdcard/android/layout_tests/fast/js/regexp-compile-crash.html
+/sdcard/android/layout_tests/fast/js/var-declarations-shadowing.html
+/sdcard/android/layout_tests/fast/js/ignored-result-null-comparison-crash.html
+/sdcard/android/layout_tests/fast/js/array-sort-reentrance.html
+/sdcard/android/layout_tests/fast/js/toString-for-var-decl.html
+/sdcard/android/layout_tests/fast/js/string-slice-abnormal-values.html
+/sdcard/android/layout_tests/fast/js/exception-linenums-in-html-1.html
+/sdcard/android/layout_tests/fast/js/do-while-without-semicolon.html
+/sdcard/android/layout_tests/fast/js/object-prototype-toLocaleString.html
+/sdcard/android/layout_tests/fast/js/function-redefinition.html
+/sdcard/android/layout_tests/fast/js/function-name.html
+/sdcard/android/layout_tests/fast/js/logical-or-jless.html
+/sdcard/android/layout_tests/fast/js/regexp-non-character.html
+/sdcard/android/layout_tests/fast/js/assign.html
+/sdcard/android/layout_tests/fast/js/for-in-avoid-duplicates.html
+/sdcard/android/layout_tests/fast/js/sort-stability.html
+/sdcard/android/layout_tests/fast/js/duplicate-param-gc-crash.html
+/sdcard/android/layout_tests/fast/js/regexp-stack-overflow.html
+/sdcard/android/layout_tests/fast/js/function-argument-evaluation-before-exception.html
+/sdcard/android/layout_tests/fast/js/number-toprecision.html
+/sdcard/android/layout_tests/fast/js/string-property-iteration.html
+/sdcard/android/layout_tests/fast/js/do-while-semicolon.html
+/sdcard/android/layout_tests/fast/js/regexp-divequal.html
+/sdcard/android/layout_tests/fast/js/named-function-expression.html
+/sdcard/android/layout_tests/fast/js/array-iterate-backwards.html
+/sdcard/android/layout_tests/fast/js/constructor-attributes.html
+/sdcard/android/layout_tests/fast/js/array-some.html
+/sdcard/android/layout_tests/fast/js/missing-title-end-tag-js.html
+/sdcard/android/layout_tests/fast/js/object-extra-comma.html
+/sdcard/android/layout_tests/fast/js/number-tofixed.html
+/sdcard/android/layout_tests/fast/js/function-declarations-in-switch-statement.html
+/sdcard/android/layout_tests/fast/js/regexp-extended-characters-crash.html
+/sdcard/android/layout_tests/fast/js/typeof-codegen-crash.html
+/sdcard/android/layout_tests/fast/js/array-indexof.html
+/sdcard/android/layout_tests/fast/js/mod-crash.html
+/sdcard/android/layout_tests/fast/js/eval-keyword-vs-function.html
+/sdcard/android/layout_tests/fast/js/debugger.html
+/sdcard/android/layout_tests/fast/js/rehash-assign.html
+/sdcard/android/layout_tests/fast/js/object-prototype-constructor.html
+/sdcard/android/layout_tests/fast/js/string-replace-exception-crash.html
+/sdcard/android/layout_tests/fast/js/date-big-setmonth.html
+/sdcard/android/layout_tests/fast/js/exception-linenums-in-html-2.html
+/sdcard/android/layout_tests/fast/js/select-options-add.html
+/sdcard/android/layout_tests/fast/js/toString-dontEnum.html
+/sdcard/android/layout_tests/fast/js/toString-elision-trailing-comma.html
+/sdcard/android/layout_tests/fast/js/regexp-negative-special-characters.html
+/sdcard/android/layout_tests/fast/js/getter-setter-gc.html
+/sdcard/android/layout_tests/fast/js/string-substr.html
+/sdcard/android/layout_tests/fast/js/for-in-var-scope.html
+/sdcard/android/layout_tests/fast/js/exec-state-marking.html
+/sdcard/android/layout_tests/fast/js/string-sort.html
+/sdcard/android/layout_tests/fast/js/primitive-method-this.html
+/sdcard/android/layout_tests/fast/js/delete-getters-setters.html
+/sdcard/android/layout_tests/fast/js/const-without-initializer.html
+/sdcard/android/layout_tests/fast/js/sparse-array.html
+/sdcard/android/layout_tests/fast/js/same-origin-subframe-about-blank.html
+/sdcard/android/layout_tests/fast/js/nested-function-scope.html
+/sdcard/android/layout_tests/fast/js/reparsing-semicolon-insertion.html
+/sdcard/android/layout_tests/fast/js/regexp-non-capturing-groups.html
+/sdcard/android/layout_tests/fast/js/has-own-property.html
+/sdcard/android/layout_tests/fast/js/window-location-href-file-urls.html
+/sdcard/android/layout_tests/fast/js/convert-nan-to-bool.html
+/sdcard/android/layout_tests/fast/js/regexp-extended-characters-more.html
+/sdcard/android/layout_tests/fast/js/arguments.html
+/sdcard/android/layout_tests/fast/js/prefix-syntax.html
+/sdcard/android/layout_tests/fast/js/exception-with-handler-inside-eval-with-dynamic-scope.html
+/sdcard/android/layout_tests/fast/js/for-in-exeception.html
+/sdcard/android/layout_tests/fast/js/array-lastIndexOf.html
+/sdcard/android/layout_tests/fast/js/modify-non-references.html
+/sdcard/android/layout_tests/fast/js/regexp-find-first-asserted.html
+/sdcard/android/layout_tests/fast/js/sort-randomly.html
+/sdcard/android/layout_tests/fast/js/array-indexing.html
+/sdcard/android/layout_tests/fast/js/regexp-caching.html
+/sdcard/android/layout_tests/fast/js/typeof-syntax.html
+/sdcard/android/layout_tests/fast/js/regexp-character-match-out-of-order.html
+/sdcard/android/layout_tests/fast/js/function-call-register-allocation.html
+/sdcard/android/layout_tests/fast/js/constant-folding.html
+/sdcard/android/layout_tests/fast/js/activation-object-function-lifetime.html
+/sdcard/android/layout_tests/fast/js/array-filter.html
+/sdcard/android/layout_tests/fast/js/implicit-global-to-global-reentry.html
+/sdcard/android/layout_tests/fast/js/array-foreach.html
+/sdcard/android/layout_tests/fast/js/regexp-many-brackets.html
+/sdcard/android/layout_tests/fast/js/activation-proto.html
+/sdcard/android/layout_tests/fast/js/toString-overrides.html
+/sdcard/android/layout_tests/fast/js/regexp-unicode-overflow.html
+/sdcard/android/layout_tests/fast/js/postfix-syntax.html
+/sdcard/android/layout_tests/fast/js/global-recursion-on-full-stack.html
+/sdcard/android/layout_tests/fast/js/number-cell-reuse.html
+/sdcard/android/layout_tests/fast/js/closure-inside-extra-arg-call.html
+/sdcard/android/layout_tests/fast/js/removing-Cf-characters.html
+/sdcard/android/layout_tests/fast/js/pretty-print.html
+/sdcard/android/layout_tests/fast/js/const.html
+/sdcard/android/layout_tests/fast/js/isPrototypeOf.html
+/sdcard/android/layout_tests/fast/js/math.html
+/sdcard/android/layout_tests/fast/js/string-from-char-code.html
+/sdcard/android/layout_tests/fast/js/eval-overriding.html
+/sdcard/android/layout_tests/fast/js/regexp-char-insensitive.html
+/sdcard/android/layout_tests/fast/js/array-float-delete.html
+/sdcard/android/layout_tests/fast/js/array-index-immediate-types.html
+/sdcard/android/layout_tests/fast/js/integer-extremes.html
+/sdcard/android/layout_tests/fast/js/regexp-non-bmp.html
+/sdcard/android/layout_tests/fast/js/delete-then-put.html
+/sdcard/android/layout_tests/fast/js/string-replace-2.html
+/sdcard/android/layout_tests/fast/js/cached-eval-gc.html
+/sdcard/android/layout_tests/fast/js/property-getters-and-setters.html
+/sdcard/android/layout_tests/fast/js/array-reset-large-index.html
+/sdcard/android/layout_tests/fast/js/date-proto-generic-invocation.html
+/sdcard/android/layout_tests/fast/js/lastModified.html
+/sdcard/android/layout_tests/fast/js/encode-URI-test.html
+/sdcard/android/layout_tests/fast/js/codegen-loops-logical-nodes.html
+/sdcard/android/layout_tests/fast/js/string-capitalization.html
+/sdcard/android/layout_tests/fast/js/caller-property.html
+/sdcard/android/layout_tests/fast/js/date-DST-time-cusps.html
+/sdcard/android/layout_tests/fast/js/regexp-unicode-handling.html
+/sdcard/android/layout_tests/fast/js/unmatching-argument-count.html
+/sdcard/android/layout_tests/fast/js/delete-multiple-global-blocks.html
+/sdcard/android/layout_tests/fast/js/text-field-resize.html
+/sdcard/android/layout_tests/fast/js/duplicate-param-crash.html
+/sdcard/android/layout_tests/fast/js/switch-behaviour.html
+/sdcard/android/layout_tests/fast/js/delete-syntax.html
+/sdcard/android/layout_tests/fast/js/date-DST-pre-1970.html
+/sdcard/android/layout_tests/fast/js/array-splice.html
+/sdcard/android/layout_tests/fast/js/statement-list-register-crash.html
+/sdcard/android/layout_tests/fast/js/date-set-to-nan.html
+/sdcard/android/layout_tests/fast/js/code-serialize-paren.html
+/sdcard/android/layout_tests/fast/js/parse-backslash-before-newline.html
+/sdcard/android/layout_tests/fast/js/delete-function-parameter.html
+/sdcard/android/layout_tests/fast/js/exception-expression-offset.html
+/sdcard/android/layout_tests/fast/js/invalid-syntax-for-function.html
+/sdcard/android/layout_tests/fast/js/cyclic-prototypes.html
+/sdcard/android/layout_tests/fast/js/equality.html
+/sdcard/android/layout_tests/fast/js/order-of-operations.html
+/sdcard/android/layout_tests/fast/js/regexp-no-extensions.html
+/sdcard/android/layout_tests/fast/js/stack-unwinding.html
+/sdcard/android/layout_tests/fast/js/reserved-words.html
+/sdcard/android/layout_tests/fast/js/toString-try-else.html
+/sdcard/android/layout_tests/fast/js/function-dot-arguments-and-caller.html
+/sdcard/android/layout_tests/fast/js/do-while-expression-value.html
+/sdcard/android/layout_tests/fast/js/bom-in-file-retains-correct-offset.html
+/sdcard/android/layout_tests/fast/js/string-split-ignore-case.html
+/sdcard/android/layout_tests/fast/js/date-constructor.html
+/sdcard/android/layout_tests/fast/js/date-big-setdate.html
+/sdcard/android/layout_tests/fast/js/array-every.html
+/sdcard/android/layout_tests/fast/js/function-toString-parentheses.html
+/sdcard/android/layout_tests/fast/js/array-functions-non-arrays.html
+/sdcard/android/layout_tests/fast/js/while-expression-value.html
+/sdcard/android/layout_tests/fast/js/string-replace-3.html
+/sdcard/android/layout_tests/fast/js/avl-crash.html
+/sdcard/android/layout_tests/fast/js/vardecl-blocks-init.html
+/sdcard/android/layout_tests/fast/js/null-char-in-string.html
+/sdcard/android/layout_tests/fast/js/codegen-temporaries-multiple-global-blocks.html
+/sdcard/android/layout_tests/fast/js/char-at.html
+/sdcard/android/layout_tests/fast/js/propertyIsEnumerable.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-equal.html
+/sdcard/android/layout_tests/fast/js/constructor.html
+/sdcard/android/layout_tests/fast/js/regexp-overflow.html
+/sdcard/android/layout_tests/fast/js/var-declarations.html
+/sdcard/android/layout_tests/fast/js/continue-break-multiple-labels.html
+/sdcard/android/layout_tests/fast/js/toString-exception.html
+/sdcard/android/layout_tests/fast/js/regexp-test-null-string.html
+/sdcard/android/layout_tests/fast/js/date-parse-comments-test.html
+/sdcard/android/layout_tests/fast/js/select-options-remove-gc.html
+/sdcard/android/layout_tests/fast/js/array-tostring-and-join.html
+/sdcard/android/layout_tests/fast/js/implicit-call-with-global-reentry.html
+/sdcard/android/layout_tests/fast/js/function-names.html
+/sdcard/android/layout_tests/fast/js/primitive-property-access-edge-cases.html
+/sdcard/android/layout_tests/fast/js/date-preserve-milliseconds.html
+/sdcard/android/layout_tests/fast/js/sort-large-array.html
+/sdcard/android/layout_tests/fast/js/for-in-to-text.html
+/sdcard/android/layout_tests/fast/js/global-var-limit.html
+/sdcard/android/layout_tests/fast/js/static-scope-object.html
+/sdcard/android/layout_tests/fast/js/var-shadows-arg-crash.html
+/sdcard/android/layout_tests/fast/js/function-apply.html
+/sdcard/android/layout_tests/fast/js/function-prototype.html
+/sdcard/android/layout_tests/fast/js/tostring-exception-in-property-access.html
+/sdcard/android/layout_tests/fast/js/function-declaration-statement.html
+/sdcard/android/layout_tests/fast/js/date-negative-setmonth.html
+/sdcard/android/layout_tests/fast/js/reentrant-call-unwind.html
+/sdcard/android/layout_tests/fast/js/regexp-lastindex.html
+/sdcard/android/layout_tests/fast/js/finally-codegen-failure.html
+/sdcard/android/layout_tests/fast/js/read-modify-eval.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-function-with-lazy-activation.html
+/sdcard/android/layout_tests/fast/js/cyclic-ref-toString.html
+/sdcard/android/layout_tests/fast/js/date-big-constructor.html
+/sdcard/android/layout_tests/fast/js/gmail-re-re.html
+/sdcard/android/layout_tests/fast/js/deep-recursion-test.html
+/sdcard/android/layout_tests/fast/js/lexical-lookup-in-function-constructor.html
+/sdcard/android/layout_tests/fast/js/regexp-range-out-of-order.html
+/sdcard/android/layout_tests/fast/js/throw-from-array-sort.html
+/sdcard/android/layout_tests/fast/js/slash-lineterminator-parse.html
+/sdcard/android/layout_tests/fast/js/dot-node-base-exception.html
+/sdcard/android/layout_tests/fast/js/codegen-peephole-locals.html
+/sdcard/android/layout_tests/fast/js/constant-count.html
+/sdcard/android/layout_tests/fast/js/regexp-compile.html
+/sdcard/android/layout_tests/fast/js/declaration-in-block.html
+/sdcard/android/layout_tests/fast/js/eval-var-decl.html
+/sdcard/android/layout_tests/fast/js/eval-cross-window.html
+/sdcard/android/layout_tests/fast/js/function-decompilation-operators.html
+/sdcard/android/layout_tests/fast/js/sort-non-numbers.html
+/sdcard/android/layout_tests/fast/js/function-declarations.html
+/sdcard/android/layout_tests/fast/js/non-object-proto.html
+/sdcard/android/layout_tests/fast/js/regexp-extended-characters-match.html
+/sdcard/android/layout_tests/fast/js/toString-number-dot-expr.html
+/sdcard/android/layout_tests/fast/js/date-parse-test.html
+/sdcard/android/layout_tests/fast/js/exception-try-finally-scope-error.html
+/sdcard/android/layout_tests/fast/js/function-dot-arguments.html
+/sdcard/android/layout_tests/fast/js/toString-prefix-postfix-preserve-parens.html
+/sdcard/android/layout_tests/fast/js/regexp-ranges-and-escaped-hyphens.html
+/sdcard/android/layout_tests/fast/js/exception-linenums.html
+/sdcard/android/layout_tests/fast/js/array-holes.html
+/sdcard/android/layout_tests/fast/js/construct-global-object.html
+/sdcard/android/layout_tests/fast/js/codegen-temporaries.html
+/sdcard/android/layout_tests/fast/js/array-join-bug-11524.html
+/sdcard/android/layout_tests/fast/js/with-scope-gc.html
+/sdcard/android/layout_tests/fast/js/array-map.html
+/sdcard/android/layout_tests/fast/js/string-index-overflow.html
+/sdcard/android/layout_tests/fast/js/eval-cache-crash.html
+/sdcard/android/layout_tests/fast/js/typeof-constant-string.html
+/sdcard/android/layout_tests/fast/js/comparefn-sort-stability.html
+/sdcard/android/layout_tests/fast/js/navigator-plugins-crash.html
+/sdcard/android/layout_tests/fast/js/vardecl-preserve-parameters.html
+/sdcard/android/layout_tests/fast/inline/clean-after-removing-temp-boxes.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/early-acid3-65-excerpt.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/early-acid3-66-excerpt.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/cellpadding-attribute.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/insert-row.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/tBodies.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/rows.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/write-multiple-calls.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/document-special-properties.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/url-getset.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/writeln-call.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/document-plugins.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/title-get.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/object-by-name-unknown-child-element.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/write-call.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/object-by-name-or-id.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/document-open-return-value.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/writeln-multiple-calls.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/title-set.html
+/sdcard/android/layout_tests/fast/dom/HTMLLabelElement/form/test1.html
+/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/options-collection-set-string-length.html
+/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/options-collection-detached.html
+/sdcard/android/layout_tests/fast/dom/Document/replace-child.html
+/sdcard/android/layout_tests/fast/dom/Document/title-property-creates-title-element.html
+/sdcard/android/layout_tests/fast/dom/Document/createElementNS-namespace-err.html
+/sdcard/android/layout_tests/fast/dom/Document/title-property-set-multiple-times.html
+/sdcard/android/layout_tests/fast/dom/Document/document-reopen.html
+/sdcard/android/layout_tests/fast/dom/Document/document-charset.html
+/sdcard/android/layout_tests/fast/dom/Document/replaceChild-null-oldChild.html
+/sdcard/android/layout_tests/fast/dom/Document/createAttributeNS-namespace-err.html
+/sdcard/android/layout_tests/fast/dom/Document/open-with-pending-load.html
+/sdcard/android/layout_tests/fast/dom/Document/doc-open-while-parsing.html
+/sdcard/android/layout_tests/fast/dom/HTMLMetaElement/meta-attributes.html
+/sdcard/android/layout_tests/fast/dom/Element/getAttribute-check-case-sensitivity.html
+/sdcard/android/layout_tests/fast/dom/Element/attr-param-typechecking.html
+/sdcard/android/layout_tests/fast/dom/Element/attribute-uppercase.html
+/sdcard/android/layout_tests/fast/dom/Element/element-traversal.html
+/sdcard/android/layout_tests/fast/dom/Element/onclick-case.html
+/sdcard/android/layout_tests/fast/dom/Element/contains-method.html
+/sdcard/android/layout_tests/fast/dom/Element/setAttribute-with-colon.html
+/sdcard/android/layout_tests/fast/dom/Element/setAttribute-case-insensitivity.html
+/sdcard/android/layout_tests/fast/dom/Element/dimension-properties-unrendered.html
+/sdcard/android/layout_tests/fast/dom/Element/offsetTop-table-cell.html
+/sdcard/android/layout_tests/fast/dom/DOMException/EventException.html
+/sdcard/android/layout_tests/fast/dom/DOMException/prototype-object.html
+/sdcard/android/layout_tests/fast/dom/DOMException/RangeException.html
+/sdcard/android/layout_tests/fast/dom/HTMLButtonElement/value/getset.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-reexecution.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-set-src.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-load-events.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-decoding-error-after-setting-src.html
+/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/collection-setter-getter.html
+/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/set-option-index-text.html
+/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/option-text.html
+/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/option-prototype.html
+/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-1.html
+/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-2.html
+/sdcard/android/layout_tests/fast/dom/NodeList/childNodes-reset-cache.html
+/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-3.html
+/sdcard/android/layout_tests/fast/dom/NodeList/invalidate-node-lists-when-parsing.html
+/sdcard/android/layout_tests/fast/dom/NodeList/item-by-id-with-no-document.html
+/sdcard/android/layout_tests/fast/dom/NodeList/nodelist-item-with-name.html
+/sdcard/android/layout_tests/fast/dom/DOMImplementation/createDocumentType-err.html
+/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/transition-property-names.html
+/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/css-properties-case-sensitive.html
+/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/empty-string-property.html
+/sdcard/android/layout_tests/fast/dom/Node/initial-values.html
+/sdcard/android/layout_tests/fast/dom/Node/DOMNodeRemovedEvent.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/viewless-document.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID-almost-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/elementRoot.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/not-supported-namespace-in-selector.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/dumpNodeList.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseTag.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/detached-element.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/bug-17313.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath-almost-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/dumpNodeList-almost-strict.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableSectionElement/rows.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/001.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/002.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/003.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/004.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/002.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/012.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/004.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/014.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/006.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/008.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/dumpNodeList.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/001.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/003.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/013.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/005.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/015.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/007.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/009.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/checked-pseudo-selector.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-text-reset.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/size-as-number.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/duplicate-element-names.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-hidden-value.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-checked-reset.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/size-attribute.html
+/sdcard/android/layout_tests/fast/dom/TreeWalker/TreeWalker-currentNode.html
+/sdcard/android/layout_tests/fast/dom/HTMLDivElement/align/getset.html
+/sdcard/android/layout_tests/fast/dom/Text/replaceWholeText.html
+/sdcard/android/layout_tests/fast/dom/HTMLFormElement/htmlformelement-indexed-getter.html
+/sdcard/android/layout_tests/fast/dom/HTMLFormElement/elements-not-in-document.html
+/sdcard/android/layout_tests/fast/dom/Window/window-closed-crash.html
+/sdcard/android/layout_tests/fast/dom/Window/setTimeout-no-arguments.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-self.html
+/sdcard/android/layout_tests/fast/dom/Window/getMatchedCSSRules-null-crash.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-self-from-other-frame.html
+/sdcard/android/layout_tests/fast/dom/Window/window-custom-prototype-crash.html
+/sdcard/android/layout_tests/fast/dom/Window/window-object-cross-frame-calls.html
+/sdcard/android/layout_tests/fast/dom/Window/window-location-replace-functions.html
+/sdcard/android/layout_tests/fast/dom/Window/attr-constructor.html
+/sdcard/android/layout_tests/fast/dom/Window/window-remove-event-listener.html
+/sdcard/android/layout_tests/fast/dom/Window/window-function-frame-getter-precedence.html
+/sdcard/android/layout_tests/fast/dom/Window/atob-btoa.html
+/sdcard/android/layout_tests/fast/dom/Window/clear-timeout.html
+/sdcard/android/layout_tests/fast/dom/Window/window-property-clearing.html
+/sdcard/android/layout_tests/fast/dom/Window/element-constructors-on-window.html
+/sdcard/android/layout_tests/fast/dom/Window/orphaned-frame-access.html
+/sdcard/android/layout_tests/fast/dom/Window/redirect-with-timer.html
+/sdcard/android/layout_tests/fast/dom/Window/window-resize-and-move-sub-frame.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-parent.html
+/sdcard/android/layout_tests/fast/dom/Window/console-trace.html
+/sdcard/android/layout_tests/fast/dom/Window/alert-undefined.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-top.html
+/sdcard/android/layout_tests/fast/dom/Window/window-appendages-cleared.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-parent-no-parent.html
+/sdcard/android/layout_tests/fast/dom/Window/closure-access-after-navigation-iframe.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableRowElement/cells.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableRowElement/insertCell.html
+/sdcard/android/layout_tests/fast/dom/HTMLFontElement/size-attribute.html
+/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/form/test1.html
+/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/object-as-frame.html
+/sdcard/android/layout_tests/fast/dom/HTMLElement/set-inner-outer-optimization.html
+/sdcard/android/layout_tests/fast/dom/Range/compareBoundaryPoints-1.html
+/sdcard/android/layout_tests/fast/dom/Range/range-compareNode.html
+/sdcard/android/layout_tests/fast/dom/Range/range-comparePoint.html
+/sdcard/android/layout_tests/fast/dom/Range/acid3-surround-contents.html
+/sdcard/android/layout_tests/fast/dom/Range/mutation.html
+/sdcard/android/layout_tests/fast/dom/Range/13000.html
+/sdcard/android/layout_tests/fast/dom/Range/range-processing-instructions.html
+/sdcard/android/layout_tests/fast/dom/Range/range-insertNode-separate-endContainer.html
+/sdcard/android/layout_tests/fast/dom/Range/range-intersectsNode.html
+/sdcard/android/layout_tests/fast/dom/Range/range-isPointInRange.html
+/sdcard/android/layout_tests/fast/dom/Range/range-clone-empty.html
+/sdcard/android/layout_tests/fast/dom/Range/compareBoundaryPoints-2.html
+/sdcard/android/layout_tests/fast/dom/Range/range-modifycontents.html
+/sdcard/android/layout_tests/fast/dom/Range/range-insertNode-splittext.html
+/sdcard/android/layout_tests/fast/dom/Range/surroundContents-check-boundary-points.html
+/sdcard/android/layout_tests/fast/dom/Range/range-exceptions.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/head-check.html
+/sdcard/android/layout_tests/fast/dom/HTMLHtmlElement/set-version.html
+/sdcard/android/layout_tests/fast/dom/HTMLHtmlElement/duplicate-html-element-crash.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-lowsrc-getset.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-src-absolute-url.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-loading-gc.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-longdesc-absolute-url.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/constructor-mutation-event-dispatch.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-without-renderer-width.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-natural-width-height.html
+/sdcard/android/layout_tests/fast/dom/StyleSheet/ownerNode-lifetime.html
+/sdcard/android/layout_tests/fast/dom/EntityReference/readonly-exceptions.html
+/sdcard/android/layout_tests/fast/dom/script-element-remove-self.html
+/sdcard/android/layout_tests/fast/dom/remove-named-attribute-crash.html
+/sdcard/android/layout_tests/fast/dom/node-item.html
+/sdcard/android/layout_tests/fast/dom/clone-node-style.html
+/sdcard/android/layout_tests/fast/dom/script-element-without-frame-crash.html
+/sdcard/android/layout_tests/fast/dom/script-element-gc.html
+/sdcard/android/layout_tests/fast/dom/duplicate-ids.html
+/sdcard/android/layout_tests/fast/dom/prototypes.html
+/sdcard/android/layout_tests/fast/dom/clone-node-form-elements.html
+/sdcard/android/layout_tests/fast/dom/import-attribute-node.html
+/sdcard/android/layout_tests/fast/dom/getter-on-window-object2.html
+/sdcard/android/layout_tests/fast/dom/objc-big-method-name.html
+/sdcard/android/layout_tests/fast/dom/importNode-prefix.html
+/sdcard/android/layout_tests/fast/dom/css-dom-read.html
+/sdcard/android/layout_tests/fast/dom/image-object.html
+/sdcard/android/layout_tests/fast/dom/gc-5.html
+/sdcard/android/layout_tests/fast/dom/node-filter-gc.html
+/sdcard/android/layout_tests/fast/dom/noscript-canvas-in-created-html-document.html
+/sdcard/android/layout_tests/fast/dom/DOMParser-assign-variable.html
+/sdcard/android/layout_tests/fast/dom/timer-clear-interval-in-handler.html
+/sdcard/android/layout_tests/fast/dom/implementation-createHTMLDocument.html
+/sdcard/android/layout_tests/fast/dom/iframe-document.html
+/sdcard/android/layout_tests/fast/dom/document-all-input.html
+/sdcard/android/layout_tests/fast/dom/null-document-location-href-put-crash.html
+/sdcard/android/layout_tests/fast/dom/getelementsbytagnamens-mixed-namespaces.html
+/sdcard/android/layout_tests/fast/dom/object-plugin-hides-properties.html
+/sdcard/android/layout_tests/fast/dom/gc-2.html
+/sdcard/android/layout_tests/fast/dom/computed-style-set-property.html
+/sdcard/android/layout_tests/fast/dom/inner-text-001.html
+/sdcard/android/layout_tests/fast/dom/css-selectorText.html
+/sdcard/android/layout_tests/fast/dom/replace-first-child.html
+/sdcard/android/layout_tests/fast/dom/importNode-null.html
+/sdcard/android/layout_tests/fast/dom/select-selectedIndex-multiple.html
+/sdcard/android/layout_tests/fast/dom/xmlhttprequest-invalid-values.html
+/sdcard/android/layout_tests/fast/dom/space-to-text.html
+/sdcard/android/layout_tests/fast/dom/css-set-property-exception.html
+/sdcard/android/layout_tests/fast/dom/java-applet-calls.html
+/sdcard/android/layout_tests/fast/dom/plugin-attributes-enumeration.html
+/sdcard/android/layout_tests/fast/dom/html-attribute-types.html
+/sdcard/android/layout_tests/fast/dom/resource-locations-in-created-html-document.html
+/sdcard/android/layout_tests/fast/dom/comment-document-fragment.html
+/sdcard/android/layout_tests/fast/dom/createAttribute-exception.html
+/sdcard/android/layout_tests/fast/dom/noscript-style.html
+/sdcard/android/layout_tests/fast/dom/serialize-cdata.html
+/sdcard/android/layout_tests/fast/dom/createDocument.html
+/sdcard/android/layout_tests/fast/dom/getelementbyname-invalidation.html
+/sdcard/android/layout_tests/fast/dom/capturing-event-listeners.html
+/sdcard/android/layout_tests/fast/dom/title-text-property.html
+/sdcard/android/layout_tests/fast/dom/incompatible-operations.html
+/sdcard/android/layout_tests/fast/dom/xmlhttprequest-html-response-encoding.html
+/sdcard/android/layout_tests/fast/dom/inner-text-rtl.html
+/sdcard/android/layout_tests/fast/dom/createDocument-empty.html
+/sdcard/android/layout_tests/fast/dom/documenturi-assigned-junk-implies-baseuri-null.html
+/sdcard/android/layout_tests/fast/dom/option-properties.html
+/sdcard/android/layout_tests/fast/dom/background-shorthand-csstext.html
+/sdcard/android/layout_tests/fast/dom/Range-insertNode-crash.html
+/sdcard/android/layout_tests/fast/dom/early-frame-url.html
+/sdcard/android/layout_tests/fast/dom/everything-to-string.html
+/sdcard/android/layout_tests/fast/dom/attribute-empty-value-no-children.html
+/sdcard/android/layout_tests/fast/dom/length-attribute-mapping.html
+/sdcard/android/layout_tests/fast/dom/documenturi-loses-to-base-tag.html
+/sdcard/android/layout_tests/fast/dom/createDocumentType2.html
+/sdcard/android/layout_tests/fast/dom/gc-6.html
+/sdcard/android/layout_tests/fast/dom/attribute-case-sensitivity.html
+/sdcard/android/layout_tests/fast/dom/compatMode-Compat.html
+/sdcard/android/layout_tests/fast/dom/namespaces-1.html
+/sdcard/android/layout_tests/fast/dom/getter-on-window-object.html
+/sdcard/android/layout_tests/fast/dom/constructors-overriding.html
+/sdcard/android/layout_tests/fast/dom/defaultView.html
+/sdcard/android/layout_tests/fast/dom/collection-null-like-arguments.html
+/sdcard/android/layout_tests/fast/dom/gc-3.html
+/sdcard/android/layout_tests/fast/dom/compatMode-Strict.html
+/sdcard/android/layout_tests/fast/dom/attribute-downcast-right.html
+/sdcard/android/layout_tests/fast/dom/document-all-select.html
+/sdcard/android/layout_tests/fast/dom/anchor-backslash.html
+/sdcard/android/layout_tests/fast/dom/css-mediarule-functions.html
+/sdcard/android/layout_tests/fast/dom/gc-acid3.html
+/sdcard/android/layout_tests/fast/dom/duplicate-ids-document-order.html
+/sdcard/android/layout_tests/fast/dom/exception-no-frame-inline-script-crash.html
+/sdcard/android/layout_tests/fast/dom/XMLSerializer-doctype2.html
+/sdcard/android/layout_tests/fast/dom/dir-no-body.html
+/sdcard/android/layout_tests/fast/dom/null-document-window-open-crash.html
+/sdcard/android/layout_tests/fast/dom/css-RGBValue.html
+/sdcard/android/layout_tests/fast/dom/innerHTML-nbsp.html
+/sdcard/android/layout_tests/fast/dom/documentElement-null.html
+/sdcard/android/layout_tests/fast/dom/class-all-whitespace.html
+/sdcard/android/layout_tests/fast/dom/wrapper-identity.html
+/sdcard/android/layout_tests/fast/dom/null-document-location-assign-crash.html
+/sdcard/android/layout_tests/fast/dom/createElement.html
+/sdcard/android/layout_tests/fast/dom/createElement-with-column.xml
+/sdcard/android/layout_tests/fast/dom/simultaneouslyRegsiteredTimerFireOrder.html
+/sdcard/android/layout_tests/fast/dom/generic-form-element-assert.html
+/sdcard/android/layout_tests/fast/dom/css-shortHands.html
+/sdcard/android/layout_tests/fast/dom/dom-instanceof.html
+/sdcard/android/layout_tests/fast/dom/array-special-accessors-should-ignore-items.html
+/sdcard/android/layout_tests/fast/dom/element-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/css-dom-read-2.html
+/sdcard/android/layout_tests/fast/dom/navigator-cookieEnabled-no-crash.html
+/sdcard/android/layout_tests/fast/dom/import-document-fragment.html
+/sdcard/android/layout_tests/fast/dom/setter-type-enforcement.html
+/sdcard/android/layout_tests/fast/dom/XMLSerializer.html
+/sdcard/android/layout_tests/fast/dom/navigator-vendorSub.html
+/sdcard/android/layout_tests/fast/dom/gc-7.html
+/sdcard/android/layout_tests/fast/dom/outerText-no-element.html
+/sdcard/android/layout_tests/fast/dom/replace-child-siblings.html
+/sdcard/android/layout_tests/fast/dom/constants.html
+/sdcard/android/layout_tests/fast/dom/inner-text-with-no-renderer.html
+/sdcard/android/layout_tests/fast/dom/onerror-img.html
+/sdcard/android/layout_tests/fast/dom/document-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/css-element-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/gc-11.html
+/sdcard/android/layout_tests/fast/dom/mutation-event-remove-inserted-node.html
+/sdcard/android/layout_tests/fast/dom/null-chardata-crash.html
+/sdcard/android/layout_tests/fast/dom/compatMode-AlmostStrict.html
+/sdcard/android/layout_tests/fast/dom/createElement-with-column.html
+/sdcard/android/layout_tests/fast/dom/exception-no-frame-timeout-crash.html
+/sdcard/android/layout_tests/fast/dom/title-text-property-2.html
+/sdcard/android/layout_tests/fast/dom/no-elements.html
+/sdcard/android/layout_tests/fast/dom/non-numeric-values-numeric-parameters.html
+/sdcard/android/layout_tests/fast/dom/gc-4.html
+/sdcard/android/layout_tests/fast/dom/inner-width-height.html
+/sdcard/android/layout_tests/fast/dom/XMLSerializer-doctype.html
+/sdcard/android/layout_tests/fast/dom/createElementNS.html
+/sdcard/android/layout_tests/fast/dom/undetectable-document-all.html
+/sdcard/android/layout_tests/fast/dom/prototype-chain.html
+/sdcard/android/layout_tests/fast/dom/gc-1.html
+/sdcard/android/layout_tests/fast/dom/select-selectedIndex-bug-12942.html
+/sdcard/android/layout_tests/fast/dom/frame-contentWindow-crash.html
+/sdcard/android/layout_tests/fast/dom/namednodemap-namelookup.html
+/sdcard/android/layout_tests/fast/dom/null-document-location-replace-crash.html
+/sdcard/android/layout_tests/fast/dom/htmlcollection-detectability.html
+/sdcard/android/layout_tests/fast/dom/documenturi-assigned-junk-implies-relative-urls-do-not-resolve.html
+/sdcard/android/layout_tests/fast/dom/collection-namedItem-via-item.html
+/sdcard/android/layout_tests/fast/dom/set-inner-text-newlines.html
+/sdcard/android/layout_tests/fast/dom/document-dir-property.html
+/sdcard/android/layout_tests/fast/dom/undetectable-style-filter.html
+/sdcard/android/layout_tests/fast/dom/domListEnumeration.html
+/sdcard/android/layout_tests/fast/dom/destroy-selected-radio-button-crash.html
+/sdcard/android/layout_tests/fast/dom/script-add.html
+/sdcard/android/layout_tests/fast/dom/iframe-contentWindow-crash.html
+/sdcard/android/layout_tests/fast/dom/comment-dom-node.html
+/sdcard/android/layout_tests/fast/dom/features.html
+/sdcard/android/layout_tests/fast/dom/canvasContext2d-element-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/remove-style-element.html
+/sdcard/android/layout_tests/fast/dom/attribute-namespaces-get-set.html
+/sdcard/android/layout_tests/fast/dom/innerHTML-escaping-attribute.html
+/sdcard/android/layout_tests/fast/dom/null-document-xmlhttprequest-open.html
+/sdcard/android/layout_tests/fast/invalid/nestedh3s-rapidweaver.html
+/sdcard/android/layout_tests/fast/forms/element-by-name.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_selected.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-003.html
+/sdcard/android/layout_tests/fast/forms/radio-button-no-change-event.html
+/sdcard/android/layout_tests/fast/forms/menulist-selection-reset.html
+/sdcard/android/layout_tests/fast/forms/textfield-focus-out.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-000.html
+/sdcard/android/layout_tests/fast/forms/form-data-encoding-normalization-overrun.html
+/sdcard/android/layout_tests/fast/forms/select-reset.html
+/sdcard/android/layout_tests/fast/forms/input-named-action-overrides-action-attribute.html
+/sdcard/android/layout_tests/fast/forms/empty-get.html
+/sdcard/android/layout_tests/fast/forms/display-none-in-onchange-keyboard.html
+/sdcard/android/layout_tests/fast/forms/range-default-value.html
+/sdcard/android/layout_tests/fast/forms/paste-into-textarea.html
+/sdcard/android/layout_tests/fast/forms/4628409.html
+/sdcard/android/layout_tests/fast/forms/radio-no-theme-padding.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-006.html
+/sdcard/android/layout_tests/fast/forms/activate-and-disabled-elements.html
+/sdcard/android/layout_tests/fast/forms/form-get-multipart2.html
+/sdcard/android/layout_tests/fast/forms/select-replace-option.html
+/sdcard/android/layout_tests/fast/forms/textarea-setvalue-submit.html
+/sdcard/android/layout_tests/fast/forms/cursor-position.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-007.html
+/sdcard/android/layout_tests/fast/forms/input-changing-value.html
+/sdcard/android/layout_tests/fast/forms/double-focus.html
+/sdcard/android/layout_tests/fast/forms/form-data-encoding-2.html
+/sdcard/android/layout_tests/fast/forms/focus.html
+/sdcard/android/layout_tests/fast/forms/button-in-forms-collection.html
+/sdcard/android/layout_tests/fast/forms/input-delete.html
+/sdcard/android/layout_tests/fast/forms/placeholder-non-textfield.html
+/sdcard/android/layout_tests/fast/forms/element-order.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-001.html
+/sdcard/android/layout_tests/fast/forms/option-constructor-selected.html
+/sdcard/android/layout_tests/fast/forms/8250.html
+/sdcard/android/layout_tests/fast/forms/input-zero-height-focus.html
+/sdcard/android/layout_tests/fast/forms/var-name-conflict-in-form-event-handler.html
+/sdcard/android/layout_tests/fast/forms/range-reset.html
+/sdcard/android/layout_tests/fast/forms/textarea-linewrap-dynamic.html
+/sdcard/android/layout_tests/fast/forms/select-remove-option.html
+/sdcard/android/layout_tests/fast/forms/onselect-selectall.html
+/sdcard/android/layout_tests/fast/forms/select-width-font-change.html
+/sdcard/android/layout_tests/fast/forms/text-field-setvalue-crash.html
+/sdcard/android/layout_tests/fast/forms/paste-multiline-text-input.html
+/sdcard/android/layout_tests/fast/forms/form-get-multipart.html
+/sdcard/android/layout_tests/fast/forms/tab-in-input.html
+/sdcard/android/layout_tests/fast/forms/button-click-DOM.html
+/sdcard/android/layout_tests/fast/forms/domstring-replace-crash.html
+/sdcard/android/layout_tests/fast/forms/submit-nil-value-field-assert.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-007.html
+/sdcard/android/layout_tests/fast/forms/form-get-multipart3.html
+/sdcard/android/layout_tests/fast/forms/select-out-of-bounds-index.html
+/sdcard/android/layout_tests/fast/forms/select-type-ahead-list-box-no-selection.html
+/sdcard/android/layout_tests/fast/forms/selected-index-assert.html
+/sdcard/android/layout_tests/fast/forms/remove-radio-button-assert.html
+/sdcard/android/layout_tests/fast/forms/textarea-crlf.html
+/sdcard/android/layout_tests/fast/forms/form-collection-lookup.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-004.html
+/sdcard/android/layout_tests/fast/forms/select-list-box-mouse-focus.html
+/sdcard/android/layout_tests/fast/forms/text-set-value-crash.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-008.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-001.html
+/sdcard/android/layout_tests/fast/forms/select-namedItem.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-005.html
+/sdcard/android/layout_tests/fast/forms/select-index-setter.html
+/sdcard/android/layout_tests/fast/forms/option-change-single-selected.html
+/sdcard/android/layout_tests/fast/forms/listbox-scroll-after-options-removed.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-002.html
+/sdcard/android/layout_tests/fast/forms/form-data-encoding.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-elementFromPoint.html
+/sdcard/android/layout_tests/fast/forms/select-set-inner.html
+/sdcard/android/layout_tests/fast/forms/missing-action.html
+/sdcard/android/layout_tests/fast/forms/textarea-scrollbar-height.html
+/sdcard/android/layout_tests/fast/forms/textarea-default-value-leading-newline.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-008.html
+/sdcard/android/layout_tests/fast/forms/listbox-typeahead-empty.html
+/sdcard/android/layout_tests/fast/forms/submit-to-url-fragment.html
+/sdcard/android/layout_tests/fast/forms/textarea-setvalue-without-renderer.html
+/sdcard/android/layout_tests/fast/forms/hidden-input-not-enabled.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-005.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-maxlength.html
+/sdcard/android/layout_tests/fast/forms/submit-with-base.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-009.html
+/sdcard/android/layout_tests/fast/forms/input-setvalue-selection.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-002.html
+/sdcard/android/layout_tests/fast/forms/old-names.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-006.html
+/sdcard/android/layout_tests/fast/forms/focus-style-pending.html
+/sdcard/android/layout_tests/fast/forms/textarea-hard-linewrap-empty.html
+/sdcard/android/layout_tests/fast/forms/document-write.html
+/sdcard/android/layout_tests/fast/forms/slow-click.html
+/sdcard/android/layout_tests/fast/forms/autofocus-attribute.html
+/sdcard/android/layout_tests/fast/table/incomplete-table-in-fragment-hang.html
+/sdcard/android/layout_tests/fast/table/section-in-table-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/large-rowspan-crash.html
+/sdcard/android/layout_tests/fast/table/colgroup-relative.html
+/sdcard/android/layout_tests/fast/table/border-changes.html
+/sdcard/android/layout_tests/fast/table/cell-in-row-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/incomplete-table-in-fragment-2.html
+/sdcard/android/layout_tests/fast/table/rowindex-comment-nodes.html
+/sdcard/android/layout_tests/fast/table/td-display-nowrap.html
+/sdcard/android/layout_tests/fast/table/row-in-tbody-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/empty-auto-column-zero-divide.html
+/sdcard/android/layout_tests/fast/table/form-in-tbody-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/form-in-table-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/destroy-cell-with-selection-crash.html
+/sdcard/android/layout_tests/fast/table/form-in-row-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/css/counters/counter-function-input-2.html
+/sdcard/android/layout_tests/fast/css/counters/counter-function-input.html
+/sdcard/android/layout_tests/fast/css/counters/counter-number-input.html
+/sdcard/android/layout_tests/fast/css/variables/invalid-identifier.html
+/sdcard/android/layout_tests/fast/css/media-rule-dyn.html
+/sdcard/android/layout_tests/fast/css/transform-function-lowercase-assert.html
+/sdcard/android/layout_tests/fast/css/word-break-user-modify-allowed-values.html
+/sdcard/android/layout_tests/fast/css/import-style-update.html
+/sdcard/android/layout_tests/fast/css/outline-invert-assertion.html
+/sdcard/android/layout_tests/fast/css/insertRule-font-face.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-004.html
+/sdcard/android/layout_tests/fast/css/transform-inline-style-remove.html
+/sdcard/android/layout_tests/fast/css/padding-no-renderer.html
+/sdcard/android/layout_tests/fast/css/transition_shorthand_parsing.html
+/sdcard/android/layout_tests/fast/css/css-selector-text.html
+/sdcard/android/layout_tests/fast/css/dashboard-regions-attr-crash.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-001.html
+/sdcard/android/layout_tests/fast/css/font-property-priority.html
+/sdcard/android/layout_tests/fast/css/computed-style-negative-top.html
+/sdcard/android/layout_tests/fast/css/device-aspect-ratio.html
+/sdcard/android/layout_tests/fast/css/pseudostyle-anonymous-text.html
+/sdcard/android/layout_tests/fast/css/css-properties-case-insensitive.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-border-image.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-border-spacing.html
+/sdcard/android/layout_tests/fast/css/font-face-descriptor-multiple-values-parsing.html
+/sdcard/android/layout_tests/fast/css/hexColor-isDigit-assert.html
+/sdcard/android/layout_tests/fast/css/transform-inline-style.html
+/sdcard/android/layout_tests/fast/css/child-selector-implicit-tbody.html
+/sdcard/android/layout_tests/fast/css/outline-hidden-illegal-value.html
+/sdcard/android/layout_tests/fast/css/emptyStyleTag.html
+/sdcard/android/layout_tests/fast/css/stale-style-selector-crash-1.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-background-size.html
+/sdcard/android/layout_tests/fast/css/display-none-inline-style-change-crash.html
+/sdcard/android/layout_tests/fast/css/getPropertyValue-clip.html
+/sdcard/android/layout_tests/fast/css/border-image-crash.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-border-box.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-005.html
+/sdcard/android/layout_tests/fast/css/insertRule-media.html
+/sdcard/android/layout_tests/fast/css/font-face-multiple-families.html
+/sdcard/android/layout_tests/fast/css/getPropertyValue-border.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-002.html
+/sdcard/android/layout_tests/fast/css/invalid-rule-value.html
+/sdcard/android/layout_tests/fast/css/max-device-aspect-ratio.html
+/sdcard/android/layout_tests/fast/css/background-currentcolor.html
+/sdcard/android/layout_tests/fast/css/orphaned_units_crash.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-relayout.html
+/sdcard/android/layout_tests/fast/css/invalid-cursor-property-crash.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-borderRadius.html
+/sdcard/android/layout_tests/fast/css/sheet-title.html
+/sdcard/android/layout_tests/fast/css/background-position-serialize.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-background-position.html
+/sdcard/android/layout_tests/fast/css/stale-style-selector-crash-2.html
+/sdcard/android/layout_tests/fast/css/webkit-marquee-speed-unit-in-quirksmode.html
+/sdcard/android/layout_tests/fast/css/CSSPrimitiveValue-exceptions.html
+/sdcard/android/layout_tests/fast/css/empty-script.html
+/sdcard/android/layout_tests/fast/css/mask-missing-image-crash.html
+/sdcard/android/layout_tests/fast/css/parse-timing-function-crash.html
+/sdcard/android/layout_tests/fast/css/background-position-inherit.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-003.html
+/sdcard/android/layout_tests/fast/css/overflow-property.html
+/sdcard/android/layout_tests/fast/css/remove-shorthand.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-zIndex-auto.html
+/sdcard/android/layout_tests/fast/css/min-device-aspect-ratio.html
+/sdcard/android/layout_tests/fast/css/case-transform.html
+/sdcard/android/layout_tests/fast/css/nested-rule-parent-sheet.html
+/sdcard/android/layout_tests/fast/css/font-family-initial.html
+/sdcard/android/layout_tests/fast/css/computed-style-display-none.html
+/sdcard/android/layout_tests/fast/css/small-caps-crash.html
+/sdcard/android/layout_tests/fast/css/max-height-and-max-width.html
+/sdcard/android/layout_tests/fast/css/legacy-opacity-styles.html
+/sdcard/android/layout_tests/fast/css/transition-timing-function.html
+/sdcard/android/layout_tests/fast/parser/remove-node-stack.html
+/sdcard/android/layout_tests/fast/parser/remove-current-node-parent.html
+/sdcard/android/layout_tests/fast/parser/entity-end-iframe-tag.html
+/sdcard/android/layout_tests/fast/parser/nsup-entity.html
+/sdcard/android/layout_tests/fast/parser/parse-wbr.html
+/sdcard/android/layout_tests/fast/parser/residual-style-close-across-n-blocks.html
+/sdcard/android/layout_tests/fast/parser/open-comment-in-script-tricky.html
+/sdcard/android/layout_tests/fast/parser/tag-with-exclamation-point.html
+/sdcard/android/layout_tests/fast/parser/p-in-scope-strict.html
+/sdcard/android/layout_tests/fast/parser/hex-entities-length.html
+/sdcard/android/layout_tests/fast/parser/entity-end-style-tag.html
+/sdcard/android/layout_tests/fast/parser/entity-end-xmp-tag.html
+/sdcard/android/layout_tests/fast/parser/html-whitespace.html
+/sdcard/android/layout_tests/fast/parser/head-comment.html
+/sdcard/android/layout_tests/fast/parser/test-unicode-characters-in-attribute-name.html
+/sdcard/android/layout_tests/fast/parser/entity-end-textarea-tag.html
+/sdcard/android/layout_tests/fast/parser/script-after-frameset-assert.html
+/sdcard/android/layout_tests/fast/parser/duplicate-html-body-element-IDs.html
+/sdcard/android/layout_tests/fast/parser/comment-in-title.html
+/sdcard/android/layout_tests/fast/parser/residual-style-close-across-removed-block.html
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-title.html
+/sdcard/android/layout_tests/fast/parser/assertion-empty-attribute.html
+/sdcard/android/layout_tests/fast/parser/entity-end-title-tag.html
+/sdcard/android/layout_tests/fast/parser/comment-in-script-tricky.html
+/sdcard/android/layout_tests/fast/parser/pre-first-line-break.html
+/sdcard/android/layout_tests/fast/parser/rewrite-form.html
+/sdcard/android/layout_tests/fast/parser/number-sign-in-map-name.html
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-script-tricky.html
+/sdcard/android/layout_tests/fast/parser/input-textarea-inside-select-element.html
+/sdcard/android/layout_tests/fast/parser/entities-in-html.html
+/sdcard/android/layout_tests/fast/parser/remove-parser-current-node.html
+/sdcard/android/layout_tests/fast/parser/area-in-div.html
+/sdcard/android/layout_tests/fast/parser/rewrite-map.html
+/sdcard/android/layout_tests/fast/parser/entity-surrogate-pairs.html
+/sdcard/android/layout_tests/fast/parser/strict-img-in-map.html
+/sdcard/android/layout_tests/fast/parser/p-in-scope.html
+/sdcard/android/layout_tests/fast/layers/removed-by-scroll-handler.html
+/sdcard/android/layout_tests/fast/layers/generated-layer-scrollbar-crash.html
+/sdcard/android/layout_tests/fast/layers/resize-layer-deletion-crash.html
+/sdcard/android/layout_tests/fast/loader/early-load-cancel.html
+/sdcard/android/layout_tests/fast/loader/iframe-recursive-synchronous-load.html
+/sdcard/android/layout_tests/fast/loader/xmlhttprequest-bad-mimetype.html
+/sdcard/android/layout_tests/fast/loader/local-css-allowed-in-strict-mode.html
+/sdcard/android/layout_tests/fast/loader/user-style-sheet-resource-load-callbacks.html
+/sdcard/android/layout_tests/fast/loader/url-strip-cr-lf-tab.html
+/sdcard/android/layout_tests/fast/loader/unloadable-script.html
+/sdcard/android/layout_tests/fast/loader/url-parse-1.html
+/sdcard/android/layout_tests/fast/loader/redirect-with-open-subframe-2.html
+/sdcard/android/layout_tests/fast/loader/simultaneous-reloads-assert.html
+/sdcard/android/layout_tests/fast/loader/invalid-charset-on-script-crashes-loader.html
+/sdcard/android/layout_tests/fast/loader/javascript-url-encoding.html
+/sdcard/android/layout_tests/fast/loader/charset-parse.html
+/sdcard/android/layout_tests/fast/loader/meta-refresh-vs-open.html
+/sdcard/android/layout_tests/fast/loader/url-data-replace-backslash.html
+/sdcard/android/layout_tests/fast/loader/redirect-with-open-subframe.html
+/sdcard/android/layout_tests/fast/loader/empty-ref-versus-no-ref.html
+/sdcard/android/layout_tests/fast/loader/window-clearing.html
+/sdcard/android/layout_tests/fast/loader/javascript-url-encoding-2.html
+/sdcard/android/layout_tests/fast/loader/external-script-URL-location.html
+/sdcard/android/layout_tests/fast/loader/loadInProgress.html
+/sdcard/android/layout_tests/fast/loader/inherit-charset-to-empty-frame.html
+/sdcard/android/layout_tests/fast/loader/font-face-empty.html
+/sdcard/android/layout_tests/fast/loader/data-url-encoding-html.html
+/sdcard/android/layout_tests/fast/loader/file-URL-with-port-number.html
+/sdcard/android/layout_tests/fast/loader/link-no-URL.html
+/sdcard/android/layout_tests/fast/canvas/pattern-with-transform.html
+/sdcard/android/layout_tests/fast/canvas/gradient-addColorStop-with-invalid-color.html
+/sdcard/android/layout_tests/fast/canvas/canvas-gradient-without-path.html
+/sdcard/android/layout_tests/fast/canvas/canvas-pattern-behaviour.html
+/sdcard/android/layout_tests/fast/canvas/radialGradient-infinite-values.html
+/sdcard/android/layout_tests/fast/canvas/drawImage-with-negative-source-destination.html
+/sdcard/android/layout_tests/fast/canvas/drawImage-with-invalid-args.html
+/sdcard/android/layout_tests/fast/canvas/canvas-stroke-empty-fill.html
+/sdcard/android/layout_tests/fast/canvas/access-zero-sized-canvas.html
+/sdcard/android/layout_tests/fast/canvas/script-inside-canvas-fallback.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-2.html
+/sdcard/android/layout_tests/fast/canvas/create-pattern-does-not-crash.html
+/sdcard/android/layout_tests/fast/canvas/gradient-with-clip.html
+/sdcard/android/layout_tests/fast/canvas/canvas-hides-fallback.html
+/sdcard/android/layout_tests/fast/canvas/arc-crash.html
+/sdcard/android/layout_tests/fast/canvas/canvas-ImageData-behaviour.html
+/sdcard/android/layout_tests/fast/canvas/canvas-putImageData.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-4.html
+/sdcard/android/layout_tests/fast/canvas/canvas-invalid-fillstyle.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-1.html
+/sdcard/android/layout_tests/fast/canvas/toDataURL-noData.html
+/sdcard/android/layout_tests/fast/canvas/canvas-with-incorrect-args.html
+/sdcard/android/layout_tests/fast/canvas/canvas-path-with-inf-nan-dimensions.html
+/sdcard/android/layout_tests/fast/canvas/canvas-radial-gradient-spreadMethod.html
+/sdcard/android/layout_tests/fast/canvas/canvas-set-properties-with-non-invertible-ctm.html
+/sdcard/android/layout_tests/fast/canvas/canvas-invalid-strokestyle.html
+/sdcard/android/layout_tests/fast/canvas/canvas-strokeRect.html
+/sdcard/android/layout_tests/fast/canvas/canvas-pattern-transform.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transparency-and-composite.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-3.html
+/sdcard/android/layout_tests/fast/canvas/linearGradient-infinite-values.html
+/sdcard/android/layout_tests/fast/canvas/canvas-setTransform.html
+/sdcard/android/layout_tests/fast/frames/frame-set-same-location.html
+/sdcard/android/layout_tests/fast/frames/set-unloaded-frame-location.html
+/sdcard/android/layout_tests/fast/frames/negative-remaining-length-crash.html
+/sdcard/android/layout_tests/fast/frames/frame-name-reset.html
+/sdcard/android/layout_tests/fast/frames/frame-set-same-src.html
+/sdcard/android/layout_tests/fast/frames/crash-removed-iframe.html
+/sdcard/android/layout_tests/fast/frames/empty-frame-document.html
+/sdcard/android/layout_tests/fast/frames/viewsource-plain-text-tags.html
+/sdcard/android/layout_tests/fast/frames/location-put-after-removal.html
+/sdcard/android/layout_tests/fast/frames/repaint-display-none-crash.html
+/sdcard/android/layout_tests/fast/frames/remove-frame-with-scrollbars-crash.html
+/sdcard/android/layout_tests/fast/frames/cross-site-this.html
+/sdcard/android/layout_tests/fast/frames/onload-remove-iframe-crash.html
+/sdcard/android/layout_tests/fast/frames/iframe-set-inner-html.html
+/sdcard/android/layout_tests/fast/frames/iframe-remove-after-id-change.html
+/sdcard/android/layout_tests/fast/frames/iframe-target.html
+/sdcard/android/layout_tests/fast/frames/hover-timer-crash.html
+/sdcard/android/layout_tests/fast/frames/iframe-set-same-src.html
+/sdcard/android/layout_tests/fast/frames/iframe-double-attach.html
+/sdcard/android/layout_tests/fast/frames/iframe-set-same-location.html
+/sdcard/android/layout_tests/fast/frames/iframe-js-url-clientWidth.html
+/sdcard/android/layout_tests/fast/frames/location-change.html
+/sdcard/android/layout_tests/fast/frames/frame-base-url.html
+/sdcard/android/layout_tests/fast/frames/iframe-display-none.html
+/sdcard/android/layout_tests/fast/frames/frame-display-none-focus.html
+/sdcard/android/layout_tests/fast/reflections/teardown-crash.html
+/sdcard/android/layout_tests/fast/reflections/reflection-computed-style.html
diff --git a/tests/DumpRenderTree/run_layout_tests.py b/tests/DumpRenderTree/run_layout_tests.py
new file mode 100755
index 0000000..5409a0c
--- /dev/null
+++ b/tests/DumpRenderTree/run_layout_tests.py
@@ -0,0 +1,286 @@
+#!/usr/bin/python
+
+"""Run layout tests using Android emulator and instrumentation.
+
+ First, you need to get an SD card or sdcard image that has layout tests on it.
+ Layout tests are in following directory:
+ /sdcard/android/layout_tests
+ For example, /sdcard/android/layout_tests/fast
+
+ Usage:
+ Run all tests under fast/ directory:
+ run_layout_tests.py, or
+ run_layout_tests.py fast
+
+ Run all tests under a sub directory:
+ run_layout_tests.py fast/dom
+
+ Run a single test:
+ run_layout_tests.py fast/dom/
+
+ After a merge, if there are changes of layout tests in SD card, you need to
+ use --refresh-test-list option *once* to re-generate test list on the card.
+
+ Some other options are:
+ --rebaseline generates expected layout tests results under /sdcard/android/expected_result/
+ --time-out-ms (default is 8000 millis) for each test
+ --adb-options="-e" passes option string to adb
+ --results-directory=..., (default is ./layout-test-results) directory name under which results are stored.
+"""
+
+import logging
+import optparse
+import os
+import subprocess
+import sys
+import time
+
+def CountLineNumber(filename):
+ """Compute the number of lines in a given file.
+
+ Args:
+ filename: a file name related to the current directory.
+ """
+
+ fp = open(os.path.abspath(filename), "r");
+ lines = 0
+ for line in fp.readlines():
+ lines = lines + 1
+ fp.close()
+ return lines
+
+def DumpRenderTreeFinished(adb_cmd):
+ """ Check if DumpRenderTree finished running tests
+
+ Args:
+ output: adb_cmd string
+ """
+
+ # pull /sdcard/android/running_test.txt, if the content is "#DONE", it's done
+ shell_cmd_str = adb_cmd + " shell cat /sdcard/android/running_test.txt"
+ adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+ return adb_output.strip() == "#DONE"
+
+def DiffResults(marker, new_results, old_results, diff_results, strip_reason):
+ """ Given two result files, generate diff and
+ write to diff_results file. All arguments are absolute paths
+ to files.
+ """
+ old_file = open(old_results, "r")
+ new_file = open(new_results, "r")
+ diff_file = open(diff_results, "a")
+
+ # Read lines from each file
+ ndict = new_file.readlines()
+ cdict = old_file.readlines()
+
+ # Write marker to diff file
+ diff_file.writelines(marker + "\n")
+ diff_file.writelines("###############\n")
+
+ # Strip reason from result lines
+ if strip_reason is True:
+ for i in range(0, len(ndict)):
+ ndict[i] = ndict[i].split(' ')[0] + "\n"
+ for i in range(0, len(cdict)):
+ cdict[i] = cdict[i].split(' ')[0] + "\n"
+
+ # Find results in new_results missing in old_results
+ new_count=0
+ for line in ndict:
+ if line not in cdict:
+ diff_file.writelines("+ " + line)
+ new_count += 1
+
+ # Find results in old_results missing in new_results
+ missing_count=0
+ for line in cdict:
+ if line not in ndict:
+ diff_file.writelines("- " + line)
+ missing_count += 1
+
+ logging.info(marker + " >>> " + str(new_count) + " new, " + str(missing_count) + " misses")
+
+ diff_file.writelines("\n\n")
+
+ old_file.close()
+ new_file.close()
+ diff_file.close()
+ return
+
+def CompareResults(ref_dir, results_dir):
+ """Compare results in two directories
+
+ Args:
+ ref_dir: the reference directory having layout results as references
+ results_dir: the results directory
+ """
+ logging.info("Comparing results to " + ref_dir)
+
+ diff_result = os.path.join(results_dir, "layout_tests_diff.txt")
+ if os.path.exists(diff_result):
+ os.remove(diff_result)
+
+ files=["passed", "failed", "nontext", "crashed"]
+ for f in files:
+ result_file_name = "layout_tests_" + f + ".txt"
+ DiffResults(f, os.path.join(results_dir, result_file_name),
+ os.path.join(ref_dir, result_file_name), diff_result,
+ f == "failed")
+ logging.info("Detailed diffs are in " + diff_result)
+
+def main(options, args):
+ """Run the tests. Will call sys.exit when complete.
+
+ Args:
+ options: a dictionary of command line options
+ args: a list of sub directories or files to test
+ """
+
+ # Set up logging format.
+ log_level = logging.INFO
+ if options.verbose:
+ log_level = logging.DEBUG
+ logging.basicConfig(level=log_level,
+ format='%(message)s')
+
+ # Include all tests if none are specified.
+ if not args:
+ path = '/';
+ else:
+ path = ' '.join(args);
+
+ adb_cmd = "adb ";
+ if options.adb_options:
+ adb_cmd += options.adb_options
+
+ # Re-generate the test list if --refresh-test-list is on
+ if options.refresh_test_list:
+ logging.info("Generating test list.");
+ generate_test_list_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#generateTestList -e path \"" + path + "\" -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+ adb_output = subprocess.Popen(generate_test_list_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+
+ if adb_output.find('Process crashed') != -1:
+ logging.info("Aborting because cannot generate test list.\n" + adb_output)
+ sys.exit(1)
+
+
+ logging.info("Running tests")
+
+ # Count crashed tests.
+ crashed_tests = []
+
+ timeout_ms = '5000'
+ if options.time_out_ms:
+ timeout_ms = options.time_out_ms
+
+ # Run test until it's done
+
+ run_layout_test_cmd_prefix = adb_cmd + " shell am instrument"
+
+ run_layout_test_cmd_postfix = " -e path \"" + path + "\" -e timeout " + timeout_ms
+ if options.rebaseline:
+ run_layout_test_cmd_postfix += " -e rebaseline true"
+ run_layout_test_cmd_postfix += " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+
+ # Call LayoutTestsAutoTest::startLayoutTests.
+ run_layout_test_cmd = run_layout_test_cmd_prefix + " -e class com.android.dumprendertree.LayoutTestsAutoTest#startLayoutTests" + run_layout_test_cmd_postfix
+
+ adb_output = subprocess.Popen(run_layout_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+ while not DumpRenderTreeFinished(adb_cmd):
+ # Get the running_test.txt
+ logging.error("DumpRenderTree crashed, output:\n" + adb_output)
+
+ shell_cmd_str = adb_cmd + " shell cat /sdcard/android/running_test.txt"
+ crashed_test = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE).communicate()[0]
+
+ logging.info(crashed_test + " CRASHED");
+ crashed_tests.append(crashed_test);
+
+ logging.info("Resuming layout test runner...");
+ # Call LayoutTestsAutoTest::resumeLayoutTests
+ run_layout_test_cmd = run_layout_test_cmd_prefix + " -e class com.android.dumprendertree.LayoutTestsAutoTest#resumeLayoutTests" + run_layout_test_cmd_postfix
+
+ adb_output = subprocess.Popen(run_layout_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+
+ if adb_output.find('INSTRUMENTATION_FAILED') != -1:
+ logging.error("Error happened : " + adb_output)
+ sys.exit(1)
+
+ logging.debug(adb_output);
+ logging.info("Done\n");
+
+ # Pull results from /sdcard
+ results_dir = options.results_directory
+ if not os.path.exists(results_dir):
+ os.makedirs(results_dir)
+ if not os.path.isdir(results_dir):
+ logging.error("Cannot create results dir: " + results_dir);
+ sys.exit(1);
+
+ result_files = ["/sdcard/layout_tests_passed.txt",
+ "/sdcard/layout_tests_failed.txt",
+ "/sdcard/layout_tests_nontext.txt"]
+ for file in result_files:
+ shell_cmd_str = adb_cmd + " pull " + file + " " + results_dir
+ adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+ logging.debug(adb_output)
+
+ # Create the crash list.
+ fp = open(results_dir + "/layout_tests_crashed.txt", "w");
+ fp.writelines('\n'.join(crashed_tests))
+ fp.close()
+
+ # Count the number of tests in each category.
+ passed_tests = CountLineNumber(results_dir + "/layout_tests_passed.txt")
+ logging.info(str(passed_tests) + " passed")
+ failed_tests = CountLineNumber(results_dir + "/layout_tests_failed.txt")
+ logging.info(str(failed_tests) + " failed")
+ crashed_tests = CountLineNumber(results_dir + "/layout_tests_crashed.txt")
+ logging.info(str(crashed_tests) + " crashed")
+ nontext_tests = CountLineNumber(results_dir + "/layout_tests_nontext.txt")
+ logging.info(str(nontext_tests) + " no dumpAsText")
+
+ logging.info("Results are stored under: " + results_dir + "\n")
+
+ # Comparing results to references to find new fixes and regressions.
+ results_dir = os.path.abspath(options.results_directory)
+ ref_dir = options.ref_directory
+
+ # if ref_dir is null, cannonify ref_dir to the script dir.
+ if not ref_dir:
+ script_self = sys.argv[0]
+ script_dir = os.path.dirname(script_self)
+ ref_dir = os.path.join(script_dir, "results")
+
+ ref_dir = os.path.abspath(ref_dir)
+
+ CompareResults(ref_dir, results_dir)
+
+if '__main__' == __name__:
+ option_parser = optparse.OptionParser()
+ option_parser.add_option("", "--rebaseline", action="store_true",
+ default=False,
+ help="generate expected results for those tests not having one")
+ option_parser.add_option("", "--time-out-ms",
+ default=None,
+ help="set the timeout for each test")
+ option_parser.add_option("", "--verbose", action="store_true",
+ default=False,
+ help="include debug-level logging")
+ option_parser.add_option("", "--refresh-test-list", action="store_true",
+ default=False,
+ help="re-generate test list, it may take some time.")
+ option_parser.add_option("", "--adb-options",
+ default=None,
+ help="pass options to adb, such as -d -e, etc");
+ option_parser.add_option("", "--results-directory",
+ default="layout-test-results",
+ help="directory which results are stored.")
+ option_parser.add_option("", "--ref-directory",
+ default=None,
+ dest="ref_directory",
+ help="directory where reference results are stored.")
+
+ options, args = option_parser.parse_args();
+ main(options, args)
diff --git a/tests/DumpRenderTree/run_page_cycler.py b/tests/DumpRenderTree/run_page_cycler.py
new file mode 100755
index 0000000..9a099b5
--- /dev/null
+++ b/tests/DumpRenderTree/run_page_cycler.py
@@ -0,0 +1,101 @@
+#!/usr/bin/python
+
+"""Run page cycler tests using Android instrumentation.
+
+ First, you need to get an SD card or sdcard image that has page cycler tests.
+
+ Usage:
+ Run a single page cycler test:
+ run_page_cycler.py "file:///sdcard/android/page_cycler/moz/start.html?auto=1\&iterations=10"
+"""
+
+import logging
+import optparse
+import os
+import subprocess
+import sys
+import time
+
+
+
+def main(options, args):
+ """Run the tests. Will call sys.exit when complete.
+
+ """
+
+ # Set up logging format.
+ log_level = logging.INFO
+ if options.verbose:
+ log_level = logging.DEBUG
+ logging.basicConfig(level=log_level,
+ format='%(message)s')
+
+ # Include all tests if none are specified.
+ if not args:
+ print "need a URL, e.g. file:///sdcard/android/page_cycler/moz/start.html"
+ sys.exit(1)
+ else:
+ path = ' '.join(args);
+
+ adb_cmd = "adb ";
+ if options.adb_options:
+ adb_cmd += options.adb_options
+
+ logging.info("Running the test ...")
+
+ # Count crashed tests.
+ crashed_tests = []
+
+ timeout_ms = '0'
+ if options.time_out_ms:
+ timeout_ms = options.time_out_ms
+
+ # Run test until it's done
+
+ run_load_test_cmd_prefix = adb_cmd + " shell am instrument"
+ run_load_test_cmd_postfix = " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+
+ # Call LoadTestsAutoTest::runTest.
+ run_load_test_cmd = run_load_test_cmd_prefix + " -e class com.android.dumprendertree.LoadTestsAutoTest#runTest -e path \"" + path + "\" -e timeout " + timeout_ms + run_load_test_cmd_postfix
+
+ (adb_output, adb_error) = subprocess.Popen(run_load_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+ if adb_output.find('INSTRUMENTATION_FAILED') != -1:
+ logging.error("Error happened : " + adb_output)
+ sys.exit(1)
+
+ logging.info(adb_output);
+ logging.info(adb_error);
+ logging.info("Done\n");
+
+ # Pull results from /sdcard/load_test_result.txt
+ results_dir = options.results_directory
+ if not os.path.exists(results_dir):
+ os.makedirs(results_dir)
+ if not os.path.isdir(results_dir):
+ logging.error("Cannot create results dir: " + results_dir)
+ sys.exit(1)
+
+ result_file = "/sdcard/load_test_result.txt"
+ shell_cmd_str = adb_cmd + " pull " + result_file + " " + results_dir
+ adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+ logging.info(adb_output)
+
+ logging.info("Results are stored under: " + results_dir + "/load_test_result.txt\n")
+
+if '__main__' == __name__:
+ option_parser = optparse.OptionParser()
+ option_parser.add_option("", "--time-out-ms",
+ default=None,
+ help="set the timeout for each test")
+ option_parser.add_option("", "--verbose", action="store_true",
+ default=False,
+ help="include debug-level logging")
+ option_parser.add_option("", "--adb-options",
+ default=None,
+ help="pass options to adb, such as -d -e, etc");
+ option_parser.add_option("", "--results-directory",
+ default="layout-test-results",
+ help="directory which results are stored.")
+
+ options, args = option_parser.parse_args();
+ main(options, args)
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 91597d5..4f162b3 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -24,13 +24,19 @@ public class FileFilter {
public static boolean ignoreTest(String file) {
// treat files like directories for the time being.
- int size = ignoreTestList.length;
- for (int i = 0; i < size; i ++) {
- if (file.startsWith(ignoreTestList[i])) {
+ for (int i = 0; i < ignoreTestList.length; i ++) {
+ if (file.endsWith(ignoreTestList[i])) {
Log.e("FileFilter", "File path in IgnoreTest: " + file);
return true;
}
}
+ for (int i = 0; i < ignoreTestDirs.length; i++) {
+ if (file.endsWith(ignoreTestDirs[i])) {
+ Log.e("FileFilter", "File path in ignore list: " + file);
+ return true;
+ }
+ }
+
return false;
}
@@ -64,33 +70,19 @@ public class FileFilter {
fillIgnoreResultSet();
fillBugTable();
}
-
- static final String [] ignoreTestList = {
+
+ static final String[] ignoreTestDirs = {
".", // ignore hidden directories and files
"resources", // ignore resource directories
"AppleScript", // AppleScript not supported
- "xpath", // xpath requires libxml2, not supported
- "xsl", //xsl requires libxml2 & libxslt, not sup.
- "kde", // don't run kde tests.
".svn", // don't run anything under .svn folder
- "gradients", //known crash
- "toString-stack-overflow.html", // Crashes #606688
- "frame-limit.html", // generates too many GREFs
- "css-insert-import-rule.html", // Crashes, #717414
- "input-text-enter.html", // Crashes. #735088
- "text-shadow-extreme-value.html", // Crashes #571671
- "001.html",
- "reflection-masks.html",
- "frame-creation-removal.html",
- "large-expressions.html",
- "null-page-show-modal-dialog-crash.html",
- "font-face-implicit-local-font.html",
- "font-face-locally-installed.html",
- "beforeSelectorOnCodeElement.html",
- "cssTarget-crash.html",
- "searchfield-heights.html", // Bug 1570692
- "tabindex-focus-blur-all.html",
- "search-rtl.html" // fast/forms/search-rtl.html
+ "profiler", // profiler is not supported
+ "svg", // svg is not supported
+ "platform", // platform specific
+ "http" // requires local http(s) server
+ };
+
+ static final String [] ignoreTestList = {
};
static void fillIgnoreResultSet() {
@@ -203,6 +195,8 @@ public class FileFilter {
ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html");
// extra spacing because iFrames rendered next to each other on Apple
ignoreResultList.add("fast/loader/opaque-base-url.html");
+ // RegExp is too large, causing OOM
+ ignoreResultList.add("fast/js/regexp-charclass-crash.html");
ignoreResultList.add("fast/text/plain-text-line-breaks.html");
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
index 8b33d16..0218317 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
@@ -17,6 +17,7 @@
package com.android.dumprendertree;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -84,7 +85,8 @@ public abstract class FileList extends ListActivity
return myData;
}
String[] files = f.list();
-
+ Arrays.sort(files);
+
for (int i = 0; i < files.length; i++) {
StringBuilder sb = new StringBuilder(mPath);
sb.append(File.separatorChar);
@@ -117,9 +119,14 @@ public abstract class FileList extends ListActivity
{
Map map = (Map) l.getItemAtPosition(position);
String path = (String)map.get("path");
- if (path.length() > 0)
- processFile(path, true);
+ if ((new File(path)).isDirectory()) {
+ mPath = path;
+ mFocusFile = null;
+ updateList();
+ } else {
+ processFile(path, false);
+ }
}
/*
@@ -148,7 +155,7 @@ public abstract class FileList extends ListActivity
protected void setupPath()
{
- mPath = "/sdcard";
+ mPath = "/sdcard/android/layout_tests";
mBaseLength = mPath.length();
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
deleted file mode 100644
index 9521f80..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * Copyright (C) 2007 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.dumprendertree;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.BufferedOutputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Vector;
-import java.util.Stack;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.ViewGroup;
-import android.webkit.JsPromptResult;
-import android.webkit.JsResult;
-import android.webkit.WebChromeClient;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.widget.LinearLayout;
-import android.os.*;
-import android.test.TestRecorder;
-
-// SQLite3 in android has a bunch of bugs which
-// is causing TestRecorder to not record the results
-// properly. This class is a wrapper around it and records
-// results in a file as well.
-class TestRecorderV2 extends TestRecorder {
- @Override
- public void passed(String layout_file) {
- try {
- mBufferedOutputPassedStream.write(layout_file.getBytes());
- mBufferedOutputPassedStream.write('\n');
- mBufferedOutputPassedStream.flush();
- } catch(Exception e) {
- e.printStackTrace();
- }
- super.passed(layout_file);
- }
-
- @Override
- public void failed(String layout_file, String reason) {
- try {
- mBufferedOutputFailedStream.write(layout_file.getBytes());
- mBufferedOutputFailedStream.write('\n');
- mBufferedOutputFailedStream.flush();
- } catch(Exception e) {
- e.printStackTrace();
- }
- super.failed(layout_file, reason);
- }
-
- public TestRecorderV2() {
- super();
- try {
- File resultsPassedFile = new File("/sdcard/layout_test_presults.txt");
- File resultsFailedFile = new File("/sdcard/layout_test_fresults.txt");
-
- mBufferedOutputPassedStream =
- new BufferedOutputStream(new FileOutputStream(resultsPassedFile, true));
- mBufferedOutputFailedStream =
- new BufferedOutputStream(new FileOutputStream(resultsFailedFile, true));
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- protected void finalize() throws Throwable {
- mBufferedOutputPassedStream.flush();
- mBufferedOutputFailedStream.flush();
- mBufferedOutputPassedStream.close();
- mBufferedOutputFailedStream.close();
- }
-
- private static BufferedOutputStream mBufferedOutputPassedStream;
- private static BufferedOutputStream mBufferedOutputFailedStream;
-}
-
-public class HTMLHostActivity extends Activity
- implements LayoutTestController {
-
- private TestRecorderV2 mResultRecorder = new TestRecorderV2();
- private HTMLHostCallbackInterface mCallback = null;
- private CallbackProxy mCallbackProxy;
-
- public class FileEntry {
- public FileEntry(String path, int index) {
- mPath = path; mIndex=index;
- }
- String mPath;
- int mIndex;
- }
-
- public class AsyncHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == MSG_DUMP) {
- this.removeMessages(MSG_TIMEOUT);
- mTimedOut = false;
- requestWebKitData();
- return;
- } else if (msg.what == MSG_TIMEOUT) {
- mTimedOut = true;
- requestWebKitData();
- return;
- } else if (msg.what == MSG_WEBKIT_DATA) {
- HTMLHostActivity.this.dump(mTimedOut, (String)msg.obj);
- return;
- }
-
- super.handleMessage(msg);
- }
-
- void requestWebKitData() {
- Message callback = obtainMessage(MSG_WEBKIT_DATA);
- if (dumpAsText) {
- mWebView.documentAsText(callback);
- } else {
- mWebView.externalRepresentation(callback);
- }
- }
-
- }
-
- // Activity methods
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- LinearLayout contentView = new LinearLayout(this);
- contentView.setOrientation(LinearLayout.VERTICAL);
- setContentView(contentView);
-
- mWebView = new WebView(this);
- mWebView.getSettings().setJavaScriptEnabled(true);
- mWebView.setWebChromeClient(mChromeClient);
- eventSender = new WebViewEventSender(mWebView);
- mCallbackProxy = new CallbackProxy(eventSender, this);
-
- mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
- mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
- contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
-
- mHandler = new AsyncHandler();
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- }
-
- protected void onResume() {
- super.onResume();
- if (mProcessStack == null || mProcessStack.isEmpty() ) {
- mOutstandingLoads = 0;
- dumpAsText = false;
- pageComplete = false;
-
- mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
-
- mFinishedStack = new Stack();
-
- Intent intent = getIntent();
- if (intent.getData() != null) {
- File f = new File(intent.getData().toString());
-
- if (f.isDirectory()) {
- mProcessStack = new Vector();
- mProcessStack.add(new FileEntry(intent.getData().toString(), 0));
- Log.v(LOGTAG, "Initial dir: "+intent.getData().toString());
- loadNextPage();
- } else {
- mCurrentFile = intent.getData().toString();
- mWebView.loadUrl("file://"+intent.getData().toString());
- }
-
- }
- else
- mWebView.loadUrl("about:");
- }
- }
-
- protected void onStop() {
- super.onStop();
- mWebView.stopLoading();
- }
-
- protected void onDestroy() {
- super.onDestroy();
- mWebView.destroy();
- mWebView = null;
- }
-
- public boolean dispatchKeyEvent(KeyEvent event) {
- // Log key strokes as they don't seem to be matched
- //Log.e(LOGTAG, "Event: "+event);
- return super.dispatchKeyEvent(event);
- }
-
- // Functions
-
- protected void loadNextPage() {
- dumpAsText = false;
- pageComplete = false;
- dumpTitleChanges = false;
- eventSender.resetMouse();
- while (!mProcessStack.isEmpty()) {
- FileEntry fe = (FileEntry)mProcessStack.remove(0);
- if (fe.mIndex == 0) {
- System.out.println();
- System.out.print(fe.mPath);
- }
- Log.v(LOGTAG, "Processing dir: "+fe.mPath+" size: "+mProcessStack.size());
- File f = new File(fe.mPath);
- String [] files = f.list();
- for (int i = fe.mIndex; i < files.length; i++) {
- if (FileFilter.ignoreTest(files[i])) {
- continue;
- }
- File c = new File(f.getPath(), files[i]);
- if (c.isDirectory()) {
- Log.v(LOGTAG, "Adding dir: "+fe.mPath+"/"+files[i]);
- mProcessStack.add(new FileEntry(fe.mPath+"/"+files[i], 0));
- } else if (files[i].toLowerCase().endsWith("ml")) {
- mProcessStack.add(0, new FileEntry(fe.mPath, i+1));
- mCurrentFile = fe.mPath+"/"+files[i];
- Log.e(LOGTAG, "Processing: "+mCurrentFile);
- mWebView.loadUrl("file://"+mCurrentFile);
-
- // Create a timeout timer
- Message m = mHandler.obtainMessage(MSG_TIMEOUT);
- // Some tests can take up to 5secs to run.
- mHandler.sendMessageDelayed(m, 6000);
- return;
- }
- }
- Log.v(LOGTAG, "Finished dir: "+fe.mPath+" size: "+mProcessStack.size());
- }
- // If we got to here, then we must have finished completely
- finished();
- }
-
- public void scheduleDump() {
- // Only schedule if we really are ready
- if (waitToDump || mOutstandingLoads > 0 || mDumpRequested) {
- return;
- }
- mDumpRequested = true;
- mHandler.obtainMessage(MSG_DUMP).sendToTarget();
- }
-
- // Dump the page
- public void dump(boolean timeout, String webkitData) {
- mDumpRequested = false;
- System.out.print('.');
-
- // remove the extension
- String resultFile = mCurrentFile.substring(0, mCurrentFile.lastIndexOf('.'));
-
- // store the finished file on the stack so that we can do a diff at the end.
- mFinishedStack.push(resultFile);
-
- // dumpAsText version can be directly compared to expected results
- if (dumpAsText) {
- resultFile += "-results.txt";
- } else {
- resultFile += "-android-results.txt";
- }
- try {
- FileOutputStream os = new FileOutputStream(resultFile);
- if (timeout) {
- Log.i("Layout test: Timeout", resultFile);
- os.write("**Test timeout\n".getBytes());
- }
- if (dumpTitleChanges)
- os.write(mTitleChanges.toString().getBytes());
- if (mDialogStrings != null)
- os.write(mDialogStrings.toString().getBytes());
- mDialogStrings = null;
- os.write(webkitData.getBytes());
- os.flush();
- os.close();
- } catch (FileNotFoundException ex) {
- ex.printStackTrace();
- } catch (IOException ex) {
- ex.printStackTrace();
- }
-
- if (mProcessStack != null)
- loadNextPage();
- else
- finished();
- }
-
- // Wrap up
- public void failedCase(String file, String reason) {
- Log.i("Layout test:", file + " failed" + reason);
- mResultRecorder.failed(file, reason);
-
- file = file + ".html";
- String bugNumber = FileFilter.isKnownBug(file);
- if (bugNumber != null) {
- System.out.println("FAIL known:"+bugNumber+ " "+file+reason);
- return;
- }
- if (FileFilter.ignoreResults(file)) {
- return;
- }
- System.out.println("FAIL: "+file+reason);
- }
-
- public void passedCase(String file) {
- // Add the result to the sqlite database
- Log.i("Layout test:", file + " passed");
- mResultRecorder.passed(file);
-
- file = file + ".html";
- String bugNumber = FileFilter.isKnownBug(file);
- if (bugNumber != null) {
- System.out.println("Bug Fixed: "+bugNumber+ " "+file);
- return;
- }
-
- if (FileFilter.ignoreResults(file)) {
- System.out.println("Ignored test passed: "+file);
- return;
- }
- }
-
- public void setCallback(HTMLHostCallbackInterface callback) {
- mCallback = callback;
- }
-
- public void finished() {
- int passed = 0;
- while (!mFinishedStack.empty()) {
- Log.v(LOGTAG, "Comparing dump and reference");
- String file = (String)mFinishedStack.pop();
-
- // Only check results that we can check, ie dumpAsText results
- String dumpFile = file + "-results.txt";
- File f = new File(dumpFile);
- if (f.exists()) {
- try {
- FileInputStream fr = new FileInputStream(file+"-results.txt");
- FileInputStream fe = new FileInputStream(file+"-expected.txt");
-
- mResultRecorder.started(file);
-
- // If the length is different then they are different
- int diff = fe.available() - fr.available();
- if (diff > 1 || diff < 0) {
- failedCase(file, " different length");
- fr.close();
- fe.close();
-
- mResultRecorder.finished(file);
- continue;
- }
- byte[] br = new byte[fr.available()];
- byte[] be = new byte[fe.available()];
- fr.read(br);
- fe.read(be);
- boolean fail = false;
- for (int i = 0; i < br.length; i++) {
- if (br[i] != be[i]) {
- failedCase(file, " @offset: "+i);
- fail = true;
- break;
- }
- }
- if (br.length != be.length && be[be.length-1] == '\n') {
- Log.d(LOGTAG, "Extra new line being ignore:" + file);
- }
- fr.close();
- fe.close();
- if (!fail) {
- passed++;
- passedCase(file);
- }
- } catch (FileNotFoundException ex) {
- // TODO do something here
- } catch (IOException ex) {
- // Failed on available() or read()
- }
- mResultRecorder.finished(file);
- }
- }
-
- if (mCallback != null) {
- mCallback.waitForFinish();
- }
-
- finish();
- }
-
- // LayoutTestController Functions
- public void dumpAsText() {
- dumpAsText = true;
- String url = mWebView.getUrl();
- Log.v(LOGTAG, "dumpAsText called:"+url);
- if (url.length() > 60)
- url = url.substring(60);
- }
-
- public void waitUntilDone() {
- waitToDump = true;
- }
- public void notifyDone() {
- waitToDump = false;
- mChromeClient.onProgressChanged(mWebView, 100);
- }
- public void display() {
- mWebView.invalidate();
- }
-
- public void clearBackForwardList() {
- mWebView.clearHistory();
-
- }
-
- public void dumpBackForwardList() {
- //printf("\n============== Back Forward List ==============\n");
- // mWebHistory
- //printf("===============================================\n");
-
- }
-
- public void dumpChildFrameScrollPositions() {
- // TODO Auto-generated method stub
-
- }
-
- public void dumpEditingCallbacks() {
- // TODO Auto-generated method stub
-
- }
-
- public void dumpSelectionRect() {
- // TODO Auto-generated method stub
-
- }
-
- public void dumpTitleChanges() {
- if (!dumpTitleChanges) {
- mTitleChanges = new StringBuffer();
- }
- dumpTitleChanges = true;
- }
-
- public void keepWebHistory() {
- if (!keepWebHistory) {
- mWebHistory = new Vector();
- }
- keepWebHistory = true;
-
- }
-
- public void queueBackNavigation(int howfar) {
- // TODO Auto-generated method stub
-
- }
-
- public void queueForwardNavigation(int howfar) {
- // TODO Auto-generated method stub
-
- }
-
- public void queueLoad(String Url, String frameTarget) {
- // TODO Auto-generated method stub
-
- }
-
- public void queueReload() {
- mWebView.reload();
- }
-
- public void queueScript(String scriptToRunInCurrentContext) {
- mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext);
- }
-
- public void repaintSweepHorizontally() {
- // TODO Auto-generated method stub
-
- }
-
- public void setAcceptsEditing(boolean b) {
- // TODO Auto-generated method stub
-
- }
-
- public void setMainFrameIsFirstResponder(boolean b) {
- // TODO Auto-generated method stub
-
- }
-
- public void setWindowIsKey(boolean b) {
- // This is meant to show/hide the window. The best I can find
- // is setEnabled()
- mWebView.setEnabled(b);
- }
-
- public void testRepaint() {
- mWebView.invalidate();
- }
-
- // Instrumentation calls this to find
- // if the activity has finished running the layout tests
- public boolean hasFinishedRunning() {
- if( mProcessStack == null || mFinishedStack == null)
- return false;
-
- if (mProcessStack.isEmpty() && mFinishedStack.empty()) {
- return true;
- }
-
- return false;
- }
-
- private final WebChromeClient mChromeClient = new WebChromeClient() {
- @Override
- public void onProgressChanged(WebView view, int newProgress) {
- if (newProgress == 100) {
- pageComplete = true;
- String url = mWebView.getUrl();
- if (url != null) {
- Log.v(LOGTAG, "Finished: "+ url);
- if (url.length() > 60)
- url = url.substring(60);
- scheduleDump();
- }
- }
- }
-
- @Override
- public void onReceivedTitle(WebView view, String title) {
- if (title.length() > 30)
- title = "..."+title.substring(title.length()-30);
- setTitle(title);
- if (dumpTitleChanges) {
- mTitleChanges.append("TITLE CHANGED: ");
- mTitleChanges.append(title);
- mTitleChanges.append("\n");
- }
- }
-
- @Override
- public boolean onJsAlert(WebView view, String url, String message,
- JsResult result) {
- if (mDialogStrings == null) {
- mDialogStrings = new StringBuffer();
- }
- mDialogStrings.append("ALERT: ");
- mDialogStrings.append(message);
- mDialogStrings.append('\n');
- return false;
- }
- };
-
- private WebView mWebView;
- private WebViewEventSender eventSender;
- private Vector mProcessStack;
- private Stack mFinishedStack;
- static final String LOGTAG="DumpRenderTree";
- private String mCurrentFile;
- private int mOutstandingLoads;
- private AsyncHandler mHandler;
- private boolean mDumpRequested;
-
- private boolean dumpAsText;
- private boolean waitToDump;
- private boolean pageComplete;
-
- private boolean dumpTitleChanges;
- private StringBuffer mTitleChanges;
-
- private StringBuffer mDialogStrings;
-
- private boolean keepWebHistory;
- private Vector mWebHistory;
-
- private boolean mTimedOut;
-
- static final int MSG_DUMP = 0;
- static final int MSG_TIMEOUT = 1;
- static final int MSG_WEBKIT_DATA = 2;
-
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
index e0e535e..8f968b4 100755
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
@@ -21,10 +21,13 @@ import com.android.dumprendertree.LayoutTestsAutoTest;
import android.test.InstrumentationTestRunner;
import android.test.InstrumentationTestSuite;
+import android.util.Log;
+import android.content.Intent;
+import android.os.Bundle;
/**
- * Instrumentation Test Runner for all MediaPlayer tests.
+ * Instrumentation Test Runner for all DumpRenderTree tests.
*
* Running all tests:
*
@@ -37,6 +40,7 @@ public class LayoutTestsAutoRunner extends InstrumentationTestRunner {
public TestSuite getAllTests() {
TestSuite suite = new InstrumentationTestSuite(this);
suite.addTestSuite(LayoutTestsAutoTest.class);
+ suite.addTestSuite(LoadTestsAutoTest.class);
return suite;
}
@@ -44,5 +48,26 @@ public class LayoutTestsAutoRunner extends InstrumentationTestRunner {
public ClassLoader getLoader() {
return LayoutTestsAutoRunner.class.getClassLoader();
}
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ this.mTestPath = (String) icicle.get("path");
+ String timeout_str = (String) icicle.get("timeout");
+ if (timeout_str != null) {
+ try {
+ this.mTimeoutInMillis = Integer.parseInt(timeout_str);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ String r = (String)icicle.get("rebaseline");
+ this.mRebaseline = (r != null && r.toLowerCase().equals("true"));
+ }
+
+ public String mTestPath = null;
+ public int mTimeoutInMillis = 0;
+ public boolean mRebaseline = false;
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index f46b263..a857e68 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -16,142 +16,440 @@
package com.android.dumprendertree;
+import android.app.Activity;
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityMonitor;
import android.content.ContentResolver;
import android.content.ContentValues;
+import android.content.Intent;
+
import android.util.Log;
import android.view.KeyEvent;
+import android.webkit.WebSettings;
-import android.test.ActivityInstrumentationTestCase;
+import android.os.Bundle;
+import android.os.Message;
+import android.test.ActivityInstrumentationTestCase2;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
-import com.android.dumprendertree.HTMLHostActivity;
+import com.android.dumprendertree.TestShellActivity;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Vector;
+
+//TestRecorder creates two files, one for passing tests
+//and another for failing tests and writes the paths to
+//layout tests one line at a time. TestRecorder does not
+//have ability to clear the results.
+class MyTestRecorder {
+ private BufferedOutputStream mBufferedOutputPassedStream;
+ private BufferedOutputStream mBufferedOutputFailedStream;
+ private BufferedOutputStream mBufferedOutputNoresultStream;
+
+ public void passed(String layout_file) {
+ try {
+ mBufferedOutputPassedStream.write(layout_file.getBytes());
+ mBufferedOutputPassedStream.write('\n');
+ mBufferedOutputPassedStream.flush();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void failed(String layout_file) {
+ try {
+ mBufferedOutputFailedStream.write(layout_file.getBytes());
+ mBufferedOutputFailedStream.write('\n');
+ mBufferedOutputFailedStream.flush();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void noresult(String layout_file) {
+ try {
+ mBufferedOutputNoresultStream.write(layout_file.getBytes());
+ mBufferedOutputNoresultStream.write('\n');
+ mBufferedOutputNoresultStream.flush();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public MyTestRecorder(boolean resume) {
+ try {
+ File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
+ File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
+ File noExpectedResultFile = new File("/sdcard/layout_tests_nontext.txt");
+
+ mBufferedOutputPassedStream =
+ new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
+ mBufferedOutputFailedStream =
+ new BufferedOutputStream(new FileOutputStream(resultsFailedFile, resume));
+ mBufferedOutputNoresultStream =
+ new BufferedOutputStream(new FileOutputStream(noExpectedResultFile, resume));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void close() {
+ try {
+ mBufferedOutputPassedStream.close();
+ mBufferedOutputFailedStream.close();
+ mBufferedOutputNoresultStream.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
+
-public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase<Menu> {
+public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> {
- private final static String LOGTAG = "LayoutTests";
- private final static String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
+ private static final String LOGTAG = "LayoutTests";
+ static final int DEFAULT_TIMEOUT_IN_MILLIS = 5000;
+
+ static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
+ static final String LAYOUT_TESTS_RESULT_DIR = "/sdcard/android/layout_tests_results/";
+ static final String ANDROID_EXPECTED_RESULT_DIR = "/sdcard/android/expected_results/";
+ static final String LAYOUT_TESTS_LIST_FILE = "/sdcard/android/layout_tests_list.txt";
+ static final String TEST_STATUS_FILE = "/sdcard/android/running_test.txt";
+ private MyTestRecorder mResultRecorder;
+ private Vector<String> mTestList;
+ private boolean mRebaselineResults;
+ private String mTestPathPrefix;
+
public LayoutTestsAutoTest() {
- super("com.android.dumprendertree", Menu.class);
+ super("com.android.dumprendertree", TestShellActivity.class);
}
- // Invokes running of layout tests
- // and waits till it has finished running.
- public void executeLayoutTests(String folder) {
+ // This function writes the result of the layout test to
+ // Am status so that it can be picked up from a script.
+ private void passOrFailCallback(String file, boolean result) {
Instrumentation inst = getInstrumentation();
- getActivity().processFile(folder, true);
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(file, result);
+ inst.sendStatus(0, bundle);
+ }
+
+ private void getTestList() {
+ // Read test list.
+ try {
+ BufferedReader inReader = new BufferedReader(new FileReader(LAYOUT_TESTS_LIST_FILE));
+ String line = inReader.readLine();
+ while (line != null) {
+ if (line.startsWith(mTestPathPrefix))
+ mTestList.add(line);
+ line = inReader.readLine();
+ }
+ inReader.close();
+ Log.v(LOGTAG, "Test list has " + mTestList.size() + " test(s).");
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
+ }
+ }
+
+ private void resumeTestList() {
+ // read out the test name it stoped last time.
+ try {
+ BufferedReader inReader = new BufferedReader(new FileReader(TEST_STATUS_FILE));
+ String line = inReader.readLine();
+ for (int i = 0; i < mTestList.size(); i++) {
+ if (mTestList.elementAt(i).equals(line)) {
+ mTestList = new Vector<String>(mTestList.subList(i+1, mTestList.size()));
+ break;
+ }
+ }
+ inReader.close();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
+ }
+ }
+
+ private void clearTestStatus() {
+ // Delete TEST_STATUS_FILE
+ try {
+ File f = new File(TEST_STATUS_FILE);
+ if (f.delete())
+ Log.v(LOGTAG, "Deleted " + TEST_STATUS_FILE);
+ else
+ Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE);
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE + " : " + e.getMessage());
+ }
+ }
+
+ private void updateTestStatus(String s) {
+ // Write TEST_STATUS_FILE
+ try {
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_STATUS_FILE));
+ bos.write(s.getBytes());
+ bos.close();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Cannot update file " + TEST_STATUS_FILE);
+ }
+ }
+
+ private String getResultFile(String test) {
+ String shortName = test.substring(0, test.lastIndexOf('.'));
+ // Write actual results to result directory.
+ return shortName.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_RESULT_DIR) + "-result.txt";
+ }
+
+ private String getExpectedResultFile(String test) {
+ String shortName = test.substring(0, test.lastIndexOf('.'));
+ return shortName + "-expected.txt";
+ }
- ActivityMonitor htmlHostActivityMonitor =
- inst.addMonitor("com.android.dumprendertree.HTMLHostActivity", null, false);
- HTMLHostActivity activity =
- (HTMLHostActivity) htmlHostActivityMonitor.waitForActivityWithTimeout(6000);
+ private String getAndroidExpectedResultFile(String expectedResultFile) {
+ return expectedResultFile.replaceFirst(LAYOUT_TESTS_ROOT, ANDROID_EXPECTED_RESULT_DIR);
+ }
+
+ // Wrap up
+ private void failedCase(String file) {
+ Log.w("Layout test: ", file + " failed");
+ mResultRecorder.failed(file);
+ }
+
+ private void passedCase(String file) {
+ Log.v("Layout test:", file + " passed");
+ mResultRecorder.passed(file);
+ }
+
+ private void noresultCase(String file) {
+ Log.v("Layout test:", file + " no expected result");
+ mResultRecorder.noresult(file);
+ }
+
+ private void processResult(String testFile, String actualResultFile, String expectedResultFile) {
+ Log.v(LOGTAG, " Processing result: " + testFile);
+
+ File actual = new File(actualResultFile);
+ File expected = new File(expectedResultFile);
+ if (actual.exists() && expected.exists()) {
+ try {
+ boolean passing = true;
+ BufferedReader fr = new BufferedReader(new FileReader(actual));
+ BufferedReader fe = new BufferedReader(new FileReader(expected));
+ while (true) {
+ String s1 = fr.readLine();
+ String s2 = fe.readLine();
+ if (s1 == null && s2 == null)
+ break; // both files are the same
+ if (s1 == null || s2 == null || !s1.equals(s2)) {
+ passing = false;
+ break;
+ }
+ }
+
+ if (passing) {
+ passedCase(testFile);
+ } else {
+ failedCase(testFile);
+ }
+
+ fe.close();
+ fr.close();
+ } catch (FileNotFoundException ex) {
+ Log.e(LOGTAG, "File not found : " + ex.getMessage());
+ } catch (IOException ex) {
+ Log.e(LOGTAG, "IO Error : " + ex.getMessage());
+ }
+ return;
+ }
+
+ if (!expected.exists()) {
+ noresultCase(testFile);
+ }
+ }
+
+ private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout) {
+ activity.setCallback(new TestShellCallback() {
+ public void finished() {
+ synchronized (LayoutTestsAutoTest.this) {
+ LayoutTestsAutoTest.this.notifyAll();
+ }
+ }
+ });
+
+ String resultFile = getResultFile(test);
+ if (mRebaselineResults) {
+ String expectedResultFile = getExpectedResultFile(test);
+ File f = new File(expectedResultFile);
+ if (f.exists()) {
+ return; // don't run test and don't overwrite default tests.
+ }
+
+ resultFile = getAndroidExpectedResultFile(expectedResultFile);
+ }
+
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setClass(activity, TestShellActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ intent.putExtra(TestShellActivity.TEST_URL, "file://" + test);
+ intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
+ intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
+ activity.startActivity(intent);
- while (!activity.hasFinishedRunning()) {
- // Poll every 5 seconds to determine if the layout
- // tests have finished running
- try {Thread.sleep(5000); } catch(Exception e){}
- }
+ // Wait until done.
+ synchronized (this) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) { }
+ }
+
+ if (!mRebaselineResults) {
+ String expectedResultFile = getExpectedResultFile(test);
+ File f = new File(expectedResultFile);
+ if (!f.exists()) {
+ expectedResultFile = getAndroidExpectedResultFile(expectedResultFile);
+ }
+
+ processResult(test, resultFile, expectedResultFile);
+ }
+ }
+
+ // Invokes running of layout tests
+ // and waits till it has finished running.
+ public void executeLayoutTests(boolean resume) {
+ LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
+ // A convenient method to be called by another activity.
+
+ if (runner.mTestPath == null) {
+ Log.e(LOGTAG, "No test specified");
+ return;
+ }
+
+ this.mTestList = new Vector<String>();
- // Wait few more seconds so that results are
- // flushed to the /sdcard
- try {Thread.sleep(5000); } catch(Exception e){}
+ // Read settings
+ try {
+ this.mTestPathPrefix =
+ (new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getCanonicalPath();
+ } catch (IOException e) {
+ Log.e(LOGTAG, "Cannot find test path prefix: " + e.getMessage());
+ return;
+ }
+
+ this.mRebaselineResults = runner.mRebaseline;
+
+ int timeout = runner.mTimeoutInMillis;
+ if (timeout <= 0) {
+ timeout = DEFAULT_TIMEOUT_IN_MILLIS;
+ }
+
+ this.mResultRecorder = new MyTestRecorder(resume);
+
+ if (!resume)
+ clearTestStatus();
+
+ getTestList();
+ if (resume)
+ resumeTestList();
+
+ TestShellActivity activity = (TestShellActivity) getActivity();
+
+ // Run tests.
+ for (int i = 0; i < mTestList.size(); i++) {
+ String s = mTestList.elementAt(i);
+ updateTestStatus(s);
+ // Run tests
+ runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis);
+ }
+
+ updateTestStatus("#DONE");
+
+ activity.finish();
+ }
+
- return ;
+ private String getTestPath() {
+ LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
+
+ String test_path = LAYOUT_TESTS_ROOT;
+ if (runner.mTestPath != null) {
+ test_path += runner.mTestPath;
+ }
+ try {
+ test_path = new File(test_path).getCanonicalPath();
+ } catch (IOException e) {
+ Log.e("LayoutTestsAutoTest", "Cannot get cannonical path " + e.getMessage());
+ }
+ Log.v("LayoutTestsAutoTest", " Test path : " + test_path);
+
+ return test_path;
+ }
+
+ public void generateTestList() {
+ try {
+ File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false));
+ findTestsRecursively(bos, getTestPath());
+ bos.flush();
+ bos.close();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Error when creating test list: " + e.getMessage());
+ }
+ }
+
+ private void findTestsRecursively(BufferedOutputStream bos, String dir) throws IOException {
+ Log.v(LOGTAG, "Searching tests under " + dir);
+
+ File d = new File(dir);
+ if (!d.isDirectory()) {
+ throw new AssertionError("A directory expected, but got " + dir);
+ }
+
+ String[] files = d.list();
+ for (int i = 0; i < files.length; i++) {
+ String s = dir + "/" + files[i];
+ if (FileFilter.ignoreTest(s)) {
+ Log.v(LOGTAG, " Ignoring: " + s);
+ continue;
+ }
+ if (s.toLowerCase().endsWith(".html")
+ || s.toLowerCase().endsWith(".xml")) {
+ bos.write(s.getBytes());
+ bos.write('\n');
+ continue;
+ }
+
+ File f = new File(s);
+ if (f.isDirectory()) {
+ findTestsRecursively(bos, s);
+ continue;
+ }
+
+ Log.v(LOGTAG, "Skipping " + s);
+ }
}
// Running all the layout tests at once sometimes
// causes the dumprendertree to run out of memory.
// So, additional tests are added to run the tests
// in chunks.
- @LargeTest
- public void testAllLayoutTests() {
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast");
- }
-
- @LargeTest
- public void testLayoutSubset1() {
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/backgrounds");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/borders");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/box-shadow");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/box-sizing");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/canvas");
- }
-
- @LargeTest
- public void testLayoutSubset2() {
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/clip");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/compact");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/cookies");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/css");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/css-generated-content");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/doctypes");
- }
-
- @LargeTest
- public void testLayoutSubset3() {
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/dom");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/dynamic");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/encoding");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/events");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/flexbox");
- }
-
- @LargeTest
- public void testLayoutSubset4() {
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/forms");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/frames");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/gradients");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/history");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/html");
- }
-
- @LargeTest
- public void testLayoutSubset5() {
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/images");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/inline");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/inline-block");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/innerHTML");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/invalid");
- }
-
- @LargeTest
- public void testLayoutSubset6() {
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/js");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/layers");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/leaks");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/lists");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/loader");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/media");
- }
-
- @LargeTest
- public void testLayoutSubset7() {
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/multicol");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/overflow");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/parser");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/profiler");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/reflections");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/regex");
- }
-
- @LargeTest
- public void testLayoutSubset8() {
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/repaint");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/replaced");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/runin");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/selectors");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/table");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/text");
- }
-
- @LargeTest
- public void testLayoutSubset9() {
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/tokenizer");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/transforms");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/xpath");
- executeLayoutTests(LAYOUT_TESTS_ROOT + "fast/xsl");
+ public void startLayoutTests() {
+ try {
+ File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
+ if (!tests_list.exists())
+ generateTestList();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ executeLayoutTests(false);
+ }
+
+ public void resumeLayoutTests() {
+ executeLayoutTests(true);
}
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
new file mode 100644
index 0000000..b064dbb
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.dumprendertree;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.content.Intent;
+
+import android.util.Log;
+
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+
+import com.android.dumprendertree.TestShellActivity;
+import com.android.dumprendertree.TestShellCallback;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+class StreamPipe extends Thread {
+ InputStream in;
+ OutputStream out;
+
+ StreamPipe(InputStream in, OutputStream out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ public void run() {
+ try {
+ byte[] buf = new byte[1024];
+ int nofb = this.in.read(buf);
+ while (nofb != -1) {
+ this.out.write(buf, 0, nofb);
+ nofb = this.in.read(buf);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> {
+
+ private final static String LOGTAG = "LoadTest";
+ private final static String LOAD_TEST_RESULT = "/sdcard/load_test_result.txt";
+
+ public LoadTestsAutoTest() {
+ super("com.android.dumprendertree", TestShellActivity.class);
+ }
+
+ // This function writes the result of the layout test to
+ // Am status so that it can be picked up from a script.
+ public void passOrFailCallback(String file, boolean result) {
+ Instrumentation inst = getInstrumentation();
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(file, result);
+ inst.sendStatus(0, bundle);
+ }
+
+ // Invokes running of layout tests
+ // and waits till it has finished running.
+ public void runTest() {
+ LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
+
+ if (runner.mTestPath == null) {
+ Log.e(LOGTAG, "No test specified");
+ return;
+ }
+
+ TestShellActivity activity = (TestShellActivity) getActivity();
+
+ // Run tests
+ runTestAndWaitUntilDone(activity, runner.mTestPath, runner.mTimeoutInMillis);
+
+ // TODO(fqian): let am instrumentation pass in the command line, currently
+ // am instrument does not allow spaces in the command.
+ runPostShellCommand("/system/bin/dumpsys meminfo");
+
+ // Kill activity
+ activity.finish();
+ }
+
+ private void runPostShellCommand(String cmd) {
+ if (cmd == null || cmd.length() == 0)
+ return;
+
+ try {
+ // Call dumpsys meminfo
+ Process proc = Runtime.getRuntime().exec(cmd);
+ // Append output to LOAD_TEST_RESULT
+ InputStream input = proc.getInputStream();
+ InputStream error = proc.getErrorStream();
+ FileOutputStream out = new FileOutputStream(LOAD_TEST_RESULT, true);
+
+ StreamPipe p_in = new StreamPipe(input, out);
+ StreamPipe p_err = new StreamPipe(error, System.err);
+
+ p_in.start();
+ p_err.start();
+
+ proc.waitFor();
+ } catch (IOException e) {
+ Log.e(LOGTAG, e.getMessage());
+ } catch (InterruptedException e) {
+ Log.e(LOGTAG, e.getMessage());
+ }
+ }
+
+ // A convenient method to be called by another activity.
+ private void runTestAndWaitUntilDone(TestShellActivity activity, String url, int timeout) {
+ activity.setCallback(new TestShellCallback() {
+ public void finished() {
+ synchronized (LoadTestsAutoTest.this) {
+ LoadTestsAutoTest.this.notifyAll();
+ }
+ }
+ });
+
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setClass(activity, TestShellActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ intent.putExtra(TestShellActivity.TEST_URL, url);
+ intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
+ intent.putExtra(TestShellActivity.RESULT_FILE, LOAD_TEST_RESULT);
+ activity.startActivity(intent);
+
+ // Wait until done.
+ synchronized (this) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) { }
+ }
+ }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
index 2def8f3..00e0f89 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
@@ -19,6 +19,7 @@ package com.android.dumprendertree;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.util.Log;
import java.io.File;
@@ -42,12 +43,12 @@ public class Menu extends FileList {
}
void processFile(String filename, boolean selection)
- {
- Intent result = new Intent(null, Uri.parse(filename));
- result.setClass(this, HTMLHostActivity.class);
- result.putExtra("ReturnWhenFinished", selection);
- startActivity(result);
+ {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setClass(this, TestShellActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ intent.putExtra(TestShellActivity.TEST_URL, "file://" + filename);
+ startActivity(intent);
}
-
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
new file mode 100644
index 0000000..bf8a3b3
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2007 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.dumprendertree;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Vector;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.util.Log;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.view.ViewGroup;
+import android.webkit.WebChromeClient;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.widget.LinearLayout;
+import android.os.*;
+
+public class TestShellActivity extends Activity implements LayoutTestController {
+ public class AsyncHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_TIMEOUT) {
+ mTimedOut = true;
+ requestWebKitData();
+ return;
+ } else if (msg.what == MSG_WEBKIT_DATA) {
+ TestShellActivity.this.dump(mTimedOut, (String)msg.obj);
+ return;
+ }
+
+ super.handleMessage(msg);
+ }
+ }
+
+ public void requestWebKitData() {
+ Message callback = mHandler.obtainMessage(MSG_WEBKIT_DATA);
+
+ if (mRequestedWebKitData)
+ throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl());
+
+ mRequestedWebKitData = true;
+ if (mDumpAsText) {
+ mWebView.documentAsText(callback);
+ } else {
+ mWebView.externalRepresentation(callback);
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ LinearLayout contentView = new LinearLayout(this);
+ contentView.setOrientation(LinearLayout.VERTICAL);
+ setContentView(contentView);
+
+ mWebView = new WebView(this);
+ mWebView.getSettings().setJavaScriptEnabled(true);
+ mWebView.setWebChromeClient(mChromeClient);
+ mEventSender = new WebViewEventSender(mWebView);
+ mCallbackProxy = new CallbackProxy(mEventSender, this);
+
+ mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
+ mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
+ contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
+
+ mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
+
+ mHandler = new AsyncHandler();
+
+ Intent intent = getIntent();
+ if (intent != null) {
+ executeIntent(intent);
+ }
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ executeIntent(intent);
+ }
+
+ private void executeIntent(Intent intent) {
+ resetTestStatus();
+ if (!Intent.ACTION_VIEW.equals(intent.getAction())) {
+ return;
+ }
+
+ mTestUrl = intent.getStringExtra(TEST_URL);
+ if (mTestUrl == null)
+ return;
+
+ mResultFile = intent.getStringExtra(RESULT_FILE);
+ mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0);
+
+ Log.v(LOGTAG, " Loading " + mTestUrl);
+ mWebView.loadUrl(mTestUrl);
+
+ if (mTimeoutInMillis > 0) {
+ // Create a timeout timer
+ Message m = mHandler.obtainMessage(MSG_TIMEOUT);
+ mHandler.sendMessageDelayed(m, mTimeoutInMillis);
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mWebView.stopLoading();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mWebView.destroy();
+ mWebView = null;
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ Log.e(LOGTAG, "Low memory, kill self");
+ System.exit(1);
+ }
+
+ // Dump the page
+ public void dump(boolean timeout, String webkitData) {
+ if (mResultFile == null || mResultFile.length() == 0) {
+ finished();
+ return;
+ }
+
+ try {
+ File parentDir = new File(mResultFile).getParentFile();
+ if (!parentDir.exists()) {
+ parentDir.mkdirs();
+ }
+
+ FileOutputStream os = new FileOutputStream(mResultFile);
+ if (timeout) {
+ Log.w("Layout test: Timeout", mResultFile);
+ os.write(TIMEOUT_STR.getBytes());
+ os.write('\n');
+ }
+ if (mDumpTitleChanges)
+ os.write(mTitleChanges.toString().getBytes());
+ if (mDialogStrings != null)
+ os.write(mDialogStrings.toString().getBytes());
+ mDialogStrings = null;
+ os.write(webkitData.getBytes());
+ os.flush();
+ os.close();
+ } catch (IOException ex) {
+ Log.e(LOGTAG, "Cannot write to " + mResultFile + ", " + ex.getMessage());
+ }
+
+ finished();
+ }
+
+ public void setCallback(TestShellCallback callback) {
+ mCallback = callback;
+ }
+
+ public void finished() {
+ if (mCallback != null) {
+ mCallback.finished();
+ }
+ }
+
+ // .......................................
+ // LayoutTestController Functions
+ public void dumpAsText() {
+ mDumpAsText = true;
+ if (mWebView != null) {
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "dumpAsText called: "+url);
+ }
+ }
+
+ public void waitUntilDone() {
+ mWaitUntilDone = true;
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "waitUntilDone called: " + url);
+ }
+
+ public void notifyDone() {
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "notifyDone called: " + url);
+ if (mWaitUntilDone) {
+ mWaitUntilDone = false;
+ mChromeClient.onProgressChanged(mWebView, 100);
+ }
+ }
+
+ public void display() {
+ mWebView.invalidate();
+ }
+
+ public void clearBackForwardList() {
+ mWebView.clearHistory();
+
+ }
+
+ public void dumpBackForwardList() {
+ //printf("\n============== Back Forward List ==============\n");
+ // mWebHistory
+ //printf("===============================================\n");
+
+ }
+
+ public void dumpChildFrameScrollPositions() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void dumpEditingCallbacks() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void dumpSelectionRect() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void dumpTitleChanges() {
+ if (!mDumpTitleChanges) {
+ mTitleChanges = new StringBuffer();
+ }
+ mDumpTitleChanges = true;
+ }
+
+ public void keepWebHistory() {
+ if (!mKeepWebHistory) {
+ mWebHistory = new Vector();
+ }
+ mKeepWebHistory = true;
+ }
+
+ public void queueBackNavigation(int howfar) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void queueForwardNavigation(int howfar) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void queueLoad(String Url, String frameTarget) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void queueReload() {
+ mWebView.reload();
+ }
+
+ public void queueScript(String scriptToRunInCurrentContext) {
+ mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext);
+ }
+
+ public void repaintSweepHorizontally() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAcceptsEditing(boolean b) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setMainFrameIsFirstResponder(boolean b) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setWindowIsKey(boolean b) {
+ // This is meant to show/hide the window. The best I can find
+ // is setEnabled()
+ mWebView.setEnabled(b);
+ }
+
+ public void testRepaint() {
+ mWebView.invalidate();
+ }
+
+ private final WebChromeClient mChromeClient = new WebChromeClient() {
+ @Override
+ public void onProgressChanged(WebView view, int newProgress) {
+ if (newProgress == 100) {
+ if (!mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) {
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "Finished: "+ url);
+ mHandler.removeMessages(MSG_TIMEOUT);
+ requestWebKitData();
+ } else {
+ String url = mWebView.getUrl();
+ if (mTimedOut) {
+ Log.v(LOGTAG, "Timed out before finishing: " + url);
+ } else if (mWaitUntilDone) {
+ Log.v(LOGTAG, "Waiting for notifyDone: " + url);
+ } else if (mRequestedWebKitData) {
+ Log.v(LOGTAG, "Requested webkit data ready: " + url);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ if (title.length() > 30)
+ title = "..."+title.substring(title.length()-30);
+ setTitle(title);
+ if (mDumpTitleChanges) {
+ mTitleChanges.append("TITLE CHANGED: ");
+ mTitleChanges.append(title);
+ mTitleChanges.append("\n");
+ }
+ }
+
+ @Override
+ public boolean onJsAlert(WebView view, String url, String message,
+ JsResult result) {
+ if (mDialogStrings == null) {
+ mDialogStrings = new StringBuffer();
+ }
+ mDialogStrings.append("ALERT: ");
+ mDialogStrings.append(message);
+ mDialogStrings.append('\n');
+ result.confirm();
+ return true;
+ }
+
+ @Override
+ public boolean onJsConfirm(WebView view, String url, String message,
+ JsResult result) {
+ if (mDialogStrings == null) {
+ mDialogStrings = new StringBuffer();
+ }
+ mDialogStrings.append("CONFIRM: ");
+ mDialogStrings.append(message);
+ mDialogStrings.append('\n');
+ result.confirm();
+ return true;
+ }
+
+ @Override
+ public boolean onJsPrompt(WebView view, String url, String message,
+ String defaultValue, JsPromptResult result) {
+ if (mDialogStrings == null) {
+ mDialogStrings = new StringBuffer();
+ }
+ mDialogStrings.append("PROMPT: ");
+ mDialogStrings.append(message);
+ mDialogStrings.append(", default text: ");
+ mDialogStrings.append(defaultValue);
+ mDialogStrings.append('\n');
+ result.confirm();
+ return true;
+ }
+ };
+
+ private void resetTestStatus() {
+ mWaitUntilDone = false;
+ mDumpAsText = false;
+ mTimedOut = false;
+ mDumpTitleChanges = false;
+ mRequestedWebKitData = false;
+ mEventSender.resetMouse();
+ }
+
+ private WebView mWebView;
+ private WebViewEventSender mEventSender;
+ private AsyncHandler mHandler;
+ private TestShellCallback mCallback;
+
+ private CallbackProxy mCallbackProxy;
+
+ private String mTestUrl;
+ private String mResultFile;
+ private int mTimeoutInMillis;
+
+ // States
+ private boolean mTimedOut;
+ private boolean mRequestedWebKitData;
+ private boolean mFinishedRunning;
+
+ // Layout test controller variables.
+ private boolean mDumpAsText;
+ private boolean mWaitUntilDone;
+ private boolean mDumpTitleChanges;
+ private StringBuffer mTitleChanges;
+ private StringBuffer mDialogStrings;
+ private boolean mKeepWebHistory;
+ private Vector mWebHistory;
+
+ static final String TIMEOUT_STR = "**Test timeout";
+
+ static final int MSG_TIMEOUT = 0;
+ static final int MSG_WEBKIT_DATA = 1;
+
+ static final String LOGTAG="TestShell";
+
+ static final String TEST_URL = "TestUrl";
+ static final String RESULT_FILE = "ResultFile";
+ static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis";
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java
index 60a2915..759c443 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java
@@ -16,6 +16,6 @@
package com.android.dumprendertree;
-public interface HTMLHostCallbackInterface {
- public void waitForFinish();
+public interface TestShellCallback {
+ public void finished();
}
diff --git a/tests/FrameworkTest/AndroidManifest.xml b/tests/FrameworkTest/AndroidManifest.xml
index 8106a50..c70302b 100644
--- a/tests/FrameworkTest/AndroidManifest.xml
+++ b/tests/FrameworkTest/AndroidManifest.xml
@@ -571,6 +571,14 @@
</intent-filter>
</activity>
+ <activity android:name=".listview.ListWithFirstScreenUnSelectable" android:label="ListWithFirstScreenUnSelectable">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+
<activity android:name=".listview.ListWithSeparators" android:label="ListWithSeparators">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -845,6 +853,13 @@
</intent-filter>
</activity>
+ <activity android:name=".drawable.MutateDrawable" android:label="MutateDrawable">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name=".activity.TranslucentFancyActivity" android:label="TranslucentFancyActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/drawable/MutateDrawable.java b/tests/FrameworkTest/src/com/android/frameworktest/drawable/MutateDrawable.java
new file mode 100644
index 0000000..2fcaea3
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/drawable/MutateDrawable.java
@@ -0,0 +1,49 @@
+/*
+ * 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.frameworktest.drawable;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import com.android.frameworktest.R;
+
+public class MutateDrawable extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+
+ Button ok = new Button(this);
+ ok.setId(R.id.a);
+ ok.setBackgroundDrawable(getResources().getDrawable(
+ R.drawable.sym_now_playing_skip_forward_1));
+
+ Button cancel = new Button(this);
+ cancel.setId(R.id.b);
+ cancel.setBackgroundDrawable(getResources().getDrawable(
+ R.drawable.sym_now_playing_skip_forward_1));
+
+ layout.addView(ok);
+ layout.addView(cancel);
+
+ ok.getBackground().mutate().setAlpha(127);
+
+ setContentView(layout);
+ }
+}
diff --git a/core/java/com/android/internal/os/HandlerHelper.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithFirstScreenUnSelectable.java
index d810e6b..4ad72fd 100644
--- a/core/java/com/android/internal/os/HandlerHelper.java
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithFirstScreenUnSelectable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,25 +14,20 @@
* limitations under the License.
*/
-package com.android.internal.os;
+package com.android.frameworktest.listview;
-import android.os.Handler;
-import android.os.HandlerInterface;
-import android.os.Message;
+import com.android.frameworktest.util.ListScenario;
-/** @hide */
-public class HandlerHelper extends Handler
-{
- public HandlerHelper(HandlerInterface target)
- {
- mTarget = target;
- }
+/**
+ * The first item is unselectable, and takes up the whole screen.
+ */
+public class ListWithFirstScreenUnSelectable extends ListScenario {
- public void handleMessage(Message msg)
- {
- mTarget.handleMessage(msg);
- }
+ @Override
+ protected void init(Params params) {
+ params.setItemScreenSizeFactor(1.2)
+ .setNumItems(2)
+ .setPositionsUnselectable(0);
- private HandlerInterface mTarget;
+ }
}
-
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/MutateDrawableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/MutateDrawableTest.java
new file mode 100644
index 0000000..53085ca
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/MutateDrawableTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.frameworktest.drawable;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+public class MutateDrawableTest extends ActivityInstrumentationTestCase2<MutateDrawable> {
+ private View mFirstButton;
+ private View mSecondButton;
+
+ public MutateDrawableTest() {
+ super("com.android.frameworktest", MutateDrawable.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mFirstButton = getActivity().findViewById(com.android.frameworktest.R.id.a);
+ mSecondButton = getActivity().findViewById(com.android.frameworktest.R.id.b);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mFirstButton);
+ assertNotNull(mSecondButton);
+ assertNotSame(mFirstButton.getBackground(), mSecondButton.getBackground());
+ }
+
+ @MediumTest
+ public void testDrawableCanMutate() throws Exception {
+ assertNotSame(mFirstButton.getBackground().getConstantState(),
+ mSecondButton.getBackground().getConstantState());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ScrollingThroughListOfFocusablesTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ScrollingThroughListOfFocusablesTest.java
index 2134e04..07916ee 100644
--- a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ScrollingThroughListOfFocusablesTest.java
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ScrollingThroughListOfFocusablesTest.java
@@ -87,9 +87,12 @@ public class ScrollingThroughListOfFocusablesTest extends InstrumentationTestCas
assertEquals(0, mListView.getSelectedItemPosition());
InternalSelectionView view = (InternalSelectionView)
mListView.getSelectedView();
- assertEquals("bottom of view should be just above fading edge",
- mListView.getBottom() - mListView.getVerticalFadingEdgeLength(),
- view.getBottom());
+
+ // 1 pixel tolerance in case height / 4 is not an even number
+ final int fadingEdge = mListView.getBottom() - mListView.getVerticalFadingEdgeLength();
+ assertTrue("bottom of view should be just above fading edge",
+ view.getBottom() >= fadingEdge - 1 &&
+ view.getBottom() <= fadingEdge);
}
@@ -138,9 +141,9 @@ public class ScrollingThroughListOfFocusablesTest extends InstrumentationTestCas
view.getRectForRow(mTempRect, mNumRowsPerItem - 1);
mListView.offsetDescendantRectToMyCoords(view, mTempRect);
- assertEquals("bottom of last row of last item should be at " +
+ assertTrue("bottom of last row of last item should be at " +
"the bottom of the list view (no fading edge)",
- mListView.getBottom(), mTempRect.bottom);
+ mListView.getBottom() - mListView.getVerticalFadingEdgeLength() < mTempRect.bottom);
}
@LargeTest
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/VerticalGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/VerticalGravityTest.java
index de3e68b..d731243 100644
--- a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/VerticalGravityTest.java
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/VerticalGravityTest.java
@@ -21,6 +21,7 @@ import com.android.frameworktest.R;
import android.test.ActivityInstrumentationTestCase;
import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
import android.test.ViewAsserts;
import android.view.View;
@@ -73,6 +74,7 @@ public class VerticalGravityTest extends ActivityInstrumentationTestCase<Vertica
ViewAsserts.assertVerticalCenterAligned(mReference2, mCenter);
}
+ @Suppress
@MediumTest
public void testBottomGravity() throws Exception {
ViewAsserts.assertBottomAligned(mReference3, mBottom);
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListScrollListenerTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListScrollListenerTest.java
index 485199e..44958d9 100644
--- a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListScrollListenerTest.java
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListScrollListenerTest.java
@@ -24,7 +24,6 @@ import android.view.KeyEvent;
import android.widget.AbsListView;
import android.widget.ListView;
-import com.android.frameworktest.listview.ListScrollListener;
import android.test.TouchUtils;
public class ListScrollListenerTest extends ActivityInstrumentationTestCase<ListScrollListener> implements
@@ -88,8 +87,6 @@ public class ListScrollListenerTest extends ActivityInstrumentationTestCase<List
@LargeTest
public void testTouchScrolling() {
- Instrumentation inst = getInstrumentation();
-
int firstVisibleItem = mFirstVisibleItem;
TouchUtils.dragQuarterScreenUp(this);
TouchUtils.dragQuarterScreenUp(this);
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListSetSelectionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListSetSelectionTest.java
index 18b6199..e35d894 100644
--- a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListSetSelectionTest.java
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListSetSelectionTest.java
@@ -58,7 +58,7 @@ public class ListSetSelectionTest extends ActivityInstrumentationTestCase2<ListS
}
}
- /** Confirm that you can unset the selection using the same API */
+ /** Confirm that you cannot unset the selection using the same API */
@MediumTest
@UiThreadTest
public void testClearSelection() {
@@ -68,7 +68,6 @@ public class ListSetSelectionTest extends ActivityInstrumentationTestCase2<ListS
// Clear the selection
mListView.setSelection(ListView.INVALID_POSITION);
- assertEquals("Set selection",
- ListView.INVALID_POSITION, mListView.getSelectedItemPosition());
+ assertEquals("Set selection", 0, mListView.getSelectedItemPosition());
}
}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
new file mode 100644
index 0000000..307c39d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.frameworktest.listview.arrowscroll;
+
+import com.android.frameworktest.listview.ListWithFirstScreenUnSelectable;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import android.widget.AdapterView;
+
+public class ListWithFirstScreenUnSelectableTest
+ extends ActivityInstrumentationTestCase2<ListWithFirstScreenUnSelectable> {
+ private ListView mListView;
+
+ public ListWithFirstScreenUnSelectableTest() {
+ super("com.android.frameworktest", ListWithFirstScreenUnSelectable.class);
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ setActivityInitialTouchMode(true);
+
+ mListView = getActivity().getListView();
+ }
+
+ public void testPreconditions() {
+ assertTrue(mListView.isInTouchMode());
+ assertEquals(1, mListView.getChildCount());
+ assertFalse(mListView.getAdapter().isEnabled(0));
+ assertEquals(AdapterView.INVALID_POSITION, mListView.getSelectedItemPosition());
+ }
+
+ public void testRessurectSelection() {
+ sendKeys(KeyEvent.KEYCODE_SPACE);
+ assertEquals(AdapterView.INVALID_POSITION, mListView.getSelectedItemPosition());
+ }
+
+ public void testScrollUpDoesNothing() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals(AdapterView.INVALID_POSITION, mListView.getSelectedItemPosition());
+ assertEquals(1, mListView.getChildCount());
+ assertEquals(0, mListView.getFirstVisiblePosition());
+ }
+
+ public void testScrollDownPansNextItemOn() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals(2, mListView.getChildCount());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/widget/ListViewTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/widget/ListViewTest.java
index dff1610..ecb7d3a 100644
--- a/tests/FrameworkTest/tests/src/com/android/frameworktest/widget/ListViewTest.java
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/widget/ListViewTest.java
@@ -92,7 +92,7 @@ public class ListViewTest extends InstrumentationTestCase {
@Override
public Resources getResources() {
- return null;
+ return getInstrumentation().getTargetContext().getResources();
}
@Override
diff --git a/tests/GadgetHost/AndroidManifest.xml b/tests/GadgetHost/AndroidManifest.xml
deleted file mode 100644
index eeb8979..0000000
--- a/tests/GadgetHost/AndroidManifest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.gadgethost">
- <uses-permission android:name="android.permission.VIBRATE" />
-
- <application>
- <activity android:name="GadgetHostActivity" android:label="_GadgetHost">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity android:name="GadgetPickActivity">
- <intent-filter>
- <action android:name="android.gadget.action.PICK_GADGET" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
- <receiver android:name="TestGadgetProvider">
- <intent-filter>
- <action android:name="android.gadget.action.GADGET_UPDATE" />
- </intent-filter>
- <meta-data android:name="android.gadget.provider" android:resource="@xml/gadget_info" />
- </receiver>
- </application>
-</manifest>
diff --git a/tests/GadgetHost/res/xml/gadget_info.xml b/tests/GadgetHost/res/xml/gadget_info.xml
deleted file mode 100644
index 84d0603..0000000
--- a/tests/GadgetHost/res/xml/gadget_info.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<gadget-provider xmlns:android="http://schemas.android.com/apk/res/android"
- android:minWidth="40dp"
- android:minHeight="30dp"
- android:updatePeriodMillis="30000"
- android:initialLayout="@layout/test_gadget"
- >
-</gadget-provider>
diff --git a/tests/GadgetHost/src/com/android/gadgethost/GadgetHostActivity.java b/tests/GadgetHost/src/com/android/gadgethost/GadgetHostActivity.java
deleted file mode 100644
index 38073fa..0000000
--- a/tests/GadgetHost/src/com/android/gadgethost/GadgetHostActivity.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.gadgethost;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.gadget.GadgetHost;
-import android.gadget.GadgetHostView;
-import android.gadget.GadgetInfo;
-import android.gadget.GadgetManager;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.View;
-import android.widget.LinearLayout;
-
-public class GadgetHostActivity extends Activity
-{
- static final String TAG = "GadgetHostActivity";
-
- static final int DISCOVER_GADGET_REQUEST = 1;
-
- GadgetManager mGadgetManager;
- GadgetContainerView mGadgetContainer;
-
- public GadgetHostActivity() {
- mGadgetManager = GadgetManager.getInstance(this);
- }
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.gadget_host);
-
- findViewById(R.id.add_gadget).setOnClickListener(mOnClickListener);
- mGadgetContainer = (GadgetContainerView)findViewById(R.id.gadget_container);
- }
-
- View.OnClickListener mOnClickListener = new View.OnClickListener() {
- public void onClick(View v) {
- discoverGadget(DISCOVER_GADGET_REQUEST);
- }
- };
-
- void discoverGadget(int requestCode) {
- Intent intent = new Intent(GadgetManager.GADGET_PICK_ACTION);
- startActivityForResult(intent, requestCode);
- }
-
- void handleGadgetPickResult(int resultCode, Intent data) {
- if (resultCode == RESULT_OK) {
- Bundle extras = data.getExtras();
- int gadgetId = extras.getInt(GadgetManager.EXTRA_GADGET_ID);
- GadgetInfo gadget = mGadgetManager.getGadgetInfo(gadgetId);
-
- if (gadget.configure != null) {
- // configure the gadget if we should
-
- // TODO: start the activity. Watch for a cancel result. If it returns
- // RESULT_CANCELED, then remove the gadget.
- } else {
- // just add it as is
- addGadgetView(gadgetId, gadget);
- }
- }
- }
-
- void addGadgetView(int gadgetId, GadgetInfo gadget) {
- // Inflate the gadget's RemoteViews
- GadgetHostView view = mHost.createView(this, gadgetId, gadget);
-
- // Add it to the list
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
- 65, // LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT);
- mGadgetContainer.addView(view, layoutParams);
- }
-
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case DISCOVER_GADGET_REQUEST:
- handleGadgetPickResult(resultCode, data);
- break;
- }
- }
-
- protected void onStart() {
- super.onStart();
- mHost.startListening();
- }
-
- protected void onStop() {
- super.onStop();
- mHost.stopListening();
- }
-
- class MyGadgetView extends GadgetHostView {
- MyGadgetView() {
- super(GadgetHostActivity.this);
- }
-
- public void createContextMenu(ContextMenu menu) {
- menu.add("Delete");
- }
- }
-
- GadgetHost mHost = new GadgetHost(this, 0) {
- protected GadgetHostView onCreateView(Context context, int gadgetId, GadgetInfo gadget) {
- return new MyGadgetView();
- }
- };
-
-}
-
-
diff --git a/tests/GadgetHost/src/com/android/gadgethost/GadgetPickActivity.java b/tests/GadgetHost/src/com/android/gadgethost/GadgetPickActivity.java
deleted file mode 100644
index a995544..0000000
--- a/tests/GadgetHost/src/com/android/gadgethost/GadgetPickActivity.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.gadgethost;
-
-import android.app.ListActivity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.gadget.GadgetInfo;
-import android.gadget.GadgetManager;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.util.Log;
-
-import java.util.List;
-
-public class GadgetPickActivity extends ListActivity
-{
- private static final String TAG = "GadgetPickActivity";
-
- GadgetManager mGadgetManager;
- List<GadgetInfo> mInstalled;
-
- public GadgetPickActivity() {
- mGadgetManager = GadgetManager.getInstance(this);
- }
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- Bundle extras = getIntent().getExtras();
-
- List<GadgetInfo> installed = mGadgetManager.getInstalledProviders();
- mInstalled = installed;
- final int N = installed.size();
- String[] labels = new String[N];
- for (int i=0; i<N; i++) {
- labels[i] = installed.get(i).provider.getClassName();
- }
-
- setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, labels));
- }
-
- @Override
- public void onListItemClick(ListView l, View v, int position, long id)
- {
- int gadgetId = mGadgetManager.allocateGadgetId(getCallingPackage());
- mGadgetManager.bindGadgetId(gadgetId, mInstalled.get(position).provider);
-
- Intent result = new Intent();
- result.putExtra(GadgetManager.EXTRA_GADGET_ID, gadgetId);
-
- setResult(RESULT_OK, result);
- finish();
- }
-}
-
diff --git a/tests/ImfTest/AndroidManifest.xml b/tests/ImfTest/AndroidManifest.xml
index 85d6b0c..55e5d38 100755
--- a/tests/ImfTest/AndroidManifest.xml
+++ b/tests/ImfTest/AndroidManifest.xml
@@ -19,6 +19,126 @@
</intent-filter>
</activity>
+ <activity android:name=".samples.BigEditTextActivityNonScrollablePanScan" android:label="Big ET !Scroll Pan/Scan">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.ManyEditTextActivityNoScrollPanScan" android:label="ManyEditTextActivityNoScrollPanScan">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.BigEditTextActivityNonScrollableResize" android:label="Big ET !Scroll Resize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.BigEditTextActivityScrollablePanScan" android:label="Big ET Scroll Pan/Scan">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.BigEditTextActivityScrollableResize" android:label="Big ET Scroll Resize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.EditTextActivityDialog" android:label="ET Dialog">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.ManyEditTextActivityScrollPanScan" android:label="ManyEditTextActivityScrollPanScan">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.ManyEditTextActivityScrollResize" android:label="ManyEditTextActivityScrollResize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.BottomEditTextActivityPanScan" android:label="BottomEditTextActivityPanScan">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.BottomEditTextActivityResize" android:label="BottomEditTextActivityResize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.OneEditTextActivitySelected" android:label="OneEditTextActivitySelected">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.OneEditTextActivityNotSelected" android:label="OneEditTextActivityNotSelected">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.AutoCompleteTextViewActivityPortrait" android:label="AutoCompleteTextViewActivityPortrait" android:screenOrientation="portrait">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.AutoCompleteTextViewActivityLandscape" android:label="AutoCompleteTextViewActivityLandscape" android:screenOrientation="landscape">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.DialogActivity" android:label="DialogActivity" android:screenOrientation="portrait">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
</application>
</manifest>
diff --git a/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml b/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
new file mode 100644
index 0000000..e8ffa1c
--- /dev/null
+++ b/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="20dip"
+ android:orientation="vertical">
+
+ <View
+ android:id="@+id/blank"
+ android:layout_height="0dip"
+ android:layout_width="fill_parent"
+ android:layout_weight="1"/>
+
+ <EditText
+ android:id="@+id/dialog_edit_text"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:scrollHorizontally="true"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/time_picker_text.xml b/tests/ImfTest/res/layout/full_screen_edit_text.xml
index bad980b..f22aa2f 100644..100755
--- a/core/res/res/layout/time_picker_text.xml
+++ b/tests/ImfTest/res/layout/full_screen_edit_text.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
**
-** Copyright 2008, The Android Open Source Project
+** Copyright 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.
@@ -17,11 +18,10 @@
*/
-->
-<!-- TextView of time picker-->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+<EditText xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/data"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:textAppearance="?attr/textAppearanceLargeInverse"
- android:gravity="center"
- />
+ android:minLines="15"
+ android:gravity="top"/>
+
diff --git a/tests/ImfTest/res/layout/one_edit_text_activity.xml b/tests/ImfTest/res/layout/one_edit_text_activity.xml
new file mode 100755
index 0000000..09925e1
--- /dev/null
+++ b/tests/ImfTest/res/layout/one_edit_text_activity.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:baselineAligned="false">
+
+ <View android:id="@+id/blank"
+ android:layout_height="0dip"
+ android:layout_width="fill_parent"
+ android:layout_weight="1"
+ />
+
+ <EditText android:id="@+id/dialog_edit_text"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:scrollHorizontally="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ />
+ </LinearLayout>
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:background="@android:drawable/divider_horizontal_dark"
+ />
+</LinearLayout>
diff --git a/location/java/com/android/internal/location/protocol/GLatLng.java b/tests/ImfTest/res/values/config.xml
index 90e23df..5ae40a3 100644
--- a/location/java/com/android/internal/location/protocol/GLatLng.java
+++ b/tests/ImfTest/res/values/config.xml
@@ -1,23 +1,21 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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
+ * 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
+ * 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
+ * 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.internal.location.protocol;
-
-public interface GLatLng {
- static final int LAT_E7 = 1;
- static final int LNG_E7 = 2;
-}
-
+-->
+<resources>
+ <bool name="def_expect_ime_autopop">false</bool>
+</resources>
diff --git a/tests/ImfTest/res/values/strings.xml b/tests/ImfTest/res/values/strings.xml
index a56c363..fc87480 100755
--- a/tests/ImfTest/res/values/strings.xml
+++ b/tests/ImfTest/res/values/strings.xml
@@ -35,5 +35,16 @@
<string name="normal_datetime_edit_text_label">Datetime</string>
<string name="date_edit_text_label">Date</string>
<string name="time_edit_text_label">Time</string>
+ <string name="cap_chars_edit_text_label">Cap Chars</string>
+ <string name="cap_words_edit_text_label">Cap Words</string>
+ <string name="multiline_edit_text_label">Multiline</string>
+ <string name="search_edit_text_label">Search (flag)</string>
+ <string name="cap_sentences_edit_text_label">Cap Sentences</string>
+ <string name="auto_complete_edit_text_label">Auto Complete</string>
+ <string name="auto_correct_edit_text_label">Auto Correct</string>
+ <string name="test_dialog">Test Dialog</string>
+ <string name="open_dialog_scrollable">open scrollable dialog</string>
+ <string name="open_dialog_nonscrollable">open nonscrollable dialog</string>
+
</resources>
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
new file mode 100644
index 0000000..9638d34
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
@@ -0,0 +1,85 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.provider.MediaStore;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.AutoCompleteTextView;
+import android.widget.ArrayAdapter;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+
+import com.android.internal.R;
+
+/*
+ * Activity with AutoCompleteTextView forced to landscape mode
+ */
+public class AutoCompleteTextViewActivityLandscape extends Activity
+{
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.auto_complete_list);
+
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_dropdown_item_1line, COUNTRIES);
+ AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.edit);
+ textView.setAdapter(adapter);
+ }
+
+ static final String[] COUNTRIES = new String[] {
+ "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+ "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+ "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+ "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+ "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+ "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
+ "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
+ "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+ "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+ "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+ "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+ "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+ "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+ "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+ "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+ "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+ "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+ "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+ "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+ "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+ "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+ "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+ "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+ "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+ "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+ "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+ "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+ "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+ "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+ "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+ "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+ "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+ "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+ "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+ "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+ "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+ "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+ "Ukraine", "United Arab Emirates", "United Kingdom",
+ "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+ "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+ "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+ };
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
new file mode 100644
index 0000000..58651e1
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
@@ -0,0 +1,79 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.AutoCompleteTextView;
+import android.widget.ArrayAdapter;
+
+import com.android.internal.R;
+
+/*
+ * Activity with AutoCompleteTextView (Candidate bar should not appear)
+ */
+public class AutoCompleteTextViewActivityPortrait extends Activity
+{
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.auto_complete_list);
+
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_dropdown_item_1line, COUNTRIES);
+ AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.edit);
+ textView.setAdapter(adapter);
+ }
+
+ static final String[] COUNTRIES = new String[] {
+ "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+ "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+ "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+ "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+ "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+ "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
+ "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
+ "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+ "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+ "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+ "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+ "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+ "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+ "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+ "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+ "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+ "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+ "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+ "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+ "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+ "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+ "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+ "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+ "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+ "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+ "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+ "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+ "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+ "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+ "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+ "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+ "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+ "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+ "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+ "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+ "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+ "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+ "Ukraine", "United Arab Emirates", "United Kingdom",
+ "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+ "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+ "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+ };
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
new file mode 100644
index 0000000..9754381
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
@@ -0,0 +1,49 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityNonScrollablePanScan extends Activity {
+
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+
+ mRootView = new LinearLayout(this);
+ ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+ mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ View view = getLayoutInflater().inflate(
+ R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
+
+ ((LinearLayout) mRootView).addView(view);
+
+ mDefaultFocusedView = view.findViewById(R.id.data);
+
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
new file mode 100644
index 0000000..701795f
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
@@ -0,0 +1,49 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityNonScrollableResize extends Activity {
+
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+
+ mRootView = new LinearLayout(this);
+ ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+ mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ View view = getLayoutInflater().inflate(
+ R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
+
+ ((LinearLayout) mRootView).addView(view);
+
+ mDefaultFocusedView = view.findViewById(R.id.data);
+
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
new file mode 100644
index 0000000..bb3f767
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
@@ -0,0 +1,57 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityScrollablePanScan extends Activity {
+
+ private View mRootView;
+ private View mDefaultFocusedView;
+ private LinearLayout mLayout;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+
+ mRootView = new ScrollView(this);
+ ((ScrollView) mRootView).setFillViewport(true);
+ mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ View view = getLayoutInflater().inflate(
+ R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
+
+ mLayout.addView(view);
+
+ ((ScrollView) mRootView).addView(mLayout);
+ mDefaultFocusedView = view.findViewById(R.id.data);
+
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
new file mode 100644
index 0000000..f2cae1c
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
@@ -0,0 +1,57 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityScrollableResize extends Activity {
+
+ private View mRootView;
+ private View mDefaultFocusedView;
+ private LinearLayout mLayout;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+
+ mRootView = new ScrollView(this);
+ ((ScrollView) mRootView).setFillViewport(true);
+ mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ View view = getLayoutInflater().inflate(
+ R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
+
+ mLayout.addView(view);
+
+ ((ScrollView) mRootView).addView(mLayout);
+ mDefaultFocusedView = view.findViewById(R.id.data);
+
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
new file mode 100644
index 0000000..51f5045
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
@@ -0,0 +1,46 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.imftest.R;
+
+/*
+ * Activity with EditText at the bottom (Pan&Scan)
+ */
+public class BottomEditTextActivityPanScan extends Activity
+{
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ mRootView = new LinearLayout(this);
+ ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+
+ View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
+ mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
+ ((LinearLayout) mRootView).addView(view);
+
+ setContentView(mRootView);
+ this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+} \ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
new file mode 100644
index 0000000..eb94b4f
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
@@ -0,0 +1,46 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.imftest.R;
+
+/*
+ * Activity with EditText at the bottom (Resize)
+ */
+public class BottomEditTextActivityResize extends Activity
+{
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ mRootView = new LinearLayout(this);
+ ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+
+ View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
+ mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
+ ((LinearLayout) mRootView).addView(view);
+
+ setContentView(mRootView);
+ this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+} \ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
index 4233811..1191f19 100644
--- a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
@@ -13,6 +13,8 @@ import android.widget.TextView;
public class ButtonActivity extends Activity
{
static boolean mKeyboardIsActive = false;
+ public static final int BUTTON_ID = 0;
+ private View mRootView;
@Override
public void onCreate(Bundle savedInstanceState)
@@ -23,6 +25,8 @@ public class ButtonActivity extends Activity
final Button myButton = new Button(this);
myButton.setClickable(true);
myButton.setText("Keyboard UP!");
+ myButton.setId(BUTTON_ID);
+ myButton.setFocusableInTouchMode(true);
myButton.setOnClickListener(new View.OnClickListener()
{
public void onClick (View v)
@@ -36,7 +40,8 @@ public class ButtonActivity extends Activity
}
else
{
- imm.showSoftInput(null, 0);
+ myButton.requestFocusFromTouch();
+ imm.showSoftInput(v, 0);
myButton.setText("Keyboard DOWN!");
}
@@ -48,5 +53,10 @@ public class ButtonActivity extends Activity
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(myButton);
setContentView(layout);
+ mRootView = layout;
+ }
+
+ public View getRootView() {
+ return mRootView;
}
}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java b/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
new file mode 100644
index 0000000..e49301c
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
@@ -0,0 +1,102 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.Button;
+import android.view.LayoutInflater;
+import android.app.Dialog;
+
+import com.android.internal.R;
+
+public class DialogActivity extends Activity {
+
+ private static final int DIALOG_WITHOUT_EDITTEXT = 0;
+ private static final int DIALOG_WITH_EDITTEXT = 1;
+
+ private LinearLayout mLayout;
+ private LayoutInflater mInflater;
+ private Button mButton1;
+ private Button mButton2;
+ private EditText mEditText;
+
+
+ @Override
+ protected void onCreate(Bundle icicle)
+ {
+ super.onCreate(icicle);
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mButton1 = new Button(this);
+ mButton1.setText("Dialog WITHOUT EditText");//(R.string.open_dialog_scrollable);
+ mButton1.setOnClickListener(new View.OnClickListener()
+ {
+ public void onClick(View v)
+ {
+ showDialog(DIALOG_WITHOUT_EDITTEXT);
+ }
+ });
+
+ mButton2 = new Button(this);
+ mButton2.setText("Dialog WITH EditText");//(R.string.open_dialog_nonscrollable);
+ mButton2.setOnClickListener(new View.OnClickListener()
+ {
+ public void onClick(View v)
+ {
+ showDialog(DIALOG_WITH_EDITTEXT);
+ }
+ });
+
+ mEditText = new EditText(this);
+ mLayout.addView(mEditText);
+ mLayout.addView(mButton1);
+ mLayout.addView(mButton2);
+
+ setContentView(mLayout);
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id)
+ {
+ switch (id)
+ {
+ case DIALOG_WITHOUT_EDITTEXT:
+ return createDialog(false);
+ case DIALOG_WITH_EDITTEXT:
+ return createDialog(true);
+ }
+
+ return super.onCreateDialog(id);
+ }
+
+ protected Dialog createDialog(boolean bEditText)
+ {
+ LinearLayout layout;
+ layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ if(bEditText)
+ {
+ EditText editText;
+ editText = new EditText(this);
+ layout.addView(editText);
+ }
+
+ Dialog d = new Dialog(this);
+ d.setTitle("The DIALOG!!!");
+ d.setCancelable(true);
+ d.setContentView(layout);
+ return d;
+ }
+
+ }
diff --git a/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
new file mode 100644
index 0000000..bd1e934
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
@@ -0,0 +1,96 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class EditTextActivityDialog extends Activity {
+
+ private static final int SCROLLABLE_DIALOG_ID = 0;
+ private static final int NONSCROLLABLE_DIALOG_ID = 1;
+
+ private LinearLayout mLayout;
+ private ScrollView mScrollView;
+ private LayoutInflater mInflater;
+ private Button mButton1;
+ private Button mButton2;
+
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mButton1 = new Button(this);
+ mButton1.setText(R.string.open_dialog_scrollable);
+ mButton1.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ showDialog(SCROLLABLE_DIALOG_ID);
+ }
+ });
+
+ mButton2 = new Button(this);
+ mButton2.setText(R.string.open_dialog_nonscrollable);
+ mButton2.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ showDialog(NONSCROLLABLE_DIALOG_ID);
+ }
+ });
+
+ mLayout.addView(mButton1);
+ mLayout.addView(mButton2);
+
+ setContentView(mLayout);
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case SCROLLABLE_DIALOG_ID:
+ return createDialog(true);
+ case NONSCROLLABLE_DIALOG_ID:
+ return createDialog(false);
+ }
+
+ return super.onCreateDialog(id);
+ }
+
+ protected Dialog createDialog(boolean scrollable) {
+ View layout;
+ EditText editText;
+
+ if (scrollable) {
+ layout = new ScrollView(EditTextActivityDialog.this);
+ ((ScrollView) layout).setMinimumHeight(mLayout.getHeight());
+
+ ((ScrollView) layout).addView((
+ LinearLayout) View.inflate(EditTextActivityDialog.this,
+ R.layout.dialog_edit_text_no_scroll, null));
+ } else {
+ layout = View.inflate(EditTextActivityDialog.this,
+ R.layout.dialog_edit_text_no_scroll, null);
+ }
+
+ Dialog d = new Dialog(EditTextActivityDialog.this);
+ d.setTitle(getString(R.string.test_dialog));
+ d.setCancelable(true);
+ d.setContentView(layout);
+ return d;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java b/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
index f7aaa7b..17f6bdc 100755
--- a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
+++ b/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
@@ -56,43 +56,63 @@ public class InputTypeActivity extends Activity {
mParent = mLayout;
/* Normal Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_TEXT_VARIATION_NORMAL,
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL,
R.string.normal_edit_text_label));
+ /* Normal Edit Text w/Cap Chars Flag*/
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS,
+ R.string.cap_chars_edit_text_label));
+
+ /* Normal Edit Text w/Cap Words Flag*/
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS,
+ R.string.cap_words_edit_text_label));
+
+ /* Normal Edit Text w/Cap Multiline Flag */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE,
+ R.string.multiline_edit_text_label));
+
+ /* Normal Edit Text w/Cap Sentences Flag */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES,
+ R.string.cap_sentences_edit_text_label));
+
+ /* Normal Edit Text w/Auto-complete Flag */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE,
+ R.string.auto_complete_edit_text_label));
+
+ /* Normal Edit Text w/Auto-correct Flag */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT,
+ R.string.auto_correct_edit_text_label));
+
/* Uri Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_TEXT_VARIATION_URI,
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_URI,
R.string.uri_edit_text_label));
/* Email Address Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
R.string.email_address_edit_text_label));
/* Email Subject Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT,
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT,
R.string.email_subject_edit_text_label));
/* Email Content Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_TEXT_VARIATION_EMAIL_CONTENT,
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_LONG_MESSAGE,
R.string.email_content_edit_text_label));
/* Person Name Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME,
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME,
R.string.person_name_edit_text_label));
/* Postal Address Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS,
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS,
R.string.postal_address_edit_text_label));
/* Password Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD,
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PASSWORD,
R.string.password_edit_text_label));
- /* Search String Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_TEXT_VARIATION_SEARCH_STRING,
- R.string.search_string_edit_text_label));
-
/* Web Edit Text */
- mLayout.addView(buildEntryView(EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT,
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT,
R.string.web_edit_text_label));
/* Signed Number Edit Text */
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
new file mode 100644
index 0000000..54ab57a
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
@@ -0,0 +1,50 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Full screen of EditTexts (Non-Scrollable, Pan&Scan)
+ */
+public class ManyEditTextActivityNoScrollPanScan extends Activity
+{
+ public static final int NUM_EDIT_TEXTS = 9;
+
+ private View mRootView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ mRootView = new LinearLayout(this);
+ ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+
+ for (int i=0; i<NUM_EDIT_TEXTS; i++)
+ {
+ final EditText editText = new EditText(this);
+ editText.setText(String.valueOf(i));
+ editText.setId(i);
+ ((LinearLayout) mRootView).addView(editText);
+ }
+ setContentView(mRootView);
+ this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
new file mode 100644
index 0000000..b228d34
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
@@ -0,0 +1,52 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Full screen of EditTexts (Scrollable, Pan&Scan)
+ */
+public class ManyEditTextActivityScrollPanScan extends Activity
+{
+ public static final int NUM_EDIT_TEXTS = 12;
+
+ private View mRootView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ mRootView = new ScrollView(this);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ for (int i=0; i<NUM_EDIT_TEXTS; i++)
+ {
+ final EditText editText = new EditText(this);
+ editText.setText(String.valueOf(i));
+ editText.setId(i);
+ layout.addView(editText);
+ }
+
+ ((ScrollView) mRootView).addView(layout);
+ setContentView(mRootView);
+ this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+} \ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
new file mode 100644
index 0000000..777fbae
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
@@ -0,0 +1,45 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.ScrollView;
+
+/*
+ * Full screen of EditTexts (Scrollable, Resize)
+ */
+public class ManyEditTextActivityScrollResize extends Activity
+{
+ public static final int NUM_EDIT_TEXTS = 12;
+
+ private View mRootView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ mRootView = new ScrollView(this);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ for (int i=0; i<NUM_EDIT_TEXTS; i++)
+ {
+ final EditText editText = new EditText(this);
+ editText.setText(String.valueOf(i));
+ editText.setId(i);
+ layout.addView(editText);
+ }
+
+ ((ScrollView) mRootView).addView(layout);
+ setContentView(mRootView);
+ this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+} \ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
new file mode 100644
index 0000000..88a3447
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
@@ -0,0 +1,56 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Debug;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Activity with non-EditText view selected initially
+ */
+public class OneEditTextActivityNotSelected extends Activity
+{
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ mRootView = new ScrollView(this);
+
+ EditText editText = new EditText(this);
+ Button button = new Button(this);
+ button.setText("The focus is here.");
+ button.setFocusableInTouchMode(true);
+ button.requestFocus();
+ mDefaultFocusedView = button;
+ layout.addView(button);
+ layout.addView(editText);
+
+ ((ScrollView) mRootView).addView(layout);
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
new file mode 100644
index 0000000..1b80263
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
@@ -0,0 +1,51 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Activity with EditText selected initially
+ */
+public class OneEditTextActivitySelected extends Activity
+{
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ mRootView = new ScrollView(this);
+
+ EditText editText = new EditText(this);
+ editText.requestFocus();
+ mDefaultFocusedView = editText;
+ layout.addView(editText);
+
+ ((ScrollView) mRootView).addView(layout);
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+}
diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk
new file mode 100755
index 0000000..0f1924c
--- /dev/null
+++ b/tests/ImfTest/tests/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := ImfTestTests
+
+LOCAL_INSTRUMENTATION_FOR := ImfTest
+
+include $(BUILD_PACKAGE)
diff --git a/tests/ImfTest/tests/AndroidManifest.xml b/tests/ImfTest/tests/AndroidManifest.xml
new file mode 100755
index 0000000..122d202
--- /dev/null
+++ b/tests/ImfTest/tests/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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 name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.imftest.tests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ This declares that this app uses the instrumentation test runner targeting
+ the package of com.android.imftest. To run the tests use the command:
+ "adb shell am instrument -w com.android.imftest.tests/android.test.InstrumentationTestRunner"
+ -->
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.imftest"
+ android:label="imf tests"/>
+
+</manifest>
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
new file mode 100755
index 0000000..a1c5fd2
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityNonScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityNonScrollablePanScan> {
+
+ public final String TAG = "BigEditTextActivityNonScrollablePanScanTests";
+
+ public BigEditTextActivityNonScrollablePanScanTests() {
+ super(BigEditTextActivityNonScrollablePanScan.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentPanScan() {
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getRootView();
+ View servedView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
new file mode 100755
index 0000000..2e0b0eb
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityNonScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityNonScrollableResize> {
+
+ public final String TAG = "BigEditTextActivityNonScrollableResizeTests";
+
+ public BigEditTextActivityNonScrollableResizeTests() {
+ super(BigEditTextActivityNonScrollableResize.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getRootView();
+ View servedView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
new file mode 100755
index 0000000..d3eefb5
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityScrollablePanScan> {
+
+ public final String TAG = "BigEditTextActivityScrollablePanScanTests";
+
+ public BigEditTextActivityScrollablePanScanTests() {
+ super(BigEditTextActivityScrollablePanScan.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getRootView();
+ View servedView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
new file mode 100755
index 0000000..5c40e6d
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityScrollableResize> {
+
+ public final String TAG = "BigEditTextActivityScrollableResizeTests";
+
+ public BigEditTextActivityScrollableResizeTests() {
+ super(BigEditTextActivityScrollableResize.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentPanScan() {
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BigEditTextActivityScrollableResize) mTargetActivity).getRootView();
+ View servedView = ((BigEditTextActivityScrollableResize) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
new file mode 100755
index 0000000..9a93133
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BottomEditTextActivityPanScanTests extends ImfBaseTestCase<BottomEditTextActivityPanScan> {
+
+ public final String TAG = "BottomEditTextActivityPanScanTests";
+
+ public BottomEditTextActivityPanScanTests() {
+ super(BottomEditTextActivityPanScan.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentPanScan() {
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BottomEditTextActivityPanScan) mTargetActivity).getRootView();
+ View servedView = ((BottomEditTextActivityPanScan) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
new file mode 100755
index 0000000..9a69fd5
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BottomEditTextActivityResizeTests extends ImfBaseTestCase<BottomEditTextActivityResize> {
+
+ public final String TAG = "BottomEditTextActivityResizeTests";
+
+ public BottomEditTextActivityResizeTests() {
+ super(BottomEditTextActivityResize.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentResize() {
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BottomEditTextActivityResize) mTargetActivity).getRootView();
+ View servedView = ((BottomEditTextActivityResize) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
new file mode 100755
index 0000000..ae900c3
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+
+
+public class ButtonActivityTest extends ImfBaseTestCase<ButtonActivity> {
+
+ final public String TAG = "ButtonActivityTest";
+
+ public ButtonActivityTest() {
+ super(ButtonActivity.class);
+ }
+
+ @LargeTest
+ public void testButtonActivatesIme() {
+
+ final Button button = (Button) mTargetActivity.findViewById(ButtonActivity.BUTTON_ID);
+
+ // Push button
+ // Bring the target EditText into focus.
+ mTargetActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ button.requestFocus();
+ }
+ });
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+
+ // Give it a couple seconds
+ pause(2000);
+
+ // We should have initialized imm.mServedView and imm.mCurrentTextBoxAttribute
+ assertTrue(mImm.isActive());
+ // imm.mServedInputConnection should be null since Button doesn't override onCreateInputConnection().
+ assertFalse(mImm.isAcceptingText());
+
+ destructiveCheckImeInitialState(mTargetActivity.getRootView(), button);
+
+ }
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
new file mode 100755
index 0000000..61dc611
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.app.Activity;
+import android.os.SystemClock;
+import android.test.InstrumentationTestCase;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+
+import com.android.imftest.R;
+
+public abstract class ImfBaseTestCase<T extends Activity> extends InstrumentationTestCase {
+
+ /*
+ * The amount of time we are willing to wait for the IME to appear after a user action
+ * before we give up and fail the test.
+ */
+ public final long WAIT_FOR_IME = 5000;
+
+ /*
+ * Unfortunately there is now way for us to know how tall the IME is,
+ * so we have to hard code a minimum and maximum value.
+ */
+ public final int IME_MIN_HEIGHT = 150;
+ public final int IME_MAX_HEIGHT = 300;
+
+ public final String TARGET_PACKAGE_NAME = "com.android.imftest";
+ protected InputMethodManager mImm;
+ protected T mTargetActivity;
+ protected boolean mExpectAutoPop;
+ private Class<T> mTargetActivityClass;
+
+ public ImfBaseTestCase(Class<T> activityClass) {
+ mTargetActivityClass = activityClass;
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mTargetActivity = launchActivity(TARGET_PACKAGE_NAME, mTargetActivityClass, null);
+ mExpectAutoPop = mTargetActivity.getResources().getBoolean(R.bool.def_expect_ime_autopop);
+ mImm = InputMethodManager.getInstance(mTargetActivity);
+ }
+
+ // Utility test methods
+ public void verifyEditTextAdjustment(final View editText, int rootViewHeight) {
+
+ int[] origLocation = new int[2];
+ int[] newLocation = new int[2];
+
+ // Tell the keyboard to go away.
+ mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
+
+ // Bring the target EditText into focus.
+ mTargetActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ editText.requestFocus();
+ }
+ });
+
+ // Get the original location of the EditText.
+ editText.getLocationOnScreen(origLocation);
+
+ // Tap the EditText to bring up the IME.
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+
+ // Wait until the EditText pops above the IME or until we hit the timeout.
+ editText.getLocationOnScreen(newLocation);
+ long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
+ while (newLocation[1] > rootViewHeight - IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
+ editText.getLocationOnScreen(newLocation);
+ pause(100);
+ }
+
+ assertTrue(newLocation[1] <= rootViewHeight - IME_MIN_HEIGHT);
+
+ // Tell the keyboard to go away.
+ mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
+ }
+
+ public void destructiveCheckImeInitialState(View rootView, View servedView) {
+ if (mExpectAutoPop && (mTargetActivity.getWindow().getAttributes().
+ softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+ assertTrue(destructiveCheckImeUp(rootView, servedView));
+ } else {
+ assertFalse(destructiveCheckImeUp(rootView, servedView));
+ }
+ }
+
+ public boolean destructiveCheckImeUp(View rootView, View servedView) {
+ int origHeight;
+ int newHeight;
+
+ origHeight = rootView.getHeight();
+
+ // Tell the keyboard to go away.
+ mImm.hideSoftInputFromWindow(servedView.getWindowToken(), 0);
+
+ // Give it five seconds to adjust
+ newHeight = rootView.getHeight();
+ long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
+ while (Math.abs(newHeight - origHeight) < IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
+ newHeight = rootView.getHeight();
+ }
+
+ return (Math.abs(origHeight - newHeight) >= IME_MIN_HEIGHT);
+ }
+
+ void pause(int millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ }
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
new file mode 100755
index 0000000..278efb1
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.app.Activity;
+import android.widget.EditText;
+
+
+public abstract class ManyEditTextActivityBaseTestCase<T extends Activity> extends ImfBaseTestCase<T> {
+
+ public ManyEditTextActivityBaseTestCase(Class<T> activityClass){
+ super(activityClass);
+ }
+
+ public abstract void testAllEditTextsAdjust();
+
+ public void verifyAllEditTextAdjustment(int numEditTexts, int rootViewHeight) {
+
+ for (int i = 0; i < numEditTexts; i++) {
+ final EditText lastEditText = (EditText) mTargetActivity.findViewById(i);
+ verifyEditTextAdjustment(lastEditText, rootViewHeight);
+ }
+
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
new file mode 100755
index 0000000..4f8d14e
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+
+public class ManyEditTextActivityNoScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityNoScrollPanScan> {
+
+ public final String TAG = "ManyEditTextActivityNoScrollPanScanTests";
+
+ public ManyEditTextActivityNoScrollPanScanTests() {
+ super(ManyEditTextActivityNoScrollPanScan.class);
+ }
+
+
+ @LargeTest
+ public void testAllEditTextsAdjust() {
+ verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
+ mTargetActivity.getRootView().getMeasuredHeight());
+ }
+}
diff --git a/location/java/com/android/internal/location/protocol/GlatlngMessageTypes.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
index b6a9086..7f98f7f 100644..100755
--- a/location/java/com/android/internal/location/protocol/GlatlngMessageTypes.java
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
@@ -14,19 +14,24 @@
* limitations under the License.
*/
-package com.android.internal.location.protocol;
+package com.android.imftest.samples;
-import com.google.common.io.protocol.ProtoBufType;
+import android.test.suitebuilder.annotation.LargeTest;
-public class GlatlngMessageTypes {
- public static final ProtoBufType GLAT_LNG = new ProtoBufType();
- static {
- GLAT_LNG
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_FIXED32,
- GLatLng.LAT_E7, null)
- .addElement(ProtoBufType.REQUIRED | ProtoBufType.TYPE_FIXED32,
- GLatLng.LNG_E7, null);
+public class ManyEditTextActivityScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollPanScan> {
+
+ public final String TAG = "ManyEditTextActivityScrollPanScanTests";
+
+
+ public ManyEditTextActivityScrollPanScanTests() {
+ super(ManyEditTextActivityScrollPanScan.class);
+ }
+
+ @LargeTest
+ public void testAllEditTextsAdjust() {
+ verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
+ mTargetActivity.getRootView().getMeasuredHeight());
+ }
- }
}
diff --git a/include/GLES/egltypes.h b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
index 698239b..68dae87 100644..100755
--- a/include/GLES/egltypes.h
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
@@ -14,34 +14,24 @@
* limitations under the License.
*/
-#ifndef ANDROID_EGL_TYPES_H
-#define ANDROID_EGL_TYPES_H
+package com.android.imftest.samples;
-#include <sys/types.h>
+import android.test.suitebuilder.annotation.LargeTest;
-#ifdef __cplusplus
-extern "C" {
-#endif
-typedef unsigned int EGLBoolean;
-typedef int32_t EGLint;
-typedef int EGLenum;
-typedef void *EGLDisplay;
-typedef void *EGLConfig;
-typedef void *EGLSurface;
-typedef void *EGLContext;
-typedef void *EGLClientBuffer;
+public class ManyEditTextActivityScrollResizeTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollResize> {
-#define EGL_DEFAULT_DISPLAY ((NativeDisplayType)0)
+ public final String TAG = "ManyEditTextActivityScrollResizeTests";
+
+
+ public ManyEditTextActivityScrollResizeTests() {
+ super(ManyEditTextActivityScrollResize.class);
+ }
-#define EGL_NO_CONTEXT ((EGLContext)0)
-#define EGL_NO_DISPLAY ((EGLDisplay)0)
-#define EGL_NO_SURFACE ((EGLSurface)0)
+ @LargeTest
+ public void testAllEditTextsAdjust() {
+ verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
+ mTargetActivity.getRootView().getMeasuredHeight());
+ }
-
-#ifdef __cplusplus
}
-#endif
-
-
-#endif /* ANDROID_EGL_TYPES_H */
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
new file mode 100755
index 0000000..ed5b0c9
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+
+public class OneEditTextActivityNotSelectedTests extends ImfBaseTestCase<OneEditTextActivityNotSelected> {
+
+ public final String TAG = "OneEditTextActivityNotSelectedTests";
+
+ public OneEditTextActivityNotSelectedTests() {
+ super(OneEditTextActivityNotSelected.class);
+ }
+
+ @LargeTest
+ public void testSoftKeyboardNoAutoPop() {
+
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ assertFalse(mImm.isAcceptingText());
+
+ View rootView = ((OneEditTextActivityNotSelected) mTargetActivity).getRootView();
+ View servedView = ((OneEditTextActivityNotSelected) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
new file mode 100755
index 0000000..42fcd66
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.KeyEvent;
+import android.view.View;
+
+
+public class OneEditTextActivitySelectedTests extends ImfBaseTestCase<OneEditTextActivitySelected> {
+
+ public final String TAG = "OneEditTextActivitySelectedTests";
+
+ public OneEditTextActivitySelectedTests() {
+ super(OneEditTextActivitySelected.class);
+ }
+
+ @LargeTest
+ public void testSoftKeyboardAutoPop() {
+
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ assertTrue(mImm.isAcceptingText());
+
+ View rootView = ((OneEditTextActivitySelected) mTargetActivity).getRootView();
+ View servedView = ((OneEditTextActivitySelected) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/SmokeTest/tests/AndroidManifest.xml b/tests/SmokeTest/tests/AndroidManifest.xml
index 20b33ee..517eb1e 100644
--- a/tests/SmokeTest/tests/AndroidManifest.xml
+++ b/tests/SmokeTest/tests/AndroidManifest.xml
@@ -25,8 +25,6 @@
<uses-library android:name="android.test.runner" />
</application>
- <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
-
<!--
This declares that this app uses the instrumentation test runner targeting
the package of com.android.smoketest. To run the tests use the command:
diff --git a/tests/StatusBar/Android.mk b/tests/StatusBar/Android.mk
index 44f5099..18fcad0 100644
--- a/tests/StatusBar/Android.mk
+++ b/tests/StatusBar/Android.mk
@@ -1,7 +1,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := test
+LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index e1a0e7d..264fcdd 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -21,6 +21,7 @@ import android.app.PendingIntent;
import android.widget.ArrayAdapter;
import android.view.View;
import android.widget.ListView;
+import android.content.ContentResolver;
import android.content.Intent;
import android.app.Notification;
import android.app.NotificationManager;
@@ -188,7 +189,8 @@ public class NotificationTestList extends TestActivity
{
Notification n = new Notification();
n.sound = Uri.parse(
- "android.resource://com.android.notificationtest/raw/ringer");
+ ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer");
Log.d(TAG, "n.sound=" + n.sound);
mNM.notify(1, n);
diff --git a/tests/GadgetHost/Android.mk b/tests/appwidgets/AppWidgetHostTest/Android.mk
index 1d88db8..1bb1e54 100644
--- a/tests/GadgetHost/Android.mk
+++ b/tests/appwidgets/AppWidgetHostTest/Android.mk
@@ -5,7 +5,7 @@ LOCAL_MODULE_TAGS := user
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := GadgetHost
+LOCAL_PACKAGE_NAME := AppWidgetHostTest
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml b/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml
new file mode 100644
index 0000000..bf6a7cb
--- /dev/null
+++ b/tests/appwidgets/AppWidgetHostTest/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.appwidgethost">
+ <uses-permission android:name="android.permission.VIBRATE" />
+
+ <application>
+ <activity android:name="AppWidgetHostActivity" android:label="_AppWidgetHost">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="TestAppWidgetConfigure" android:label="Configure TestAppWidgetProvider">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <!-- BEGIN_INCLUDE(AppWidgetProvider) -->
+ <receiver android:name="TestAppWidgetProvider"
+ android:label="@string/oh_hai"
+ android:icon="@drawable/oh_hai_icon"
+ >
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+ <meta-data android:name="android.appwidget.provider"
+ android:resource="@xml/appwidget_info"
+ />
+ </receiver>
+ <!-- END_INCLUDE(AppWidgetProvider) -->
+
+ </application>
+</manifest>
diff --git a/tests/appwidgets/AppWidgetHostTest/res/drawable/oh_hai_icon.png b/tests/appwidgets/AppWidgetHostTest/res/drawable/oh_hai_icon.png
new file mode 100644
index 0000000..30ff267
--- /dev/null
+++ b/tests/appwidgets/AppWidgetHostTest/res/drawable/oh_hai_icon.png
Binary files differ
diff --git a/tests/GadgetHost/res/layout/gadget_host.xml b/tests/appwidgets/AppWidgetHostTest/res/layout/appwidget_host.xml
index 824cc44..e5c3b28 100644
--- a/tests/GadgetHost/res/layout/gadget_host.xml
+++ b/tests/appwidgets/AppWidgetHostTest/res/layout/appwidget_host.xml
@@ -22,7 +22,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/gadget_view_title"
+ android:text="@string/appwidget_view_title"
/>
<ScrollView
@@ -31,17 +31,18 @@
android:layout_weight="1"
>
- <com.android.gadgethost.GadgetContainerView
- android:id="@+id/gadget_container"
+ <com.android.tests.appwidgethost.AppWidgetContainerView
+ android:id="@+id/appwidget_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:orientation="vertical"
/>
</ScrollView>
<Button
- android:id="@+id/add_gadget"
- android:text="@string/add_gadget"
+ android:id="@+id/add_appwidget"
+ android:text="@string/add_appwidget"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
diff --git a/tests/GadgetHost/res/layout/test_gadget.xml b/tests/appwidgets/AppWidgetHostTest/res/layout/test_appwidget.xml
index 0fb7929..4d483c7 100644
--- a/tests/GadgetHost/res/layout/test_gadget.xml
+++ b/tests/appwidgets/AppWidgetHostTest/res/layout/test_appwidget.xml
@@ -15,6 +15,7 @@
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/oh_hai_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/oh_hai"
diff --git a/tests/appwidgets/AppWidgetHostTest/res/layout/test_appwidget_configure.xml b/tests/appwidgets/AppWidgetHostTest/res/layout/test_appwidget_configure.xml
new file mode 100644
index 0000000..0d9b983
--- /dev/null
+++ b/tests/appwidgets/AppWidgetHostTest/res/layout/test_appwidget_configure.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ >
+
+ <TextView
+ android:id="@+id/oh_hai_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/oh_hai"
+ />
+
+ <EditText
+ android:id="@+id/edit_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ />
+
+ <Button
+ android:id="@+id/save_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/save"
+ />
+
+
+</LinearLayout>
diff --git a/tests/appwidgets/AppWidgetHostTest/res/values/strings.xml b/tests/appwidgets/AppWidgetHostTest/res/values/strings.xml
new file mode 100644
index 0000000..8a617e7
--- /dev/null
+++ b/tests/appwidgets/AppWidgetHostTest/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<resources>
+ <string name="appwidget_view_title">Widget Test</string>
+ <string name="add_appwidget">Add Widget</string>
+ <string name="oh_hai">Oh hai.</string>
+ <string name="delete_appwidget">Delete</string>
+ <string name="save">Save</string>
+</resources>
+
diff --git a/tests/appwidgets/AppWidgetHostTest/res/xml/appwidget_info.xml b/tests/appwidgets/AppWidgetHostTest/res/xml/appwidget_info.xml
new file mode 100644
index 0000000..f12ba16
--- /dev/null
+++ b/tests/appwidgets/AppWidgetHostTest/res/xml/appwidget_info.xml
@@ -0,0 +1,10 @@
+<!-- BEGIN_INCLUDE(AppWidgetProviderInfo) -->
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="40dp"
+ android:minHeight="30dp"
+ android:updatePeriodMillis="86400000"
+ android:initialLayout="@layout/test_appwidget"
+ android:configure="com.android.tests.appwidgethost.TestAppWidgetConfigure"
+ >
+</appwidget-provider>
+<!-- END_INCLUDE(AppWidgetProviderInfo) -->
diff --git a/tests/GadgetHost/src/com/android/gadgethost/GadgetContainerView.java b/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetContainerView.java
index 159cbe4..b08ba52 100644
--- a/tests/GadgetHost/src/com/android/gadgethost/GadgetContainerView.java
+++ b/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetContainerView.java
@@ -14,19 +14,19 @@
* limitations under the License.
*/
-package com.android.gadgethost;
+package com.android.tests.appwidgethost;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
-public class GadgetContainerView extends LinearLayout
+public class AppWidgetContainerView extends LinearLayout
{
- public GadgetContainerView(Context context) {
+ public AppWidgetContainerView(Context context) {
super(context);
}
- public GadgetContainerView(Context context, AttributeSet attrs) {
+ public AppWidgetContainerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
diff --git a/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java b/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java
new file mode 100644
index 0000000..2fb2d1d
--- /dev/null
+++ b/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java
@@ -0,0 +1,198 @@
+/*
+ * 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.tests.appwidgethost;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetProviderInfo;
+import android.appwidget.AppWidgetManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.LinearLayout;
+
+public class AppWidgetHostActivity extends Activity
+{
+ static final String TAG = "AppWidgetHostActivity";
+
+ static final int DISCOVER_APPWIDGET_REQUEST = 1;
+ static final int CONFIGURE_APPWIDGET_REQUEST = 2;
+ static final int HOST_ID = 1234;
+
+ static final String PENDING_APPWIDGET_ID = "pending_appwidget";
+
+ AppWidgetManager mAppWidgetManager;
+ AppWidgetContainerView mAppWidgetContainer;
+
+ public AppWidgetHostActivity() {
+ mAppWidgetManager = AppWidgetManager.getInstance(this);
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.appwidget_host);
+
+ findViewById(R.id.add_appwidget).setOnClickListener(mOnClickListener);
+ mAppWidgetContainer = (AppWidgetContainerView)findViewById(R.id.appwidget_container);
+
+ if (false) {
+ if (false) {
+ mHost.deleteHost();
+ } else {
+ AppWidgetHost.deleteAllHosts();
+ }
+ }
+ }
+
+ View.OnClickListener mOnClickListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ discoverAppWidget(DISCOVER_APPWIDGET_REQUEST);
+ }
+ };
+
+ void discoverAppWidget(int requestCode) {
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mHost.allocateAppWidgetId());
+ startActivityForResult(intent, requestCode);
+ }
+
+ void configureAppWidget(int requestCode, int appWidgetId, ComponentName configure) {
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
+ intent.setComponent(configure);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ SharedPreferences.Editor prefs = getPreferences(0).edit();
+ prefs.putInt(PENDING_APPWIDGET_ID, appWidgetId);
+ prefs.commit();
+ startActivityForResult(intent, requestCode);
+ }
+
+ void handleAppWidgetPickResult(int resultCode, Intent intent) {
+ // BEGIN_INCLUDE(getExtra_EXTRA_APPWIDGET_ID)
+ Bundle extras = intent.getExtras();
+ int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
+ // END_INCLUDE(getExtra_EXTRA_APPWIDGET_ID)
+ if (resultCode == RESULT_OK) {
+ AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+
+ if (appWidget.configure != null) {
+ // configure the AppWidget if we should
+ configureAppWidget(CONFIGURE_APPWIDGET_REQUEST, appWidgetId, appWidget.configure);
+ } else {
+ // just add it as is
+ addAppWidgetView(appWidgetId, appWidget);
+ }
+ } else {
+ mHost.deleteAppWidgetId(appWidgetId);
+ }
+ }
+
+ void handleAppWidgetConfigureResult(int resultCode, Intent data) {
+ int appWidgetId = getPreferences(0).getInt(PENDING_APPWIDGET_ID, -1);
+ Log.d(TAG, "resultCode=" + resultCode + " appWidgetId=" + appWidgetId);
+ if (appWidgetId < 0) {
+ Log.w(TAG, "was no preference for PENDING_APPWIDGET_ID");
+ return;
+ }
+ if (resultCode == RESULT_OK) {
+ AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+ addAppWidgetView(appWidgetId, appWidget);
+ } else {
+ mHost.deleteAppWidgetId(appWidgetId);
+ }
+ }
+
+ void addAppWidgetView(int appWidgetId, AppWidgetProviderInfo appWidget) {
+ // Inflate the AppWidget's RemoteViews
+ AppWidgetHostView view = mHost.createView(this, appWidgetId, appWidget);
+
+ // Add it to the list
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.FILL_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ mAppWidgetContainer.addView(view, layoutParams);
+
+ registerForContextMenu(view);
+ }
+
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case DISCOVER_APPWIDGET_REQUEST:
+ handleAppWidgetPickResult(resultCode, data);
+ break;
+ case CONFIGURE_APPWIDGET_REQUEST:
+ handleAppWidgetConfigureResult(resultCode, data);
+ }
+ }
+
+ protected void onStart() {
+ super.onStart();
+ mHost.startListening();
+ }
+
+ protected void onStop() {
+ super.onStop();
+ mHost.stopListening();
+ }
+
+ public void onCreateContextMenu(ContextMenu menu, View v,
+ ContextMenu.ContextMenuInfo menuInfo) {
+ menu.add(ContextMenu.NONE, R.string.delete_appwidget, ContextMenu.NONE,
+ R.string.delete_appwidget);
+ }
+
+ public boolean onContextItemSelected(MenuItem item) {
+ MyAppWidgetView view = (MyAppWidgetView)item.getMenuInfo();
+ switch (item.getItemId()) {
+ case R.string.delete_appwidget:
+ Log.d(TAG, "delete! " + view.appWidgetId);
+ mAppWidgetContainer.removeView(view);
+ mHost.deleteAppWidgetId(view.appWidgetId);
+ break;
+ }
+
+ return true;
+ }
+
+ class MyAppWidgetView extends AppWidgetHostView implements ContextMenu.ContextMenuInfo {
+ int appWidgetId;
+
+ MyAppWidgetView(int appWidgetId) {
+ super(AppWidgetHostActivity.this);
+ this.appWidgetId = appWidgetId;
+ }
+
+ public ContextMenu.ContextMenuInfo getContextMenuInfo() {
+ return this;
+ }
+ }
+
+ AppWidgetHost mHost = new AppWidgetHost(this, HOST_ID) {
+ protected AppWidgetHostView onCreateView(Context context, int appWidgetId, AppWidgetProviderInfo appWidget) {
+ return new MyAppWidgetView(appWidgetId);
+ }
+ };
+}
+
+
diff --git a/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetConfigure.java b/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetConfigure.java
new file mode 100644
index 0000000..9a6099a
--- /dev/null
+++ b/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetConfigure.java
@@ -0,0 +1,57 @@
+/*
+ * 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.tests.appwidgethost;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.EditText;
+
+public class TestAppWidgetConfigure extends Activity {
+ static final String TAG = "TestAppWidgetConfigure";
+
+ public TestAppWidgetConfigure() {
+ super();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.test_appwidget_configure);
+
+ findViewById(R.id.save_button).setOnClickListener(mOnClickListener);
+ }
+
+ View.OnClickListener mOnClickListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ String text = ((EditText)findViewById(R.id.edit_text)).getText().toString();
+ Log.d(TAG, "text is '" + text + '\'');
+ SharedPreferences.Editor prefs = getSharedPreferences(TestAppWidgetProvider.PREFS_NAME, 0)
+ .edit();
+ prefs.putString(TestAppWidgetProvider.PREF_PREFIX_KEY, text);
+ prefs.commit();
+ setResult(RESULT_OK);
+ finish();
+ }
+ };
+
+}
+
+
diff --git a/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java b/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java
new file mode 100644
index 0000000..b5d91d4
--- /dev/null
+++ b/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java
@@ -0,0 +1,69 @@
+/*
+ * 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.tests.appwidgethost;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.appwidget.AppWidgetManager;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+public class TestAppWidgetProvider extends BroadcastReceiver {
+ static final String TAG = "TestAppWidgetProvider";
+
+ static final String PREFS_NAME = "com.android.tests.appwidgethost.TestAppWidgetProvider";
+ static final String PREF_PREFIX_KEY = "prefix";
+
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.d(TAG, "intent=" + intent);
+
+ if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
+ Log.d(TAG, "ENABLED");
+ }
+ else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
+ Log.d(TAG, "DISABLED");
+ }
+ else if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
+ Log.d(TAG, "UPDATE");
+ // BEGIN_INCLUDE(getExtra_EXTRA_APPWIDGET_IDS)
+ Bundle extras = intent.getExtras();
+ int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
+ // END_INCLUDE(getExtra_EXTRA_APPWIDGET_IDS)
+
+ SharedPreferences prefs = context.getSharedPreferences(
+ TestAppWidgetProvider.PREFS_NAME, 0);
+ String prefix = prefs.getString(PREF_PREFIX_KEY, "hai");
+
+ AppWidgetManager gm = AppWidgetManager.getInstance(context);
+ RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.test_appwidget);
+ views.setTextViewText(R.id.oh_hai_text, prefix + ": " + SystemClock.elapsedRealtime());
+ if (false) {
+ gm.updateAppWidget(appWidgetIds, views);
+ } else {
+ gm.updateAppWidget(new ComponentName("com.android.tests.appwidgethost",
+ "com.android.tests.appwidgethost.TestAppWidgetProvider"), views);
+ }
+ }
+ }
+}
+
diff --git a/tests/appwidgets/AppWidgetProviderTest/Android.mk b/tests/appwidgets/AppWidgetProviderTest/Android.mk
new file mode 100644
index 0000000..c87a0f2
--- /dev/null
+++ b/tests/appwidgets/AppWidgetProviderTest/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := AppWidgetProvider
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml b/tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml
new file mode 100644
index 0000000..ec4d583
--- /dev/null
+++ b/tests/appwidgets/AppWidgetProviderTest/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.appwidgetprovider">
+ <uses-permission android:name="android.permission.VIBRATE" />
+
+ <application>
+ <receiver android:name="TestAppWidgetProvider">
+ <intent-filter>
+ <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+ </intent-filter>
+ <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget_info" />
+ </receiver>
+ </application>
+</manifest>
diff --git a/tests/appwidgets/AppWidgetProviderTest/res/layout/test_appwidget.xml b/tests/appwidgets/AppWidgetProviderTest/res/layout/test_appwidget.xml
new file mode 100644
index 0000000..e0a416e
--- /dev/null
+++ b/tests/appwidgets/AppWidgetProviderTest/res/layout/test_appwidget.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/oh_hai_text"
+ android:layout_width="150dp"
+ android:layout_height="150dp"
+ android:text="@string/oh_hai"
+ android:background="#8fff"
+ android:textColor="#000"
+ android:textStyle="bold"
+/>
+
diff --git a/tests/GadgetHost/res/values/strings.xml b/tests/appwidgets/AppWidgetProviderTest/res/values/strings.xml
index d94cfbd..e51299b 100644
--- a/tests/GadgetHost/res/values/strings.xml
+++ b/tests/appwidgets/AppWidgetProviderTest/res/values/strings.xml
@@ -15,8 +15,9 @@
-->
<resources>
- <string name="gadget_view_title">Gadget Test</string>
- <string name="add_gadget">Add Gadget</string>
+ <string name="appwidget_view_title">Widget Test</string>
+ <string name="add_appwidget">Add Widget</string>
<string name="oh_hai">Oh hai.</string>
+ <string name="delete_appwidget">Delete</string>
</resources>
diff --git a/tests/appwidgets/AppWidgetProviderTest/res/xml/appwidget_info.xml b/tests/appwidgets/AppWidgetProviderTest/res/xml/appwidget_info.xml
new file mode 100644
index 0000000..c133743
--- /dev/null
+++ b/tests/appwidgets/AppWidgetProviderTest/res/xml/appwidget_info.xml
@@ -0,0 +1,7 @@
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="150dp"
+ android:minHeight="150dp"
+ android:updatePeriodMillis="2000"
+ android:initialLayout="@layout/test_appwidget"
+ >
+</appwidget-provider>
diff --git a/tests/appwidgets/AppWidgetProviderTest/src/com/android/tests/appwidgetprovider/TestAppWidgetProvider.java b/tests/appwidgets/AppWidgetProviderTest/src/com/android/tests/appwidgetprovider/TestAppWidgetProvider.java
new file mode 100644
index 0000000..418be65
--- /dev/null
+++ b/tests/appwidgets/AppWidgetProviderTest/src/com/android/tests/appwidgetprovider/TestAppWidgetProvider.java
@@ -0,0 +1,60 @@
+/*
+ * 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.tests.appwidgetprovider;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.appwidget.AppWidgetManager;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+public class TestAppWidgetProvider extends BroadcastReceiver {
+
+ static final String TAG = "TestAppWidgetProvider";
+
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.d(TAG, "intent=" + intent);
+
+ if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
+ Log.d(TAG, "ENABLED");
+ }
+ else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
+ Log.d(TAG, "DISABLED");
+ }
+ else if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
+ Log.d(TAG, "UPDATE");
+ Bundle extras = intent.getExtras();
+ int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
+
+ AppWidgetManager gm = AppWidgetManager.getInstance(context);
+ RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.test_appwidget);
+ views.setTextViewText(R.id.oh_hai_text, "hai: " + SystemClock.elapsedRealtime());
+ if (false) {
+ gm.updateAppWidget(appWidgetIds, views);
+ } else {
+ gm.updateAppWidget(new ComponentName("com.android.tests.appwidgetprovider",
+ "com.android.tests.appwidgetprovider.TestAppWidgetProvider"), views);
+ }
+ }
+ }
+}
+
diff --git a/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java b/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java
index 4994845..0368651 100644
--- a/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java
+++ b/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java
@@ -17,6 +17,7 @@
package com.android.internal.policy.impl;
import android.content.Context;
+
import com.android.internal.telephony.SimCard;
import android.test.AndroidTestCase;
import android.view.View;
@@ -112,6 +113,11 @@ public class LockPatternKeyguardViewTest extends AndroidTestCase {
}
/** {@inheritDoc} */
+ public boolean needsInput() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
public void onPause() {
mOnPauseCount++;
}
@@ -149,8 +155,9 @@ public class LockPatternKeyguardViewTest extends AndroidTestCase {
- private TestableLockPatternKeyguardView(Context context, KeyguardUpdateMonitor updateMonitor, LockPatternUtils lockPatternUtils) {
- super(context, updateMonitor, lockPatternUtils);
+ private TestableLockPatternKeyguardView(Context context, KeyguardUpdateMonitor updateMonitor,
+ LockPatternUtils lockPatternUtils, KeyguardWindowController controller) {
+ super(context, updateMonitor, lockPatternUtils, controller);
}
@Override
@@ -214,7 +221,11 @@ public class LockPatternKeyguardViewTest extends AndroidTestCase {
mUpdateMonitor = new MockUpdateMonitor(getContext());
mLockPatternUtils = new MockLockPatternUtils();
- mLPKV = new TestableLockPatternKeyguardView(getContext(), mUpdateMonitor, mLockPatternUtils);
+ mLPKV = new TestableLockPatternKeyguardView(getContext(), mUpdateMonitor,
+ mLockPatternUtils, new KeyguardWindowController() {
+ public void setNeedsInput(boolean needsInput) {
+ }
+ });
mKeyguardViewCallback = new MockKeyguardCallback();
mLPKV.setCallback(mKeyguardViewCallback);
}
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index a516a5a..0a4c68b 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -332,8 +332,8 @@ static status_t do_9patch(const char* imageName, image_info* image)
int H = image->height;
int i, j;
- int maxSizeXDivs = (W / 2 + 1) * sizeof(int32_t);
- int maxSizeYDivs = (H / 2 + 1) * sizeof(int32_t);
+ int maxSizeXDivs = W * sizeof(int32_t);
+ int maxSizeYDivs = H * sizeof(int32_t);
int32_t* xDivs = (int32_t*) malloc(maxSizeXDivs);
int32_t* yDivs = (int32_t*) malloc(maxSizeYDivs);
uint8_t numXDivs = 0;
@@ -600,10 +600,22 @@ static bool patch_equals(Res_png_9patch& patch1, Res_png_9patch& patch2) {
return true;
}
-static void dump_image(int w, int h, png_bytepp rows, int bpp)
+static void dump_image(int w, int h, png_bytepp rows, int color_type)
{
int i, j, rr, gg, bb, aa;
+ int bpp;
+ if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY) {
+ bpp = 1;
+ } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+ bpp = 2;
+ } else if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
+ // We use a padding byte even when there is no alpha
+ bpp = 4;
+ } else {
+ printf("Unknown color type %d.\n", color_type);
+ }
+
for (j = 0; j < h; j++) {
png_bytep row = rows[j];
for (i = 0; i < w; i++) {
@@ -640,7 +652,7 @@ static void dump_image(int w, int h, png_bytepp rows, int bpp)
#define MAX(a,b) ((a)>(b)?(a):(b))
#define ABS(a) ((a)<0?-(a):(a))
-static void analyze_image(image_info &imageInfo, int grayscaleTolerance,
+static void analyze_image(const char *imageName, image_info &imageInfo, int grayscaleTolerance,
png_colorp rgbPalette, png_bytep alphaPalette,
int *paletteEntries, bool *hasTransparency, int *colorType,
png_bytepp outRows)
@@ -662,7 +674,7 @@ static void analyze_image(image_info &imageInfo, int grayscaleTolerance,
// 3. There are no more than 256 distinct RGBA colors
// NOISY(printf("Initial image data:\n"));
- // dump_image(w, h, imageInfo.rows, 4);
+ // dump_image(w, h, imageInfo.rows, PNG_COLOR_TYPE_RGB_ALPHA);
for (j = 0; j < h; j++) {
png_bytep row = imageInfo.rows[j];
@@ -763,7 +775,7 @@ static void analyze_image(image_info &imageInfo, int grayscaleTolerance,
*colorType = PNG_COLOR_TYPE_PALETTE;
} else {
if (maxGrayDeviation <= grayscaleTolerance) {
- NOISY(printf("Forcing image to gray (max deviation = %d)\n", maxGrayDeviation));
+ printf("%s: forcing image to gray (max deviation = %d)\n", imageName, maxGrayDeviation);
*colorType = isOpaque ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_GRAY_ALPHA;
} else {
*colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
@@ -845,8 +857,16 @@ static void write_png(const char* imageName,
bool hasTransparency;
int paletteEntries;
- analyze_image(imageInfo, grayscaleTolerance, rgbPalette, alphaPalette,
+ analyze_image(imageName, imageInfo, grayscaleTolerance, rgbPalette, alphaPalette,
&paletteEntries, &hasTransparency, &color_type, outRows);
+
+ // If the image is a 9-patch, we need to preserve it as a ARGB file to make
+ // sure the pixels will not be pre-dithered/clamped until we decide they are
+ if (imageInfo.is9Patch && (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)) {
+ color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ }
+
switch (color_type) {
case PNG_COLOR_TYPE_PALETTE:
NOISY(printf("Image %s has %d colors%s, using PNG_COLOR_TYPE_PALETTE\n",
@@ -910,21 +930,8 @@ static void write_png(const char* imageName,
}
png_write_image(write_ptr, rows);
-// int bpp;
-// if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY) {
-// bpp = 1;
-// } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
-// bpp = 2;
-// } else if (color_type == PNG_COLOR_TYPE_RGB) {
-// bpp = 4;
-// } else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
-// bpp = 4;
-// } else {
-// printf("Uknknown color type %d, exiting.\n", color_type);
-// exit(1);
-// }
// NOISY(printf("Final image data:\n"));
-// dump_image(imageInfo.width, imageInfo.height, rows, bpp);
+// dump_image(imageInfo.width, imageInfo.height, rows, color_type);
png_write_end(write_ptr, write_info);
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index ee0dbad..71b1a3c 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -146,9 +146,11 @@ int handleCommand(Bundle* bundle)
*/
int main(int argc, char* const argv[])
{
+ char *prog = argv[0];
Bundle bundle;
bool wantUsage = false;
int result = 1; // pessimistically assume an error.
+ int tolerance = 0;
/* default to compression */
bundle.setCompressionMethod(ZipEntry::kCompressDeflated);
@@ -214,7 +216,9 @@ int main(int argc, char* const argv[])
wantUsage = true;
goto bail;
}
- bundle.setGrayscaleTolerance(atoi(argv[0]));
+ tolerance = atoi(argv[0]);
+ bundle.setGrayscaleTolerance(tolerance);
+ printf("%s: Images with deviation <= %d will be forced to grayscale.\n", prog, tolerance);
break;
case 'm':
bundle.setMakePackageDirs(true);
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index 5d9e140..eb7d6f5 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -5,6 +5,7 @@
//
#include "Main.h"
#include "AaptAssets.h"
+#include "ResourceTable.h"
#include <utils.h>
#include <utils/ZipFile.h>
@@ -190,11 +191,20 @@ bail:
ssize_t processAssets(Bundle* bundle, ZipFile* zip,
const sp<AaptAssets>& assets)
{
+ ResourceFilter filter;
+ status_t status = filter.parse(bundle->getConfigurations());
+ if (status != NO_ERROR) {
+ return -1;
+ }
+
ssize_t count = 0;
const size_t N = assets->getGroupEntries().size();
for (size_t i=0; i<N; i++) {
const AaptGroupEntry& ge = assets->getGroupEntries()[i];
+ if (!filter.match(ge.toParams())) {
+ continue;
+ }
ssize_t res = processAssets(bundle, zip, assets, ge);
if (res < 0) {
return res;
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index c438366..6f71a1e 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -644,6 +644,7 @@ status_t compileResourceFile(Bundle* bundle,
const String16 bool16("bool");
const String16 integer16("integer");
const String16 dimen16("dimen");
+ const String16 fraction16("fraction");
const String16 style16("style");
const String16 plurals16("plurals");
const String16 array16("array");
@@ -1022,6 +1023,10 @@ status_t compileResourceFile(Bundle* bundle,
curTag = &dimen16;
curType = dimen16;
curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_DIMENSION;
+ } else if (strcmp16(block.getElementName(&len), fraction16.string()) == 0) {
+ curTag = &fraction16;
+ curType = fraction16;
+ curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_FRACTION;
} else if (strcmp16(block.getElementName(&len), bag16.string()) == 0) {
curTag = &bag16;
curIsBag = true;
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 2ea453c..d476567 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -220,9 +220,9 @@ moveon:
spanStack.pop();
if (empty) {
- fprintf(stderr, "%s:%d: WARNING: empty '%s' span found for at text '%s'\n",
+ fprintf(stderr, "%s:%d: WARNING: empty '%s' span found in text '%s'\n",
fileName, inXml->getLineNumber(),
- String8(*outString).string(), String8(spanTag).string());
+ String8(spanTag).string(), String8(*outString).string());
}
} else if (code == ResXMLTree::START_NAMESPACE) {
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index dc61567..fc658f5 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -610,6 +610,62 @@ generate_dep_file(const Options& options)
}
// ==========================================================
+static string
+generate_outputFileName(const Options& options, const document_item_type* items)
+{
+ string result;
+
+ // items has already been checked to have only one interface.
+ if (items->item_type == INTERFACE_TYPE) {
+ interface_type* type = (interface_type*)items;
+
+ // create the path to the destination folder based on the
+ // interface package name
+ result = options.outputBaseFolder;
+ result += OS_PATH_SEPARATOR;
+
+ string package = type->package;
+ size_t len = package.length();
+ for (size_t i=0; i<len; i++) {
+ if (package[i] == '.') {
+ package[i] = OS_PATH_SEPARATOR;
+ }
+ }
+
+ result += package;
+
+ // add the filename by replacing the .aidl extension to .java
+ const char* p = strchr(type->name.data, '.');
+ len = p ? p-type->name.data : strlen(type->name.data);
+
+ result += OS_PATH_SEPARATOR;
+ result.append(type->name.data, len);
+ result += ".java";
+ }
+
+ return result;
+}
+
+// ==========================================================
+static void
+check_outputFileName(const string& path) {
+ size_t len = path.length();
+ for (size_t i=0; i<len ; i++) {
+ if (path[i] == OS_PATH_SEPARATOR) {
+ string p = path.substr(0, i);
+ if (access(path.data(), F_OK) != 0) {
+#ifdef HAVE_MS_C_RUNTIME
+ _mkdir(p.data());
+#else
+ mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+#endif
+ }
+ }
+ }
+}
+
+
+// ==========================================================
static int
parse_preprocessed_file(const string& filename)
{
@@ -617,7 +673,7 @@ parse_preprocessed_file(const string& filename)
FILE* f = fopen(filename.c_str(), "rb");
if (f == NULL) {
- fprintf(stderr, "aidl: can't open preprocessd file: %s\n",
+ fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
filename.c_str());
return 1;
}
@@ -804,7 +860,17 @@ compile_aidl(const Options& options)
generate_dep_file(options);
}
- err = generate_java(options.outputFileName, options.inputFileName.c_str(),
+ // if needed, generate the outputFileName from the outputBaseFolder
+ string outputFileName = options.outputFileName;
+ if (outputFileName.length() == 0 &&
+ options.outputBaseFolder.length() > 0) {
+ outputFileName = generate_outputFileName(options, mainDoc);
+ }
+
+ // make sure the folders of the output file all exists
+ check_outputFileName(outputFileName);
+
+ err = generate_java(outputFileName, options.inputFileName.c_str(),
(interface_type*)mainDoc);
return err;
diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp
index 57b10ae..0aa7db2 100644
--- a/tools/aidl/options.cpp
+++ b/tools/aidl/options.cpp
@@ -13,16 +13,19 @@ usage()
" aidl --preprocess OUTPUT INPUT...\n"
"\n"
"OPTIONS:\n"
- " -I<DIR> search path for import statements.\n"
- " -d<FILE> generate dependency file.\n"
- " -p<FILE> file created by --preprocess to import.\n"
- " -b fail when trying to compile a parcelable.\n"
+ " -I<DIR> search path for import statements.\n"
+ " -d<FILE> generate dependency file.\n"
+ " -p<FILE> file created by --preprocess to import.\n"
+ " -o<FOLDER> base output folder for generated files.\n"
+ " -b fail when trying to compile a parcelable.\n"
"\n"
"INPUT:\n"
" An aidl interface file.\n"
"\n"
"OUTPUT:\n"
- " The generated interface files. If omitted, the input filename is used, with the .aidl extension changed to a .java extension.\n"
+ " The generated interface files.\n"
+ " If omitted and the -o option is not used, the input filename is used, with the .aidl extension changed to a .java extension.\n"
+ " If the -o option is used, the generated files will be placed in the base output folder, under their package folder\n"
);
return 1;
}
@@ -78,6 +81,14 @@ parse_options(int argc, const char* const* argv, Options *options)
return usage();
}
}
+ else if (s[1] == 'o') {
+ if (len > 2) {
+ options->outputBaseFolder = s+2;
+ } else {
+ fprintf(stderr, "-o option (%d) requires a path.\n", i);
+ return usage();
+ }
+ }
else if (len == 2 && s[1] == 'b') {
options->failOnParcelable = true;
}
@@ -111,7 +122,7 @@ parse_options(int argc, const char* const* argv, Options *options)
if (i < argc) {
options->outputFileName = argv[i];
i++;
- } else {
+ } else if (options->outputBaseFolder.length() == 0) {
// copy input into output and change the extension from .aidl to .java
options->outputFileName = options->inputFileName;
string::size_type pos = options->outputFileName.size()-5;
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
index e7e62ec..d88d988 100644
--- a/tools/aidl/options.h
+++ b/tools/aidl/options.h
@@ -21,6 +21,7 @@ struct Options
vector<string> preprocessedFiles;
string inputFileName;
string outputFileName;
+ string outputBaseFolder;
string depFileName;
vector<string> filesToPreprocess;
diff --git a/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java b/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
index 0810d29..df1876d 100644
--- a/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
+++ b/tools/layoutlib/api/src/com/android/layoutlib/api/ILayoutBridge.java
@@ -24,28 +24,35 @@ import java.util.Map;
* <p/>
* <p/>{@link #getApiLevel()} gives the ability to know which methods are available.
* <p/>
+ * Changes in API level 3:
+ * <ul>
+ * <li>{@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * <li> deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * </ul>
* Changes in API level 2:
* <ul>
* <li>{@link #getApiLevel()}</li>
- * <li>{@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)},
- * deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, String, Map, Map, IProjectCallback, ILayoutLog)}.</li>
+ * <li>{@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}</li>
+ * <li>deprecated {@link #computeLayout(IXmlPullParser, Object, int, int, String, Map, Map, IProjectCallback, ILayoutLog)}</li>
* </ul>
*/
public interface ILayoutBridge {
- final int API_CURRENT = 2;
+ final int API_CURRENT = 3;
/**
* Returns the API level of the layout library.
* While no methods will ever be removed, some may become deprecated, and some new ones
* will appear.
+ * <p/>If calling this method throws an {@link AbstractMethodError}, then the API level
+ * should be considered to be 1.
*/
int getApiLevel();
/**
* Initializes the Bridge object.
* @param fontOsLocation the location of the fonts.
- * @param enumValueMap map attrName => { map enumFlagName => Integer value }.
+ * @param enumValueMap map attrName => { map enumFlagName => Integer value }.
* @return true if success.
* @since 1
*/
@@ -56,8 +63,11 @@ public interface ILayoutBridge {
* @param layoutDescription the {@link IXmlPullParser} letting the LayoutLib Bridge visit the
* layout file.
* @param projectKey An Object identifying the project. This is used for the cache mechanism.
- * @param screenWidth
- * @param screenHeight
+ * @param screenWidth the screen width
+ * @param screenHeight the screen height
+ * @param density the density factor for the screen.
+ * @param xdpi the screen actual dpi in X
+ * @param ydpi the screen actual dpi in Y
* @param themeName The name of the theme to use.
* @param isProjectTheme true if the theme is a project theme, false if it is a framework theme.
* @param projectResources the resources of the project. The map contains (String, map) pairs
@@ -72,8 +82,41 @@ public interface ILayoutBridge {
* the project.
* @param logger the object responsible for displaying warning/errors to the user.
* @return an {@link ILayoutResult} object that contains the result of the layout.
+ * @since 3
+ */
+ ILayoutResult computeLayout(IXmlPullParser layoutDescription,
+ Object projectKey,
+ int screenWidth, int screenHeight, int density, float xdpi, float ydpi,
+ String themeName, boolean isProjectTheme,
+ Map<String, Map<String, IResourceValue>> projectResources,
+ Map<String, Map<String, IResourceValue>> frameworkResources,
+ IProjectCallback projectCallback, ILayoutLog logger);
+
+ /**
+ * Computes and renders a layout
+ * @param layoutDescription the {@link IXmlPullParser} letting the LayoutLib Bridge visit the
+ * layout file.
+ * @param projectKey An Object identifying the project. This is used for the cache mechanism.
+ * @param screenWidth the screen width
+ * @param screenHeight the screen height
+ * @param themeName The name of the theme to use.
+ * @param isProjectTheme true if the theme is a project theme, false if it is a framework theme.
+ * @param projectResources the resources of the project. The map contains (String, map) pairs
+ * where the string is the type of the resource reference used in the layout file, and the
+ * map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
+ * and the value is the resource value.
+ * @param frameworkResources the framework resources. The map contains (String, map) pairs
+ * where the string is the type of the resource reference used in the layout file, and the map
+ * contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
+ * value is the resource value.
+ * @param projectCallback The {@link IProjectCallback} object to get information from
+ * the project.
+ * @param logger the object responsible for displaying warning/errors to the user.
+ * @return an {@link ILayoutResult} object that contains the result of the layout.
+ * @deprecated Use {@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}
* @since 2
*/
+ @Deprecated
ILayoutResult computeLayout(IXmlPullParser layoutDescription,
Object projectKey,
int screenWidth, int screenHeight, String themeName, boolean isProjectTheme,
@@ -102,7 +145,7 @@ public interface ILayoutBridge {
* the project.
* @param logger the object responsible for displaying warning/errors to the user.
* @return an {@link ILayoutResult} object that contains the result of the layout.
- * @deprecated Use {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}.
+ * @deprecated Use {@link #computeLayout(IXmlPullParser, Object, int, int, int, float, float, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}
* @since 1
*/
@Deprecated
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java
index 13cc62d..ade07d6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint.java
@@ -380,7 +380,6 @@ public class Paint extends _Original_Paint {
int filterNative = 0;
if (filter != null)
filterNative = filter.native_instance;
- native_setColorFilter(mNativePaint, filterNative);
mColorFilter = filter;
return filter;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index f5087d9..47a7ec0 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -27,8 +27,8 @@ import com.android.layoutlib.api.IXmlPullParser;
import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo;
import com.android.layoutlib.bridge.LayoutResult.LayoutViewInfo;
import com.android.ninepatch.NinePatch;
-import com.android.tools.layoutlib.create.OverrideMethod;
import com.android.tools.layoutlib.create.MethodAdapter;
+import com.android.tools.layoutlib.create.OverrideMethod;
import android.graphics.Bitmap;
import android.graphics.Rect;
@@ -40,6 +40,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.BridgeInflater;
import android.view.IWindow;
@@ -55,6 +56,7 @@ import android.view.View.MeasureSpec;
import android.view.WindowManager.LayoutParams;
import android.widget.FrameLayout;
+import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
@@ -72,6 +74,8 @@ public final class Bridge implements ILayoutBridge {
private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
public static class StaticMethodNotImplementedException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
public StaticMethodNotImplementedException(String msg) {
super(msg);
}
@@ -91,14 +95,15 @@ public final class Bridge implements ILayoutBridge {
private final static Map<String, Map<String, Integer>> sRFullMap =
new HashMap<String, Map<String,Integer>>();
- private final static Map<Object, Map<String, Bitmap>> sProjectBitmapCache =
- new HashMap<Object, Map<String, Bitmap>>();
- private final static Map<Object, Map<String, NinePatch>> sProject9PatchCache =
- new HashMap<Object, Map<String, NinePatch>>();
-
- private final static Map<String, Bitmap> sFrameworkBitmapCache = new HashMap<String, Bitmap>();
- private final static Map<String, NinePatch> sFramework9PatchCache =
- new HashMap<String, NinePatch>();
+ private final static Map<Object, Map<String, SoftReference<Bitmap>>> sProjectBitmapCache =
+ new HashMap<Object, Map<String, SoftReference<Bitmap>>>();
+ private final static Map<Object, Map<String, SoftReference<NinePatch>>> sProject9PatchCache =
+ new HashMap<Object, Map<String, SoftReference<NinePatch>>>();
+
+ private final static Map<String, SoftReference<Bitmap>> sFrameworkBitmapCache =
+ new HashMap<String, SoftReference<Bitmap>>();
+ private final static Map<String, SoftReference<NinePatch>> sFramework9PatchCache =
+ new HashMap<String, SoftReference<NinePatch>>();
private static Map<String, Map<String, Integer>> sEnumValueMap;
@@ -277,20 +282,40 @@ public final class Bridge implements ILayoutBridge {
isProjectTheme = true;
}
- return computeLayout(layoutDescription, projectKey, screenWidth, screenHeight, themeName, isProjectTheme,
+ return computeLayout(layoutDescription, projectKey,
+ screenWidth, screenHeight, DisplayMetrics.DEFAULT_DENSITY,
+ DisplayMetrics.DEFAULT_DENSITY, DisplayMetrics.DEFAULT_DENSITY,
+ themeName, isProjectTheme,
projectResources, frameworkResources, customViewLoader, logger);
}
/*
+ * For compatilibty purposes, we implement the old deprecated version of computeLayout.
* (non-Javadoc)
* @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
*/
- public ILayoutResult computeLayout(IXmlPullParser layoutDescription,
- Object projectKey,
+ public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
int screenWidth, int screenHeight, String themeName, boolean isProjectTheme,
Map<String, Map<String, IResourceValue>> projectResources,
Map<String, Map<String, IResourceValue>> frameworkResources,
IProjectCallback customViewLoader, ILayoutLog logger) {
+ return computeLayout(layoutDescription, projectKey,
+ screenWidth, screenHeight, DisplayMetrics.DEFAULT_DENSITY,
+ DisplayMetrics.DEFAULT_DENSITY, DisplayMetrics.DEFAULT_DENSITY,
+ themeName, isProjectTheme,
+ projectResources, frameworkResources, customViewLoader, logger);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
+ */
+ public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
+ int screenWidth, int screenHeight, int density, float xdpi, float ydpi,
+ String themeName, boolean isProjectTheme,
+ Map<String, Map<String, IResourceValue>> projectResources,
+ Map<String, Map<String, IResourceValue>> frameworkResources,
+ IProjectCallback customViewLoader, ILayoutLog logger) {
if (logger == null) {
logger = sDefaultLogger;
}
@@ -298,7 +323,7 @@ public final class Bridge implements ILayoutBridge {
synchronized (sDefaultLogger) {
sLogger = logger;
}
-
+
// find the current theme and compute the style inheritance map
Map<IStyleResourceValue, IStyleResourceValue> styleParentMap =
new HashMap<IStyleResourceValue, IStyleResourceValue>();
@@ -307,32 +332,42 @@ public final class Bridge implements ILayoutBridge {
projectResources.get(BridgeConstants.RES_STYLE),
frameworkResources.get(BridgeConstants.RES_STYLE), styleParentMap);
- BridgeContext context = new BridgeContext(projectKey, currentTheme, projectResources,
- frameworkResources, styleParentMap, customViewLoader, logger);
- BridgeInflater inflater = new BridgeInflater(context, customViewLoader);
- context.setBridgeInflater(inflater);
-
- IResourceValue windowBackground = null;
- int screenOffset = 0;
- if (currentTheme != null) {
- windowBackground = context.findItemInStyle(currentTheme, "windowBackground");
- windowBackground = context.resolveResValue(windowBackground);
-
- screenOffset = getScreenOffset(currentTheme, context);
- }
-
- // we need to make sure the Looper has been initialized for this thread.
- // this is required for View that creates Handler objects.
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
- BridgeXmlBlockParser parser = new BridgeXmlBlockParser(layoutDescription,
- context, false /* platformResourceFlag */);
-
- ViewGroup root = new FrameLayout(context);
-
+ BridgeContext context = null;
try {
+ // setup the display Metrics.
+ DisplayMetrics metrics = new DisplayMetrics();
+ metrics.density = density / (float) DisplayMetrics.DEFAULT_DENSITY;
+ metrics.scaledDensity = metrics.density;
+ metrics.widthPixels = screenWidth;
+ metrics.heightPixels = screenHeight;
+ metrics.xdpi = xdpi;
+ metrics.ydpi = ydpi;
+
+ context = new BridgeContext(projectKey, metrics, currentTheme, projectResources,
+ frameworkResources, styleParentMap, customViewLoader, logger);
+ BridgeInflater inflater = new BridgeInflater(context, customViewLoader);
+ context.setBridgeInflater(inflater);
+
+ IResourceValue windowBackground = null;
+ int screenOffset = 0;
+ if (currentTheme != null) {
+ windowBackground = context.findItemInStyle(currentTheme, "windowBackground");
+ windowBackground = context.resolveResValue(windowBackground);
+
+ screenOffset = getScreenOffset(currentTheme, context);
+ }
+
+ // we need to make sure the Looper has been initialized for this thread.
+ // this is required for View that creates Handler objects.
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ BridgeXmlBlockParser parser = new BridgeXmlBlockParser(layoutDescription,
+ context, false /* platformResourceFlag */);
+
+ ViewGroup root = new FrameLayout(context);
+
View view = inflater.inflate(parser, root);
// set the AttachInfo on the root view.
@@ -381,6 +416,10 @@ public final class Bridge implements ILayoutBridge {
return new LayoutResult(ILayoutResult.ERROR,
t.getClass().getSimpleName() + ": " + t.getMessage());
} finally {
+ // Make sure to remove static references, otherwise we could not unload the lib
+ BridgeResources.clearSystem();
+ BridgeAssetManager.clearSystem();
+
// Remove the global logger
synchronized (sDefaultLogger) {
sLogger = sDefaultLogger;
@@ -680,15 +719,21 @@ public final class Bridge implements ILayoutBridge {
*/
static Bitmap getCachedBitmap(String value, Object projectKey) {
if (projectKey != null) {
- Map<String, Bitmap> map = sProjectBitmapCache.get(projectKey);
+ Map<String, SoftReference<Bitmap>> map = sProjectBitmapCache.get(projectKey);
if (map != null) {
- return map.get(value);
+ SoftReference<Bitmap> ref = map.get(value);
+ if (ref != null) {
+ return ref.get();
+ }
+ }
+ } else {
+ SoftReference<Bitmap> ref = sFrameworkBitmapCache.get(value);
+ if (ref != null) {
+ return ref.get();
}
-
- return null;
}
-
- return sFrameworkBitmapCache.get(value);
+
+ return null;
}
/**
@@ -699,17 +744,17 @@ public final class Bridge implements ILayoutBridge {
*/
static void setCachedBitmap(String value, Bitmap bmp, Object projectKey) {
if (projectKey != null) {
- Map<String, Bitmap> map = sProjectBitmapCache.get(projectKey);
+ Map<String, SoftReference<Bitmap>> map = sProjectBitmapCache.get(projectKey);
if (map == null) {
- map = new HashMap<String, Bitmap>();
+ map = new HashMap<String, SoftReference<Bitmap>>();
sProjectBitmapCache.put(projectKey, map);
}
- map.put(value, bmp);
+ map.put(value, new SoftReference<Bitmap>(bmp));
+ } else {
+ sFrameworkBitmapCache.put(value, new SoftReference<Bitmap>(bmp));
}
-
- sFrameworkBitmapCache.put(value, bmp);
}
/**
@@ -721,16 +766,22 @@ public final class Bridge implements ILayoutBridge {
*/
static NinePatch getCached9Patch(String value, Object projectKey) {
if (projectKey != null) {
- Map<String, NinePatch> map = sProject9PatchCache.get(projectKey);
+ Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey);
if (map != null) {
- return map.get(value);
+ SoftReference<NinePatch> ref = map.get(value);
+ if (ref != null) {
+ return ref.get();
+ }
+ }
+ } else {
+ SoftReference<NinePatch> ref = sFramework9PatchCache.get(value);
+ if (ref != null) {
+ return ref.get();
}
-
- return null;
}
- return sFramework9PatchCache.get(value);
+ return null;
}
/**
@@ -741,19 +792,19 @@ public final class Bridge implements ILayoutBridge {
*/
static void setCached9Patch(String value, NinePatch ninePatch, Object projectKey) {
if (projectKey != null) {
- Map<String, NinePatch> map = sProject9PatchCache.get(projectKey);
+ Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey);
if (map == null) {
- map = new HashMap<String, NinePatch>();
+ map = new HashMap<String, SoftReference<NinePatch>>();
sProject9PatchCache.put(projectKey, map);
}
- map.put(value, ninePatch);
+ map.put(value, new SoftReference<NinePatch>(ninePatch));
+ } else {
+ sFramework9PatchCache.put(value, new SoftReference<NinePatch>(ninePatch));
}
-
- sFramework9PatchCache.put(value, ninePatch);
}
-
+
/**
* Implementation of {@link IWindowSession} so that mSession is not null in
* the {@link SurfaceView}.
@@ -784,6 +835,12 @@ public final class Bridge implements ILayoutBridge {
}
@SuppressWarnings("unused")
+ public boolean performHapticFeedback(IWindow window, int effectId, boolean always) {
+ // pass for now.
+ return false;
+ }
+
+ @SuppressWarnings("unused")
public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
// pass for now.
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
index 02545af..1fa11af 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
@@ -24,9 +24,36 @@ import java.util.Locale;
public class BridgeAssetManager extends AssetManager {
/**
- * Change the configuation used when retrieving resources. Not for use by
- * applications.
- * {@hide}
+ * This initializes the static field {@link AssetManager#mSystem} which is used
+ * by methods who get a global asset manager using {@link AssetManager#getSystem()}.
+ * <p/>
+ * They will end up using our bridge asset manager.
+ * <p/>
+ * {@link Bridge} calls this method after setting up a new bridge.
+ */
+ /*package*/ static AssetManager initSystem() {
+ if (!(AssetManager.mSystem instanceof BridgeAssetManager)) {
+ // Note that AssetManager() creates a system AssetManager and we override it
+ // with our BridgeAssetManager.
+ AssetManager.mSystem = new BridgeAssetManager();
+ AssetManager.mSystem.makeStringBlocks(false);
+ }
+ return AssetManager.mSystem;
+ }
+
+ /**
+ * Clears the static {@link AssetManager#mSystem} to make sure we don't leave objects
+ * around that would prevent us from unloading the library.
+ */
+ /*package*/ static void clearSystem() {
+ AssetManager.mSystem = null;
+ }
+
+ private BridgeAssetManager() {
+ }
+
+ /**
+ * Change the configuration used when retrieving resources. Not for use by applications.
*/
@Override
public void setConfiguration(int mcc, int mnc, String locale,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java
new file mode 100644
index 0000000..727d6f2
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java
@@ -0,0 +1,107 @@
+/*
+ * 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.layoutlib.bridge;
+
+import android.content.ContentResolver;
+import android.content.ContentServiceNative;
+import android.content.Context;
+import android.content.IContentProvider;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * A mock content resolver for the LayoutLib Bridge.
+ * <p/>
+ * It won't serve any actual data but it's good enough for all
+ * the widgets which expect to have a content resolver available via
+ * {@link BridgeContext#getContentResolver()}.
+ */
+public class BridgeContentResolver extends ContentResolver {
+
+ public BridgeContentResolver(Context context) {
+ super(context);
+ }
+
+ @Override
+ public IContentProvider acquireProvider(Context c, String name) {
+ // ignore
+ return null;
+ }
+
+ @Override
+ public boolean releaseProvider(IContentProvider icp) {
+ // ignore
+ return false;
+ }
+
+ /**
+ * Stub for the layoutlib bridge content resolver.
+ * <p/>
+ * The super implementation accesses the {@link ContentServiceNative#getDefault()}
+ * which returns null and would make the call crash. Instead we do nothing.
+ */
+ @Override
+ public void registerContentObserver(Uri uri, boolean notifyForDescendents,
+ ContentObserver observer) {
+ // pass
+ }
+
+ /**
+ * Stub for the layoutlib bridge content resolver.
+ * <p/>
+ * The super implementation accesses the {@link ContentServiceNative#getDefault()}
+ * which returns null and would make the call crash. Instead we do nothing.
+ */
+ @Override
+ public void unregisterContentObserver(ContentObserver observer) {
+ // pass
+ }
+
+ /**
+ * Stub for the layoutlib bridge content resolver.
+ * <p/>
+ * The super implementation accesses the {@link ContentServiceNative#getDefault()}
+ * which returns null and would make the call crash. Instead we do nothing.
+ */
+ @Override
+ public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+ // pass
+ }
+
+ /**
+ * Stub for the layoutlib bridge content resolver.
+ * <p/>
+ * The super implementation accesses the {@link ContentServiceNative#getDefault()}
+ * which returns null and would make the call crash. Instead we do nothing.
+ */
+ @Override
+ public void startSync(Uri uri, Bundle extras) {
+ // pass
+ }
+
+ /**
+ * Stub for the layoutlib bridge content resolver.
+ * <p/>
+ * The super implementation accesses the {@link ContentServiceNative#getDefault()}
+ * which returns null and would make the call crash. Instead we do nothing.
+ */
+ @Override
+ public void cancelSync(Uri uri) {
+ // pass
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index cb9509b..baa3d53 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -84,16 +84,24 @@ public final class BridgeContext extends Context {
private final IProjectCallback mProjectCallback;
private final ILayoutLog mLogger;
+ private BridgeContentResolver mContentResolver;
/**
- * @param projectKey
- * @param currentTheme
- * @param projectResources
- * @param frameworkResources
+ * @param projectKey An Object identifying the project. This is used for the cache mechanism.
+ * @param metrics the {@link DisplayMetrics}.
+ * @param themeName The name of the theme to use.
+ * @param projectResources the resources of the project. The map contains (String, map) pairs
+ * where the string is the type of the resource reference used in the layout file, and the
+ * map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
+ * and the value is the resource value.
+ * @param frameworkResources the framework resources. The map contains (String, map) pairs
+ * where the string is the type of the resource reference used in the layout file, and the map
+ * contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
+ * value is the resource value.
* @param styleInheritanceMap
* @param customViewLoader
*/
- public BridgeContext(Object projectKey,
+ public BridgeContext(Object projectKey, DisplayMetrics metrics,
IStyleResourceValue currentTheme,
Map<String, Map<String, IResourceValue>> projectResources,
Map<String, Map<String, IResourceValue>> frameworkResources,
@@ -104,12 +112,10 @@ public final class BridgeContext extends Context {
mLogger = logger;
Configuration config = new Configuration();
- DisplayMetrics metrics = new DisplayMetrics();
- metrics.setToDefaults();
-
- mResources = new BridgeResources(
+ AssetManager assetManager = BridgeAssetManager.initSystem();
+ mResources = BridgeResources.initSystem(
this,
- new BridgeAssetManager(),
+ assetManager,
metrics,
config,
customViewLoader);
@@ -168,6 +174,12 @@ public final class BridgeContext extends Context {
if (LAYOUT_INFLATER_SERVICE.equals(service)) {
return mInflater;
}
+
+ // AutoCompleteTextView and MultiAutoCompleteTextView want a window
+ // service. We don't have any but it's not worth an exception.
+ if (WINDOW_SERVICE.equals(service)) {
+ return null;
+ }
throw new UnsupportedOperationException("Unsupported Service: " + service);
}
@@ -899,8 +911,10 @@ public final class BridgeContext extends Context {
@Override
public ContentResolver getContentResolver() {
- // TODO Auto-generated method stub
- return null;
+ if (mContentResolver == null) {
+ mContentResolver = new BridgeContentResolver(this);
+ }
+ return mContentResolver;
}
@Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
index 6ab6e32..0bcc7fd 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
@@ -51,11 +51,46 @@ public final class BridgeResources extends Resources {
private IProjectCallback mProjectCallback;
private boolean[] mPlatformResourceFlag = new boolean[1];
- public BridgeResources(BridgeContext context, AssetManager assets, DisplayMetrics metrics,
- Configuration config, IProjectCallback projetCallback) {
+ /**
+ * This initializes the static field {@link Resources#mSystem} which is used
+ * by methods who get global resources using {@link Resources#getSystem()}.
+ * <p/>
+ * They will end up using our bridge resources.
+ * <p/>
+ * {@link Bridge} calls this method after setting up a new bridge.
+ */
+ /*package*/ static Resources initSystem(BridgeContext context,
+ AssetManager assets,
+ DisplayMetrics metrics,
+ Configuration config,
+ IProjectCallback projectCallback) {
+ if (!(Resources.mSystem instanceof BridgeResources)) {
+ Resources.mSystem = new BridgeResources(context,
+ assets,
+ metrics,
+ config,
+ projectCallback);
+ }
+ return Resources.mSystem;
+ }
+
+ /**
+ * Clears the static {@link Resources#mSystem} to make sure we don't leave objects
+ * around that would prevent us from unloading the library.
+ */
+ /*package*/ static void clearSystem() {
+ if (Resources.mSystem instanceof BridgeResources) {
+ ((BridgeResources)(Resources.mSystem)).mContext = null;
+ ((BridgeResources)(Resources.mSystem)).mProjectCallback = null;
+ }
+ Resources.mSystem = null;
+ }
+
+ private BridgeResources(BridgeContext context, AssetManager assets, DisplayMetrics metrics,
+ Configuration config, IProjectCallback projectCallback) {
super(assets, metrics, config);
mContext = context;
- mProjectCallback = projetCallback;
+ mProjectCallback = projectCallback;
}
public BridgeTypedArray newTypeArray(int numEntries, boolean platformFile) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
index ca3c8b0..1ca3182 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
@@ -24,7 +24,8 @@ import android.widget.TextView;
/**
* Base class for mocked views.
*
- * TODO: implement onDraw and draw a rectangle in a random color with the name of the class (or better the id of the view).
+ * TODO: implement onDraw and draw a rectangle in a random color with the name of the class
+ * (or better the id of the view).
*/
public class MockView extends TextView {
diff --git a/tools/preload/Android.mk b/tools/preload/Android.mk
index d3457fe..e6fa103 100644
--- a/tools/preload/Android.mk
+++ b/tools/preload/Android.mk
@@ -2,7 +2,19 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := *.java
+LOCAL_SRC_FILES := \
+ ClassRank.java \
+ Compile.java \
+ LoadedClass.java \
+ MemoryUsage.java \
+ Operation.java \
+ Policy.java \
+ PrintCsv.java \
+ PrintPsTree.java \
+ Proc.java \
+ Record.java \
+ Root.java \
+ WritePreloadedClassFile.java
LOCAL_MODULE:= preload
diff --git a/tools/preload/Compile.java b/tools/preload/Compile.java
index 8388b12..67258ef 100644
--- a/tools/preload/Compile.java
+++ b/tools/preload/Compile.java
@@ -15,26 +15,22 @@
*/
import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.IOException;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.ObjectOutputStream;
-import java.io.BufferedOutputStream;
-import java.util.List;
+import java.io.IOException;
+import java.io.InputStreamReader;
import java.util.ArrayList;
-import java.lang.reflect.InvocationTargetException;
+import java.util.List;
/**
* Parses and analyzes a log, pulling our PRELOAD information. If you have
* an emulator or device running in the background, this class will use it
* to measure and record the memory usage of each class.
+ *
+ * TODO: Should analyze lines and select substring dynamically (instead of hardcoded 19)
*/
public class Compile {
- public static void main(String[] args)
- throws IOException, NoSuchMethodException, IllegalAccessException,
- InvocationTargetException {
+ public static void main(String[] args) throws IOException {
if (args.length != 2) {
System.err.println("Usage: Compile [log file] [output file]");
System.exit(0);
@@ -48,10 +44,17 @@ public class Compile {
new FileInputStream(args[0])));
String line;
+ int lineNumber = 0;
while ((line = in.readLine()) != null) {
+ lineNumber++;
if (line.startsWith("I/PRELOAD")) {
- line = line.substring(19);
- records.add(new Record(line));
+ try {
+ String clipped = line.substring(19);
+ records.add(new Record(clipped, lineNumber));
+ } catch (RuntimeException e) {
+ throw new RuntimeException(
+ "Exception while recording line " + lineNumber + ": " + line, e);
+ }
}
}
diff --git a/tools/preload/LoadedClass.java b/tools/preload/LoadedClass.java
index 6b3d345..5782807 100644
--- a/tools/preload/LoadedClass.java
+++ b/tools/preload/LoadedClass.java
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-import java.util.List;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Set;
-import java.util.HashSet;
-import java.io.Serializable;
/**
* A loaded class.
@@ -134,6 +133,7 @@ class LoadedClass implements Serializable, Comparable<LoadedClass> {
return name.compareTo(o.name);
}
+ @Override
public String toString() {
return name;
}
diff --git a/tools/preload/MemoryUsage.java b/tools/preload/MemoryUsage.java
index 89717eb..e5dfb2a 100644
--- a/tools/preload/MemoryUsage.java
+++ b/tools/preload/MemoryUsage.java
@@ -32,6 +32,9 @@ class MemoryUsage implements Serializable {
private static final long serialVersionUID = 0;
static final MemoryUsage NOT_AVAILABLE = new MemoryUsage();
+
+ static int errorCount = 0;
+ static final int MAXIMUM_ERRORS = 10; // give up after this many fails
final int nativeSharedPages;
final int javaSharedPages;
@@ -160,6 +163,13 @@ class MemoryUsage implements Serializable {
* Measures memory usage for the given class.
*/
static MemoryUsage forClass(String className) {
+
+ // This is a coarse approximation for determining that no device is connected,
+ // or that the communication protocol has changed, but we'll keep going and stop whining.
+ if (errorCount >= MAXIMUM_ERRORS) {
+ return NOT_AVAILABLE;
+ }
+
MeasureWithTimeout measurer = new MeasureWithTimeout(className);
new Thread(measurer).start();
@@ -237,6 +247,7 @@ class MemoryUsage implements Serializable {
if (line == null || !line.startsWith("DECAFBAD,")) {
System.err.println("Got bad response for " + className
+ ": " + line);
+ errorCount += 1;
return NOT_AVAILABLE;
}
diff --git a/tools/preload/Operation.java b/tools/preload/Operation.java
index 65c9a03..4f1938e 100644
--- a/tools/preload/Operation.java
+++ b/tools/preload/Operation.java
@@ -115,4 +115,22 @@ class Operation implements Serializable {
}
return microsInt;
}
+
+ /**
+ * Primarily for debugger support
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(type.toString());
+ sb.append(' ');
+ sb.append(loadedClass.toString());
+ if (subops.size() > 0) {
+ sb.append(" (");
+ sb.append(subops.size());
+ sb.append(" sub ops)");
+ }
+ return sb.toString();
+ }
+
}
diff --git a/tools/preload/Policy.java b/tools/preload/Policy.java
new file mode 100644
index 0000000..554966b
--- /dev/null
+++ b/tools/preload/Policy.java
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This is not instantiated - we just provide data for other classes to use
+ */
+public class Policy {
+
+ /**
+ * This location (in the build system) of the preloaded-classes file.
+ */
+ private static final String PRELOADED_CLASS_FILE = "frameworks/base/preloaded-classes";
+
+ /**
+ * The internal process name of the system process. Note, this also shows up as
+ * "system_process", e.g. in ddms.
+ */
+ private static final String SYSTEM_SERVER_PROCESS_NAME = "system_server";
+
+ /**
+ * Names of non-application processes - these will not be checked for preloaded classes.
+ *
+ * TODO: Replace this hardcoded list with a walk up the parent chain looking for zygote.
+ */
+ private static final Set<String> NOT_FROM_ZYGOTE = new HashSet<String>(Arrays.asList(
+ "zygote",
+ "dexopt",
+ "unknown",
+ SYSTEM_SERVER_PROCESS_NAME,
+ "com.android.development",
+ "app_process" // am & other shell commands
+ ));
+
+ /**
+ * Long running services. These are restricted in their contribution to the preloader
+ * because their launch time is less critical.
+ */
+ private static final Set<String> SERVICES = new HashSet<String>(Arrays.asList(
+ SYSTEM_SERVER_PROCESS_NAME,
+ "com.android.acore",
+ // Commented out to make sure DefaultTimeZones gets preloaded.
+ // "com.android.phone",
+ "com.google.process.content",
+ "android.process.media"
+ ));
+
+ /**
+ * Classes which we shouldn't load from the Zygote.
+ */
+ private static final Set<String> EXCLUDED_CLASSES = new HashSet<String>(Arrays.asList(
+ // Binders
+ "android.app.AlarmManager",
+ "android.app.SearchManager",
+ "android.os.FileObserver",
+ "com.android.server.PackageManagerService$AppDirObserver",
+
+ // Threads
+ "android.os.AsyncTask",
+ "android.pim.ContactsAsyncHelper",
+ "java.lang.ProcessManager"
+
+ ));
+
+ /**
+ * No constructor - use static methods only
+ */
+ private Policy() {}
+
+ /**
+ * Returns the path/file name of the preloaded classes file that will be written
+ * by WritePreloadedClassFile.
+ */
+ public static String getPreloadedClassFileName() {
+ return PRELOADED_CLASS_FILE;
+ }
+
+ /**
+ * Reports if a given process name was created from zygote
+ */
+ public static boolean isFromZygote(String processName) {
+ return !NOT_FROM_ZYGOTE.contains(processName);
+ }
+
+ /**
+ * Reports if the given process name is a "long running" process or service
+ */
+ public static boolean isService(String processName) {
+ return SERVICES.contains(processName);
+ }
+
+ /**
+ * Reports if the given class should never be preloaded
+ */
+ public static boolean isPreloadableClass(String className) {
+ return !EXCLUDED_CLASSES.contains(className);
+ }
+}
diff --git a/tools/preload/Proc.java b/tools/preload/Proc.java
index 0b27a51..22697f8 100644
--- a/tools/preload/Proc.java
+++ b/tools/preload/Proc.java
@@ -43,49 +43,6 @@ class Proc implements Serializable {
*/
static final int MAX_TO_PRELOAD = 100;
- /** Name of system server process. */
- private static final String SYSTEM_SERVER = "system_server";
-
- /** Names of non-application processes. */
- private static final Set<String> NOT_FROM_ZYGOTE
- = new HashSet<String>(Arrays.asList(
- "zygote",
- "dexopt",
- "unknown",
- SYSTEM_SERVER,
- "com.android.development",
- "app_process" // am
- ));
-
- /** Long running services. */
- private static final Set<String> SERVICES
- = new HashSet<String>(Arrays.asList(
- SYSTEM_SERVER,
- "com.android.home",
-// Commented out to make sure DefaultTimeZones gets preloaded.
-// "com.android.phone",
- "com.google.process.content",
- "com.android.process.media"
- ));
-
- /**
- * Classes which we shouldn't load from the Zygote.
- */
- static final Set<String> EXCLUDED_CLASSES
- = new HashSet<String>(Arrays.asList(
- // Binders
- "android.app.AlarmManager",
- "android.app.SearchManager",
- "android.os.FileObserver",
- "com.android.server.PackageManagerService$AppDirObserver",
-
- // Threads
- "java.lang.ProcessManager",
-
- // This class was deleted.
- "java.math.Elementary"
- ));
-
/** Parent process. */
final Proc parent;
@@ -139,17 +96,12 @@ class Proc implements Serializable {
}
/**
- * Is this a long running process?
- */
- boolean isService() {
- return SERVICES.contains(this.name);
- }
-
- /**
* Returns a list of classes which should be preloaded.
+ *
+ * @param takeAllClasses forces all classes to be taken (irrespective of ranking)
*/
- List<LoadedClass> highestRankedClasses() {
- if (NOT_FROM_ZYGOTE.contains(this.name)) {
+ List<LoadedClass> highestRankedClasses(boolean takeAllClasses) {
+ if (!isApplication()) {
return Collections.emptyList();
}
@@ -162,23 +114,30 @@ class Proc implements Serializable {
int timeToSave = totalTimeMicros() * percentageToPreload() / 100;
int timeSaved = 0;
- boolean service = isService();
+ boolean service = Policy.isService(this.name);
List<LoadedClass> highest = new ArrayList<LoadedClass>();
for (Operation operation : ranked) {
- if (highest.size() >= MAX_TO_PRELOAD) {
- System.out.println(name + " got "
- + (timeSaved * 100 / timeToSave) + "% through");
-
- break;
+
+ // These are actual ranking decisions, which can be overridden
+ if (!takeAllClasses) {
+ if (highest.size() >= MAX_TO_PRELOAD) {
+ System.out.println(name + " got "
+ + (timeSaved * 100 / timeToSave) + "% through");
+ break;
+ }
+
+ if (timeSaved >= timeToSave) {
+ break;
+ }
}
- if (timeSaved >= timeToSave) {
- break;
+ // The remaining rules apply even to wired-down processes
+ if (!Policy.isPreloadableClass(operation.loadedClass.name)) {
+ continue;
}
-
- if (EXCLUDED_CLASSES.contains(operation.loadedClass.name)
- || !operation.loadedClass.systemClass) {
+
+ if (!operation.loadedClass.systemClass) {
continue;
}
@@ -205,9 +164,13 @@ class Proc implements Serializable {
return totalTime;
}
- /** Returns true if this process is an app. */
+ /**
+ * Returns true if this process is an app.
+ *
+ * TODO: Replace the hardcoded list with a walk up the parent chain looking for zygote.
+ */
public boolean isApplication() {
- return !NOT_FROM_ZYGOTE.contains(name);
+ return Policy.isFromZygote(name);
}
/**
diff --git a/tools/preload/Record.java b/tools/preload/Record.java
index 9ffab46..b2be4d4 100644
--- a/tools/preload/Record.java
+++ b/tools/preload/Record.java
@@ -56,11 +56,14 @@ class Record {
/** Record time (ns). */
final long time;
+
+ /** Source file line# */
+ int sourceLineNumber;
/**
* Parses a line from the loaded-classes file.
*/
- Record(String line) {
+ Record(String line, int lineNum) {
char typeChar = line.charAt(0);
switch (typeChar) {
case '>': type = Type.START_LOAD; break;
@@ -70,6 +73,8 @@ class Record {
default: throw new AssertionError("Bad line: " + line);
}
+ sourceLineNumber = lineNum;
+
line = line.substring(1);
String[] parts = line.split(":");
@@ -77,20 +82,51 @@ class Record {
pid = Integer.parseInt(parts[1]);
tid = Integer.parseInt(parts[2]);
- processName = parts[3].intern();
+ processName = decode(parts[3]).intern();
classLoader = Integer.parseInt(parts[4]);
- className = vmTypeToLanguage(parts[5]).intern();
+ className = vmTypeToLanguage(decode(parts[5])).intern();
time = Long.parseLong(parts[6]);
}
+
+ /**
+ * Decode any escaping that may have been written to the log line.
+ *
+ * Supports unicode-style escaping: \\uXXXX = character in hex
+ *
+ * @param rawField the field as it was written into the log
+ * @result the same field with any escaped characters replaced
+ */
+ String decode(String rawField) {
+ String result = rawField;
+ int offset = result.indexOf("\\u");
+ while (offset >= 0) {
+ String before = result.substring(0, offset);
+ String escaped = result.substring(offset+2, offset+6);
+ String after = result.substring(offset+6);
+
+ result = String.format("%s%c%s", before, Integer.parseInt(escaped, 16), after);
+
+ // find another but don't recurse
+ offset = result.indexOf("\\u", offset + 1);
+ }
+ return result;
+ }
/**
* Converts a VM-style name to a language-style name.
*/
- static String vmTypeToLanguage(String typeName) {
+ String vmTypeToLanguage(String typeName) {
+ // if the typename is (null), just return it as-is. This is probably in dexopt and
+ // will be discarded anyway. NOTE: This corresponds to the case in dalvik/vm/oo/Class.c
+ // where dvmLinkClass() returns false and we clean up and exit.
+ if ("(null)".equals(typeName)) {
+ return typeName;
+ }
+
if (!typeName.startsWith("L") || !typeName.endsWith(";") ) {
- throw new AssertionError("Bad name: " + typeName);
+ throw new AssertionError("Bad name: " + typeName + " in line " + sourceLineNumber);
}
typeName = typeName.substring(1, typeName.length() - 1);
diff --git a/tools/preload/WritePreloadedClassFile.java b/tools/preload/WritePreloadedClassFile.java
index 5596a62..d87b1f0 100644
--- a/tools/preload/WritePreloadedClassFile.java
+++ b/tools/preload/WritePreloadedClassFile.java
@@ -14,54 +14,69 @@
* limitations under the License.
*/
-import java.io.IOException;
-import java.io.Writer;
import java.io.BufferedWriter;
-import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
import java.util.TreeSet;
-import java.util.List;
/**
- * Writes /java/android/preloaded-classes. Also updates LoadedClass.preloaded
+ * Writes /frameworks/base/preloaded-classes. Also updates LoadedClass.preloaded
* fields and writes over compiled log file.
*/
public class WritePreloadedClassFile {
- private static final String PRELOADED_CLASS_FILE
- = "java/android/preloaded-classes";
-
- public static void main(String[] args)
- throws IOException, ClassNotFoundException {
- if (args.length != 1) {
- System.err.println(
- "Usage: WritePreloadedClassFile [compiled log file]");
+ public static void main(String[] args) throws IOException, ClassNotFoundException {
+
+ // Process command-line arguments first
+ List<String> wiredProcesses = new ArrayList<String>();
+ String inputFileName = null;
+ int argOffset = 0;
+ try {
+ while ("--preload-all-process".equals(args[argOffset])) {
+ argOffset++;
+ wiredProcesses.add(args[argOffset++]);
+ }
+
+ inputFileName = args[argOffset++];
+ } catch (RuntimeException e) {
+ System.err.println("Usage: WritePreloadedClassFile " +
+ "[--preload-all-process process-name] " +
+ "[compiled log file]");
System.exit(0);
}
- Root root = Root.fromFile(args[0]);
+ Root root = Root.fromFile(inputFileName);
for (LoadedClass loadedClass : root.loadedClasses.values()) {
loadedClass.preloaded = false;
}
Writer out = new BufferedWriter(new OutputStreamWriter(
- new FileOutputStream(PRELOADED_CLASS_FILE),
+ new FileOutputStream(Policy.getPreloadedClassFileName()),
Charset.forName("US-ASCII")));
- out.write("# Classes which are preloaded by " +
- "com.android.internal.os.ZygoteInit.\n");
- out.write("# Automatically generated by /tools/preload.\n");
+ out.write("# Classes which are preloaded by com.android.internal.os.ZygoteInit.\n");
+ out.write("# Automatically generated by /frameworks/base/tools/preload.\n");
out.write("# percent=" + Proc.PERCENTAGE_TO_PRELOAD + ", weight="
+ ClassRank.SEQUENCE_WEIGHT
+ ", bucket_size=" + ClassRank.BUCKET_SIZE
+ "\n");
+ for (String wiredProcess : wiredProcesses) {
+ out.write("# forcing classes loaded by: " + wiredProcess + "\n");
+ }
Set<LoadedClass> highestRanked = new TreeSet<LoadedClass>();
for (Proc proc : root.processes.values()) {
- List<LoadedClass> highestForProc = proc.highestRankedClasses();
+ // test to see if this is one of the wired-down ("take all classes") processes
+ boolean isWired = wiredProcesses.contains(proc.name);
+
+ List<LoadedClass> highestForProc = proc.highestRankedClasses(isWired);
System.out.println(proc.name + ": " + highestForProc.size());
@@ -82,6 +97,6 @@ public class WritePreloadedClassFile {
+ " classes will be preloaded.");
// Update data to reflect LoadedClass.preloaded changes.
- root.toFile(args[0]);
+ root.toFile(inputFileName);
}
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index e454cae..f9a0845 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -54,7 +54,7 @@ interface IWifiManager
boolean setWifiEnabled(boolean enable);
- int getWifiState();
+ int getWifiEnabledState();
int getNumAllowedChannels();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index db989d0..483e0fa 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -605,7 +605,7 @@ public class WifiManager {
*/
public int getWifiState() {
try {
- return mService.getWifiState();
+ return mService.getWifiEnabledState();
} catch (RemoteException e) {
return WIFI_STATE_UNKNOWN;
}
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index 8c9e5fa..fc750e2 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -28,7 +28,7 @@ import java.util.regex.Matcher;
* Listens for events from the wpa_supplicant server, and passes them on
* to the {@link WifiStateTracker} for handling. Runs in its own thread.
*
- * {@hide}
+ * @hide
*/
public class WifiMonitor {
@@ -119,14 +119,8 @@ public class WifiMonitor {
private final WifiStateTracker mWifiStateTracker;
- private boolean supplicantConnected;
-
- private boolean oneShot;
-
public WifiMonitor(WifiStateTracker tracker) {
mWifiStateTracker = tracker;
- supplicantConnected = false;
- oneShot = true;
}
public void startMonitoring() {
@@ -144,25 +138,30 @@ public class WifiMonitor {
public void run() {
+ if (connectToSupplicant()) {
+ // Send a message indicating that it is now possible to send commands
+ // to the supplicant
+ mWifiStateTracker.notifySupplicantConnection();
+ } else {
+ mWifiStateTracker.notifySupplicantLost();
+ return;
+ }
+
//noinspection InfiniteLoopStatement
for (;;) {
- ensureSupplicantConnection();
-
String eventStr = WifiNative.waitForEvent();
- if (Config.LOGD) {
- // Skip logging the common but mostly uninteresting scan-results event
- if (eventStr.indexOf(scanResultsEvent) == -1) {
- Log.v(TAG, "Event [" + eventStr +"]");
- }
- }
if (eventStr == null) {
continue;
- } else if (!eventStr.startsWith(eventPrefix)) {
- if (eventStr.startsWith(wpaEventPrefix)) {
- if (0 < eventStr.indexOf(passwordKeyMayBeIncorrectEvent)) {
- handlePasswordKeyMayBeIncorrect();
- }
+ }
+
+ // Skip logging the common but mostly uninteresting scan-results event
+ if (Config.LOGD && eventStr.indexOf(scanResultsEvent) == -1) {
+ Log.v(TAG, "Event [" + eventStr + "]");
+ }
+ if (!eventStr.startsWith(eventPrefix)) {
+ if (eventStr.startsWith(wpaEventPrefix) && 0 < eventStr.indexOf(passwordKeyMayBeIncorrectEvent)) {
+ handlePasswordKeyMayBeIncorrect();
}
continue;
}
@@ -216,42 +215,32 @@ public class WifiMonitor {
handleSupplicantStateChange(eventData);
} else if (event == DRIVER_STATE) {
handleDriverEvent(eventData);
+ } else if (event == TERMINATING) {
+ mWifiStateTracker.notifySupplicantLost();
+ // If supplicant is gone, exit the thread
+ break;
} else {
handleEvent(event, eventData);
- // If supplicant is gone, exit the thread
- if (event == TERMINATING) {
- break;
- }
}
}
}
- private void ensureSupplicantConnection() {
- while (!supplicantConnected) {
- boolean connected;
+ private boolean connectToSupplicant() {
+ int connectTries = 0;
+
+ while (true) {
synchronized (mWifiStateTracker) {
- connected = WifiNative.connectToSupplicant();
- }
- if (!connected) {
- /*
- * If we fail to connect on the very first attempt, send a message
- * indicating a lost connection to the supplicant, so that the
- * receiver can initialize to the proper state.
- */
- if (oneShot) {
- oneShot = false;
- mWifiStateTracker.notifySupplicantLost();
+ if (WifiNative.connectToSupplicant()) {
+ return true;
}
+ }
+ if (connectTries++ < 3) {
nap(5);
} else {
- supplicantConnected = true;
- oneShot = false;
- // Send a message indicating that it is now possible to send commands
- // to the supplicant
- mWifiStateTracker.notifySupplicantConnection();
-
+ break;
}
}
+ return false;
}
private void handlePasswordKeyMayBeIncorrect() {
@@ -289,11 +278,6 @@ public class WifiMonitor {
mWifiStateTracker.notifyScanResultsAvailable();
break;
- case TERMINATING:
- supplicantConnected = false;
- mWifiStateTracker.notifySupplicantLost();
- break;
-
case UNKNOWN:
break;
}
@@ -372,7 +356,7 @@ public class WifiMonitor {
private static void nap(int secs) {
try {
Thread.sleep(secs * 1000);
- } catch (InterruptedException e) {
+ } catch (InterruptedException ignore) {
}
}
}
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 49021cd..3851ac0 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -89,6 +89,19 @@ public class WifiNative {
public native static boolean stopDriverCommand();
+ /**
+ * Start filtering out multicast packets, to reduce battery consumption
+ * that would result from processing them, only to discard them.
+ * @return {@code true} if the operation succeeded, {@code false} otherwise
+ */
+ public native static boolean startPacketFiltering();
+
+ /**
+ * Stop filtering out multicast packets.
+ * @return {@code true} if the operation succeeded, {@code false} otherwise
+ */
+ public native static boolean stopPacketFiltering();
+
public native static boolean setPowerModeCommand(int mode);
public native static boolean setNumAllowedChannelsCommand(int numChannels);
@@ -104,6 +117,16 @@ public class WifiNative {
* @return Whether the mode was successfully set.
*/
public native static boolean setBluetoothCoexistenceModeCommand(int mode);
+
+ /**
+ * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
+ * some of the low-level scan parameters used by the driver are changed to
+ * reduce interference with A2DP streaming.
+ *
+ * @param isSet whether to enable or disable this mode
+ * @return {@code true} if the command succeeded, {@code false} otherwise.
+ */
+ public native static boolean setBluetoothCoexistenceScanModeCommand(boolean setCoexScanMode);
public native static boolean saveConfigCommand();
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 9b96da0..452a8fa 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -16,6 +16,7 @@
package android.net.wifi;
+import android.app.ActivityManagerNative;
import android.net.NetworkInfo;
import android.net.NetworkStateTracker;
import android.net.DhcpInfo;
@@ -37,6 +38,7 @@ import android.util.Config;
import android.app.Notification;
import android.app.PendingIntent;
import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothA2dp;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.Context;
@@ -159,7 +161,16 @@ public class WifiStateTracker extends NetworkStateTracker {
private boolean mHaveIPAddress;
private boolean mObtainingIPAddress;
private boolean mTornDownByConnMgr;
+ /**
+ * A DISCONNECT event has been received, but processing it
+ * is being deferred.
+ */
private boolean mDisconnectPending;
+ /**
+ * An operation has been performed as a result of which we expect the next event
+ * will be a DISCONNECT.
+ */
+ private boolean mDisconnectExpected;
private DhcpHandler mDhcpTarget;
private DhcpInfo mDhcpInfo;
private int mLastSignalLevel = -1;
@@ -234,6 +245,10 @@ public class WifiStateTracker extends NetworkStateTracker {
private int mRunState;
private boolean mIsScanOnly;
+
+ private BluetoothA2dp mBluetoothA2dp;
+
+ private boolean mBluetoothScanMode;
private String mInterfaceName;
private static String LS = System.getProperty("line.separator");
@@ -379,8 +394,11 @@ public class WifiStateTracker extends NetworkStateTracker {
*/
public synchronized boolean isAvailable() {
/*
- * TODO: Should we also look at scan results to see whether we're
- * in range of any access points?
+ * TODO: Need to also look at scan results to see whether we're
+ * in range of any access points. If we have scan results that
+ * are no more than N seconds old, use those, otherwise, initiate
+ * a scan and wait for the results. This only matters if we
+ * allow mobile to be the preferred network.
*/
SupplicantState suppState = mWifiInfo.getSupplicantState();
return suppState != SupplicantState.UNINITIALIZED &&
@@ -564,6 +582,30 @@ public class WifiStateTracker extends NetworkStateTracker {
}
}
+ /**
+ * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
+ * some of the low-level scan parameters used by the driver are changed to
+ * reduce interference with A2DP streaming.
+ *
+ * @param isBluetoothPlaying whether to enable or disable this mode
+ */
+ public synchronized void setBluetoothScanMode(boolean isBluetoothPlaying) {
+ WifiNative.setBluetoothCoexistenceScanModeCommand(isBluetoothPlaying);
+ }
+
+ private void checkIsBluetoothPlaying() {
+ boolean isBluetoothPlaying = false;
+ List<String> connected = mBluetoothA2dp.listConnectedSinks();
+
+ for (String address : connected) {
+ if (mBluetoothA2dp.getSinkState(address) == BluetoothA2dp.STATE_PLAYING) {
+ isBluetoothPlaying = true;
+ break;
+ }
+ }
+ setBluetoothScanMode(isBluetoothPlaying);
+ }
+
@Override
public void releaseWakeLock() {
if (mReleaseWakeLockCallback != null) {
@@ -653,14 +695,29 @@ public class WifiStateTracker extends NetworkStateTracker {
mLastSsid = mWifiInfo.getSSID();
configureInterface();
}
- intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
- intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, true);
- mContext.sendBroadcast(intent);
+ if (ActivityManagerNative.isSystemReady()) {
+ intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
+ intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, true);
+ mContext.sendBroadcast(intent);
+ }
if (supplState == SupplicantState.COMPLETED && mHaveIPAddress) {
setDetailedState(DetailedState.CONNECTED);
} else {
setDetailedState(WifiInfo.getDetailedStateOf(supplState));
}
+ /*
+ * Filter out multicast packets. This saves battery power, since
+ * the CPU doesn't have to spend time processing packets that
+ * are going to end up being thrown away. Obviously, if we
+ * ever want to support multicast, this will have to change.
+ */
+ if (mBluetoothA2dp == null) {
+ mBluetoothA2dp = new BluetoothA2dp(mContext);
+ }
+ synchronized (this) {
+ WifiNative.startPacketFiltering();
+ }
+ checkIsBluetoothPlaying();
break;
case EVENT_SUPPLICANT_DISCONNECT:
@@ -689,13 +746,18 @@ public class WifiStateTracker extends NetworkStateTracker {
mDhcpTarget = null;
}
mContext.removeStickyBroadcast(new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION));
- intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
- intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false);
- mContext.sendBroadcast(intent);
+ if (ActivityManagerNative.isSystemReady()) {
+ intent = new Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
+ intent.putExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false);
+ mContext.sendBroadcast(intent);
+ }
setDetailedState(DetailedState.DISCONNECTED);
setSupplicantState(SupplicantState.UNINITIALIZED);
mHaveIPAddress = false;
mObtainingIPAddress = false;
+ if (died) {
+ mWM.setWifiEnabled(false);
+ }
break;
case EVENT_SUPPLICANT_STATE_CHANGED:
@@ -749,13 +811,12 @@ public class WifiStateTracker extends NetworkStateTracker {
setSupplicantState(newState);
if (newState == SupplicantState.DORMANT) {
DetailedState newDetailedState;
- if (!mIsScanOnly) {
- newDetailedState = DetailedState.FAILED;
- } else {
+ if (mIsScanOnly || mRunState == RUN_STATE_STOPPING) {
newDetailedState = DetailedState.IDLE;
+ } else {
+ newDetailedState = DetailedState.FAILED;
}
handleDisconnectedState(newDetailedState);
- sendNetworkStateChangeBroadcast();
if (mRunState == RUN_STATE_RUNNING && !mIsScanOnly) {
sendEmptyMessageDelayed(EVENT_DEFERRED_RECONNECT, RECONNECT_DELAY_MSECS);
} else if (mRunState == RUN_STATE_STOPPING) {
@@ -768,9 +829,8 @@ public class WifiStateTracker extends NetworkStateTracker {
}
}
} else if (newState == SupplicantState.DISCONNECTED) {
- if (isDriverStopped()) {
+ if (isDriverStopped() || mDisconnectExpected) {
handleDisconnectedState(DetailedState.DISCONNECTED);
- sendNetworkStateChangeBroadcast();
} else {
scheduleDisconnect();
}
@@ -788,7 +848,9 @@ public class WifiStateTracker extends NetworkStateTracker {
}
}
+ mDisconnectExpected = false;
intent = new Intent(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_NEW_STATE, (Parcelable)newState);
if (failedToAuthenticate) {
if (LOCAL_LOGD) Log.d(TAG, "Failed to authenticate, disabling network " + networkId);
@@ -872,7 +934,7 @@ public class WifiStateTracker extends NetworkStateTracker {
* The connection is fully configured as far as link-level
* connectivity is concerned, but we may still need to obtain
* an IP address. But do this only if we are connecting to
- * a different access point than we were connected to previously.
+ * a different network than we were connected to previously.
*/
if (wasDisconnectPending) {
DetailedState saveState = getNetworkInfo().getDetailedState();
@@ -890,11 +952,13 @@ public class WifiStateTracker extends NetworkStateTracker {
setDetailedState(DetailedState.OBTAINING_IPADDR);
}
}
- sendNetworkStateChangeBroadcast();
+ sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID());
break;
case EVENT_SCAN_RESULTS_AVAILABLE:
- mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
+ if (ActivityManagerNative.isSystemReady()) {
+ mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
+ }
sendScanResultsAvailable();
/**
* On receiving the first scan results after connecting to
@@ -956,7 +1020,7 @@ public class WifiStateTracker extends NetworkStateTracker {
mLastSignalLevel = -1; // force update of signal strength
if (mNetworkInfo.getDetailedState() != DetailedState.CONNECTED) {
setDetailedState(DetailedState.CONNECTED);
- sendNetworkStateChangeBroadcast();
+ sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID());
} else {
mTarget.sendEmptyMessage(EVENT_CONFIGURATION_CHANGED);
}
@@ -1083,16 +1147,13 @@ public class WifiStateTracker extends NetworkStateTracker {
if (mDisconnectPending) {
cancelDisconnect();
}
- Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
- if (mLastBssid != null)
- intent.putExtra(WifiManager.EXTRA_BSSID, mLastBssid);
+ mDisconnectExpected = false;
+ resetInterface();
+ setDetailedState(newState);
+ sendNetworkStateChangeBroadcast(mLastBssid);
mWifiInfo.setBSSID(null);
mLastBssid = null;
mLastSsid = null;
- resetInterface();
- mContext.sendStickyBroadcast(intent);
- setDetailedState(newState);
mDisconnectPending = false;
}
@@ -1114,6 +1175,7 @@ public class WifiStateTracker extends NetworkStateTracker {
// Stop DHCP
if (mDhcpTarget != null) {
mDhcpTarget.setCancelCallback(true);
+ mDhcpTarget.removeMessages(EVENT_DHCP_START);
}
if (!NetworkUtils.stopDhcp(mInterfaceName)) {
Log.e(TAG, "Could not stop DHCP");
@@ -1246,16 +1308,19 @@ public class WifiStateTracker extends NetworkStateTracker {
}
private void sendRssiChangeBroadcast(final int newRssi) {
- Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
- intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
- mContext.sendBroadcast(intent);
+ if (ActivityManagerNative.isSystemReady()) {
+ Intent intent = new Intent(WifiManager.RSSI_CHANGED_ACTION);
+ intent.putExtra(WifiManager.EXTRA_NEW_RSSI, newRssi);
+ mContext.sendBroadcast(intent);
+ }
}
- private void sendNetworkStateChangeBroadcast() {
+ private void sendNetworkStateChangeBroadcast(String bssid) {
Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
- if (mWifiInfo.getBSSID() != null)
- intent.putExtra(WifiManager.EXTRA_BSSID, mWifiInfo.getBSSID());
+ if (bssid != null)
+ intent.putExtra(WifiManager.EXTRA_BSSID, bssid);
mContext.sendStickyBroadcast(intent);
}
@@ -1292,11 +1357,28 @@ public class WifiStateTracker extends NetworkStateTracker {
}
public synchronized boolean disconnectAndStop() {
- // Take down any open network notifications
- setNotificationVisible(false, 0, false, 0);
+ if (mRunState != RUN_STATE_STOPPING && mRunState != RUN_STATE_STOPPED) {
+ // Take down any open network notifications
+ setNotificationVisible(false, 0, false, 0);
- mRunState = RUN_STATE_STOPPING;
- return WifiNative.disconnectCommand();
+ mRunState = RUN_STATE_STOPPING;
+ return WifiNative.disconnectCommand();
+ } else {
+ /*
+ * The "driver-stop" wake lock normally is released from the
+ * connectivity manager after the mobile data connection has
+ * been established, or after a timeout period, if that never
+ * happens. Because WifiService.updateWifiState() can get called
+ * multiple times, we can end up acquiring the wake lock and calling
+ * disconnectAndStop() even when a disconnect or stop operation
+ * is already in progress. In that case, we want to ignore the
+ * disconnectAndStop request and release the (ref-counted) wake
+ * lock, so that eventually, when the mobile data connection is
+ * established, the ref count will drop to zero.
+ */
+ releaseWakeLock();
+ }
+ return true;
}
public synchronized boolean restart() {
@@ -1309,6 +1391,10 @@ public class WifiStateTracker extends NetworkStateTracker {
return true;
}
+ public synchronized boolean removeNetwork(int networkId) {
+ return mDisconnectExpected = WifiNative.removeNetworkCommand(networkId);
+ }
+
public boolean setRadio(boolean turnOn) {
return mWM.setWifiEnabled(turnOn);
}
@@ -1468,8 +1554,9 @@ public class WifiStateTracker extends NetworkStateTracker {
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
+ sb.append("interface ").append(mInterfaceName).
+ append(" runState=").append(mRunState).append(LS);
sb.append(mWifiInfo).append(LS);
- sb.append("interface ").append(mInterfaceName).append(LS);
sb.append(mDhcpInfo).append(LS);
sb.append("haveIpAddress=").append(mHaveIPAddress).
append(", obtainingIpAddress=").append(mObtainingIPAddress).