summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/BackupRestoreConfirmation/Android.mk31
-rw-r--r--packages/BackupRestoreConfirmation/AndroidManifest.xml33
-rw-r--r--packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml54
-rw-r--r--packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml54
-rw-r--r--packages/BackupRestoreConfirmation/res/values/strings.xml32
-rw-r--r--packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java242
-rw-r--r--packages/DefaultContainerService/jni/Android.mk2
-rw-r--r--packages/DefaultContainerService/res/values-af/strings.xml24
-rw-r--r--packages/DefaultContainerService/res/values-am/strings.xml24
-rw-r--r--packages/DefaultContainerService/res/values-ms/strings.xml24
-rw-r--r--packages/DefaultContainerService/res/values-sw/strings.xml24
-rw-r--r--packages/DefaultContainerService/res/values-zu/strings.xml24
-rw-r--r--packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java313
-rw-r--r--packages/SettingsProvider/AndroidManifest.xml1
-rw-r--r--packages/SettingsProvider/res/values-af/strings.xml23
-rw-r--r--packages/SettingsProvider/res/values-am/strings.xml23
-rw-r--r--packages/SettingsProvider/res/values-ms/strings.xml23
-rw-r--r--packages/SettingsProvider/res/values-sw/strings.xml23
-rw-r--r--packages/SettingsProvider/res/values-zu/strings.xml23
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java5
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java167
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java6
-rw-r--r--packages/SharedStorageBackup/Android.mk33
-rw-r--r--packages/SharedStorageBackup/AndroidManifest.xml29
-rw-r--r--packages/SharedStorageBackup/proguard.flags1
-rw-r--r--packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java93
-rw-r--r--packages/SystemUI/AndroidManifest.xml11
-rw-r--r--packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png (renamed from packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png)bin7927 -> 7927 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png (renamed from packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png)bin9784 -> 9784 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/recents_callout_line.png (renamed from packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png)bin114 -> 114 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.pngbin0 -> 1750 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.pngbin0 -> 1753 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_background.9.pngbin3233 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.pngbin0 -> 1262 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.pngbin0 -> 1139 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.pngbin0 -> 288 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png (renamed from packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png)bin3981 -> 2846 bytes
-rw-r--r--packages/SystemUI/res/drawable-large-hdpi/app_icon.pngbin7310 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.pngbin10841 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-large-mdpi/app_icon.pngbin5167 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.pngbin2056 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/panel_notification.pngbin7854 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.pngbin0 -> 7927 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.pngbin0 -> 9784 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/recents_callout_line.pngbin0 -> 114 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.pngbin0 -> 1750 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.pngbin0 -> 1753 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_background.9.pngbin204 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/statusbar_background.9.pngbin0 -> 2849 bytes
-rw-r--r--packages/SystemUI/res/drawable-nodpi/panel_notification.pngbin243 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-sw600dp-hdpi/app_icon.pngbin7310 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-sw600dp-mdpi/app_icon.pngbin5167 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable/panel_notification_tiled.xml22
-rw-r--r--packages/SystemUI/res/layout-land/status_bar_recent_item.xml79
-rw-r--r--packages/SystemUI/res/layout-land/status_bar_recent_panel.xml83
-rw-r--r--packages/SystemUI/res/layout-port/status_bar_recent_item.xml89
-rw-r--r--packages/SystemUI/res/layout-port/status_bar_recent_panel.xml84
-rw-r--r--packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml4
-rw-r--r--packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml45
-rw-r--r--packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml52
-rw-r--r--packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml33
-rw-r--r--packages/SystemUI/res/layout/navigation_bar.xml130
-rw-r--r--packages/SystemUI/res/layout/recent_apps_activity.xml55
-rw-r--r--packages/SystemUI/res/layout/recents_detail_view.xml40
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml14
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_row.xml52
-rw-r--r--packages/SystemUI/res/layout/status_bar_tracking.xml13
-rw-r--r--packages/SystemUI/res/layout/usb_preference_buttons.xml43
-rw-r--r--packages/SystemUI/res/values-af-land/strings.xml23
-rw-r--r--packages/SystemUI/res/values-af/strings.xml88
-rw-r--r--packages/SystemUI/res/values-am-land/strings.xml23
-rw-r--r--packages/SystemUI/res/values-am/strings.xml88
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml8
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml8
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml8
-rw-r--r--packages/SystemUI/res/values-da/strings.xml8
-rw-r--r--packages/SystemUI/res/values-de/strings.xml8
-rw-r--r--packages/SystemUI/res/values-el/strings.xml8
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml12
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml8
-rw-r--r--packages/SystemUI/res/values-es/strings.xml8
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml8
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml8
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml8
-rw-r--r--packages/SystemUI/res/values-hdpi/dimens.xml24
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml8
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml8
-rw-r--r--packages/SystemUI/res/values-in/strings.xml8
-rw-r--r--packages/SystemUI/res/values-it/strings.xml8
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml8
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml39
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml8
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml8
-rw-r--r--packages/SystemUI/res/values-mdpi/dimens.xml24
-rw-r--r--packages/SystemUI/res/values-ms-land/strings.xml23
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml72
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml8
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-port/dimens.xml34
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml8
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml8
-rw-r--r--packages/SystemUI/res/values-rm/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sw-land/strings.xml23
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml88
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml36
-rw-r--r--packages/SystemUI/res/values-th/strings.xml8
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml8
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml8
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml8
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml8
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml8
-rw-r--r--packages/SystemUI/res/values-zu-land/strings.xml23
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml88
-rw-r--r--packages/SystemUI/res/values/attrs.xml3
-rw-r--r--packages/SystemUI/res/values/colors.xml1
-rw-r--r--packages/SystemUI/res/values/config.xml5
-rw-r--r--packages/SystemUI/res/values/dimens.xml23
-rw-r--r--packages/SystemUI/res/values/strings.xml9
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/Choreographer.java136
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java533
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java (renamed from packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsCarouselView.java)29
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java307
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java92
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java)349
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java309
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java114
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java267
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java407
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java96
-rw-r--r--packages/TtsService/Android.mk15
-rwxr-xr-xpackages/TtsService/AndroidManifest.xml17
-rw-r--r--packages/TtsService/MODULE_LICENSE_APACHE20
-rw-r--r--packages/TtsService/NOTICE190
-rwxr-xr-xpackages/TtsService/jni/Android.mk30
-rw-r--r--packages/TtsService/jni/android_tts_SynthProxy.cpp1073
-rw-r--r--packages/TtsService/proguard.flags5
-rw-r--r--packages/TtsService/res/drawable-hdpi/ic_launcher_text_to_speech.pngbin6931 -> 0 bytes
-rw-r--r--packages/TtsService/res/drawable-mdpi/ic_launcher_text_to_speech.pngbin6809 -> 0 bytes
-rwxr-xr-xpackages/TtsService/src/android/tts/SynthProxy.java238
-rwxr-xr-xpackages/TtsService/src/android/tts/TtsService.java1503
-rw-r--r--packages/VpnDialogs/Android.mk27
-rw-r--r--packages/VpnDialogs/AndroidManifest.xml22
-rw-r--r--packages/VpnDialogs/res/layout/confirm.xml61
-rw-r--r--packages/VpnDialogs/res/layout/manage.xml43
-rw-r--r--packages/VpnDialogs/res/values/strings.xml45
-rw-r--r--packages/VpnDialogs/res/values/styles.xml37
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java119
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java187
-rw-r--r--packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java19
168 files changed, 5329 insertions, 4319 deletions
diff --git a/packages/BackupRestoreConfirmation/Android.mk b/packages/BackupRestoreConfirmation/Android.mk
new file mode 100644
index 0000000..e775b44
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2011 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := BackupRestoreConfirmation
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+########################
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/packages/BackupRestoreConfirmation/AndroidManifest.xml b/packages/BackupRestoreConfirmation/AndroidManifest.xml
new file mode 100644
index 0000000..19848f6
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2011, 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.android.backupconfirm" >
+
+ <uses-permission android:name="android.permission.BACKUP" />
+
+ <application android:allowClearUserData="false"
+ android:allowBackup="false"
+ android:permission="android.permission.CONFIRM_FULL_BACKUP" >
+
+ <activity android:name=".BackupRestoreConfirmation"
+ android:windowSoftInputMode="stateAlwaysHidden"
+ android:excludeFromRecents="true"
+ android:exported="true" >
+ </activity>
+ </application>
+</manifest>
diff --git a/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml b/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml
new file mode 100644
index 0000000..a4564e6
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+/*
+ * Copyright (C) 2011, 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.
+ */
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dp" >
+
+ <TextView android:id="@+id/confirm_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="30dp"
+ android:text="@string/backup_confirm_text" />
+
+ <TextView android:id="@+id/package_name"
+ android:layout_width="match_parent"
+ android:layout_height="20dp"
+ android:layout_marginLeft="30dp"
+ android:layout_below="@id/confirm_text"
+ android:layout_marginBottom="30dp" />
+
+ <Button android:id="@+id/button_allow"
+ android:filterTouchesWhenObscured="true"
+ android:text="@string/allow_backup_button_label"
+ android:layout_below="@id/package_name"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <Button android:id="@+id/button_deny"
+ android:text="@string/deny_backup_button_label"
+ android:layout_below="@id/package_name"
+ android:layout_toRightOf="@id/button_allow"
+ android:layout_alignTop="@id/button_allow"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+</RelativeLayout>
diff --git a/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
new file mode 100644
index 0000000..ca99ae1
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+/*
+ * Copyright (C) 2011, 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.
+ */
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dp" >
+
+ <TextView android:id="@+id/confirm_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="30dp"
+ android:text="@string/restore_confirm_text" />
+
+ <TextView android:id="@+id/package_name"
+ android:layout_width="match_parent"
+ android:layout_height="20dp"
+ android:layout_marginLeft="30dp"
+ android:layout_below="@id/confirm_text"
+ android:layout_marginBottom="30dp" />
+
+ <Button android:id="@+id/button_allow"
+ android:filterTouchesWhenObscured="true"
+ android:text="@string/allow_restore_button_label"
+ android:layout_below="@id/package_name"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <Button android:id="@+id/button_deny"
+ android:text="@string/deny_restore_button_label"
+ android:layout_below="@id/package_name"
+ android:layout_toRightOf="@id/button_allow"
+ android:layout_alignTop="@id/button_allow"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+</RelativeLayout>
diff --git a/packages/BackupRestoreConfirmation/res/values/strings.xml b/packages/BackupRestoreConfirmation/res/values/strings.xml
new file mode 100644
index 0000000..3d85e86
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Text for message to user that a full backup has been requested, and must be confirmed. -->
+ <string name="backup_confirm_text">A full backup of all data to a connected desktop computer has been requested. Do you want to allow this to happen\?\n\nIf you did not request the backup yourself, do not allow the operation to proceed.</string>
+ <!-- Button to allow a requested full backup to occur -->
+ <string name="allow_backup_button_label">Back up my data</string>
+ <!-- Button to refuse to allow the requested full backup -->
+ <string name="deny_backup_button_label">Do not back up</string>
+
+ <!-- Text for message to user that a full restore has been requested, and must be confirmed. -->
+ <string name="restore_confirm_text">A full restore of all data from a connected desktop computer has been requested. Do you want to allow this to happen\?\n\nIf you did not request the restore yourself, do not allow the operation to proceed. This will replace any data currently on the device!</string>
+ <!-- Button to allow a requested full restore to occur -->
+ <string name="allow_restore_button_label">Restore my data</string>
+ <!-- Button to refuse to allow the requested full restore -->
+ <string name="deny_restore_button_label">Do not restore</string>
+
+</resources>
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
new file mode 100644
index 0000000..ed413e6
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2011 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.backupconfirm;
+
+import android.app.Activity;
+import android.app.backup.FullBackup;
+import android.app.backup.IBackupManager;
+import android.app.backup.IFullBackupRestoreObserver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+/**
+ * Confirm with the user that a requested full backup/restore operation is legitimate.
+ * Any attempt to perform a full backup/restore will launch this UI and wait for a
+ * designated timeout interval (nominally 30 seconds) for the user to confirm. If the
+ * user fails to respond within the timeout period, or explicitly refuses the operation
+ * within the UI presented here, no data will be transferred off the device.
+ *
+ * Note that the fully scoped name of this class is baked into the backup manager service.
+ *
+ * @hide
+ */
+public class BackupRestoreConfirmation extends Activity {
+ static final String TAG = "BackupRestoreConfirmation";
+ static final boolean DEBUG = true;
+
+ static final int MSG_START_BACKUP = 1;
+ static final int MSG_BACKUP_PACKAGE = 2;
+ static final int MSG_END_BACKUP = 3;
+ static final int MSG_START_RESTORE = 11;
+ static final int MSG_RESTORE_PACKAGE = 12;
+ static final int MSG_END_RESTORE = 13;
+ static final int MSG_TIMEOUT = 100;
+
+ Handler mHandler;
+ IBackupManager mBackupManager;
+ FullObserver mObserver;
+ int mToken;
+ boolean mDidAcknowledge;
+
+ TextView mStatusView;
+ Button mAllowButton;
+ Button mDenyButton;
+
+ // Handler for dealing with observer callbacks on the main thread
+ class ObserverHandler extends Handler {
+ Context mContext;
+ ObserverHandler(Context context) {
+ mContext = context;
+ mDidAcknowledge = false;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_START_BACKUP: {
+ Toast.makeText(mContext, "!!! Backup starting !!!", Toast.LENGTH_LONG).show();
+ }
+ break;
+
+ case MSG_BACKUP_PACKAGE: {
+ String name = (String) msg.obj;
+ mStatusView.setText(name);
+ }
+ break;
+
+ case MSG_END_BACKUP: {
+ Toast.makeText(mContext, "!!! Backup ended !!!", Toast.LENGTH_SHORT).show();
+ finish();
+ }
+ break;
+
+ case MSG_START_RESTORE: {
+ Toast.makeText(mContext, "!!! Restore starting !!!", Toast.LENGTH_LONG).show();
+ }
+ break;
+
+ case MSG_RESTORE_PACKAGE: {
+ String name = (String) msg.obj;
+ mStatusView.setText(name);
+ }
+ break;
+
+ case MSG_END_RESTORE: {
+ Toast.makeText(mContext, "!!! Restore ended !!!", Toast.LENGTH_SHORT).show();
+ finish();
+ }
+ break;
+
+ case MSG_TIMEOUT: {
+ Toast.makeText(mContext, "!!! TIMED OUT !!!", Toast.LENGTH_LONG).show();
+ }
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final Intent intent = getIntent();
+ final String action = intent.getAction();
+
+ int layoutId;
+ if (action.equals(FullBackup.FULL_BACKUP_INTENT_ACTION)) {
+ layoutId = R.layout.confirm_backup;
+ } else if (action.equals(FullBackup.FULL_RESTORE_INTENT_ACTION)) {
+ layoutId = R.layout.confirm_restore;
+ } else {
+ Slog.w(TAG, "Backup/restore confirmation activity launched with invalid action!");
+ finish();
+ return;
+ }
+
+ mToken = intent.getIntExtra(FullBackup.CONF_TOKEN_INTENT_EXTRA, -1);
+ if (mToken < 0) {
+ Slog.e(TAG, "Backup/restore confirmation requested but no token passed!");
+ finish();
+ return;
+ }
+
+ mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
+
+ mHandler = new ObserverHandler(getApplicationContext());
+ mObserver = new FullObserver();
+
+ setContentView(layoutId);
+
+ // Same resource IDs for each layout variant (backup / restore)
+ mStatusView = (TextView) findViewById(R.id.package_name);
+ mAllowButton = (Button) findViewById(R.id.button_allow);
+ mDenyButton = (Button) findViewById(R.id.button_deny);
+
+ mAllowButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ sendAcknowledgement(mToken, true, mObserver);
+ mAllowButton.setEnabled(false);
+ mDenyButton.setEnabled(false);
+ }
+ });
+
+ mDenyButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ sendAcknowledgement(mToken, false, mObserver);
+ mAllowButton.setEnabled(false);
+ mDenyButton.setEnabled(false);
+ }
+ });
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+
+ // We explicitly equate departure from the UI with refusal. This includes the
+ // implicit configuration-changed stop/restart cycle.
+ sendAcknowledgement(mToken, false, null);
+ finish();
+ }
+
+ void sendAcknowledgement(int token, boolean allow, IFullBackupRestoreObserver observer) {
+ if (!mDidAcknowledge) {
+ mDidAcknowledge = true;
+ try {
+ mBackupManager.acknowledgeFullBackupOrRestore(mToken, true, mObserver);
+ } catch (RemoteException e) {
+ // TODO: bail gracefully if we can't contact the backup manager
+ }
+ }
+ }
+
+ /**
+ * The observer binder for showing backup/restore progress. This binder just bounces
+ * the notifications onto the main thread.
+ */
+ class FullObserver extends IFullBackupRestoreObserver.Stub {
+ //
+ // IFullBackupRestoreObserver implementation
+ //
+ @Override
+ public void onStartBackup() throws RemoteException {
+ mHandler.sendEmptyMessage(MSG_START_BACKUP);
+ }
+
+ @Override
+ public void onBackupPackage(String name) throws RemoteException {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_BACKUP_PACKAGE, name));
+ }
+
+ @Override
+ public void onEndBackup() throws RemoteException {
+ mHandler.sendEmptyMessage(MSG_END_BACKUP);
+ }
+
+ @Override
+ public void onStartRestore() throws RemoteException {
+ mHandler.sendEmptyMessage(MSG_START_RESTORE);
+ }
+
+ @Override
+ public void onRestorePackage(String name) throws RemoteException {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_RESTORE_PACKAGE, name));
+ }
+
+ @Override
+ public void onEndRestore() throws RemoteException {
+ mHandler.sendEmptyMessage(MSG_END_RESTORE);
+ }
+
+ @Override
+ public void onTimeout() throws RemoteException {
+ mHandler.sendEmptyMessage(MSG_TIMEOUT);
+ }
+ }
+}
diff --git a/packages/DefaultContainerService/jni/Android.mk b/packages/DefaultContainerService/jni/Android.mk
index a2febec..79ff451 100644
--- a/packages/DefaultContainerService/jni/Android.mk
+++ b/packages/DefaultContainerService/jni/Android.mk
@@ -18,7 +18,7 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_PRELINK_MODULE := false
+
LOCAL_SRC_FILES := \
com_android_defcontainer_MeasurementUtils.cpp
diff --git a/packages/DefaultContainerService/res/values-af/strings.xml b/packages/DefaultContainerService/res/values-af/strings.xml
new file mode 100644
index 0000000..5fa075b
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-af/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Pakkettoegangshelper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-am/strings.xml b/packages/DefaultContainerService/res/values-am/strings.xml
new file mode 100644
index 0000000..1101a45
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-am/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"ጥቅል ድረስ አጋዥ"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-ms/strings.xml b/packages/DefaultContainerService/res/values-ms/strings.xml
new file mode 100644
index 0000000..77d7927
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-ms/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Pembantu Akses Pakej"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-sw/strings.xml b/packages/DefaultContainerService/res/values-sw/strings.xml
new file mode 100644
index 0000000..8d1f515
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-sw/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Kisaidizi cha Kufikia Furushi"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-zu/strings.xml b/packages/DefaultContainerService/res/values-zu/strings.xml
new file mode 100644
index 0000000..d501165
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-zu/strings.xml
@@ -0,0 +1,24 @@
+<?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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Umsizi Wokufinyelela Kwiphakheji"</string>
+</resources>
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 337593f..15c1653 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -47,7 +47,7 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.util.LinkedList;
+import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
@@ -117,7 +117,7 @@ public class DefaultContainerService extends IntentService {
* @return Returns PackageInfoLite object containing
* the package info and recommended app location.
*/
- public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags) {
+ public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags, long threshold) {
PackageInfoLite ret = new PackageInfoLite();
if (fileUri == null) {
Log.i(TAG, "Invalid package uri " + fileUri);
@@ -131,15 +131,9 @@ public class DefaultContainerService extends IntentService {
return ret;
}
String archiveFilePath = fileUri.getPath();
- PackageParser packageParser = new PackageParser(archiveFilePath);
- File sourceFile = new File(archiveFilePath);
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
- PackageParser.PackageLite pkg = packageParser.parsePackageLite(
- archiveFilePath, 0);
- // Nuke the parser reference right away and force a gc
- packageParser = null;
- Runtime.getRuntime().gc();
+ PackageParser.PackageLite pkg = PackageParser.parsePackageLite(archiveFilePath, 0);
if (pkg == null) {
Log.w(TAG, "Failed to parse package");
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
@@ -147,12 +141,22 @@ public class DefaultContainerService extends IntentService {
}
ret.packageName = pkg.packageName;
ret.installLocation = pkg.installLocation;
- ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation, archiveFilePath, flags);
+ ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation,
+ archiveFilePath, flags, threshold);
return ret;
}
- public boolean checkFreeStorage(boolean external, Uri fileUri) {
- return checkFreeStorageInner(external, fileUri);
+ @Override
+ public boolean checkInternalFreeStorage(Uri packageUri, long threshold)
+ throws RemoteException {
+ final File apkFile = new File(packageUri.getPath());
+ return isUnderInternalThreshold(apkFile, threshold);
+ }
+
+ @Override
+ public boolean checkExternalFreeStorage(Uri packageUri) throws RemoteException {
+ final File apkFile = new File(packageUri.getPath());
+ return isUnderExternalThreshold(apkFile);
}
public ObbInfo getObbInfo(String filename) {
@@ -225,41 +229,15 @@ public class DefaultContainerService extends IntentService {
String codePath = packageURI.getPath();
File codeFile = new File(codePath);
- // Calculate size of container needed to hold base APK.
- long sizeBytes = codeFile.length();
-
- // Check all the native files that need to be copied and add that to the container size.
- ZipFile zipFile;
- List<Pair<ZipEntry, String>> nativeFiles;
- try {
- zipFile = new ZipFile(codeFile);
-
- nativeFiles = new LinkedList<Pair<ZipEntry, String>>();
-
- NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles);
+ // Native files we need to copy to the container.
+ List<Pair<ZipEntry, String>> nativeFiles = new ArrayList<Pair<ZipEntry, String>>();
- final int N = nativeFiles.size();
- for (int i = 0; i < N; i++) {
- final Pair<ZipEntry, String> entry = nativeFiles.get(i);
-
- /*
- * Note that PackageHelper.createSdDir adds a 1MB padding on
- * our claimed size, so we don't have to worry about block
- * alignment here.
- */
- sizeBytes += entry.first.getSize();
- }
- } catch (ZipException e) {
- Log.w(TAG, "Failed to extract data from package file", e);
- return null;
- } catch (IOException e) {
- Log.w(TAG, "Failed to cache package shared libs", e);
- return null;
- }
+ // Calculate size of container needed to hold base APK.
+ final int sizeMb = calculateContainerSize(codeFile, nativeFiles);
// Create new container
String newCachePath = null;
- if ((newCachePath = PackageHelper.createSdDir(sizeBytes, newCid, key, Process.myUid())) == null) {
+ if ((newCachePath = PackageHelper.createSdDir(sizeMb, newCid, key, Process.myUid())) == null) {
Log.e(TAG, "Failed to create container " + newCid);
return null;
}
@@ -274,6 +252,8 @@ public class DefaultContainerService extends IntentService {
}
try {
+ ZipFile zipFile = new ZipFile(codeFile);
+
File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);
sharedLibraryDir.mkdir();
@@ -386,163 +366,196 @@ public class DefaultContainerService extends IntentService {
return true;
}
- // Constants related to app heuristics
- // No-installation limit for internal flash: 10% or less space available
- private static final double LOW_NAND_FLASH_TRESHOLD = 0.1;
+ private static final int PREFER_INTERNAL = 1;
+ private static final int PREFER_EXTERNAL = 2;
- // No-installation limit for internal flash: 150MB or less space available
- private static final long NAND_MIN_FREE_SPACE = (1024L * 1024L * 150L);
-
- // SD-to-internal app size threshold: currently set to 1 MB
- private static final long INSTALL_ON_SD_THRESHOLD = (1024 * 1024);
- private static final int ERR_LOC = -1;
-
- private int recommendAppInstallLocation(int installLocation,
- String archiveFilePath, int flags) {
- boolean checkInt = false;
- boolean checkExt = false;
+ private int recommendAppInstallLocation(int installLocation, String archiveFilePath, int flags,
+ long threshold) {
+ int prefer;
boolean checkBoth = false;
+
check_inner : {
- // Check flags.
+ /*
+ * Explicit install flags should override the manifest settings.
+ */
if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
- // Check for forward locked app
- checkInt = true;
+ /*
+ * Forward-locked applications cannot be installed on SD card,
+ * so only allow checking internal storage.
+ */
+ prefer = PREFER_INTERNAL;
break check_inner;
} else if ((flags & PackageManager.INSTALL_INTERNAL) != 0) {
- // Explicit flag to install internally.
- // Check internal storage and return
- checkInt = true;
+ prefer = PREFER_INTERNAL;
break check_inner;
} else if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) {
- // Explicit flag to install externally.
- // Check external storage and return
- checkExt = true;
+ prefer = PREFER_EXTERNAL;
break check_inner;
}
- // Check for manifest option
+
+ /* No install flags. Check for manifest option. */
if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
- checkInt = true;
+ prefer = PREFER_INTERNAL;
break check_inner;
} else if (installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
- checkExt = true;
+ prefer = PREFER_EXTERNAL;
checkBoth = true;
break check_inner;
} else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
- checkInt = true;
+ // We default to preferring internal storage.
+ prefer = PREFER_INTERNAL;
checkBoth = true;
break check_inner;
}
+
// Pick user preference
int installPreference = Settings.System.getInt(getApplicationContext()
.getContentResolver(),
Settings.Secure.DEFAULT_INSTALL_LOCATION,
PackageHelper.APP_INSTALL_AUTO);
if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) {
- checkInt = true;
+ prefer = PREFER_INTERNAL;
break check_inner;
} else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) {
- checkExt = true;
+ prefer = PREFER_EXTERNAL;
break check_inner;
}
- // Fall back to default policy if nothing else is specified.
- checkInt = true;
+
+ /*
+ * Fall back to default policy of internal-only if nothing else is
+ * specified.
+ */
+ prefer = PREFER_INTERNAL;
}
- // Package size = code size + cache size + data size
- // If code size > 1 MB, install on SD card.
- // Else install on internal NAND flash, unless space on NAND is less than 10%
- String status = Environment.getExternalStorageState();
- long availSDSize = -1;
- boolean mediaAvailable = false;
- final boolean mediaEmulated = Environment.isExternalStorageEmulated();
- if (!mediaEmulated && status.equals(Environment.MEDIA_MOUNTED)) {
- StatFs sdStats = new StatFs(
- Environment.getExternalStorageDirectory().getPath());
- availSDSize = (long)sdStats.getAvailableBlocks() *
- (long)sdStats.getBlockSize();
- mediaAvailable = true;
+ final boolean emulated = Environment.isExternalStorageEmulated();
+
+ final File apkFile = new File(archiveFilePath);
+
+ boolean fitsOnInternal = false;
+ if (checkBoth || prefer == PREFER_INTERNAL) {
+ fitsOnInternal = isUnderInternalThreshold(apkFile, threshold);
}
- StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
- long totalInternalSize = (long)internalStats.getBlockCount() *
- (long)internalStats.getBlockSize();
- long availInternalSize = (long)internalStats.getAvailableBlocks() *
- (long)internalStats.getBlockSize();
-
- double pctNandFree = (double)availInternalSize / (double)totalInternalSize;
-
- File apkFile = new File(archiveFilePath);
- long pkgLen = apkFile.length();
-
- // To make final copy
- long reqInstallSize = pkgLen;
- // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now.
- long reqInternalSize = 0;
- boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
- boolean intAvailOk = (reqInstallSize + reqInternalSize) < (availInternalSize - NAND_MIN_FREE_SPACE);
+
boolean fitsOnSd = false;
- if (mediaAvailable && (reqInstallSize < availSDSize)) {
- // If we do not have an internal size requirement
- // don't do a threshold check.
- if (reqInternalSize == 0) {
- fitsOnSd = true;
- } else if ((reqInternalSize < availInternalSize) && intThresholdOk) {
- fitsOnSd = true;
- }
+ if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) {
+ fitsOnSd = isUnderExternalThreshold(apkFile);
}
- boolean fitsOnInt = intThresholdOk || intAvailOk;
- if (checkInt) {
- // Check for internal memory availability
- if (fitsOnInt) {
+
+ if (prefer == PREFER_INTERNAL) {
+ if (fitsOnInternal) {
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
}
- } else if (checkExt) {
+ } else if (!emulated && prefer == PREFER_EXTERNAL) {
if (fitsOnSd) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
}
+
if (checkBoth) {
- // Check for internal first
- if (fitsOnInt) {
+ if (fitsOnInternal) {
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
- }
- // Check for external next
- if (fitsOnSd) {
+ } else if (!emulated && fitsOnSd) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
}
- if (!mediaEmulated && (checkExt || checkBoth) && !mediaAvailable) {
+
+ /*
+ * If they requested to be on the external media by default, return that
+ * the media was unavailable. Otherwise, indicate there was insufficient
+ * storage space available.
+ */
+ if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)
+ && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE;
+ } else {
+ return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
- return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
- private boolean checkFreeStorageInner(boolean external, Uri packageURI) {
- File apkFile = new File(packageURI.getPath());
- long size = apkFile.length();
- if (external) {
- String status = Environment.getExternalStorageState();
- long availSDSize = -1;
- if (status.equals(Environment.MEDIA_MOUNTED)) {
- StatFs sdStats = new StatFs(
- Environment.getExternalStorageDirectory().getPath());
- availSDSize = (long)sdStats.getAvailableBlocks() *
- (long)sdStats.getBlockSize();
+ private boolean isUnderInternalThreshold(File apkFile, long threshold) {
+ final long size = apkFile.length();
+
+ final StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
+ final long availInternalSize = (long) internalStats.getAvailableBlocks()
+ * (long) internalStats.getBlockSize();
+
+ return (availInternalSize - size) > threshold;
+ }
+
+
+ private boolean isUnderExternalThreshold(File apkFile) {
+ if (Environment.isExternalStorageEmulated()) {
+ return false;
+ }
+
+ final int sizeMb = calculateContainerSize(apkFile, null);
+
+ final int availSdMb;
+ if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
+ StatFs sdStats = new StatFs(Environment.getExternalStorageDirectory().getPath());
+ long availSdSize = (long) (sdStats.getAvailableBlocks() * sdStats.getBlockSize());
+ availSdMb = (int) (availSdSize >> 20);
+ } else {
+ availSdMb = -1;
+ }
+
+ return availSdMb > sizeMb;
+ }
+
+ /**
+ * Calculate the container size for an APK. Takes into account the
+ *
+ * @param apkFile file from which to calculate size
+ * @return size in megabytes (2^20 bytes)
+ */
+ private int calculateContainerSize(File apkFile, List<Pair<ZipEntry, String>> outFiles) {
+ // Calculate size of container needed to hold base APK.
+ long sizeBytes = apkFile.length();
+
+ // Check all the native files that need to be copied and add that to the
+ // container size.
+ ZipFile zipFile;
+ final List<Pair<ZipEntry, String>> nativeFiles;
+ try {
+ zipFile = new ZipFile(apkFile);
+
+ if (outFiles != null) {
+ nativeFiles = outFiles;
+ } else {
+ nativeFiles = new ArrayList<Pair<ZipEntry, String>>();
+ }
+
+ NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles);
+
+ final int N = nativeFiles.size();
+ for (int i = 0; i < N; i++) {
+ final Pair<ZipEntry, String> entry = nativeFiles.get(i);
+
+ /*
+ * Note a 1MB padding is added to the claimed size, so we don't
+ * have to worry about block alignment here.
+ */
+ sizeBytes += entry.first.getSize();
}
- return availSDSize > size;
+ } catch (ZipException e) {
+ Log.w(TAG, "Failed to extract data from package file", e);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to cache package shared libs", e);
}
- StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
- long totalInternalSize = (long)internalStats.getBlockCount() *
- (long)internalStats.getBlockSize();
- long availInternalSize = (long)internalStats.getAvailableBlocks() *
- (long)internalStats.getBlockSize();
-
- double pctNandFree = (double)availInternalSize / (double)totalInternalSize;
- // To make final copy
- long reqInstallSize = size;
- // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now.
- long reqInternalSize = 0;
- boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
- boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalSize);
- return intThresholdOk && intAvailOk;
+
+ int sizeMb = (int) (sizeBytes >> 20);
+ if ((sizeBytes - (sizeMb * 1024 * 1024)) > 0) {
+ sizeMb++;
+ }
+
+ /*
+ * Add buffer size because we don't have a good way to determine the
+ * real FAT size. Your FAT size varies with how many directory entries
+ * you need, how big the whole filesystem is, and other such headaches.
+ */
+ sizeMb++;
+
+ return sizeMb;
}
}
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index dd0d064..e5f52e2 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -6,6 +6,7 @@
android:label="@string/app_label"
android:process="system"
android:backupAgent="SettingsBackupAgent"
+ android:fullBackupAgent="SettingsBackupAgent"
android:killAfterRestore="false"
android:icon="@drawable/ic_launcher_settings">
diff --git a/packages/SettingsProvider/res/values-af/strings.xml b/packages/SettingsProvider/res/values-af/strings.xml
new file mode 100644
index 0000000..79a7f2d
--- /dev/null
+++ b/packages/SettingsProvider/res/values-af/strings.xml
@@ -0,0 +1,23 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"Instellingsberging"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-am/strings.xml b/packages/SettingsProvider/res/values-am/strings.xml
new file mode 100644
index 0000000..6380b99
--- /dev/null
+++ b/packages/SettingsProvider/res/values-am/strings.xml
@@ -0,0 +1,23 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"የቅንብሮች ማከማቻ"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-ms/strings.xml b/packages/SettingsProvider/res/values-ms/strings.xml
new file mode 100644
index 0000000..9108b07
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ms/strings.xml
@@ -0,0 +1,23 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"Storan Tetapan"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-sw/strings.xml b/packages/SettingsProvider/res/values-sw/strings.xml
new file mode 100644
index 0000000..d17f60b
--- /dev/null
+++ b/packages/SettingsProvider/res/values-sw/strings.xml
@@ -0,0 +1,23 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">"Hifadhi ya Mipangilio"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-zu/strings.xml b/packages/SettingsProvider/res/values-zu/strings.xml
new file mode 100644
index 0000000..61f3d11
--- /dev/null
+++ b/packages/SettingsProvider/res/values-zu/strings.xml
@@ -0,0 +1,23 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4567566098528588863">" Izilungiselelo zokugcina"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 2e2768f..b349030 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -77,8 +77,6 @@
<!-- Default for Settings.System.VIBRATE_IN_SILENT -->
<bool name="def_vibrate_in_silent">true</bool>
- <bool name="def_use_ptp_interface">false</bool>
-
<!-- Default for Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION -->
<bool name="def_accessibility_script_injection">false</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 964fe9c..47ab150 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -63,7 +63,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 64;
+ private static final int DATABASE_VERSION = 65;
private Context mContext;
@@ -1209,9 +1209,6 @@ public class DatabaseHelper extends SQLiteOpenHelper {
loadBooleanSetting(stmt, Settings.System.VIBRATE_IN_SILENT,
R.bool.def_vibrate_in_silent);
- loadBooleanSetting(stmt, Settings.System.USE_PTP_INTERFACE,
- R.bool.def_use_ptp_interface);
-
// Set notification volume to follow ringer volume by default
loadBooleanSetting(stmt, Settings.System.NOTIFICATIONS_USE_RING_VOLUME,
R.bool.def_notifications_use_ring_volume);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 744798e..0c4ef7d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -36,6 +36,7 @@ import java.util.zip.CRC32;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupAgentHelper;
+import android.app.backup.FullBackup;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -54,6 +55,7 @@ import android.util.Log;
*/
public class SettingsBackupAgent extends BackupAgentHelper {
private static final boolean DEBUG = false;
+ private static final boolean DEBUG_BACKUP = DEBUG || true;
private static final String KEY_SYSTEM = "system";
private static final String KEY_SECURE = "secure";
@@ -74,6 +76,9 @@ public class SettingsBackupAgent extends BackupAgentHelper {
private static final int STATE_WIFI_CONFIG = 4;
private static final int STATE_SIZE = 5; // The number of state items
+ // Versioning of the 'full backup' format
+ private static final int FULL_BACKUP_VERSION = 1;
+
private static String[] sortedSystemKeys = null;
private static String[] sortedSecureKeys = null;
@@ -99,11 +104,17 @@ public class SettingsBackupAgent extends BackupAgentHelper {
private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
+ // Name of the temporary file we use during full backup/restore. This is
+ // stored in the full-backup tarfile as well, so should not be changed.
+ private static final String STAGE_FILE = "flattened-data";
+
private SettingsHelper mSettingsHelper;
private WifiManager mWfm;
private static String mWifiConfigFile;
public void onCreate() {
+ if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
+
mSettingsHelper = new SettingsHelper(this);
super.onCreate();
@@ -121,22 +132,58 @@ public class SettingsBackupAgent extends BackupAgentHelper {
byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
byte[] wifiConfigData = getFileData(mWifiConfigFile);
- long[] stateChecksums = readOldChecksums(oldState);
+ // This same agent class is used for both full and incremental backups. A full
+ // backup is flagged by a 'null' oldState argument. In the case of a full backup,
+ // the output is structured as tarfile contents.
+ if (oldState != null) {
+ long[] stateChecksums = readOldChecksums(oldState);
- stateChecksums[STATE_SYSTEM] =
+ stateChecksums[STATE_SYSTEM] =
writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
- stateChecksums[STATE_SECURE] =
+ stateChecksums[STATE_SECURE] =
writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
- stateChecksums[STATE_LOCALE] =
+ stateChecksums[STATE_LOCALE] =
writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
- stateChecksums[STATE_WIFI_SUPPLICANT] =
+ stateChecksums[STATE_WIFI_SUPPLICANT] =
writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
- wifiSupplicantData, data);
- stateChecksums[STATE_WIFI_CONFIG] =
+ wifiSupplicantData, data);
+ stateChecksums[STATE_WIFI_CONFIG] =
writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
- data);
-
- writeNewChecksums(stateChecksums, newState);
+ data);
+
+ writeNewChecksums(stateChecksums, newState);
+ } else {
+ // Write the data to the staging file, then emit that as our tarfile
+ // representation of the backed-up settings.
+ String root = getFilesDir().getAbsolutePath();
+ File stage = new File(root, STAGE_FILE);
+ try {
+ FileOutputStream filestream = new FileOutputStream(stage);
+ BufferedOutputStream bufstream = new BufferedOutputStream(filestream);
+ DataOutputStream out = new DataOutputStream(bufstream);
+
+ out.writeInt(FULL_BACKUP_VERSION);
+
+ out.writeInt(systemSettingsData.length);
+ out.write(systemSettingsData);
+ out.writeInt(secureSettingsData.length);
+ out.write(secureSettingsData);
+ out.writeInt(locale.length);
+ out.write(locale);
+ out.writeInt(wifiSupplicantData.length);
+ out.write(wifiSupplicantData);
+ out.writeInt(wifiConfigData.length);
+ out.write(wifiConfigData);
+
+ out.flush(); // also flushes downstream
+
+ // now we're set to emit the tar stream
+ FullBackup.backupToTar(getPackageName(), FullBackup.DATA_TREE_TOKEN, null,
+ root, stage.getAbsolutePath(), data);
+ } finally {
+ stage.delete();
+ }
+ }
}
@Override
@@ -164,7 +211,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
} else if (KEY_LOCALE.equals(key)) {
byte[] localeData = new byte[size];
data.readEntityData(localeData, 0, size);
- mSettingsHelper.setLocaleData(localeData);
+ mSettingsHelper.setLocaleData(localeData, size);
} else if (KEY_WIFI_CONFIG.equals(key)) {
restoreFileData(mWifiConfigFile, data);
} else {
@@ -173,6 +220,70 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
}
+ @Override
+ public void onRestoreFile(ParcelFileDescriptor data, long size,
+ int type, String domain, String relpath, long mode, long mtime)
+ throws IOException {
+ if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked");
+ // Our data is actually a blob of flattened settings data identical to that
+ // produced during incremental backups. Just unpack and apply it all in
+ // turn.
+ FileInputStream instream = new FileInputStream(data.getFileDescriptor());
+ DataInputStream in = new DataInputStream(instream);
+
+ int version = in.readInt();
+ if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version);
+ if (version == FULL_BACKUP_VERSION) {
+ // system settings data first
+ int nBytes = in.readInt();
+ if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
+ byte[] buffer = new byte[nBytes];
+ in.read(buffer, 0, nBytes);
+ restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI);
+
+ // secure settings
+ nBytes = in.readInt();
+ if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
+ if (nBytes > buffer.length) buffer = new byte[nBytes];
+ in.read(buffer, 0, nBytes);
+ restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI);
+
+ // locale
+ nBytes = in.readInt();
+ if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data");
+ if (nBytes > buffer.length) buffer = new byte[nBytes];
+ in.read(buffer, 0, nBytes);
+ mSettingsHelper.setLocaleData(buffer, nBytes);
+
+ // wifi supplicant
+ nBytes = in.readInt();
+ if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of wifi supplicant data");
+ if (nBytes > buffer.length) buffer = new byte[nBytes];
+ in.read(buffer, 0, nBytes);
+ int retainedWifiState = enableWifi(false);
+ restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, buffer, nBytes);
+ FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
+ FileUtils.S_IRUSR | FileUtils.S_IWUSR |
+ FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+ Process.myUid(), Process.WIFI_UID);
+ // retain the previous WIFI state.
+ enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
+ retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
+
+ // wifi config
+ nBytes = in.readInt();
+ if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of wifi config data");
+ if (nBytes > buffer.length) buffer = new byte[nBytes];
+ in.read(buffer, 0, nBytes);
+ restoreFileData(mWifiConfigFile, buffer, nBytes);
+
+ if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
+ } else {
+ data.close();
+ throw new IOException("Invalid file schema");
+ }
+ }
+
private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
long[] stateChecksums = new long[STATE_SIZE];
@@ -252,6 +363,17 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
private void restoreSettings(BackupDataInput data, Uri contentUri) {
+ byte[] settings = new byte[data.getDataSize()];
+ try {
+ data.readEntityData(settings, 0, settings.length);
+ } catch (IOException ioe) {
+ Log.e(TAG, "Couldn't read entity data");
+ return;
+ }
+ restoreSettings(settings, settings.length, contentUri);
+ }
+
+ private void restoreSettings(byte[] settings, int bytes, Uri contentUri) {
if (DEBUG) Log.i(TAG, "restoreSettings: " + contentUri);
String[] whitelist = null;
if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
@@ -261,15 +383,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
ContentValues cv = new ContentValues(2);
- byte[] settings = new byte[data.getDataSize()];
- try {
- data.readEntityData(settings, 0, settings.length);
- } catch (IOException ioe) {
- Log.e(TAG, "Couldn't read entity data");
- return;
- }
int pos = 0;
- while (pos < settings.length) {
+ while (pos < bytes) {
int length = readInt(settings, pos);
pos += 4;
String settingName = length > 0? new String(settings, pos, length) : null;
@@ -416,13 +531,16 @@ public class SettingsBackupAgent extends BackupAgentHelper {
private void restoreFileData(String filename, BackupDataInput data) {
byte[] bytes = new byte[data.getDataSize()];
if (bytes.length <= 0) return;
+ restoreFileData(filename, bytes, bytes.length);
+ }
+
+ private void restoreFileData(String filename, byte[] bytes, int size) {
try {
- data.readEntityData(bytes, 0, bytes.length);
File file = new File(filename);
if (file.exists()) file.delete();
OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true));
- os.write(bytes);
+ os.write(bytes, 0, size);
os.close();
} catch (IOException ioe) {
Log.w(TAG, "Couldn't restore " + filename);
@@ -471,15 +589,18 @@ public class SettingsBackupAgent extends BackupAgentHelper {
private void restoreWifiSupplicant(String filename, BackupDataInput data) {
byte[] bytes = new byte[data.getDataSize()];
if (bytes.length <= 0) return;
+ restoreWifiSupplicant(filename, bytes, bytes.length);
+ }
+
+ private void restoreWifiSupplicant(String filename, byte[] bytes, int size) {
try {
- data.readEntityData(bytes, 0, bytes.length);
File supplicantFile = new File(FILE_WIFI_SUPPLICANT);
if (supplicantFile.exists()) supplicantFile.delete();
copyWifiSupplicantTemplate();
OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true));
os.write("\n".getBytes());
- os.write(bytes);
+ os.write(bytes, 0, size);
os.close();
} catch (IOException ioe) {
Log.w(TAG, "Couldn't restore " + filename);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 0e75fbc..3e7d86a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -147,7 +147,7 @@ public class SettingsHelper {
* "ll" is the language code and "cc" is the country code.
* @param data the locale string in bytes.
*/
- void setLocaleData(byte[] data) {
+ void setLocaleData(byte[] data, int size) {
// Check if locale was set by the user:
Configuration conf = mContext.getResources().getConfiguration();
Locale loc = conf.locale;
@@ -157,9 +157,9 @@ public class SettingsHelper {
if (conf.userSetLocale) return; // Don't change if user set it in the SetupWizard
final String[] availableLocales = mContext.getAssets().getLocales();
- String localeCode = new String(data);
+ String localeCode = new String(data, 0, size);
String language = new String(data, 0, 2);
- String country = data.length > 4 ? new String(data, 3, 2) : "";
+ String country = size > 4 ? new String(data, 3, 2) : "";
loc = null;
for (int i = 0; i < availableLocales.length; i++) {
if (availableLocales[i].equals(localeCode)) {
diff --git a/packages/SharedStorageBackup/Android.mk b/packages/SharedStorageBackup/Android.mk
new file mode 100644
index 0000000..1d4f4da
--- /dev/null
+++ b/packages/SharedStorageBackup/Android.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2011 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PACKAGE_NAME := SharedStorageBackup
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+########################
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/packages/SharedStorageBackup/AndroidManifest.xml b/packages/SharedStorageBackup/AndroidManifest.xml
new file mode 100644
index 0000000..258059c
--- /dev/null
+++ b/packages/SharedStorageBackup/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2011, 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.android.sharedstoragebackup" >
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
+
+ <application android:allowClearUserData="false"
+ android:permission="android.permission.CONFIRM_FULL_BACKUP"
+ android:fullBackupAgent=".SharedStorageAgent"
+ android:allowBackup="false" >
+ </application>
+</manifest>
diff --git a/packages/SharedStorageBackup/proguard.flags b/packages/SharedStorageBackup/proguard.flags
new file mode 100644
index 0000000..f43cb81
--- /dev/null
+++ b/packages/SharedStorageBackup/proguard.flags
@@ -0,0 +1 @@
+-keep class com.android.sharedstoragebackup.SharedStorageAgent
diff --git a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
new file mode 100644
index 0000000..b02ca2e
--- /dev/null
+++ b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java
@@ -0,0 +1,93 @@
+package com.android.sharedstoragebackup;
+
+import android.app.backup.FullBackup;
+import android.app.backup.FullBackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.content.Context;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+
+public class SharedStorageAgent extends FullBackupAgent {
+ static final String TAG = "SharedStorageAgent";
+ static final boolean DEBUG = true;
+
+ StorageVolume[] mVolumes;
+
+ @Override
+ public void onCreate() {
+ StorageManager mgr = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
+ if (mgr != null) {
+ mVolumes = mgr.getVolumeList();
+ } else {
+ Slog.e(TAG, "Unable to access Storage Manager");
+ }
+ }
+
+ @Override
+ public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) throws IOException {
+ // If there are shared-storage volumes available, run the inherited directory-
+ // hierarchy backup process on them. By convention in the Storage Manager, the
+ // "primary" shared storage volume is first in the list.
+ if (mVolumes != null) {
+ for (int i = 0; i < mVolumes.length; i++) {
+ StorageVolume v = mVolumes[i];
+ // Express the contents of volume N this way in the tar stream:
+ // shared/N/path/to/file
+ // The restore will then extract to the given volume
+ String domain = FullBackup.SHARED_PREFIX + i;
+ processTree(null, domain, v.getPath(), null, data);
+ }
+ }
+ }
+
+ /**
+ * Incremental onRestore() implementation is not used.
+ */
+ @Override
+ public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+ throws IOException {
+ }
+
+ /**
+ * Full restore of one file to shared storage
+ */
+ @Override
+ public void onRestoreFile(ParcelFileDescriptor data, long size,
+ int type, String domain, String relpath, long mode, long mtime)
+ throws IOException {
+ Slog.d(TAG, "Shared restore: [ " + domain + " : " + relpath + "]");
+
+ File outFile = null;
+
+ // The file path must be in the semantic form [number]/path/to/file...
+ int slash = relpath.indexOf('/');
+ if (slash > 0) {
+ try {
+ int i = Integer.parseInt(relpath.substring(0, slash));
+ if (i <= mVolumes.length) {
+ outFile = new File(mVolumes[i].getPath(), relpath.substring(slash + 1));
+ if (DEBUG) Slog.i(TAG, " => " + outFile.getAbsolutePath());
+ } else {
+ Slog.w(TAG, "Cannot restore data for unavailable volume " + i);
+ }
+ } catch (NumberFormatException e) {
+ if (DEBUG) Slog.w(TAG, "Bad volume number token: " + relpath.substring(0, slash));
+ }
+ } else {
+ if (DEBUG) Slog.i(TAG, "Can't find volume-number token");
+ }
+ if (outFile == null) {
+ Slog.e(TAG, "Skipping data with malformed path " + relpath);
+ }
+
+ FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, false);
+ }
+}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index bbe146d..6d8eab6 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -25,6 +25,10 @@
android:exported="true"
/>
+ <activity android:name=".usb.UsbPreferenceActivity"
+ android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:excludeFromRecents="true">
+ </activity>
<activity android:name=".usb.UsbStorageActivity"
android:excludeFromRecents="true">
</activity>
@@ -33,13 +37,6 @@
android:excludeFromRecents="true">
</activity>
- <activity android:name=".recent.RecentApplicationsActivity"
- android:theme="@android:style/Theme.NoTitleBar"
- android:excludeFromRecents="true"
- android:launchMode="singleInstance"
- android:exported="true">
- </activity>
-
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbConfirmActivity"
android:exported="true"
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png
index 87c7be6..87c7be6 100644
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
index 4f4ae78..4f4ae78 100644
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png
index 5f4c035..5f4c035 100644
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png
new file mode 100644
index 0000000..23aabce
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png
new file mode 100644
index 0000000..0b0765b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
deleted file mode 100644
index a4be298..0000000
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
new file mode 100644
index 0000000..87d1944
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png
new file mode 100644
index 0000000..3b7c9c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png
new file mode 100644
index 0000000..653acbb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png
index 87a67c9..a933833 100644
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png
+++ b/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/app_icon.png b/packages/SystemUI/res/drawable-large-hdpi/app_icon.png
deleted file mode 100644
index aedf7e7..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png
deleted file mode 100644
index a57c27a..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/app_icon.png b/packages/SystemUI/res/drawable-large-mdpi/app_icon.png
deleted file mode 100644
index 50a8ac8..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index a1c39e6..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/panel_notification.png b/packages/SystemUI/res/drawable-mdpi/panel_notification.png
deleted file mode 100644
index 3789f3c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/panel_notification.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png
new file mode 100644
index 0000000..87c7be6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
new file mode 100644
index 0000000..4f4ae78
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png
new file mode 100644
index 0000000..5f4c035
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png
new file mode 100644
index 0000000..23aabce
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png
new file mode 100644
index 0000000..0b0765b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
deleted file mode 100644
index eb7c1a4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png b/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png
new file mode 100644
index 0000000..6c588f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-nodpi/panel_notification.png b/packages/SystemUI/res/drawable-nodpi/panel_notification.png
deleted file mode 100644
index 437deff..0000000
--- a/packages/SystemUI/res/drawable-nodpi/panel_notification.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/app_icon.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/app_icon.png
deleted file mode 100644
index aedf7e7..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/app_icon.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/app_icon.png
deleted file mode 100644
index 50a8ac8..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/panel_notification_tiled.xml b/packages/SystemUI/res/drawable/panel_notification_tiled.xml
deleted file mode 100644
index 9d41e28..0000000
--- a/packages/SystemUI/res/drawable/panel_notification_tiled.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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.
--->
-
-<bitmap
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/panel_notification"
- android:tileMode="repeat"
- />
-
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
new file mode 100644
index 0000000..be4f1d7
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** 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.
+*/
+-->
+
+<!-- android:background="@drawable/status_bar_closed_default_background" -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
+
+ <ImageView android:id="@+id/app_thumbnail"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
+ android:scaleType="center"
+ android:background="@drawable/recents_thumbnail_bg_selector"
+ />
+
+ <ImageView android:id="@+id/app_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_alignTop="@id/app_thumbnail"
+ android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
+ android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
+ android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
+ android:adjustViewBounds="true"
+ />
+
+ <TextView android:id="@+id/app_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_label_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_below="@id/app_thumbnail"
+ android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
+ android:layout_marginLeft="@dimen/recents_thumbnail_bg_padding_left"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ />
+
+ <TextView android:id="@+id/app_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_description_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_below="@id/app_label"
+ android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
+ android:layout_marginLeft="@dimen/recents_thumbnail_bg_padding_left"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ />
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
new file mode 100644
index 0000000..4a80489
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2010, 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.
+*/
+-->
+
+<com.android.systemui.recent.RecentsPanelView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/recents_root"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content">
+
+ <FrameLayout
+ android:id="@+id/recents_bg_protect"
+ android:background="@drawable/recents_bg_protect_tile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentBottom="true"
+ android:paddingBottom="@*android:dimen/status_bar_height"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <LinearLayout android:id="@+id/recents_glow"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|right"
+ android:background="@drawable/recents_blue_glow"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ >
+ <com.android.systemui.recent.RecentsHorizontalScrollView android:id="@+id/recents_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
+ android:divider="@null"
+ android:stackFromBottom="true"
+ android:fadingEdge="horizontal"
+ android:scrollbars="none"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:listSelector="@drawable/recents_thumbnail_bg_selector"
+ android:layout_gravity="bottom|left"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <LinearLayout android:id="@+id/recents_linear_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+ </LinearLayout>
+
+ </com.android.systemui.recent.RecentsHorizontalScrollView>
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+ <View android:id="@+id/recents_dismiss_button"
+ android:layout_width="80px"
+ android:layout_height="@*android:dimen/status_bar_height"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:background="@drawable/ic_sysbar_back_ime"
+ />
+
+</com.android.systemui.recent.RecentsPanelView>
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
new file mode 100644
index 0000000..76965c9
--- /dev/null
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** 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.
+*/
+-->
+
+<!-- android:background="@drawable/status_bar_closed_default_background" -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
+
+ <ImageView android:id="@+id/app_thumbnail"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
+ android:scaleType="center"
+ />
+
+ <ImageView android:id="@+id/app_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_alignTop="@id/app_thumbnail"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
+ android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
+ android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
+ android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
+ android:adjustViewBounds="true"
+ />
+
+ <TextView android:id="@+id/app_label"
+ android:layout_width="@dimen/status_bar_recents_app_label_width"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_label_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignTop="@id/app_icon"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ />
+
+ <View android:id="@+id/recents_callout_line"
+ android:layout_width="@dimen/status_bar_recents_app_label_width"
+ android:layout_height="1dip"
+ android:layout_alignParentLeft="true"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+ android:layout_toLeftOf="@id/app_thumbnail"
+ android:layout_below="@id/app_label"
+ android:layout_marginRight="3dip"
+ android:layout_marginTop="3dip"
+ android:background="@drawable/recents_callout_line"
+ />
+
+ <TextView android:id="@+id/app_description"
+ android:layout_width="@dimen/status_bar_recents_app_label_width"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_description_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignParentLeft="true"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+ android:layout_below="@id/recents_callout_line"
+ android:layout_marginTop="3dip"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ />
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
new file mode 100644
index 0000000..9391f9d
--- /dev/null
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2010, 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.
+*/
+-->
+
+<com.android.systemui.recent.RecentsPanelView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/recents_root"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent">
+
+ <FrameLayout
+ android:id="@+id/recents_bg_protect"
+ android:background="@drawable/recents_bg_protect_tile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentBottom="true"
+ android:paddingBottom="@*android:dimen/status_bar_height"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <LinearLayout android:id="@+id/recents_glow"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="0dp"
+ android:layout_gravity="bottom"
+ android:background="@drawable/recents_blue_glow"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ >
+ <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
+ android:layout_width="@dimen/status_bar_recents_width"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="0dp"
+ android:divider="@null"
+ android:stackFromBottom="true"
+ android:fadingEdge="vertical"
+ android:scrollbars="none"
+ android:fadingEdgeLength="20dip"
+ android:listSelector="@drawable/recents_thumbnail_bg_selector"
+ android:layout_gravity="bottom|left"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <LinearLayout android:id="@+id/recents_linear_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+ </LinearLayout>
+
+ </com.android.systemui.recent.RecentsVerticalScrollView>
+
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+ <View android:id="@+id/recents_dismiss_button"
+ android:layout_width="80px"
+ android:layout_height="@*android:dimen/status_bar_height"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:background="@drawable/ic_sysbar_back_ime"
+ />
+
+</com.android.systemui.recent.RecentsPanelView>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
index ef57228..72519fb 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel.xml
@@ -57,15 +57,15 @@
android:layout_width="match_parent"
android:layout_weight="1"
>
- <LinearLayout
+ <com.android.systemui.statusbar.policy.NotificationRowLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal|bottom"
- android:orientation="vertical"
android:clickable="true"
android:focusable="true"
android:descendantFocusability="afterDescendants"
+ systemui:rowHeight="@dimen/notification_height"
/>
</ScrollView>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
deleted file mode 100644
index 8e456b2..0000000
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_row.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="65dp"
- >
-
- <ImageButton
- android:id="@+id/veto"
- android:layout_width="48dp"
- android:layout_height="match_parent"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true"
- android:src="@drawable/status_bar_veto"
- android:scaleType="center"
- android:background="@null"
- android:paddingRight="8dp"
- android:paddingLeft="8dp"
- />
-
- <ImageView
- android:id="@+id/large_icon"
- android:layout_width="@android:dimen/notification_large_icon_width"
- android:layout_height="@android:dimen/notification_large_icon_height"
- android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
- android:scaleType="center"
- />
-
- <com.android.systemui.statusbar.LatestItemView android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="64dp"
- android:layout_alignParentTop="true"
- android:layout_toRightOf="@id/large_icon"
- android:layout_toLeftOf="@id/veto"
- android:focusable="true"
- android:clickable="true"
- />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_alignParentBottom="true"
- android:background="@android:drawable/divider_horizontal_dark"
- />
-
-</RelativeLayout>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index 3f172e6..9687866 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -36,53 +36,53 @@
<ImageView android:id="@+id/app_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:layout_marginLeft="131dip"
- android:layout_marginTop="13dip"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_alignTop="@id/app_thumbnail"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
+ android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
android:adjustViewBounds="true"
/>
- <View android:id="@+id/recents_callout_line"
- android:layout_width="97dip"
- android:layout_height="1dip"
- android:layout_alignParentTop="true"
- android:layout_marginTop="61dip"
- android:layout_alignParentLeft="true"
- android:layout_marginLeft="16dip"
- android:layout_toLeftOf="@id/app_thumbnail"
- android:layout_marginRight="3dip"
- android:background="@drawable/recents_callout_line"
- />
-
<TextView android:id="@+id/app_label"
- android:layout_width="97dip"
+ android:layout_width="@dimen/status_bar_recents_app_label_width"
android:layout_height="wrap_content"
- android:textSize="18dip"
+ android:textSize="@dimen/status_bar_recents_app_label_text_size"
android:fadingEdge="horizontal"
- android:fadingEdgeLength="10dip"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
android:scrollHorizontally="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
- android:layout_marginLeft="16dip"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
android:layout_marginTop="32dip"
android:singleLine="true"
android:ellipsize="marquee"
/>
+ <View android:id="@+id/recents_callout_line"
+ android:layout_width="@dimen/status_bar_recents_app_label_width"
+ android:layout_height="1dip"
+ android:layout_below="@id/app_label"
+ android:layout_marginTop="3dip"
+ android:layout_alignParentLeft="true"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+ android:layout_toLeftOf="@id/app_thumbnail"
+ android:layout_marginRight="3dip"
+ android:background="@drawable/recents_callout_line"
+ />
+
<TextView android:id="@+id/app_description"
- android:layout_width="97dip"
+ android:layout_width="@dimen/status_bar_recents_app_label_width"
android:layout_height="wrap_content"
- android:textSize="18dip"
+ android:textSize="@dimen/status_bar_recents_app_description_text_size"
android:fadingEdge="horizontal"
- android:fadingEdgeLength="10dip"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
android:scrollHorizontally="true"
android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:layout_marginLeft="16dip"
- android:layout_marginTop="61dip"
+ android:layout_below="@id/recents_callout_line"
+ android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+ android:layout_marginTop="3dip"
android:singleLine="true"
android:ellipsize="marquee"
/>
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
index 42940be..75fdc67 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
@@ -18,11 +18,13 @@
*/
-->
-<com.android.systemui.statusbar.tablet.RecentAppsPanel
+<com.android.systemui.recent.RecentsPanelView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recents_root"
android:layout_height="match_parent"
- android:layout_width="wrap_content">
+ android:layout_width="wrap_content"
+ android:clipToPadding="false"
+ android:clipChildren="false">
<FrameLayout
android:id="@+id/recents_bg_protect"
@@ -31,7 +33,8 @@
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:paddingBottom="@*android:dimen/status_bar_height"
- android:clipToPadding="false">
+ android:clipToPadding="false"
+ android:clipChildren="false">
<LinearLayout android:id="@+id/recents_glow"
android:layout_width="wrap_content"
@@ -40,20 +43,32 @@
android:layout_gravity="bottom"
android:background="@drawable/recents_blue_glow"
android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:clipChildren="false"
>
-
- <ListView android:id="@+id/recents_container"
+ <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
android:layout_width="@dimen/status_bar_recents_width"
android:layout_height="wrap_content"
- android:layout_marginRight="100dip"
+ android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
android:divider="@null"
- android:scrollingCache="true"
android:stackFromBottom="true"
android:fadingEdge="vertical"
android:scrollbars="none"
android:fadingEdgeLength="20dip"
+ android:layout_gravity="bottom|left"
android:listSelector="@drawable/recents_thumbnail_bg_selector"
- />
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <LinearLayout android:id="@+id/recents_linear_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+ </LinearLayout>
+
+ </com.android.systemui.recent.RecentsVerticalScrollView>
</LinearLayout>
@@ -67,4 +82,4 @@
android:background="@drawable/ic_sysbar_back_ime"
/>
-</com.android.systemui.statusbar.tablet.RecentAppsPanel>
+</com.android.systemui.recent.RecentsPanelView>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
new file mode 100644
index 0000000..b97c6a5
--- /dev/null
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2011, 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.
+*/
+-->
+
+<com.android.systemui.statusbar.phone.NavigationBarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ >
+
+ <FrameLayout
+ android:id="@+id/background"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="#FF000000"
+ >
+
+ <LinearLayout android:id="@+id/rot0"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:orientation="horizontal"
+ >
+
+ <!-- navigation controls -->
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_back"
+ systemui:keyCode="4"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_home"
+ systemui:keyCode="3"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_menu"
+ systemui:keyCode="82"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/rot90"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:visibility="gone"
+ >
+
+ <!-- navigation controls -->
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_menu"
+ systemui:keyCode="82"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_home"
+ systemui:keyCode="3"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_back"
+ systemui:keyCode="4"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/rot270"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:visibility="gone"
+ >
+
+ <!-- navigation controls -->
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_back"
+ systemui:keyCode="4"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_home"
+ systemui:keyCode="3"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_menu"
+ systemui:keyCode="82"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+
+ </FrameLayout>
+</com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/res/layout/recent_apps_activity.xml b/packages/SystemUI/res/layout/recent_apps_activity.xml
deleted file mode 100644
index ec661e8..0000000
--- a/packages/SystemUI/res/layout/recent_apps_activity.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?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.
-*/
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <!-- Title -->
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="#80FFFFFF"
- android:textStyle="bold"
- android:singleLine="true"
- android:text="@string/recent_tasks_title"
- android:visibility="gone"/>
-
- <!-- This is only intended to be visible when carousel is invisible -->
- <TextView
- android:id="@+id/no_applications_message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:text="@string/recent_tasks_empty"
- android:visibility="gone"/>
-
- <com.android.systemui.recent.RecentApplicationsCarouselView
- android:id="@+id/carousel"
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1">
- </com.android.systemui.recent.RecentApplicationsCarouselView>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/recents_detail_view.xml b/packages/SystemUI/res/layout/recents_detail_view.xml
deleted file mode 100644
index 879d0f2..0000000
--- a/packages/SystemUI/res/layout/recents_detail_view.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?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.
-*/
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <!-- Application Title -->
- <TextView android:id="@+id/app_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:singleLine="true"/>
-
- <!-- Application Details -->
- <TextView
- android:id="@+id/app_description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"/>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 18e8273..6670eff 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -18,7 +18,9 @@
*/
-->
-<com.android.systemui.statusbar.phone.ExpandedView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.systemui.statusbar.phone.ExpandedView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:orientation="vertical"
android:focusable="true"
android:descendantFocusability="afterDescendants"
@@ -97,10 +99,11 @@
android:textAppearance="@style/TextAppearance.StatusBar.Title"
android:text="@string/status_bar_ongoing_events_title"
/>
- <LinearLayout android:id="@+id/ongoingItems"
+ <com.android.systemui.statusbar.policy.NotificationRowLayout
+ android:id="@+id/ongoingItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
+ systemui:rowHeight="@dimen/notification_height"
/>
<TextView android:id="@+id/latestTitle"
@@ -111,10 +114,11 @@
android:textAppearance="@style/TextAppearance.StatusBar.Title"
android:text="@string/status_bar_latest_events_title"
/>
- <LinearLayout android:id="@+id/latestItems"
+ <com.android.systemui.statusbar.policy.NotificationRowLayout
+ android:id="@+id/latestItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
+ systemui:rowHeight="@dimen/notification_height"
/>
</LinearLayout>
</ScrollView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 88d9739..aff6a6e 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -1,24 +1,46 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="65sp"
- android:orientation="vertical"
+ android:layout_height="@dimen/notification_height"
>
+ <ImageButton
+ android:id="@+id/veto"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:layout_marginRight="-80dp"
+ android:src="@drawable/status_bar_veto"
+ android:scaleType="center"
+ android:background="@null"
+ android:paddingRight="8dp"
+ android:paddingLeft="8dp"
+ />
+
+ <ImageView
+ android:id="@+id/large_icon"
+ android:layout_width="@android:dimen/notification_large_icon_width"
+ android:layout_height="@android:dimen/notification_large_icon_height"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:scaleType="center"
+ />
+
<com.android.systemui.statusbar.LatestItemView android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="64sp"
- android:background="@android:drawable/status_bar_item_background"
- android:focusable="true"
- android:clickable="true"
- android:paddingRight="6sp"
- >
- </com.android.systemui.statusbar.LatestItemView>
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/large_icon"
+ android:layout_alignParentRight="true"
+ android:focusable="true"
+ android:clickable="true"
+ />
<View
android:layout_width="match_parent"
- android:layout_height="1sp"
- android:background="@android:drawable/divider_horizontal_bright"
+ android:layout_height="1dp"
+ android:layout_alignParentBottom="true"
+ android:background="@android:drawable/divider_horizontal_dark"
/>
-</LinearLayout>
-
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_tracking.xml b/packages/SystemUI/res/layout/status_bar_tracking.xml
index a0ddab5..baa45c5 100644
--- a/packages/SystemUI/res/layout/status_bar_tracking.xml
+++ b/packages/SystemUI/res/layout/status_bar_tracking.xml
@@ -26,11 +26,12 @@
android:paddingRight="0px"
>
- <com.android.systemui.statusbar.phone.TrackingPatternView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:background="#ff000000"
+ />
<com.android.systemui.statusbar.phone.CloseDragHandle android:id="@+id/close"
android:layout_width="match_parent"
@@ -42,7 +43,7 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:scaleType="fitXY"
- android:src="@drawable/shade_handlebar"
+ android:src="@drawable/status_bar_close_on"
/>
</com.android.systemui.statusbar.phone.CloseDragHandle>
diff --git a/packages/SystemUI/res/layout/usb_preference_buttons.xml b/packages/SystemUI/res/layout/usb_preference_buttons.xml
new file mode 100644
index 0000000..babe07e
--- /dev/null
+++ b/packages/SystemUI/res/layout/usb_preference_buttons.xml
@@ -0,0 +1,43 @@
+<?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.
+-->
+
+<!-- Check box that is displayed in the activity resolver UI for the user
+ to make their selection the preferred activity. -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="14dip"
+ android:paddingRight="15dip"
+ android:orientation="vertical">
+
+ <Button
+ android:id="@+id/mtp_ptp_button"
+ android:text="@string/use_ptp_button_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:clickable="true" />
+
+ <Button
+ android:id="@+id/installer_cd_button"
+ android:text="@string/installer_cd_button_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:focusable="true"
+ android:clickable="true" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-af-land/strings.xml b/packages/SystemUI/res/values-af-land/strings.xml
new file mode 100644
index 0000000..9db7121
--- /dev/null
+++ b/packages/SystemUI/res/values-af-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, 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="toast_rotation_locked" msgid="7609673011431556092">"Skerm is nou in landskapsoriëntering gesluit."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
new file mode 100644
index 0000000..c0c39d2
--- /dev/null
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -0,0 +1,88 @@
+<?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="app_label" msgid="7164937344850004466">"Stelsel-UI"</string>
+ <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Maak skoon"</string>
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Moenie steur nie"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Wys kennisgewings"</string>
+ <!-- no translation found for status_bar_no_notifications_title (4755261167193833213) -->
+ <skip />
+ <!-- no translation found for status_bar_ongoing_events_title (1682504513316879202) -->
+ <skip />
+ <!-- no translation found for status_bar_latest_events_title (6594767438577593172) -->
+ <skip />
+ <!-- no translation found for battery_low_title (7923774589611311406) -->
+ <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Die battery raak pap."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> oor"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"USB-laaiery nie ondersteun nie."\n"Gebruik net die laaier wat verskaf is."</string>
+ <string name="battery_low_why" msgid="7279169609518386372">"Batterygebruik"</string>
+ <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellings"</string>
+ <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
+ <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegtuigmodus"</string>
+ <!-- no translation found for status_bar_settings_auto_rotation (3790482541357798421) -->
+ <skip />
+ <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEMP"</string>
+ <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"OUTO"</string>
+ <string name="status_bar_settings_notifications" msgid="397146176280905137">"Kennisgewings"</string>
+ <string name="recent_tasks_title" msgid="3691764623638127888">"Onlangs"</string>
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Geen onlangse programme nie."</string>
+ <string name="recent_tasks_app_label" msgid="3796483981246752469">"Apps"</string>
+ <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-verbind"</string>
+ <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+ <skip />
+ <!-- no translation found for status_bar_use_physical_keyboard (3695516942412442936) -->
+ <skip />
+ <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for always_use_device (1450287437017315906) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (1210954576979621596) -->
+ <skip />
+ <!-- no translation found for compat_mode_on (6623839244840638213) -->
+ <skip />
+ <!-- no translation found for compat_mode_off (4434467572461327898) -->
+ <skip />
+ <!-- no translation found for compat_mode_help_header (7020175705401506719) -->
+ <skip />
+ <!-- no translation found for compat_mode_help_body (4946726776359270040) -->
+ <skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
+</resources>
diff --git a/packages/SystemUI/res/values-am-land/strings.xml b/packages/SystemUI/res/values-am-land/strings.xml
new file mode 100644
index 0000000..993b7d3
--- /dev/null
+++ b/packages/SystemUI/res/values-am-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, 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="toast_rotation_locked" msgid="7609673011431556092">"አሁን ማያበወርድ ገፅ አቀማመጥ ተሸንጉሯል።"</string>
+</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
new file mode 100644
index 0000000..7b37070
--- /dev/null
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -0,0 +1,88 @@
+<?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="app_label" msgid="7164937344850004466">"የስርዓት UI"</string>
+ <string name="status_bar_clear_all_button" msgid="7774721344716731603">"አጥራ"</string>
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"አይረብሹ"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"ማሳወቂያዎች አሳይ"</string>
+ <!-- no translation found for status_bar_no_notifications_title (4755261167193833213) -->
+ <skip />
+ <!-- no translation found for status_bar_ongoing_events_title (1682504513316879202) -->
+ <skip />
+ <!-- no translation found for status_bar_latest_events_title (6594767438577593172) -->
+ <skip />
+ <!-- no translation found for battery_low_title (7923774589611311406) -->
+ <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"ባትሪው እያነሰ ነው።"</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> ቀሪ"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"USB ኃይል መሙያ አይታገዝም።"\n" የቀረበውን ኃይል መሙያ ብቻ ተጠቀም።"</string>
+ <string name="battery_low_why" msgid="7279169609518386372">"የባትሪ ጥቅም"</string>
+ <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ቅንብሮች"</string>
+ <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
+ <string name="status_bar_settings_airplane" msgid="4879879698500955300">"የአውሮፕላን ሁነታ"</string>
+ <!-- no translation found for status_bar_settings_auto_rotation (3790482541357798421) -->
+ <skip />
+ <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ድምጽ አጥፋ"</string>
+ <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ራስ ሰር"</string>
+ <string name="status_bar_settings_notifications" msgid="397146176280905137">"ማሳወቂያዎች"</string>
+ <string name="recent_tasks_title" msgid="3691764623638127888">"የቅርብ ጊዜ"</string>
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"ምንም የቅርብ ጊዜ ትግበራዎች የሉም።"</string>
+ <string name="recent_tasks_app_label" msgid="3796483981246752469">"ትግበራዎች"</string>
+ <string name="bluetooth_tethered" msgid="7094101612161133267">"ብሉቱዝ አያይዝ"</string>
+ <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+ <skip />
+ <!-- no translation found for status_bar_use_physical_keyboard (3695516942412442936) -->
+ <skip />
+ <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for always_use_device (1450287437017315906) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (1210954576979621596) -->
+ <skip />
+ <!-- no translation found for compat_mode_on (6623839244840638213) -->
+ <skip />
+ <!-- no translation found for compat_mode_off (4434467572461327898) -->
+ <skip />
+ <!-- no translation found for compat_mode_help_header (7020175705401506719) -->
+ <skip />
+ <!-- no translation found for compat_mode_help_body (4946726776359270040) -->
+ <skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
+</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index d71cf2b..1555048 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 88357d1..1d7f558 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 09519a2..d27cb81 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 0f73333..e82ad34 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 99e67bc..2cdd3cc 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 78b1652..6dc11d1 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 4af57c1..6fd21ce 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 7e1db15..a7962d2 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -53,12 +53,16 @@
<string name="label_view" msgid="6304565553218192990">"View"</string>
<string name="always_use_device" msgid="1450287437017315906">"Use by default for this USB device"</string>
<string name="always_use_accessory" msgid="1210954576979621596">"Use by default for this USB accessory"</string>
- <!-- no translation found for compat_mode_on (6623839244840638213) -->
+ <string name="compat_mode_on" msgid="6623839244840638213">"Zoom to fill screen"</string>
+ <string name="compat_mode_off" msgid="4434467572461327898">"Stretch to fill screen"</string>
+ <string name="compat_mode_help_header" msgid="7020175705401506719">"Compatibility Zoom"</string>
+ <string name="compat_mode_help_body" msgid="4946726776359270040">"When an app was designed for a smaller screen, a zoom control will appear by the clock."</string>
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
<skip />
- <!-- no translation found for compat_mode_off (4434467572461327898) -->
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
<skip />
- <!-- no translation found for compat_mode_help_header (7020175705401506719) -->
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
<skip />
- <!-- no translation found for compat_mode_help_body (4946726776359270040) -->
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 6528c38..a730459 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a3c2302..3a489da 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 360bb8b..04e5d5f 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 71deb4a..0e20ecb 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 46e4cd2..d765570 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hdpi/dimens.xml b/packages/SystemUI/res/values-hdpi/dimens.xml
new file mode 100644
index 0000000..741b75a
--- /dev/null
+++ b/packages/SystemUI/res/values-hdpi/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2011, 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>
+ <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
+ <dimen name="recents_thumbnail_bg_padding_left">6px</dimen>
+ <dimen name="recents_thumbnail_bg_padding_top">7px</dimen>
+ <dimen name="recents_thumbnail_bg_padding_right">6px</dimen>
+ <dimen name="recents_thumbnail_bg_padding_bottom">6px</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index cc44359..9eccc49 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index bc192d7..22b9bbb 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 6e3d929..14ee7b6 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 5153550..b85175f 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 9b0cab5..8f0a95a 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 04e9906..39bf1f1 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 2511beb..516bc63 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
new file mode 100644
index 0000000..0219a77
--- /dev/null
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2011, 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>
+ <!-- thickness (width) of the navigation bar on phones that require it -->
+ <dimen name="navigation_bar_size">42dp</dimen>
+
+ <!-- Recent Applications parameters -->
+ <!-- Width of a recent app view, including all content -->
+ <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
+ <!-- How far the thumbnail for a recent app appears from left edge -->
+ <dimen name="status_bar_recents_thumbnail_left_margin">8dp</dimen>
+ <!-- How far the thumbnail for a recent app appears from top edge -->
+ <dimen name="status_bar_recents_thumbnail_top_margin">12dp</dimen>
+ <!-- Width of scrollable area in recents -->
+ <dimen name="status_bar_recents_width">128dp</dimen>
+ <!-- Padding for text descriptions -->
+ <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
+ <!-- Width of application label text -->
+ <dimen name="status_bar_recents_app_label_width">97dip</dimen>
+ <!-- Left margin of application label text -->
+ <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
+ <!-- Margin between recents container and glow on the right -->
+ <dimen name="status_bar_recents_right_glow_margin">0dip</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 8f86e85..3e2733c 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 0220d21..a899170 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mdpi/dimens.xml b/packages/SystemUI/res/values-mdpi/dimens.xml
new file mode 100644
index 0000000..741b75a
--- /dev/null
+++ b/packages/SystemUI/res/values-mdpi/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2011, 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>
+ <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
+ <dimen name="recents_thumbnail_bg_padding_left">6px</dimen>
+ <dimen name="recents_thumbnail_bg_padding_top">7px</dimen>
+ <dimen name="recents_thumbnail_bg_padding_right">6px</dimen>
+ <dimen name="recents_thumbnail_bg_padding_bottom">6px</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-ms-land/strings.xml b/packages/SystemUI/res/values-ms-land/strings.xml
new file mode 100644
index 0000000..175b0fa
--- /dev/null
+++ b/packages/SystemUI/res/values-ms-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, 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="toast_rotation_locked" msgid="7609673011431556092">"Skrin kini dikunci dalam orientasi landskap."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
new file mode 100644
index 0000000..06527d2
--- /dev/null
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -0,0 +1,72 @@
+<?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="app_label" msgid="7164937344850004466">"Sistem UI"</string>
+ <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Pdm bersih"</string>
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Jangan ganggu"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Tunjukkan pemberitahuan"</string>
+ <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Tiada pemberitahuan"</string>
+ <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sedang berlangsung"</string>
+ <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pemberitahuan"</string>
+ <string name="battery_low_title" msgid="7923774589611311406">"Sila sambungkan pengecas"</string>
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Bateri semakin lemah."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"Berbaki <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Pengecasan USB tidak disokong."\n"Gunakan hanya pengecas yang dibekalkan."</string>
+ <string name="battery_low_why" msgid="7279169609518386372">"Penggunaan bateri"</string>
+ <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Tetapan"</string>
+ <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
+ <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mod pesawat"</string>
+ <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Autoputar skrin"</string>
+ <string name="status_bar_settings_mute_label" msgid="554682549917429396">"REDAM"</string>
+ <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
+ <string name="status_bar_settings_notifications" msgid="397146176280905137">"Pemberitahuan"</string>
+ <string name="recent_tasks_title" msgid="3691764623638127888">"Baru-baru ini"</string>
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Tiada aplikasi terbaru."</string>
+ <string name="recent_tasks_app_label" msgid="3796483981246752469">"Apl"</string>
+ <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth ditambatkan"</string>
+ <string name="status_bar_input_method_settings_configure_input_methods" msgid="737483394044014246">"Konfigurasikan kaedah input"</string>
+ <string name="status_bar_use_physical_keyboard" msgid="3695516942412442936">"Guna ppn kekunci fizikal"</string>
+ <string name="usb_device_permission_prompt" msgid="3816016361969816903">"Benarkan aplikasi <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses peranti USB?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="6888598803988889959">"Benarkan aplikasi <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses aksesori USB?"</string>
+ <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Buka <xliff:g id="ACTIVITY">%1$s</xliff:g> apabila peranti USB ini disambungkan?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Buka <xliff:g id="ACTIVITY">%1$s</xliff:g> apabila aksesori USB ini disambungkan?"</string>
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Tiada apl yg dipsg boleh berfgsi dgn aksri USB ini. Ketahui ttg aksri ini di <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Aksesori USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Lihat"</string>
+ <string name="always_use_device" msgid="1450287437017315906">"Gunakan secara lalai untuk peranti USB ini"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Gunakan secara lalai untuk aksesori USB ini"</string>
+ <!-- no translation found for compat_mode_on (6623839244840638213) -->
+ <skip />
+ <!-- no translation found for compat_mode_off (4434467572461327898) -->
+ <skip />
+ <!-- no translation found for compat_mode_help_header (7020175705401506719) -->
+ <skip />
+ <!-- no translation found for compat_mode_help_body (4946726776359270040) -->
+ <skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
+</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index be5131c..90dee30 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 4ba77cb..92af8fd 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 7ed7e7c..14269df 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-port/dimens.xml b/packages/SystemUI/res/values-port/dimens.xml
new file mode 100644
index 0000000..54c25fa
--- /dev/null
+++ b/packages/SystemUI/res/values-port/dimens.xml
@@ -0,0 +1,34 @@
+<?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.
+*/
+-->
+<resources>
+ <!-- Recent Applications parameters -->
+ <!-- Width of a recent app view, including all content -->
+ <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
+ <!-- How far the thumbnail for a recent app appears from left edge -->
+ <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
+ <!-- Width of scrollable area in recents -->
+ <dimen name="status_bar_recents_width">356dp</dimen>
+ <!-- Padding for text descriptions -->
+ <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
+ <!-- Width of application label text -->
+ <dimen name="status_bar_recents_app_label_width">97dip</dimen>
+ <!-- Left margin of application label text -->
+ <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
+ <!-- Margin between recents container and glow on the right -->
+ <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index d86cea6..eadfa4c 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 9f3997a..c7d1edf 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 4d0a43a..30f317c 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -87,4 +87,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ea20ec7..c204b82 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ff6b3c6..b9ac0cb 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 82e59a6..fcb6d14 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 713b6b2..e5e365b 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 6da66c2..c6cc7db 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 4a5ea22..558f5f8 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw-land/strings.xml b/packages/SystemUI/res/values-sw-land/strings.xml
new file mode 100644
index 0000000..c9769c2
--- /dev/null
+++ b/packages/SystemUI/res/values-sw-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, 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="toast_rotation_locked" msgid="7609673011431556092">"Skrini imefungwa sasa katika uelekezo wa mandhari."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
new file mode 100644
index 0000000..12d86e3
--- /dev/null
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -0,0 +1,88 @@
+<?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="app_label" msgid="7164937344850004466">"UI ya Mfumo"</string>
+ <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Futa"</string>
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Usisumbue"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Onyesha arifa"</string>
+ <!-- no translation found for status_bar_no_notifications_title (4755261167193833213) -->
+ <skip />
+ <!-- no translation found for status_bar_ongoing_events_title (1682504513316879202) -->
+ <skip />
+ <!-- no translation found for status_bar_latest_events_title (6594767438577593172) -->
+ <skip />
+ <!-- no translation found for battery_low_title (7923774589611311406) -->
+ <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Betri inaisha."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> zimebakia"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Chaji ya USB haihamiliwi."\n" Tumia chaka iliyopeanwa."</string>
+ <string name="battery_low_why" msgid="7279169609518386372">"Utumiaji wa betri"</string>
+ <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Mipangilio"</string>
+ <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Mtandao-Hewa"</string>
+ <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Hali ya Ndege"</string>
+ <!-- no translation found for status_bar_settings_auto_rotation (3790482541357798421) -->
+ <skip />
+ <string name="status_bar_settings_mute_label" msgid="554682549917429396">"NYAMAZISHA"</string>
+ <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"KIOTOMATIKI"</string>
+ <string name="status_bar_settings_notifications" msgid="397146176280905137">"Arifa"</string>
+ <string name="recent_tasks_title" msgid="3691764623638127888">"Za hivi karibuni"</string>
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Hakuna programu za hivi karibuni."</string>
+ <string name="recent_tasks_app_label" msgid="3796483981246752469">"Programu"</string>
+ <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth imefungwa"</string>
+ <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+ <skip />
+ <!-- no translation found for status_bar_use_physical_keyboard (3695516942412442936) -->
+ <skip />
+ <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for always_use_device (1450287437017315906) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (1210954576979621596) -->
+ <skip />
+ <!-- no translation found for compat_mode_on (6623839244840638213) -->
+ <skip />
+ <!-- no translation found for compat_mode_off (4434467572461327898) -->
+ <skip />
+ <!-- no translation found for compat_mode_help_header (7020175705401506719) -->
+ <skip />
+ <!-- no translation found for compat_mode_help_body (4946726776359270040) -->
+ <skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 944e0ee..b4fd8ab 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -28,4 +28,40 @@
<dimen name="notification_panel_min_height">770dp</dimen>
<!-- Bottom margin (from display edge) for status bar panels -->
<dimen name="panel_float">56dp</dimen>
+
+ <!-- Recent Applications parameters -->
+ <!-- Width of a recent app view, including all content -->
+ <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
+ <!-- How far the thumbnail for a recent app appears from left edge -->
+ <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
+ <!-- Upper width limit for application icon -->
+ <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen>
+ <!-- Upper height limit for application icon -->
+ <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen>
+ <!-- Width of scrollable area in recents -->
+ <dimen name="status_bar_recents_width">356dp</dimen>
+ <!-- Padding for text descriptions -->
+ <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
+ <!-- Size of application label text -->
+ <dimen name="status_bar_recents_app_label_text_size">18dip</dimen>
+ <!-- Size of application description text -->
+ <dimen name="status_bar_recents_app_description_text_size">18dip</dimen>
+ <!-- Width of application label text -->
+ <dimen name="status_bar_recents_app_label_width">97dip</dimen>
+ <!-- Left margin for application label -->
+ <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
+ <!-- Size of fading edge for scroll effect -->
+ <dimen name="status_bar_recents_fading_edge_length">20dip</dimen>
+ <!-- Margin between recents container and glow on the right -->
+ <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
+
+ <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
+ <dimen name="recents_thumbnail_bg_padding_left">15px</dimen>
+ <dimen name="recents_thumbnail_bg_padding_top">8px</dimen>
+ <dimen name="recents_thumbnail_bg_padding_right">12px</dimen>
+ <dimen name="recents_thumbnail_bg_padding_bottom">8px</dimen>
+
+ <!-- Where to place the app icon over the thumbnail -->
+ <dimen name="status_bar_recents_app_icon_left_margin">13dp</dimen>
+ <dimen name="status_bar_recents_app_icon_top_margin">13dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 75c0140..942ce5b 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 8427d32..4178e2e 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 9ff285a..beeb56f 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 52441de..22529e6 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index b367c56..41975b8 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index b92b3b0..d87268d 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 8989b2f..bb14bd6 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -61,4 +61,12 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zu-land/strings.xml b/packages/SystemUI/res/values-zu-land/strings.xml
new file mode 100644
index 0000000..9efeef6
--- /dev/null
+++ b/packages/SystemUI/res/values-zu-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, 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="toast_rotation_locked" msgid="7609673011431556092">"Isikrini okwamanje sivaliwe ekujikelezeni okumile."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
new file mode 100644
index 0000000..7597c3a
--- /dev/null
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -0,0 +1,88 @@
+<?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="app_label" msgid="7164937344850004466">"Uhlelo lwe-UI"</string>
+ <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Sula"</string>
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Ungaphazamisi"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Bonisa izaziso"</string>
+ <!-- no translation found for status_bar_no_notifications_title (4755261167193833213) -->
+ <skip />
+ <!-- no translation found for status_bar_ongoing_events_title (1682504513316879202) -->
+ <skip />
+ <!-- no translation found for status_bar_latest_events_title (6594767438577593172) -->
+ <skip />
+ <!-- no translation found for battery_low_title (7923774589611311406) -->
+ <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Ibhetri iya ngokuphela."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"okusele okungu-<xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Ukushaja i-USB akusekelwe."\n"Sebenzisa kuphela ishaja enikeziwe."</string>
+ <string name="battery_low_why" msgid="7279169609518386372">"Ukusebenzisa ibhetri"</string>
+ <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Izilungiselelo"</string>
+ <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"I-Wi-Fi"</string>
+ <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Imodi yendiza"</string>
+ <!-- no translation found for status_bar_settings_auto_rotation (3790482541357798421) -->
+ <skip />
+ <string name="status_bar_settings_mute_label" msgid="554682549917429396">"THULISA"</string>
+ <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"OKUZENZAKALELAYO"</string>
+ <string name="status_bar_settings_notifications" msgid="397146176280905137">"Izaziso"</string>
+ <string name="recent_tasks_title" msgid="3691764623638127888">"Okwakamuva"</string>
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Azikho izinhlelo zokusebenza zamanje."</string>
+ <string name="recent_tasks_app_label" msgid="3796483981246752469">"Izinhlelo zokusebenza"</string>
+ <string name="bluetooth_tethered" msgid="7094101612161133267">"Ukusebenzisa i-Bluetooth njengemodemu"</string>
+ <!-- no translation found for status_bar_input_method_settings_configure_input_methods (737483394044014246) -->
+ <skip />
+ <!-- no translation found for status_bar_use_physical_keyboard (3695516942412442936) -->
+ <skip />
+ <!-- no translation found for usb_device_permission_prompt (3816016361969816903) -->
+ <skip />
+ <!-- no translation found for usb_accessory_permission_prompt (6888598803988889959) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (5161205258635253206) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3808984931830229888) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for always_use_device (1450287437017315906) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (1210954576979621596) -->
+ <skip />
+ <!-- no translation found for compat_mode_on (6623839244840638213) -->
+ <skip />
+ <!-- no translation found for compat_mode_off (4434467572461327898) -->
+ <skip />
+ <!-- no translation found for compat_mode_help_header (7020175705401506719) -->
+ <skip />
+ <!-- no translation found for compat_mode_help_body (4946726776359270040) -->
+ <skip />
+ <!-- no translation found for usb_preference_title (6551050377388882787) -->
+ <skip />
+ <!-- no translation found for use_mtp_button_title (4333504413563023626) -->
+ <skip />
+ <!-- no translation found for use_ptp_button_title (7517127540301625751) -->
+ <skip />
+ <!-- no translation found for installer_cd_button_title (8485631662288445893) -->
+ <skip />
+</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index fb2f7d63..5291629 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -24,5 +24,8 @@
<declare-styleable name="NotificationLinearLayout">
<attr name="insetLeft" format="dimension" />
</declare-styleable>
+ <declare-styleable name="NotificationRowLayout">
+ <attr name="rowHeight" format="dimension" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 964e69b..9341693 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -20,4 +20,5 @@
<drawable name="notification_number_text_color">#ffffffff</drawable>
<drawable name="notification_item_background_color">#ff000000</drawable>
<drawable name="ticker_background_color">#ff1d1d1d</drawable>
+ <drawable name="status_bar_background">#000000</drawable>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 372aa39..7a4ac5d 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -36,9 +36,12 @@
<!-- Whether or not we show the number in the bar. -->
<bool name="config_statusBarShowNumber">true</bool>
+ <!-- Whether a software navigation bar should be shown. NOTE: in the future this may be
+ autodetected from the Configuration. -->
+ <bool name="config_showNavigationBar">false</bool>
+
<!-- How many icons may be shown at once in the system bar. Includes any
slots that may be reused for things like IME control. -->
<integer name="config_maxNotificationIcons">5</integer>
-
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ff979a0..fc35a48 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -20,18 +20,29 @@
<dimen name="status_bar_edge_ignore">5dp</dimen>
<!-- Recent Applications parameters -->
- <!-- Width of a recent app view, including all content -->
- <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
- <!-- How far the thumbnail for a recent app appears from left edge -->
- <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
<!-- Upper width limit for application icon -->
<dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen>
<!-- Upper height limit for application icon -->
<dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen>
- <!-- Width of scrollable area in recents -->
- <dimen name="status_bar_recents_width">356dp</dimen>
+ <!-- Where to place the app icon over the thumbnail -->
+ <dimen name="status_bar_recents_app_icon_left_margin">13dp</dimen>
+ <dimen name="status_bar_recents_app_icon_top_margin">13dp</dimen>
+
+ <!-- Size of application label text -->
+ <dimen name="status_bar_recents_app_label_text_size">18dip</dimen>
+ <!-- Size of application description text -->
+ <dimen name="status_bar_recents_app_description_text_size">18dip</dimen>
+ <!-- Size of fading edge for scroll effect -->
+ <dimen name="status_bar_recents_fading_edge_length">20dip</dimen>
+ <!-- Margin between recents container and glow on the right -->
+ <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
<!-- Amount to offset bottom of notification peek window from top of status bar. -->
<dimen name="peek_window_y_offset">-12dp</dimen>
+ <!-- thickness (height) of the navigation bar on phones that require it -->
+ <dimen name="navigation_bar_size">42dp</dimen>
+
+ <!-- thickness (height) of each notification row, including any separators or padding -->
+ <dimen name="notification_height">65dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8945da5..86e0cd0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -156,4 +156,13 @@
<!-- Compatibility mode help screen: body text. [CHAR LIMIT=150] -->
<string name="compat_mode_help_body">When an app was designed for a smaller screen, a zoom control will appear by the clock.</string>
+
+ <!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] -->
+ <string name="usb_preference_title">USB file transfer options</string>
+ <!-- Label for the MTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+ <string name="use_mtp_button_title">Mount as a media player (MTP)</string>
+ <!-- Label for the PTP USB function in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+ <string name="use_ptp_button_title">Mount as a camera (PTP)</string>
+ <!-- Label for the installer CD image option in UsbPreferenceActivity. [CHAR LIMIT=50] -->
+ <string name="installer_cd_button_title">Install Android File Transfer application for Mac</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 3401441..a549f51 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -139,7 +139,6 @@ public class PowerUI extends SystemUI {
showInvalidChargerDialog();
return;
} else if (oldInvalidCharger != 0 && mInvalidCharger == 0) {
- Slog.d(TAG, "closing invalid charger warning");
dismissInvalidChargerDialog();
} else if (mInvalidChargerDialog != null) {
// if invalid charger is showing, don't show low battery
@@ -150,10 +149,9 @@ public class PowerUI extends SystemUI {
&& (bucket < oldBucket || oldPlugged)
&& mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
&& bucket < 0) {
- Slog.d(TAG, "showing low battery warning: level=" + mBatteryLevel);
+ Slog.i(TAG, "showing low battery warning: level=" + mBatteryLevel);
showLowBatteryWarning();
} else if (plugged || (bucket > oldBucket && bucket > 0)) {
- Slog.d(TAG, "closing low battery warning: level=" + mBatteryLevel);
dismissLowBatteryWarning();
} else if (mBatteryLevelTextView != null) {
showLowBatteryWarning();
@@ -166,6 +164,7 @@ public class PowerUI extends SystemUI {
void dismissLowBatteryWarning() {
if (mLowBatteryDialog != null) {
+ Slog.i(TAG, "closing low battery warning: level=" + mBatteryLevel);
mLowBatteryDialog.dismiss();
}
}
@@ -237,6 +236,7 @@ public class PowerUI extends SystemUI {
void dismissInvalidChargerDialog() {
if (mInvalidChargerDialog != null) {
+ Slog.d(TAG, "closing invalid charger warning");
mInvalidChargerDialog.dismiss();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
new file mode 100644
index 0000000..49a65d8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2011 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.systemui.recent;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.util.Log;
+import android.util.Slog;
+import android.view.View;
+
+/* package */ class Choreographer implements Animator.AnimatorListener {
+ // should group this into a multi-property animation
+ private static final int OPEN_DURATION = 136;
+ private static final int CLOSE_DURATION = 250;
+ private static final String TAG = RecentsPanelView.TAG;
+ private static final boolean DEBUG = RecentsPanelView.DEBUG;
+
+ boolean mVisible;
+ int mPanelHeight;
+ View mRootView;
+ View mScrimView;
+ View mContentView;
+ AnimatorSet mContentAnim;
+ Animator.AnimatorListener mListener;
+
+ // the panel will start to appear this many px from the end
+ final int HYPERSPACE_OFFRAMP = 200;
+
+ public Choreographer(View root, View scrim, View content, Animator.AnimatorListener listener) {
+ mRootView = root;
+ mScrimView = scrim;
+ mContentView = content;
+ mListener = listener;
+ }
+
+ void createAnimation(boolean appearing) {
+ float start, end;
+
+ if (RecentsPanelView.DEBUG) Log.e(TAG, "createAnimation()", new Exception());
+
+ // 0: on-screen
+ // height: off-screen
+ float y = mContentView.getTranslationY();
+ if (appearing) {
+ // we want to go from near-the-top to the top, unless we're half-open in the right
+ // general vicinity
+ start = (y < HYPERSPACE_OFFRAMP) ? y : HYPERSPACE_OFFRAMP;
+ end = 0;
+ } else {
+ start = y;
+ end = y + HYPERSPACE_OFFRAMP;
+ }
+
+ Animator posAnim = ObjectAnimator.ofFloat(mContentView, "translationY",
+ start, end);
+ posAnim.setInterpolator(appearing
+ ? new android.view.animation.DecelerateInterpolator(2.5f)
+ : new android.view.animation.AccelerateInterpolator(2.5f));
+
+ Animator glowAnim = ObjectAnimator.ofFloat(mContentView, "alpha",
+ mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
+ glowAnim.setInterpolator(appearing
+ ? new android.view.animation.AccelerateInterpolator(1.0f)
+ : new android.view.animation.DecelerateInterpolator(1.0f));
+
+ Animator bgAnim = ObjectAnimator.ofInt(mScrimView.getBackground(),
+ "alpha", appearing ? 0 : 255, appearing ? 255 : 0);
+
+ mContentAnim = new AnimatorSet();
+ mContentAnim
+ .play(bgAnim)
+ .with(glowAnim)
+ .with(posAnim);
+ mContentAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
+ mContentAnim.addListener(this);
+ if (mListener != null) {
+ mContentAnim.addListener(mListener);
+ }
+ }
+
+ void startAnimation(boolean appearing) {
+ if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
+
+ createAnimation(appearing);
+
+ mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mContentAnim.start();
+
+ mVisible = appearing;
+ }
+
+ void jumpTo(boolean appearing) {
+ mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
+ }
+
+ public void setPanelHeight(int h) {
+ if (DEBUG) Slog.d(TAG, "panelHeight=" + h);
+ mPanelHeight = h;
+ }
+
+ public void onAnimationCancel(Animator animation) {
+ if (DEBUG) Slog.d(TAG, "onAnimationCancel");
+ // force this to zero so we close the window
+ mVisible = false;
+ }
+
+ public void onAnimationEnd(Animator animation) {
+ if (DEBUG) Slog.d(TAG, "onAnimationEnd");
+ if (!mVisible) {
+ mRootView.setVisibility(View.GONE);
+ }
+ mContentView.setLayerType(View.LAYER_TYPE_NONE, null);
+ mContentAnim = null;
+ }
+
+ public void onAnimationRepeat(Animator animation) {
+ }
+
+ public void onAnimationStart(Animator animation) {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
deleted file mode 100644
index 8c6eefb..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * Copyright (C) 2010 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.systemui.recent;
-
-import com.android.systemui.R;
-
-import com.android.ex.carousel.CarouselView;
-import com.android.ex.carousel.CarouselViewHelper;
-import com.android.ex.carousel.CarouselRS.CarouselCallback;
-import com.android.ex.carousel.CarouselViewHelper.DetailTextureParameters;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
-import android.app.IActivityManager;
-import android.app.IThumbnailReceiver;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.content.ActivityNotFoundException;
-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.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.PaintFlagsDrawFilter;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.PorterDuff;
-import android.graphics.Bitmap.Config;
-import android.graphics.drawable.Drawable;
-import android.graphics.PixelFormat;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.widget.TextView;
-
-public class RecentApplicationsActivity extends Activity {
- private static final String TAG = "RecentApplicationsActivity";
- private static boolean DBG = false;
- private static final int CARD_SLOTS = 56;
- private static final int VISIBLE_SLOTS = 7;
- private static final int MAX_TASKS = VISIBLE_SLOTS * 2;
-
- // TODO: these should be configurable
- private static final int DETAIL_TEXTURE_MAX_WIDTH = 200;
- private static final int DETAIL_TEXTURE_MAX_HEIGHT = 80;
- private static final int TEXTURE_WIDTH = 256;
- private static final int TEXTURE_HEIGHT = 256;
-
- private ActivityManager mActivityManager;
- private List<RunningTaskInfo> mRunningTaskList;
- private boolean mPortraitMode = true;
- private ArrayList<ActivityDescription> mActivityDescriptions
- = new ArrayList<ActivityDescription>();
- private CarouselView mCarouselView;
- private LocalCarouselViewHelper mHelper;
- private View mNoRecentsView;
- private Bitmap mLoadingBitmap;
- private Bitmap mRecentOverlay;
- private boolean mHidden = false;
- private boolean mHiding = false;
- private DetailInfo mDetailInfo;
-
- /**
- * This class is a container for all items associated with the DetailView we'll
- * be drawing to a bitmap and sending to Carousel.
- *
- */
- static final class DetailInfo {
- public DetailInfo(View _view, TextView _title, TextView _desc) {
- view = _view;
- title = _title;
- description = _desc;
- }
-
- /**
- * Draws view into the given bitmap, if provided
- * @param bitmap
- */
- public Bitmap draw(Bitmap bitmap) {
- resizeView(view, DETAIL_TEXTURE_MAX_WIDTH, DETAIL_TEXTURE_MAX_HEIGHT);
- int desiredWidth = view.getWidth();
- int desiredHeight = view.getHeight();
- if (bitmap == null || desiredWidth != bitmap.getWidth()
- || desiredHeight != bitmap.getHeight()) {
- bitmap = Bitmap.createBitmap(desiredWidth, desiredHeight, Config.ARGB_8888);
- }
- Canvas canvas = new Canvas(bitmap);
- view.draw(canvas);
- return bitmap;
- }
-
- /**
- * Force a layout pass on the given view.
- */
- private void resizeView(View view, int maxWidth, int maxHeight) {
- int widthSpec = MeasureSpec.getMode(MeasureSpec.AT_MOST)
- | MeasureSpec.getSize(maxWidth);
- int heightSpec = MeasureSpec.getMode(MeasureSpec.AT_MOST)
- | MeasureSpec.getSize(maxHeight);
- view.measure(widthSpec, heightSpec);
- view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
- Log.v(TAG, "RESIZED VIEW: " + view.getWidth() + ", " + view.getHeight());
- }
-
- public View view;
- public TextView title;
- public TextView description;
- }
-
- static class ActivityDescription {
- int id;
- Bitmap thumbnail; // generated by Activity.onCreateThumbnail()
- Drawable icon; // application package icon
- String label; // application package label
- CharSequence description; // generated by Activity.onCreateDescription()
- Intent intent; // launch intent for application
- Matrix matrix; // arbitrary rotation matrix to correct orientation
- int position; // position in list
-
- public ActivityDescription(Bitmap _thumbnail,
- Drawable _icon, String _label, String _desc, int _id, int _pos)
- {
- thumbnail = _thumbnail;
- icon = _icon;
- label = _label;
- description = _desc;
- id = _id;
- position = _pos;
- }
-
- public void clear() {
- icon = null;
- thumbnail = null;
- label = null;
- description = null;
- intent = null;
- matrix = null;
- id = -1;
- position = -1;
- }
- };
-
- private ActivityDescription findActivityDescription(int id) {
- for (int i = 0; i < mActivityDescriptions.size(); i++) {
- ActivityDescription item = mActivityDescriptions.get(i);
- if (item != null && item.id == id) {
- return item;
- }
- }
- return null;
- }
-
- private class LocalCarouselViewHelper extends CarouselViewHelper {
- private DetailTextureParameters mDetailParams = new DetailTextureParameters(10.0f, 20.0f);
-
- public LocalCarouselViewHelper(Context context) {
- super(context);
- }
-
- @Override
- public DetailTextureParameters getDetailTextureParameters(int id) {
- return mDetailParams;
- }
-
- public void onCardSelected(int n) {
- if (n < mActivityDescriptions.size()) {
- ActivityDescription item = mActivityDescriptions.get(n);
- if (item.id >= 0) {
- // This is an active task; it should just go to the foreground.
- final ActivityManager am = (ActivityManager)
- getSystemService(Context.ACTIVITY_SERVICE);
- am.moveTaskToFront(item.id, ActivityManager.MOVE_TASK_WITH_HOME);
- } else if (item.intent != null) {
- // prepare a launch intent and send it
- item.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
- | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
- try {
- if (DBG) Log.v(TAG, "Starting intent " + item.intent);
- startActivity(item.intent);
- overridePendingTransition(R.anim.recent_app_enter, R.anim.recent_app_leave);
- } catch (ActivityNotFoundException e) {
- if (DBG) Log.w("Recent", "Unable to launch recent task", e);
- }
- finish();
- }
- }
- }
-
- @Override
- public Bitmap getTexture(final int id) {
- if (DBG) Log.v(TAG, "onRequestTexture(" + id + ")");
- ActivityDescription info;
- synchronized(mActivityDescriptions) {
- info = mActivityDescriptions.get(id);
- }
- Bitmap bitmap = null;
- if (info != null) {
- bitmap = compositeBitmap(info);
- }
- return bitmap;
- }
-
- @Override
- public Bitmap getDetailTexture(int n) {
- Bitmap bitmap = null;
- if (n < mActivityDescriptions.size()) {
- ActivityDescription item = mActivityDescriptions.get(n);
- mDetailInfo.title.setText(item.label);
- mDetailInfo.description.setText(item.description);
- bitmap = mDetailInfo.draw(null);
- }
- return bitmap;
- }
- };
-
- private Bitmap compositeBitmap(ActivityDescription info) {
- final int targetWidth = TEXTURE_WIDTH;
- final int targetHeight = TEXTURE_HEIGHT;
- final int border = 3; // inset along the edge for thumnnail content
- final int overlap = 1; // how many pixels of overlap between border and thumbnail
- final Resources res = getResources();
- if (mRecentOverlay == null) {
- mRecentOverlay = BitmapFactory.decodeResource(res, R.drawable.recent_overlay);
- }
-
- // Create a bitmap of the proper size/format and set the canvas to draw to it
- final Bitmap result = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(result);
- canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG, Paint.FILTER_BITMAP_FLAG));
- Paint paint = new Paint();
- paint.setFilterBitmap(false);
-
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
- canvas.save();
- if (info.thumbnail != null) {
- // Draw the thumbnail
- int sourceWidth = targetWidth - 2 * (border - overlap);
- int sourceHeight = targetHeight - 2 * (border - overlap);
- final float scaleX = (float) sourceWidth / info.thumbnail.getWidth();
- final float scaleY = (float) sourceHeight / info.thumbnail.getHeight();
- canvas.translate(border * 0.5f, border * 0.5f);
- canvas.scale(scaleX, scaleY);
- canvas.drawBitmap(info.thumbnail, 0, 0, paint);
- } else {
- // Draw the Loading bitmap placeholder, TODO: Remove when RS handles blending
- final float scaleX = (float) targetWidth / mLoadingBitmap.getWidth();
- final float scaleY = (float) targetHeight / mLoadingBitmap.getHeight();
- canvas.scale(scaleX, scaleY);
- canvas.drawBitmap(mLoadingBitmap, 0, 0, paint);
- }
- canvas.restore();
-
- // Draw overlay
- canvas.save();
- final float scaleOverlayX = (float) targetWidth / mRecentOverlay.getWidth();
- final float scaleOverlayY = (float) targetHeight / mRecentOverlay.getHeight();
- canvas.scale(scaleOverlayX, scaleOverlayY);
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
- canvas.drawBitmap(mRecentOverlay, 0, 0, paint);
- canvas.restore();
-
- // Draw icon
- if (info.icon != null) {
- canvas.save();
- info.icon.draw(canvas);
- canvas.restore();
- }
-
- return result;
- }
-
- private final IThumbnailReceiver mThumbnailReceiver = new IThumbnailReceiver.Stub() {
-
- public void finished() throws RemoteException {
-
- }
-
- public void newThumbnail(final int id, final Bitmap bitmap, CharSequence description)
- throws RemoteException {
- int w = bitmap.getWidth();
- int h = bitmap.getHeight();
- if (DBG) Log.v(TAG, "New thumbnail for id=" + id + ", dimensions=" + w + "x" + h
- + " description '" + description + "'");
- ActivityDescription info = findActivityDescription(id);
- if (info != null) {
- info.thumbnail = bitmap;
- info.description = description;
- final int thumbWidth = bitmap.getWidth();
- final int thumbHeight = bitmap.getHeight();
- if ((mPortraitMode && thumbWidth > thumbHeight)
- || (!mPortraitMode && thumbWidth < thumbHeight)) {
- Matrix matrix = new Matrix();
- matrix.setRotate(90.0f, (float) thumbWidth / 2, (float) thumbHeight / 2);
- info.matrix = matrix;
- } else {
- info.matrix = null;
- }
- // Force Carousel to request new textures for this item.
- mCarouselView.setTextureForItem(info.position, null);
- mCarouselView.setDetailTextureForItem(info.position, 0, 0, 0, 0, null);
- } else {
- if (DBG) Log.v(TAG, "Can't find view for id " + id);
- }
- }
- };
-
- /**
- * We never really finish() RecentApplicationsActivity, since we don't want to
- * get destroyed and pay the start-up cost to restart it.
- */
- @Override
- public void finish() {
- moveTaskToBack(true);
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- mHidden = !mHidden;
- if (mHidden) {
- mHiding = true;
- moveTaskToBack(true);
- } else {
- mHiding = false;
- }
- super.onNewIntent(intent);
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- final Resources res = getResources();
- final View decorView = getWindow().getDecorView();
-
- getWindow().getDecorView().setBackgroundColor(0x80000000);
-
- if (mCarouselView == null) {
- long t = System.currentTimeMillis();
- setContentView(R.layout.recent_apps_activity);
- long elapsed = System.currentTimeMillis() - t;
- Log.v(TAG, "Recents layout took " + elapsed + "ms to load");
- mLoadingBitmap = BitmapFactory.decodeResource(res, R.drawable.recent_rez_border);
- mCarouselView = (CarouselView)findViewById(R.id.carousel);
- mHelper = new LocalCarouselViewHelper(this);
- mHelper.setCarouselView(mCarouselView);
-
- mCarouselView.setSlotCount(CARD_SLOTS);
- mCarouselView.setVisibleSlots(VISIBLE_SLOTS);
- mCarouselView.createCards(0);
- mCarouselView.setStartAngle((float) -(2.0f*Math.PI * 5 / CARD_SLOTS));
- mCarouselView.setDefaultBitmap(mLoadingBitmap);
- mCarouselView.setLoadingBitmap(mLoadingBitmap);
- mCarouselView.setRezInCardCount(3.0f);
- mCarouselView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
-
- mNoRecentsView = (View) findViewById(R.id.no_applications_message);
-
- mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
- mPortraitMode = decorView.getHeight() > decorView.getWidth();
-
- // Load detail view which will be used to render text
- View detail = getLayoutInflater().inflate(R.layout.recents_detail_view, null);
- TextView title = (TextView) detail.findViewById(R.id.app_title);
- TextView description = (TextView) detail.findViewById(R.id.app_description);
- mDetailInfo = new DetailInfo(detail, title, description);
-
- refresh();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- refresh();
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- mPortraitMode = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT;
- if (DBG) Log.v(TAG, "CONFIG CHANGE, mPortraitMode = " + mPortraitMode);
- refresh();
- }
-
- void updateRunningTasks() {
- mRunningTaskList = mActivityManager.getRunningTasks(MAX_TASKS,
- ActivityManager.TASKS_GET_THUMBNAILS, mThumbnailReceiver);
- if (DBG) Log.v(TAG, "Portrait: " + mPortraitMode);
- for (RunningTaskInfo r : mRunningTaskList) {
- if (r.thumbnail != null) {
- int thumbWidth = r.thumbnail.getWidth();
- int thumbHeight = r.thumbnail.getHeight();
- if (DBG) Log.v(TAG, "Got thumbnail " + thumbWidth + "x" + thumbHeight);
- ActivityDescription desc = findActivityDescription(r.id);
- if (desc != null) {
- desc.thumbnail = r.thumbnail;
- desc.description = r.description;
- if ((mPortraitMode && thumbWidth > thumbHeight)
- || (!mPortraitMode && thumbWidth < thumbHeight)) {
- Matrix matrix = new Matrix();
- matrix.setRotate(90.0f, (float) thumbWidth / 2, (float) thumbHeight / 2);
- desc.matrix = matrix;
- }
- } else {
- if (DBG) Log.v(TAG, "Couldn't find ActivityDesc for id=" + r.id);
- }
- } else {
- if (DBG) Log.v(TAG, "*** RUNNING THUMBNAIL WAS NULL ***");
- }
- }
- }
-
- private void updateRecentTasks() {
- final PackageManager pm = getPackageManager();
- final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
-
- final List<ActivityManager.RecentTaskInfo> recentTasks =
- am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE
- | ActivityManager.TASKS_GET_THUMBNAILS);
-
- ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
- .resolveActivityInfo(pm, 0);
-
- // IconUtilities iconUtilities = new IconUtilities(this); // FIXME
-
- int numTasks = recentTasks.size();
- mActivityDescriptions.clear();
- for (int i = 0, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
- final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
-
- Intent intent = new Intent(recentInfo.baseIntent);
- if (recentInfo.origActivity != null) {
- intent.setComponent(recentInfo.origActivity);
- }
-
- // Skip the current home activity.
- if (homeInfo != null
- && homeInfo.packageName.equals(intent.getComponent().getPackageName())
- && homeInfo.name.equals(intent.getComponent().getClassName())) {
- continue;
- }
-
- intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
- | Intent.FLAG_ACTIVITY_NEW_TASK);
- final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
- if (resolveInfo != null) {
- final ActivityInfo info = resolveInfo.activityInfo;
- final String title = info.loadLabel(pm).toString();
- Drawable icon = info.loadIcon(pm);
-
- int id = recentTasks.get(i).id;
- if (id != -1 && title != null && title.length() > 0 && icon != null) {
- // icon = null; FIXME: iconUtilities.createIconDrawable(icon);
- ActivityDescription item = new ActivityDescription(
- null, icon, title, null, id, index);
- item.intent = intent;
- mActivityDescriptions.add(item);
- if (DBG) Log.v(TAG, "Added item[" + index
- + "], id=" + item.id
- + ", title=" + item.label);
- ++index;
- } else {
- if (DBG) Log.v(TAG, "SKIPPING item " + id);
- }
- }
- }
- }
-
- private final Runnable mRefreshRunnable = new Runnable() {
- public void run() {
- updateRecentTasks();
- updateRunningTasks();
- showCarousel(mActivityDescriptions.size() > 0);
- }
- };
-
- private void showCarousel(boolean show) {
- if (show) {
- mCarouselView.createCards(mActivityDescriptions.size());
- for (int i = 1; i < mActivityDescriptions.size(); i++) {
- // Force Carousel to update textures. Note we don't do this for the first item,
- // since it will be updated when mThumbnailReceiver returns a thumbnail.
- // TODO: only do this for apps that have changed.
- mCarouselView.setTextureForItem(i, null);
- mCarouselView.setDetailTextureForItem(i, 0, 0, 0, 0, null);
- }
- // Make carousel visible
- mNoRecentsView.setVisibility(View.GONE);
- mCarouselView.setVisibility(View.VISIBLE);
- mCarouselView.createCards(mActivityDescriptions.size());
- } else {
- // show "No Recent Tasks"
- mNoRecentsView.setVisibility(View.VISIBLE);
- mCarouselView.setVisibility(View.GONE);
- }
- }
-
- private void refresh() {
- if (!mHiding && mCarouselView != null) {
- // Don't update the view now. Instead, post a request so it happens next time
- // we reach the looper after a delay. This way we can fold multiple refreshes
- // into just the latest.
- mCarouselView.removeCallbacks(mRefreshRunnable);
- mCarouselView.postDelayed(mRefreshRunnable, 50);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsCarouselView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
index 1c8ec95..5d29e2a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsCarouselView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -16,24 +16,15 @@
package com.android.systemui.recent;
-import android.content.Context;
-import android.util.AttributeSet;
+import android.view.View;
-import com.android.ex.carousel.CarouselView;
-import com.android.systemui.R;
-
-public class RecentApplicationsCarouselView extends CarouselView {
-
- public RecentApplicationsCarouselView(Context context) {
- this(context, null);
- }
-
- public RecentApplicationsCarouselView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public Info getRenderScriptInfo() {
- return new Info(R.raw.carousel);
- }
+public interface RecentsCallback {
+ static final int SWIPE_LEFT = 0;
+ static final int SWIPE_RIGHT = 1;
+ static final int SWIPE_UP = 2;
+ static final int SWIPE_DOWN = 3;
+ void handleOnClick(View selectedView);
+ void handleSwipe(View selectedView, int direction);
+ void handleLongPress(View selectedView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
new file mode 100644
index 0000000..3dbcc59
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2011 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.systemui.recent;
+
+import com.android.systemui.recent.RecentsPanelView.ActivityDescriptionAdapter;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+import android.widget.HorizontalScrollView;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+
+public class RecentsHorizontalScrollView extends HorizontalScrollView
+ implements View.OnClickListener, View.OnTouchListener {
+ private static final float FADE_CONSTANT = 0.5f;
+ private static final int SNAP_BACK_DURATION = 250;
+ private static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it
+ private static final String TAG = RecentsPanelView.TAG;
+ private static final float THRESHHOLD = 50;
+ private static final boolean DEBUG_INVALIDATE = false;
+ private LinearLayout mLinearLayout;
+ private ActivityDescriptionAdapter mAdapter;
+ private RecentsCallback mCallback;
+ protected int mLastScrollPosition;
+ private View mCurrentView;
+ private float mLastY;
+ private boolean mDragging;
+ private VelocityTracker mVelocityTracker;
+
+ public RecentsHorizontalScrollView(Context context) {
+ this(context, null);
+ }
+
+ public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs, 0);
+ }
+
+ private int scrollPositionOfMostRecent() {
+ return mLinearLayout.getWidth() - getWidth();
+ }
+
+ public void update() {
+ mLinearLayout.removeAllViews();
+ for (int i = 0; i < mAdapter.getCount(); i++) {
+ View view = mAdapter.getView(i, null, mLinearLayout);
+ view.setClickable(true);
+ view.setOnClickListener(this);
+ view.setOnTouchListener(this);
+ mLinearLayout.addView(view);
+ }
+ // Scroll to end after layout.
+ post(new Runnable() {
+ public void run() {
+ mLastScrollPosition = scrollPositionOfMostRecent();
+ scrollTo(mLastScrollPosition, 0);
+ }
+ });
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(ev);
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mDragging = false;
+ mLastY = ev.getY();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ float delta = ev.getY() - mLastY;
+ if (Math.abs(delta) > THRESHHOLD) {
+ mDragging = true;
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ mDragging = false;
+ break;
+ }
+ return mDragging ? true : super.onInterceptTouchEvent(ev);
+ }
+
+ private float getAlphaForOffset(View view, float thumbHeight) {
+ final float fadeHeight = FADE_CONSTANT * thumbHeight;
+ float result = 1.0f;
+ if (view.getY() >= thumbHeight) {
+ result = 1.0f - (view.getY() - thumbHeight) / fadeHeight;
+ } else if (view.getY() < 0.0f) {
+ result = 1.0f + (thumbHeight + view.getY()) / fadeHeight;
+ }
+ return result;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (!mDragging) {
+ return super.onTouchEvent(ev);
+ }
+
+ mVelocityTracker.addMovement(ev);
+
+ final View animView = mCurrentView;
+ // TODO: Cache thumbnail
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_MOVE:
+ if (animView != null) {
+ final float delta = ev.getY() - mLastY;
+ animView.setY(animView.getY() + delta);
+ animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
+ invalidateGlobalRegion(animView);
+ }
+ mLastY = ev.getY();
+ break;
+
+ case MotionEvent.ACTION_UP:
+ final ObjectAnimator anim;
+ if (animView != null) {
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000, 10000);
+ final float velocityX = velocityTracker.getXVelocity();
+ final float velocityY = velocityTracker.getYVelocity();
+ final float curY = animView.getY();
+ final float newY = (velocityY >= 0.0f ? 1 : -1) * animView.getHeight();
+
+ if (Math.abs(velocityY) > Math.abs(velocityX)
+ && Math.abs(velocityY) > ESCAPE_VELOCITY
+ && (velocityY >= 0.0f) == (animView.getY() >= 0)) {
+ final long duration =
+ (long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY));
+ anim = ObjectAnimator.ofFloat(animView, "y", curY, newY);
+ anim.setInterpolator(new LinearInterpolator());
+ final int swipeDirection = animView.getY() >= 0.0f ?
+ RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
+ anim.addListener(new AnimatorListener() {
+ public void onAnimationStart(Animator animation) {
+ }
+ public void onAnimationRepeat(Animator animation) {
+ }
+ public void onAnimationEnd(Animator animation) {
+ mLinearLayout.removeView(mCurrentView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ public void onAnimationCancel(Animator animation) {
+ mLinearLayout.removeView(mCurrentView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ });
+ anim.setDuration(duration);
+ } else { // Animate back to position
+ final long duration = Math.abs(velocityY) > 0.0f ?
+ (long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY))
+ : SNAP_BACK_DURATION;
+ anim = ObjectAnimator.ofFloat(animView, "y", animView.getY(), 0.0f);
+ anim.setInterpolator(new DecelerateInterpolator(2.0f));
+ anim.setDuration(duration);
+ }
+
+ anim.addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
+ invalidateGlobalRegion(animView);
+ }
+ });
+ anim.start();
+ }
+
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ break;
+ }
+ return true;
+ }
+
+ void invalidateGlobalRegion(View view) {
+ RectF childBounds
+ = new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
+ childBounds.offset(view.getX(), view.getY());
+ if (DEBUG_INVALIDATE) Log.v(TAG, "-------------");
+ while (view.getParent() != null && view.getParent() instanceof View) {
+ view = (View) view.getParent();
+ view.getMatrix().mapRect(childBounds);
+ view.invalidate((int) Math.floor(childBounds.left),
+ (int) Math.floor(childBounds.top),
+ (int) Math.ceil(childBounds.right),
+ (int) Math.ceil(childBounds.bottom));
+ if (DEBUG_INVALIDATE) {
+ Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
+ + "," + (int) Math.floor(childBounds.top)
+ + "," + (int) Math.ceil(childBounds.right)
+ + "," + (int) Math.ceil(childBounds.bottom));
+ }
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ LayoutInflater inflater = (LayoutInflater)
+ mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ setScrollbarFadingEnabled(true);
+
+ mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
+
+ final int leftPadding = mContext.getResources()
+ .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
+ setOverScrollEffectPadding(leftPadding, 0);
+ }
+
+ private void setOverScrollEffectPadding(int leftPadding, int i) {
+ // TODO Add to RecentsHorizontalScrollView
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ // Keep track of the last visible item in the list so we can restore it
+ // to the bottom when the orientation changes.
+ mLastScrollPosition = scrollPositionOfMostRecent();
+
+ // This has to happen post-layout, so run it "in the future"
+ post(new Runnable() {
+ public void run() {
+ scrollTo(0, mLastScrollPosition);
+ }
+ });
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ // scroll to bottom after reloading
+ if (visibility == View.VISIBLE && changedView == this) {
+ post(new Runnable() {
+ public void run() {
+ update();
+ }
+ });
+ }
+ }
+
+ public void setAdapter(ActivityDescriptionAdapter adapter) {
+ mAdapter = adapter;
+ mAdapter.registerDataSetObserver(new DataSetObserver() {
+ public void onChanged() {
+ update();
+ }
+
+ public void onInvalidated() {
+ update();
+ }
+ });
+ }
+
+ @Override
+ public void setLayoutTransition(LayoutTransition transition) {
+ // The layout transition applies to our embedded LinearLayout
+ mLinearLayout.setLayoutTransition(transition);
+ }
+
+ public void onClick(View view) {
+ mCallback.handleOnClick(view);
+ }
+
+ public void setCallback(RecentsCallback callback) {
+ mCallback = callback;
+ }
+
+ public boolean onTouch(View v, MotionEvent event) {
+ mCurrentView = v;
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java
new file mode 100644
index 0000000..d8b086b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011 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.systemui.recent;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ListView;
+
+import com.android.systemui.R;
+
+public class RecentsListView extends ListView {
+ private int mLastVisiblePosition;
+ private RecentsCallback mCallback;
+
+ public RecentsListView(Context context) {
+ this(context, null);
+ }
+
+ public RecentsListView(Context context, AttributeSet attrs) {
+ super(context, attrs, 0);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ LayoutInflater inflater = (LayoutInflater)
+ mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer, this, false);
+ setScrollbarFadingEnabled(true);
+ addFooterView(footer, null, false);
+ final int leftPadding = mContext.getResources()
+ .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
+ setOverScrollEffectPadding(leftPadding, 0);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ // Keep track of the last visible item in the list so we can restore it
+ // to the bottom when the orientation changes.
+ final int childCount = getChildCount();
+ if (childCount > 0) {
+ mLastVisiblePosition = getFirstVisiblePosition() + childCount - 1;
+ View view = getChildAt(childCount - 1);
+ final int distanceFromBottom = getHeight() - view.getTop();
+
+ // This has to happen post-layout, so run it "in the future"
+ post(new Runnable() {
+ public void run() {
+ setSelectionFromTop(mLastVisiblePosition, getHeight() - distanceFromBottom);
+ }
+ });
+ }
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ // scroll to bottom after reloading
+ int count = getAdapter().getCount();
+ mLastVisiblePosition = count - 1;
+ if (visibility == View.VISIBLE && changedView == this) {
+ post(new Runnable() {
+ public void run() {
+ setSelection(mLastVisiblePosition);
+ }
+ });
+ }
+ }
+
+ public void setCallback(RecentsCallback callback) {
+ mCallback = callback;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index fd07a5a..b8dc63d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 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,14 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.tablet;
+package com.android.systemui.recent;
import java.util.ArrayList;
import java.util.List;
import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
+import android.animation.LayoutTransition;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@@ -43,43 +42,47 @@ import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
-import android.widget.CheckBox;
import android.widget.ImageView;
-import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.systemui.R;
-
-public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, OnItemClickListener {
- private static final int GLOW_PADDING = 15;
- private static final String TAG = "RecentAppsPanel";
- private static final boolean DEBUG = TabletStatusBar.DEBUG;
+import com.android.systemui.statusbar.StatusBar;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.tablet.StatusBarPanel;
+import com.android.systemui.statusbar.tablet.TabletStatusBar;
+
+public class RecentsPanelView extends RelativeLayout
+ implements OnItemClickListener, RecentsCallback, StatusBarPanel, Animator.AnimatorListener {
+ static final String TAG = "RecentsListView";
+ static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG;
private static final int DISPLAY_TASKS = 20;
private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps
- private TabletStatusBar mBar;
+ private StatusBar mBar;
private ArrayList<ActivityDescription> mActivityDescriptions;
private int mIconDpi;
private View mRecentsScrim;
private View mRecentsGlowView;
- private ListView mRecentsContainer;
- private CheckBox mCompatMode;
+ private View mRecentsContainer;
private Bitmap mGlowBitmap;
+ // TODO: add these widgets attributes to the layout file
+ private int mGlowBitmapPaddingLeftPx;
+ private int mGlowBitmapPaddingTopPx;
+ private int mGlowBitmapPaddingRightPx;
+ private int mGlowBitmapPaddingBottomPx;
private boolean mShowing;
private Choreographer mChoreo;
private View mRecentsDismissButton;
- private ActvityDescriptionAdapter mListAdapter;
- protected int mLastVisibleItem;
+ private ActivityDescriptionAdapter mListAdapter;
- static class ActivityDescription {
- int id;
+ /* package */ final static class ActivityDescription {
+ int taskId; // application task id for curating apps
Bitmap thumbnail; // generated by Activity.onCreateThumbnail()
Drawable icon; // application package icon
String label; // application package label
@@ -98,24 +101,24 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
label = _label;
description = _desc;
intent = _intent;
- id = _id;
+ taskId = _id;
position = _pos;
packageName = _packageName;
}
};
/* package */ final static class ViewHolder {
- private ImageView thumbnailView;
- private ImageView iconView;
- private TextView labelView;
- private TextView descriptionView;
- private ActivityDescription activityDescription;
+ ImageView thumbnailView;
+ ImageView iconView;
+ TextView labelView;
+ TextView descriptionView;
+ ActivityDescription activityDescription;
}
- /* package */ final class ActvityDescriptionAdapter extends BaseAdapter {
+ /* package */ final class ActivityDescriptionAdapter extends BaseAdapter {
private LayoutInflater mInflater;
- public ActvityDescriptionAdapter(Context context) {
+ public ActivityDescriptionAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
@@ -187,6 +190,26 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
}
}
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ public void onAnimationEnd(Animator animation) {
+ if (mShowing) {
+ final LayoutTransition transitioner = new LayoutTransition();
+ ((ViewGroup)mRecentsContainer).setLayoutTransition(transitioner);
+ createCustomAnimations(transitioner);
+ } else {
+ ((ViewGroup)mRecentsContainer).setLayoutTransition(null);
+ }
+ }
+
+ public void onAnimationRepeat(Animator animation) {
+ }
+
+ public void onAnimationStart(Animator animation) {
+ }
+
+
/**
* We need to be aligned at the bottom. LinearLayout can't do this, so instead,
* let LinearLayout do all the hard work, and then shift everything down to the bottom.
@@ -205,120 +228,15 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
return mShowing;
}
- private static class Choreographer implements Animator.AnimatorListener {
- // should group this into a multi-property animation
- private static final int OPEN_DURATION = 136;
- private static final int CLOSE_DURATION = 250;
-
- boolean mVisible;
- int mPanelHeight;
- View mRootView;
- View mScrimView;
- View mContentView;
- AnimatorSet mContentAnim;
-
- // the panel will start to appear this many px from the end
- final int HYPERSPACE_OFFRAMP = 200;
-
- public Choreographer(View root, View scrim, View content) {
- mRootView = root;
- mScrimView = scrim;
- mContentView = content;
- }
-
- void createAnimation(boolean appearing) {
- float start, end;
-
- if (DEBUG) Log.e(TAG, "createAnimation()", new Exception());
-
- // 0: on-screen
- // height: off-screen
- float y = mContentView.getTranslationY();
- if (appearing) {
- // we want to go from near-the-top to the top, unless we're half-open in the right
- // general vicinity
- start = (y < HYPERSPACE_OFFRAMP) ? y : HYPERSPACE_OFFRAMP;
- end = 0;
- } else {
- start = y;
- end = y + HYPERSPACE_OFFRAMP;
- }
-
- Animator posAnim = ObjectAnimator.ofFloat(mContentView, "translationY",
- start, end);
- posAnim.setInterpolator(appearing
- ? new android.view.animation.DecelerateInterpolator(2.5f)
- : new android.view.animation.AccelerateInterpolator(2.5f));
-
- Animator glowAnim = ObjectAnimator.ofFloat(mContentView, "alpha",
- mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
- glowAnim.setInterpolator(appearing
- ? new android.view.animation.AccelerateInterpolator(1.0f)
- : new android.view.animation.DecelerateInterpolator(1.0f));
-
- Animator bgAnim = ObjectAnimator.ofInt(mScrimView.getBackground(),
- "alpha", appearing ? 0 : 255, appearing ? 255 : 0);
-
- mContentAnim = new AnimatorSet();
- mContentAnim
- .play(bgAnim)
- .with(glowAnim)
- .with(posAnim);
- mContentAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
- mContentAnim.addListener(this);
- }
-
- void startAnimation(boolean appearing) {
- if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
-
- createAnimation(appearing);
-
- mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- mContentAnim.start();
-
- mVisible = appearing;
- }
-
- void jumpTo(boolean appearing) {
- mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
- }
-
- public void setPanelHeight(int h) {
- if (DEBUG) Slog.d(TAG, "panelHeight=" + h);
- mPanelHeight = h;
- }
-
- public void onAnimationCancel(Animator animation) {
- if (DEBUG) Slog.d(TAG, "onAnimationCancel");
- // force this to zero so we close the window
- mVisible = false;
- }
-
- public void onAnimationEnd(Animator animation) {
- if (DEBUG) Slog.d(TAG, "onAnimationEnd");
- if (!mVisible) {
- mRootView.setVisibility(View.GONE);
- }
- mContentView.setLayerType(View.LAYER_TYPE_NONE, null);
- mContentAnim = null;
- }
-
- public void onAnimationRepeat(Animator animation) {
- }
-
- public void onAnimationStart(Animator animation) {
- }
- }
-
- public void setBar(TabletStatusBar bar) {
+ public void setBar(StatusBar bar) {
mBar = bar;
}
- public RecentAppsPanel(Context context, AttributeSet attrs) {
+ public RecentsPanelView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public RecentAppsPanel(Context context, AttributeSet attrs, int defStyle) {
+ public RecentsPanelView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
Resources res = context.getResources();
@@ -326,51 +244,48 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
& Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
mIconDpi = xlarge ? DisplayMetrics.DENSITY_HIGH : res.getDisplayMetrics().densityDpi;
- mGlowBitmap = BitmapFactory.decodeResource(res, R.drawable.recents_thumbnail_bg);
- }
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- // Keep track of the last visible item in the list so we can restore it
- // to the bottom when the orientation changes.
- int childCount = mRecentsContainer.getChildCount();
- if (childCount > 0) {
- mLastVisibleItem = mRecentsContainer.getFirstVisiblePosition() + childCount - 1;
- View view = mRecentsContainer.getChildAt(childCount - 1);
- final int distanceFromBottom = mRecentsContainer.getHeight() - view.getTop();
- //final int distanceFromBottom = view.getHeight() + BOTTOM_OFFSET;
-
- // This has to happen post-layout, so run it "in the future"
- post(new Runnable() {
- public void run() {
- mRecentsContainer.setSelectionFromTop(mLastVisibleItem,
- mRecentsContainer.getHeight() - distanceFromBottom);
- }
- });
- }
+ mGlowBitmap = BitmapFactory.decodeResource(res, R.drawable.recents_thumbnail_bg);
+ mGlowBitmapPaddingLeftPx =
+ res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_left);
+ mGlowBitmapPaddingTopPx =
+ res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_top);
+ mGlowBitmapPaddingRightPx =
+ res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_right);
+ mGlowBitmapPaddingBottomPx =
+ res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_bottom);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- LayoutInflater inflater = (LayoutInflater)
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mRecentsContainer = findViewById(R.id.recents_container);
+ mListAdapter = new ActivityDescriptionAdapter(mContext);
+ if (mRecentsContainer instanceof RecentsListView) {
+ RecentsListView listView = (RecentsListView) mRecentsContainer;
+ listView.setAdapter(mListAdapter);
+ listView.setOnItemClickListener(this);
+ listView.setCallback(this);
+ } else if (mRecentsContainer instanceof RecentsHorizontalScrollView){
+ RecentsHorizontalScrollView scrollView
+ = (RecentsHorizontalScrollView) mRecentsContainer;
+ scrollView.setAdapter(mListAdapter);
+ scrollView.setCallback(this);
+ } else if (mRecentsContainer instanceof RecentsVerticalScrollView){
+ RecentsVerticalScrollView scrollView
+ = (RecentsVerticalScrollView) mRecentsContainer;
+ scrollView.setAdapter(mListAdapter);
+ scrollView.setCallback(this);
+ }
+ else {
+ throw new IllegalArgumentException("missing RecentsListView/RecentsScrollView");
+ }
- mRecentsContainer = (ListView) findViewById(R.id.recents_container);
- View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer,
- mRecentsContainer, false);
- mRecentsContainer.setScrollbarFadingEnabled(true);
- mRecentsContainer.addFooterView(footer, null, false);
- mRecentsContainer.setAdapter(mListAdapter = new ActvityDescriptionAdapter(mContext));
- mRecentsContainer.setOnItemClickListener(this);
- final int leftPadding = mContext.getResources()
- .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
- mRecentsContainer.setOverScrollEffectPadding(leftPadding, 0);
mRecentsGlowView = findViewById(R.id.recents_glow);
mRecentsScrim = (View) findViewById(R.id.recents_bg_protect);
- mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView);
+ mChoreo = new Choreographer(this, mRecentsScrim, mRecentsGlowView, this);
mRecentsDismissButton = findViewById(R.id.recents_dismiss_button);
mRecentsDismissButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
@@ -384,17 +299,16 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
}
}
+ private void createCustomAnimations(LayoutTransition transitioner) {
+ transitioner.setDuration(LayoutTransition.DISAPPEARING, 250);
+ }
+
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + changedView + ", " + visibility + ")");
if (visibility == View.VISIBLE && changedView == this) {
refreshApplicationList();
- post(new Runnable() {
- public void run() {
- mRecentsContainer.setSelection(mActivityDescriptions.size() - 1);
- }
- });
}
}
@@ -431,8 +345,7 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
mContext.getSystemService(Context.ACTIVITY_SERVICE);
final List<ActivityManager.RecentTaskInfo> recentTasks =
- am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE
- | ActivityManager.TASKS_GET_THUMBNAILS);
+ am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
@@ -467,8 +380,10 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
int id = recentTasks.get(i).id;
if (title != null && title.length() > 0 && icon != null) {
if (DEBUG) Log.v(TAG, "creating activity desc for id=" + id + ", label=" + title);
+ ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(
+ recentInfo.persistentId);
ActivityDescription item = new ActivityDescription(
- am.getTaskThumbnail(recentInfo.persistentId),
+ thumbs != null ? thumbs.mainThumbnail : null,
icon, title, recentInfo.description, intent, id,
index, info.packageName);
activityDescriptions.add(item);
@@ -486,7 +401,7 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
ActivityDescription desc = null;
for (int i = 0; i < mActivityDescriptions.size(); i++) {
ActivityDescription item = mActivityDescriptions.get(i);
- if (item != null && item.id == id) {
+ if (item != null && item.taskId == id) {
desc = item;
break;
}
@@ -494,37 +409,15 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
return desc;
}
- private void updateShownCompatMode() {
- if (mCompatMode == null) {
- return;
- }
- final ActivityManager am = (ActivityManager)
- mContext.getSystemService(Context.ACTIVITY_SERVICE);
- int mode = am.getFrontActivityScreenCompatMode();
- switch (mode) {
- case ActivityManager.COMPAT_MODE_DISABLED:
- mCompatMode.setVisibility(View.VISIBLE);
- mCompatMode.setChecked(true);
- break;
- case ActivityManager.COMPAT_MODE_ENABLED:
- mCompatMode.setVisibility(View.VISIBLE);
- mCompatMode.setChecked(false);
- break;
- default:
- mCompatMode.setVisibility(View.GONE);
- break;
- }
- }
-
private void refreshApplicationList() {
mActivityDescriptions = getRecentTasks();
mListAdapter.notifyDataSetInvalidated();
if (mActivityDescriptions.size() > 0) {
- mLastVisibleItem = mActivityDescriptions.size() - 1; // scroll to bottom after reloading
+ Log.v(TAG, "Showing " + mActivityDescriptions.size() + " apps");
updateUiElements(getResources().getConfiguration());
- updateShownCompatMode();
} else {
// Immediately hide this panel
+ Log.v(TAG, "Nothing to show");
hide(false);
}
}
@@ -539,12 +432,12 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
paint.setAlpha(255);
final int srcWidth = thumbnail.getWidth();
final int srcHeight = thumbnail.getHeight();
+ Log.v(TAG, "Source thumb: " + srcWidth + "x" + srcHeight);
canvas.drawBitmap(thumbnail,
new Rect(0, 0, srcWidth-1, srcHeight-1),
- new RectF(GLOW_PADDING,
- GLOW_PADDING - 7.0f,
- outBitmap.getWidth() - GLOW_PADDING + 3.0f,
- outBitmap.getHeight() - GLOW_PADDING + 7.0f), paint);
+ new RectF(mGlowBitmapPaddingLeftPx, mGlowBitmapPaddingTopPx,
+ outBitmap.getWidth() - mGlowBitmapPaddingRightPx,
+ outBitmap.getHeight() - mGlowBitmapPaddingBottomPx), paint);
}
return outBitmap;
}
@@ -556,27 +449,57 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
mRecentsGlowView.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
}
- private void hide(boolean animate) {
+ public void hide(boolean animate) {
if (!animate) {
setVisibility(View.GONE);
}
- mBar.animateCollapse();
+ if (mBar != null) {
+ mBar.animateCollapse();
+ }
}
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ public void handleOnClick(View view) {
ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription;
+ final Context context = view.getContext();
final ActivityManager am = (ActivityManager)
- getContext().getSystemService(Context.ACTIVITY_SERVICE);
- if (ad.id >= 0) {
+ context.getSystemService(Context.ACTIVITY_SERVICE);
+ if (ad.taskId >= 0) {
// This is an active task; it should just go to the foreground.
- am.moveTaskToFront(ad.id, ActivityManager.MOVE_TASK_WITH_HOME);
+ am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME);
} else {
Intent intent = ad.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
if (DEBUG) Log.v(TAG, "Starting activity " + intent);
- getContext().startActivity(intent);
+ context.startActivity(intent);
}
hide(true);
}
+
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ handleOnClick(view);
+ }
+
+ public void handleSwipe(View view, int direction) {
+ ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription;
+ Log.v(TAG, "Jettison " + ad.label);
+ mActivityDescriptions.remove(ad);
+
+ // Handled by widget containers to enable LayoutTransitions properly
+ // mListAdapter.notifyDataSetChanged();
+
+ if (mActivityDescriptions.size() == 0) {
+ hide(false);
+ }
+
+ // Currently, either direction means the same thing, so ignore direction and remove
+ // the task.
+ final ActivityManager am = (ActivityManager)
+ mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ am.removeTask(ad.taskId, 0);
+ }
+
+ public void handleLongPress(View selectedView) {
+ // TODO show context menu : "Remove from list", "Show properties"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
new file mode 100644
index 0000000..6a962cb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2011 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.systemui.recent;
+
+import com.android.systemui.recent.RecentsPanelView.ActivityDescriptionAdapter;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+import com.android.systemui.R;
+
+public class RecentsVerticalScrollView extends ScrollView
+ implements View.OnClickListener, View.OnTouchListener {
+ private static final float FADE_CONSTANT = 0.5f;
+ private static final int SNAP_BACK_DURATION = 250;
+ private static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it
+ private static final String TAG = RecentsPanelView.TAG;
+ private static final float THRESHHOLD = 50;
+ private static final boolean DEBUG_INVALIDATE = false;
+ private LinearLayout mLinearLayout;
+ private ActivityDescriptionAdapter mAdapter;
+ private RecentsCallback mCallback;
+ protected int mLastScrollPosition;
+ private View mCurrentView;
+ private float mLastX;
+ private boolean mDragging;
+ private VelocityTracker mVelocityTracker;
+
+ public RecentsVerticalScrollView(Context context) {
+ this(context, null);
+ }
+
+ public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs, 0);
+ }
+
+ private int scrollPositionOfMostRecent() {
+ return mLinearLayout.getHeight() - getHeight();
+ }
+
+ public void update() {
+ mLinearLayout.removeAllViews();
+ for (int i = 0; i < mAdapter.getCount(); i++) {
+ View view = mAdapter.getView(i, null, mLinearLayout);
+ view.setClickable(true);
+ view.setOnClickListener(this);
+ view.setOnTouchListener(this);
+ mLinearLayout.addView(view);
+ }
+ // Scroll to end after layout.
+ post(new Runnable() {
+ public void run() {
+ mLastScrollPosition = scrollPositionOfMostRecent();
+ scrollTo(0, mLastScrollPosition);
+ }
+ });
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(ev);
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mDragging = false;
+ mLastX = ev.getX();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ float delta = ev.getX() - mLastX;
+ Log.v(TAG, "ACTION_MOVE : " + delta);
+ if (Math.abs(delta) > THRESHHOLD) {
+ mDragging = true;
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ mDragging = false;
+ break;
+ }
+ return mDragging ? true : super.onInterceptTouchEvent(ev);
+ }
+
+ private float getAlphaForOffset(View view, float thumbWidth) {
+ final float fadeWidth = FADE_CONSTANT * thumbWidth;
+ float result = 1.0f;
+ if (view.getX() >= thumbWidth) {
+ result = 1.0f - (view.getX() - thumbWidth) / fadeWidth;
+ } else if (view.getX() < 0.0f) {
+ result = 1.0f + (thumbWidth + view.getX()) / fadeWidth;
+ }
+ Log.v(TAG, "FADE AMOUNT: " + result);
+ return result;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (!mDragging) {
+ return super.onTouchEvent(ev);
+ }
+
+ mVelocityTracker.addMovement(ev);
+
+ final View animView = mCurrentView;
+ // TODO: Cache thumbnail
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_MOVE:
+ if (animView != null) {
+ final float delta = ev.getX() - mLastX;
+ animView.setX(animView.getX() + delta);
+ animView.setAlpha(getAlphaForOffset(animView, thumb.getWidth()));
+ invalidateGlobalRegion(animView);
+ }
+ mLastX = ev.getX();
+ break;
+
+ case MotionEvent.ACTION_UP:
+ final ObjectAnimator anim;
+ if (animView != null) {
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000, 10000);
+ final float velocityX = velocityTracker.getXVelocity();
+ final float velocityY = velocityTracker.getYVelocity();
+ final float curX = animView.getX();
+ final float newX = (velocityX >= 0.0f ? 1 : -1) * animView.getWidth();
+
+ if (Math.abs(velocityX) > Math.abs(velocityY)
+ && Math.abs(velocityX) > ESCAPE_VELOCITY
+ && (velocityX > 0.0f) == (animView.getX() >= 0)) {
+ final long duration =
+ (long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX));
+ anim = ObjectAnimator.ofFloat(animView, "x", curX, newX);
+ anim.setInterpolator(new LinearInterpolator());
+ final int swipeDirection = animView.getX() >= 0.0f ?
+ RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
+ anim.addListener(new AnimatorListener() {
+ public void onAnimationStart(Animator animation) {
+ }
+ public void onAnimationRepeat(Animator animation) {
+ }
+ public void onAnimationEnd(Animator animation) {
+ mLinearLayout.removeView(mCurrentView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ public void onAnimationCancel(Animator animation) {
+ mLinearLayout.removeView(mCurrentView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ });
+ anim.setDuration(duration);
+ } else { // Animate back to position
+ final long duration = Math.abs(velocityX) > 0.0f ?
+ (long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX))
+ : SNAP_BACK_DURATION;
+ anim = ObjectAnimator.ofFloat(animView, "x", animView.getX(), 0.0f);
+ anim.setInterpolator(new DecelerateInterpolator(4.0f));
+ anim.setDuration(duration);
+ }
+
+ anim.addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ animView.setAlpha(getAlphaForOffset(animView, thumb.getWidth()));
+ invalidateGlobalRegion(animView);
+ }
+ });
+ anim.start();
+ }
+
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ break;
+ }
+ return true;
+ }
+
+ void invalidateGlobalRegion(View view) {
+ RectF childBounds
+ = new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
+ childBounds.offset(view.getX(), view.getY());
+ if (DEBUG_INVALIDATE) Log.v(TAG, "-------------");
+ while (view.getParent() != null && view.getParent() instanceof View) {
+ view = (View) view.getParent();
+ view.getMatrix().mapRect(childBounds);
+ view.invalidate((int) Math.floor(childBounds.left),
+ (int) Math.floor(childBounds.top),
+ (int) Math.ceil(childBounds.right),
+ (int) Math.ceil(childBounds.bottom));
+ if (DEBUG_INVALIDATE) {
+ Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
+ + "," + (int) Math.floor(childBounds.top)
+ + "," + (int) Math.ceil(childBounds.right)
+ + "," + (int) Math.ceil(childBounds.bottom));
+ }
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ LayoutInflater inflater = (LayoutInflater)
+ mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ setScrollbarFadingEnabled(true);
+
+ mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
+
+ final int leftPadding = mContext.getResources()
+ .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
+ setOverScrollEffectPadding(leftPadding, 0);
+ }
+
+ private void setOverScrollEffectPadding(int leftPadding, int i) {
+ // TODO Add to (Vertical)ScrollView
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ // Keep track of the last visible item in the list so we can restore it
+ // to the bottom when the orientation changes.
+ mLastScrollPosition = scrollPositionOfMostRecent();
+
+ // This has to happen post-layout, so run it "in the future"
+ post(new Runnable() {
+ public void run() {
+ scrollTo(0, mLastScrollPosition);
+ }
+ });
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ // scroll to bottom after reloading
+ if (visibility == View.VISIBLE && changedView == this) {
+ post(new Runnable() {
+ public void run() {
+ update();
+ }
+ });
+ }
+ }
+
+ public void setAdapter(ActivityDescriptionAdapter adapter) {
+ mAdapter = adapter;
+ mAdapter.registerDataSetObserver(new DataSetObserver() {
+ public void onChanged() {
+ update();
+ }
+
+ public void onInvalidated() {
+ update();
+ }
+ });
+ }
+
+ @Override
+ public void setLayoutTransition(LayoutTransition transition) {
+ // The layout transition applies to our embedded LinearLayout
+ mLinearLayout.setLayoutTransition(transition);
+ }
+
+ public void onClick(View view) {
+ mCallback.handleOnClick(view);
+ }
+
+ public void setCallback(RecentsCallback callback) {
+ mCallback = callback;
+ }
+
+ public boolean onTouch(View v, MotionEvent event) {
+ mCurrentView = v;
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 07f9ad8..62d7500 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -35,28 +35,33 @@ import com.android.internal.statusbar.StatusBarNotification;
public class CommandQueue extends IStatusBar.Stub {
private static final String TAG = "StatusBar.CommandQueue";
- private static final int MSG_MASK = 0xffff0000;
- private static final int INDEX_MASK = 0x0000ffff;
+ private static final int INDEX_MASK = 0xffff;
+ private static final int MSG_SHIFT = 16;
+ private static final int MSG_MASK = 0xffff << MSG_SHIFT;
- private static final int MSG_ICON = 0x00010000;
- private static final int OP_SET_ICON = 1;
+
+ private static final int MSG_ICON = 1 << MSG_SHIFT;
+ private static final int OP_SET_ICON = 1;
private static final int OP_REMOVE_ICON = 2;
- private static final int MSG_ADD_NOTIFICATION = 0x00020000;
- private static final int MSG_UPDATE_NOTIFICATION = 0x00030000;
- private static final int MSG_REMOVE_NOTIFICATION = 0x00040000;
+ private static final int MSG_ADD_NOTIFICATION = 2 << MSG_SHIFT;
+ private static final int MSG_UPDATE_NOTIFICATION = 3 << MSG_SHIFT;
+ private static final int MSG_REMOVE_NOTIFICATION = 4 << MSG_SHIFT;
- private static final int MSG_DISABLE = 0x00050000;
+ private static final int MSG_DISABLE = 5 << MSG_SHIFT;
- private static final int MSG_SET_VISIBILITY = 0x00060000;
- private static final int OP_EXPAND = 1;
- private static final int OP_COLLAPSE = 2;
+ private static final int MSG_SET_VISIBILITY = 6 << MSG_SHIFT;
+ private static final int OP_EXPAND = 1;
+ private static final int OP_COLLAPSE = 2;
- private static final int MSG_SET_LIGHTS_ON = 0x00070000;
+ private static final int MSG_SET_LIGHTS_ON = 7 << MSG_SHIFT;
- private static final int MSG_TOP_APP_WINDOW_CHANGED = 0x00080000;
- private static final int MSG_SHOW_IME_BUTTON = 0x00090000;
- private static final int MSG_SET_HARD_KEYBOARD_STATUS = 0x000a0000;
+ private static final int MSG_TOP_APP_WINDOW_CHANGED = 8 << MSG_SHIFT;
+ private static final int MSG_SHOW_IME_BUTTON = 9 << MSG_SHIFT;
+ private static final int MSG_SET_HARD_KEYBOARD_STATUS = 10 << MSG_SHIFT;
+
+ private static final int MSG_USER_ACTIVITY = 11 << MSG_SHIFT;
+ private static final int MSG_TOGGLE_RECENT_APPS = 12 << MSG_SHIFT;
private StatusBarIconList mList;
private Callbacks mCallbacks;
@@ -85,6 +90,8 @@ public class CommandQueue extends IStatusBar.Stub {
public void topAppWindowChanged(boolean visible);
public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
public void setHardKeyboardStatus(boolean available, boolean enabled);
+ public void userActivity();
+ public void toggleRecentApps();
}
public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -184,6 +191,20 @@ public class CommandQueue extends IStatusBar.Stub {
}
}
+ public void userActivity() {
+ synchronized (mList) {
+ mHandler.removeMessages(MSG_USER_ACTIVITY);
+ mHandler.obtainMessage(MSG_USER_ACTIVITY, 0, 0, null).sendToTarget();
+ }
+ }
+
+ public void toggleRecentApps() {
+ synchronized (mList) {
+ mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
+ mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null).sendToTarget();
+ }
+ }
+
private final class H extends Handler {
public void handleMessage(Message msg) {
final int what = msg.what & MSG_MASK;
@@ -250,6 +271,12 @@ public class CommandQueue extends IStatusBar.Stub {
case MSG_SET_HARD_KEYBOARD_STATUS:
mCallbacks.setHardKeyboardStatus(msg.arg1 != 0, msg.arg2 != 0);
break;
+ case MSG_USER_ACTIVITY:
+ mCallbacks.userActivity();
+ break;
+ case MSG_TOGGLE_RECENT_APPS:
+ mCallbacks.toggleRecentApps();
+ break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
index e567dc7..ca75138 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
@@ -53,6 +53,7 @@ public abstract class StatusBar extends SystemUI implements CommandQueue.Callbac
protected abstract View makeStatusBarView();
protected abstract int getStatusBarGravity();
public abstract int getStatusBarHeight();
+ public abstract void animateCollapse();
private DoNotDisturb mDoNotDisturb;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index dbfbe11..d9d9c06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -29,6 +29,8 @@ import android.view.View;
import android.view.ViewDebug;
import android.widget.FrameLayout;
+import java.text.NumberFormat;
+
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.R;
@@ -180,7 +182,18 @@ public class StatusBarIconView extends AnimatedImageView {
}
void placeNumber() {
- final String str = mNumberText = Integer.toString(mIcon.number);
+ final String str;
+ final int tooBig = mContext.getResources().getInteger(
+ android.R.integer.status_bar_notification_info_maxnum);
+ if (mIcon.number > tooBig) {
+ str = mContext.getResources().getString(
+ android.R.string.status_bar_notification_info_overflow);
+ } else {
+ NumberFormat f = NumberFormat.getIntegerInstance();
+ str = f.format(mIcon.number);
+ }
+ mNumberText = str;
+
final int w = getWidth();
final int h = getHeight();
final Rect r = new Rect();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
index 92b8976..51fc7c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.animation.LayoutTransition;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Display;
@@ -37,6 +38,8 @@ public class ExpandedView extends LinearLayout {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+
+ setLayerType(LAYER_TYPE_HARDWARE, null);
}
/** We want to shrink down to 0, and ignore the background. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
new file mode 100644
index 0000000..7dafb89
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.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.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.os.ServiceManager;
+import android.util.AttributeSet;
+import android.view.Display;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Surface;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.content.res.Configuration;
+
+import com.android.internal.statusbar.IStatusBarService;
+
+import com.android.systemui.R;
+
+public class NavigationBarView extends LinearLayout {
+ final static boolean NAVBAR_ALWAYS_AT_RIGHT = true;
+
+ protected IStatusBarService mBarService;
+ final Display mDisplay;
+ View[] mRotatedViews = new View[4];
+ View mBackground;
+ Animator mLastAnimator = null;
+
+ public NavigationBarView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mDisplay = ((WindowManager)context.getSystemService(
+ Context.WINDOW_SERVICE)).getDefaultDisplay();
+ mBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+
+ //setLayerType(View.LAYER_TYPE_HARDWARE, null);
+
+ setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
+ @Override
+ public void onSystemUiVisibilityChange(int visibility) {
+ boolean on = (visibility == View.STATUS_BAR_VISIBLE);
+ android.util.Log.d("NavigationBarView", "LIGHTS "
+ + (on ? "ON" : "OUT"));
+ setLights(on);
+ }
+ });
+ }
+
+ private void setLights(final boolean on) {
+ float oldAlpha = mBackground.getAlpha();
+ android.util.Log.d("NavigationBarView", "animating alpha: " + oldAlpha + " -> "
+ + (on ? 1f : 0f));
+
+ if (mLastAnimator != null && mLastAnimator.isRunning()) mLastAnimator.cancel();
+
+ mLastAnimator = ObjectAnimator.ofFloat(mBackground, "alpha", oldAlpha, on ? 1f : 0f)
+ .setDuration(on ? 250 : 1500);
+ mLastAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator _a) {
+ mLastAnimator = null;
+ }
+ });
+ mLastAnimator.start();
+ }
+
+ public void onFinishInflate() {
+ mBackground = findViewById(R.id.background);
+
+ mRotatedViews[Surface.ROTATION_0] =
+ mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
+
+ mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
+
+ mRotatedViews[Surface.ROTATION_270] = NAVBAR_ALWAYS_AT_RIGHT
+ ? findViewById(R.id.rot90)
+ : findViewById(R.id.rot270);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ // immediately bring up the lights
+ setLights(true);
+ return false; // pass it on
+ }
+
+ public void reorient() {
+ final int rot = mDisplay.getRotation();
+ for (int i=0; i<4; i++) {
+ mRotatedViews[i].setVisibility(View.GONE);
+ }
+ mRotatedViews[rot].setVisibility(View.VISIBLE);
+
+ android.util.Log.d("NavigationBarView", "reorient(): rot=" + mDisplay.getRotation());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 84ae766..f3c2623 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -28,23 +28,28 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
+import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Handler;
import android.os.Message;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Slog;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
+import android.view.IWindowManager;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.Surface;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
@@ -71,6 +76,7 @@ import com.android.internal.statusbar.StatusBarIconList;
import com.android.internal.statusbar.StatusBarNotification;
import com.android.systemui.R;
+import com.android.systemui.recent.RecentsPanelView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBar;
import com.android.systemui.statusbar.StatusBarIconView;
@@ -80,6 +86,7 @@ import com.android.systemui.statusbar.policy.DateView;
public class PhoneStatusBar extends StatusBar {
static final String TAG = "PhoneStatusBar";
static final boolean SPEW = false;
+ public static final boolean DEBUG = false;
public static final String ACTION_STATUSBAR_START
= "com.android.internal.policy.statusbar.START";
@@ -91,6 +98,8 @@ public class PhoneStatusBar extends StatusBar {
private static final int MSG_ANIMATE_REVEAL = 1001;
private static final int MSG_SHOW_INTRUDER = 1002;
private static final int MSG_HIDE_INTRUDER = 1003;
+ private static final int MSG_OPEN_RECENTS_PANEL = 1020;
+ private static final int MSG_CLOSE_RECENTS_PANEL = 1021;
// will likely move to a resource or other tunable param at some point
private static final int INTRUDER_ALERT_DECAY_MS = 10000;
@@ -100,6 +109,8 @@ public class PhoneStatusBar extends StatusBar {
int mIconSize;
Display mDisplay;
+ IWindowManager mWindowManager;
+
PhoneStatusBarView mStatusBarView;
int mPixelFormat;
H mHandler = new H();
@@ -125,11 +136,11 @@ public class PhoneStatusBar extends StatusBar {
// ongoing
NotificationData mOngoing = new NotificationData();
TextView mOngoingTitle;
- LinearLayout mOngoingItems;
+ ViewGroup mOngoingItems;
// latest
NotificationData mLatest = new NotificationData();
TextView mLatestTitle;
- LinearLayout mLatestItems;
+ ViewGroup mLatestItems;
// position
int[] mPositionTmp = new int[2];
boolean mExpanded;
@@ -141,6 +152,9 @@ public class PhoneStatusBar extends StatusBar {
// for immersive activities
private View mIntruderAlertView;
+ // on-screen navigation buttons
+ private NavigationBarView mNavigationBarView = null;
+
// the tracker view
TrackingView mTrackingView;
WindowManager.LayoutParams mTrackingParams;
@@ -152,6 +166,9 @@ public class PhoneStatusBar extends StatusBar {
private View mTickerView;
private boolean mTicking;
+ // Recent applications
+ private RecentsPanelView mRecentsPanel;
+
// Tracking finger for opening/closing.
int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
boolean mTracking;
@@ -197,9 +214,14 @@ public class PhoneStatusBar extends StatusBar {
mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
+ mWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+
super.start();
- addIntruderView();
+ addNavigationBar();
+
+ //addIntruderView();
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext);
@@ -223,6 +245,16 @@ public class PhoneStatusBar extends StatusBar {
mIntruderAlertView.setVisibility(View.GONE);
mIntruderAlertView.setClickable(true);
+ try {
+ boolean showNav = res.getBoolean(R.bool.config_showNavigationBar);
+ if (showNav) {
+ mNavigationBarView =
+ (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
+ }
+ } catch (Resources.NotFoundException ex) {
+ // no nav bar for you
+ }
+
PhoneStatusBarView sb = (PhoneStatusBarView)View.inflate(context,
R.layout.status_bar, null);
sb.mService = this;
@@ -245,9 +277,9 @@ public class PhoneStatusBar extends StatusBar {
mExpandedView = expanded;
mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
- mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
+ mOngoingItems = (ViewGroup)expanded.findViewById(R.id.ongoingItems);
mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
- mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
+ mLatestItems = (ViewGroup)expanded.findViewById(R.id.latestItems);
mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle);
mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
mClearButton.setOnClickListener(mClearButtonListener);
@@ -273,6 +305,9 @@ public class PhoneStatusBar extends StatusBar {
setAreThereNotifications();
mDateView.setVisibility(View.INVISIBLE);
+ // Recents Panel
+ initializeRecentsPanel();
+
// receive broadcasts
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
@@ -283,6 +318,51 @@ public class PhoneStatusBar extends StatusBar {
return sb;
}
+ protected WindowManager.LayoutParams getRecentsLayoutParams() {
+ boolean translucent = false;
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+ (translucent ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
+ lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
+ lp.setTitle("RecentsPanel");
+ lp.windowAnimations = R.style.Animation_RecentPanel;
+ lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
+ | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+ return lp;
+ }
+
+ protected void initializeRecentsPanel() {
+ // Recents Panel
+ boolean visible = false;
+ if (mRecentsPanel != null) {
+ visible = mRecentsPanel.getVisibility() == View.VISIBLE;
+ WindowManagerImpl.getDefault().removeView(mRecentsPanel);
+ }
+ mRecentsPanel = (RecentsPanelView) View.inflate(mContext,
+ R.layout.status_bar_recent_panel, null);
+
+ mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
+ mRecentsPanel));
+ mRecentsPanel.setVisibility(View.GONE);
+ WindowManager.LayoutParams lp = getRecentsLayoutParams();
+
+ WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
+ mRecentsPanel.setBar(this);
+ if (visible) {
+ // need to set visibility to View.GONE earlier since that
+ // triggers refreshing application list
+ mRecentsPanel.setVisibility(View.VISIBLE);
+ mRecentsPanel.show(true, false);
+ }
+
+ }
+
protected int getStatusBarGravity() {
return Gravity.TOP | Gravity.FILL_HORIZONTAL;
}
@@ -292,6 +372,65 @@ public class PhoneStatusBar extends StatusBar {
return res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
}
+ // For small-screen devices (read: phones) that lack hardware navigation buttons
+ private void addNavigationBar() {
+ if (mNavigationBarView == null) return;
+
+ mNavigationBarView.reorient();
+ WindowManagerImpl.getDefault().addView(
+ mNavigationBarView, getNavigationBarLayoutParams());
+ }
+
+ private void repositionNavigationBar() {
+ if (mNavigationBarView == null) return;
+
+ mNavigationBarView.reorient();
+ WindowManagerImpl.getDefault().updateViewLayout(
+ mNavigationBarView, getNavigationBarLayoutParams());
+ }
+
+ private WindowManager.LayoutParams getNavigationBarLayoutParams() {
+ final int rotation = mDisplay.getRotation();
+ final boolean sideways =
+ (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
+
+ final Resources res = mContext.getResources();
+ final int size = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
+
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ sideways ? size : ViewGroup.LayoutParams.MATCH_PARENT,
+ sideways ? ViewGroup.LayoutParams.MATCH_PARENT : size,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+ 0
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+ | WindowManager.LayoutParams.FLAG_SLIPPERY,
+ PixelFormat.TRANSLUCENT);
+
+ lp.setTitle("NavigationBar");
+ switch (rotation) {
+ case Surface.ROTATION_90:
+ // device has been turned 90deg counter-clockwise
+ lp.gravity = Gravity.RIGHT | Gravity.FILL_VERTICAL;
+ break;
+ case Surface.ROTATION_270:
+ // device has been turned 90deg clockwise
+ lp.gravity = (NavigationBarView.NAVBAR_ALWAYS_AT_RIGHT ? Gravity.RIGHT
+ : Gravity.LEFT)
+ | Gravity.FILL_VERTICAL;
+ break;
+ default:
+ lp.gravity = Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
+ break;
+ }
+ lp.windowAnimations = 0;
+
+ return lp;
+ }
+
private void addIntruderView() {
final int height = getStatusBarHeight();
@@ -499,6 +638,12 @@ public class PhoneStatusBar extends StatusBar {
}
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ initializeRecentsPanel();
+ }
+
+
View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
Notification n = notification.notification;
RemoteViews remoteViews = n.contentView;
@@ -511,6 +656,38 @@ public class PhoneStatusBar extends StatusBar {
Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
+ // wire up the veto button
+ View vetoButton = row.findViewById(R.id.veto);
+ if (notification.isClearable()) {
+ final String _pkg = notification.pkg;
+ final String _tag = notification.tag;
+ final int _id = notification.id;
+ vetoButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ try {
+ mBarService.onNotificationClear(_pkg, _tag, _id);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+ }
+ });
+ } else {
+ if ((notification.notification.flags & Notification.FLAG_ONGOING_EVENT) == 0) {
+ vetoButton.setVisibility(View.INVISIBLE);
+ } else {
+ vetoButton.setVisibility(View.GONE);
+ }
+ }
+
+ // the large icon
+ ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon);
+ if (notification.notification.largeIcon != null) {
+ largeIcon.setImageBitmap(notification.notification.largeIcon);
+ } else {
+ largeIcon.getLayoutParams().width = 0;
+ largeIcon.setVisibility(View.INVISIBLE);
+ }
+
// bind the click event to the content area
ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
@@ -675,6 +852,21 @@ public class PhoneStatusBar extends StatusBar {
case MSG_HIDE_INTRUDER:
setIntruderAlertVisibility(false);
break;
+ case MSG_OPEN_RECENTS_PANEL:
+ if (DEBUG) Slog.d(TAG, "opening recents panel");
+ if (mRecentsPanel != null) {
+ disable(StatusBarManager.DISABLE_BACK);
+ mRecentsPanel.setVisibility(View.VISIBLE);
+ mRecentsPanel.show(true, true);
+ }
+ break;
+ case MSG_CLOSE_RECENTS_PANEL:
+ if (DEBUG) Slog.d(TAG, "closing recents panel");
+ if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
+ disable(StatusBarManager.DISABLE_NONE);
+ mRecentsPanel.show(false, true);
+ }
+ break;
}
}
}
@@ -721,6 +913,10 @@ public class PhoneStatusBar extends StatusBar {
}
public void animateCollapse() {
+ animateCollapse(false);
+ }
+
+ public void animateCollapse(boolean excludeRecents) {
if (SPEW) {
Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+ " mExpandedVisible=" + mExpandedVisible
@@ -730,6 +926,11 @@ public class PhoneStatusBar extends StatusBar {
+ " mAnimVel=" + mAnimVel);
}
+ if (!excludeRecents) {
+ mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
+ mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
+ }
+
if (!mExpandedVisible) {
return;
}
@@ -1010,12 +1211,23 @@ public class PhoneStatusBar extends StatusBar {
}
public void setLightsOn(boolean on) {
+ Log.v(TAG, "lights " + (on ? "on" : "off"));
if (!on) {
// All we do for "lights out" mode on a phone is hide the status bar,
// which the window manager does. But we do need to hide the windowshade
// on our own.
animateCollapse();
}
+ notifyLightsChanged(on);
+ }
+
+ private void notifyLightsChanged(boolean shown) {
+ try {
+ Slog.d(TAG, "lights " + (shown?"on":"out"));
+ mWindowManager.statusBarVisibilityChanged(
+ shown ? View.STATUS_BAR_VISIBLE : View.STATUS_BAR_HIDDEN);
+ } catch (RemoteException ex) {
+ }
}
// Not supported
@@ -1426,6 +1638,19 @@ public class PhoneStatusBar extends StatusBar {
}
}
+ public void userActivity() {
+ try {
+ mBarService.setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
+ } catch (RemoteException ex) { }
+ }
+
+ public void toggleRecentApps() {
+ int msg = (mRecentsPanel.getVisibility() == View.GONE)
+ ? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL;
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
+ }
+
/**
* The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
* This was added last-minute and is inconsistent with the way the rest of the notifications
@@ -1494,9 +1719,17 @@ public class PhoneStatusBar extends StatusBar {
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
|| Intent.ACTION_SCREEN_OFF.equals(action)) {
- animateCollapse();
+ boolean excludeRecents = false;
+ if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
+ String reason = intent.getStringExtra("reason");
+ if (reason != null) {
+ excludeRecents = reason.equals("recentapps");
+ }
+ }
+ animateCollapse(excludeRecents);
}
else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+ repositionNavigationBar();
updateResources();
}
}
@@ -1558,5 +1791,27 @@ public class PhoneStatusBar extends StatusBar {
vibrate();
}
};
+
+ public class TouchOutsideListener implements View.OnTouchListener {
+ private int mMsg;
+ private RecentsPanelView mPanel;
+
+ public TouchOutsideListener(int msg, RecentsPanelView panel) {
+ mMsg = msg;
+ mPanel = panel;
+ }
+
+ public boolean onTouch(View v, MotionEvent ev) {
+ final int action = ev.getAction();
+ if (action == MotionEvent.ACTION_OUTSIDE
+ || (action == MotionEvent.ACTION_DOWN
+ && !mPanel.isInContentArea((int)ev.getX(), (int)ev.getY()))) {
+ mHandler.removeMessages(mMsg);
+ mHandler.sendEmptyMessage(mMsg);
+ return true;
+ }
+ return false;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
new file mode 100644
index 0000000..981fb24
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2011 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.systemui.statusbar.policy;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.HashSet;
+
+import com.android.systemui.R;
+
+public class NotificationRowLayout extends ViewGroup {
+ private static final String TAG = "NotificationRowLayout";
+ private static final boolean DEBUG = false;
+ private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
+
+ private static final boolean ANIMATE_LAYOUT = true;
+
+ private static final boolean CLEAR_IF_SWIPED_FAR_ENOUGH = true;
+
+ private static final boolean CONSTRAIN_SWIPE_ON_PERMANENT = true;
+
+ private static final int APPEAR_ANIM_LEN = SLOW_ANIMATIONS ? 5000 : 250;
+ private static final int DISAPPEAR_ANIM_LEN = APPEAR_ANIM_LEN;
+ private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250;
+
+ private static final float SWIPE_ESCAPE_VELOCITY = 1500f;
+ private static final float SWIPE_ANIM_VELOCITY_MIN = 1000f;
+
+ Rect mTmpRect = new Rect();
+ int mNumRows = 0;
+ int mRowHeight = 0;
+ int mHeight = 0;
+
+ HashSet<View> mAppearingViews = new HashSet<View>();
+ HashSet<View> mDisappearingViews = new HashSet<View>();
+
+ VelocityTracker mVT;
+ float mInitialTouchX, mInitialTouchY;
+ View mSlidingChild = null;
+ float mLiftoffVelocity;
+
+ public NotificationRowLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public NotificationRowLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ mVT = VelocityTracker.obtain();
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NotificationRowLayout,
+ defStyle, 0);
+ mRowHeight = a.getDimensionPixelSize(R.styleable.NotificationRowLayout_rowHeight, 0);
+ a.recycle();
+
+ setLayoutTransition(null);
+
+ if (DEBUG) {
+ setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
+ @Override
+ public void onChildViewAdded(View parent, View child) {
+ Slog.d(TAG, "view added: " + child + "; new count: " + getChildCount());
+ }
+ @Override
+ public void onChildViewRemoved(View parent, View child) {
+ Slog.d(TAG, "view removed: " + child + "; new count: " + (getChildCount() - 1));
+ }
+ });
+
+ setBackgroundColor(0x80FF8000);
+ }
+
+ }
+
+ // Swipey code
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ final int action = ev.getAction();
+// if (DEBUG) Slog.d(TAG, "intercepting touch event: " + ev);
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mVT.clear();
+ mVT.addMovement(ev);
+ mInitialTouchX = ev.getX();
+ mInitialTouchY = ev.getY();
+ mSlidingChild = null;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ mVT.addMovement(ev);
+ if (mSlidingChild == null) {
+ if (Math.abs(ev.getX() - mInitialTouchX) > 4) { // slide slop
+
+ // find the view under the pointer, accounting for GONE views
+ final int count = getChildCount();
+ int y = 0;
+ int childIdx = 0;
+ for (; childIdx < count; childIdx++) {
+ mSlidingChild = getChildAt(childIdx);
+ if (mSlidingChild.getVisibility() == GONE) {
+ continue;
+ }
+ y += mRowHeight;
+ if (mInitialTouchY < y) break;
+ }
+
+ mInitialTouchX -= mSlidingChild.getTranslationX();
+ mSlidingChild.animate().cancel();
+
+ if (DEBUG) {
+ Slog.d(TAG, String.format(
+ "now sliding child %d: %s (touchY=%.1f, rowHeight=%d, count=%d)",
+ childIdx, mSlidingChild, mInitialTouchY, mRowHeight, count));
+ }
+ }
+ }
+ break;
+ }
+ return mSlidingChild != null;
+ }
+
+ protected boolean canBeCleared(View v) {
+ final View veto = v.findViewById(R.id.veto);
+ return (veto != null && veto.getVisibility() != View.GONE);
+ }
+
+ protected boolean clear(View v) {
+ final View veto = v.findViewById(R.id.veto);
+ if (veto != null && veto.getVisibility() != View.GONE) {
+ veto.performClick();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ final int action = ev.getAction();
+// if (DEBUG) Slog.d(TAG, "touch event: " + ev + " sliding: " + mSlidingChild);
+ if (mSlidingChild != null) {
+ switch (action) {
+ case MotionEvent.ACTION_OUTSIDE:
+ case MotionEvent.ACTION_MOVE:
+ mVT.addMovement(ev);
+
+ float delta = (ev.getX() - mInitialTouchX);
+ if (CONSTRAIN_SWIPE_ON_PERMANENT && !canBeCleared(mSlidingChild)) {
+ delta = Math.copySign(
+ Math.min(Math.abs(delta),
+ mSlidingChild.getMeasuredWidth() * 0.2f), delta);
+ }
+ mSlidingChild.setTranslationX(delta);
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mVT.addMovement(ev);
+ mVT.computeCurrentVelocity(1000 /* px/sec */);
+ if (DEBUG) Slog.d(TAG, "exit velocity: " + mVT.getXVelocity());
+ boolean restore = true;
+ mLiftoffVelocity = mVT.getXVelocity();
+ if (Math.abs(mLiftoffVelocity) > SWIPE_ESCAPE_VELOCITY
+ || (CLEAR_IF_SWIPED_FAR_ENOUGH &&
+ (mSlidingChild.getTranslationX() * 2) > mSlidingChild.getMeasuredWidth()))
+ {
+
+ // flingadingy
+ restore = ! clear(mSlidingChild);
+ }
+ if (restore) {
+ // snappity
+ mSlidingChild.animate().translationX(0)
+ .setDuration(SNAP_ANIM_LEN)
+ .start();
+ }
+ break;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ //**
+ @Override
+ public void addView(View child, int index, LayoutParams params) {
+ super.addView(child, index, params);
+
+ final View childF = child;
+
+ if (ANIMATE_LAYOUT) {
+ mAppearingViews.add(child);
+
+ child.setPivotY(0);
+ AnimatorSet a = new AnimatorSet();
+ a.playTogether(
+ ObjectAnimator.ofFloat(child, "alpha", 0f, 1f)
+// ,ObjectAnimator.ofFloat(child, "scaleY", 0f, 1f)
+ );
+ a.setDuration(APPEAR_ANIM_LEN);
+ a.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAppearingViews.remove(childF);
+ }
+ });
+ a.start();
+ requestLayout(); // start the container animation
+ }
+ }
+
+ @Override
+ public void removeView(View child) {
+ final View childF = child;
+ if (ANIMATE_LAYOUT) {
+ if (mAppearingViews.contains(child)) {
+ mAppearingViews.remove(child);
+ }
+ mDisappearingViews.add(child);
+
+ child.setPivotY(0);
+
+ final float velocity = (mSlidingChild == child)
+ ? Math.min(mLiftoffVelocity, SWIPE_ANIM_VELOCITY_MIN)
+ : SWIPE_ESCAPE_VELOCITY;
+ final TimeAnimator zoom = new TimeAnimator();
+ zoom.setTimeListener(new TimeAnimator.TimeListener() {
+ @Override
+ public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
+ childF.setTranslationX(childF.getTranslationX() + deltaTime / 1000f * velocity);
+ }
+ });
+
+ final ObjectAnimator alphaFade = ObjectAnimator.ofFloat(child, "alpha", 0f);
+ alphaFade.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ zoom.cancel(); // it won't end on its own
+ if (DEBUG) Slog.d(TAG, "actually removing child: " + childF);
+ NotificationRowLayout.super.removeView(childF);
+ childF.setAlpha(1f);
+ mDisappearingViews.remove(childF);
+ }
+ });
+
+ AnimatorSet a = new AnimatorSet();
+ a.playTogether(alphaFade, zoom);
+
+// ,ObjectAnimator.ofFloat(child, "scaleY", 0f)
+// ,ObjectAnimator.ofFloat(child, "translationX", child.getTranslationX() + 300f)
+
+ a.setDuration(DISAPPEAR_ANIM_LEN);
+ a.start();
+ requestLayout(); // start the container animation
+ } else {
+ super.removeView(child);
+ }
+ }
+ //**
+
+ @Override
+ public void onFinishInflate() {
+ super.onFinishInflate();
+ setWillNotDraw(false);
+ }
+
+ @Override
+ public void onDraw(android.graphics.Canvas c) {
+ super.onDraw(c);
+ if (DEBUG) {
+ //Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
+ // + getMeasuredHeight() + "px");
+ c.save();
+ c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6,
+ android.graphics.Region.Op.DIFFERENCE);
+ c.drawColor(0xFFFF8000);
+ c.restore();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int count = getChildCount();
+
+ // pass 1: count the number of non-GONE views
+ int numRows = 0;
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+ if (mDisappearingViews.contains(child)) {
+ continue;
+ }
+ numRows++;
+ }
+ if (numRows != mNumRows) {
+ // uh oh, now you made us go and do work
+
+ final int computedHeight = numRows * mRowHeight;
+ if (DEBUG) {
+ Slog.d(TAG, String.format("rows went from %d to %d, resizing to %dpx",
+ mNumRows, numRows, computedHeight));
+ }
+
+ mNumRows = numRows;
+
+ if (ANIMATE_LAYOUT && isShown()) {
+ ObjectAnimator.ofInt(this, "forcedHeight", computedHeight)
+ .setDuration(APPEAR_ANIM_LEN)
+ .start();
+ } else {
+ setForcedHeight(computedHeight);
+ }
+ }
+
+ // pass 2: you know, do the measuring
+ final int childWidthMS = widthMeasureSpec;
+ final int childHeightMS = MeasureSpec.makeMeasureSpec(
+ mRowHeight, MeasureSpec.EXACTLY);
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+
+ child.measure(childWidthMS, childHeightMS);
+ }
+
+ setMeasuredDimension(
+ getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
+ resolveSize(getForcedHeight(), heightMeasureSpec));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ final int width = right - left;
+ final int height = bottom - top;
+
+ //if (DEBUG) Slog.d(TAG, "onLayout: height=" + height);
+
+ final int count = getChildCount();
+ int y = 0;
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+// final int thisRowHeight = (int)(
+// ((mAppearingViews.contains(child) || mDisappearingViews.contains(child))
+// ? child.getScaleY()
+// : 1.0f)
+// * mRowHeight);
+ final int thisRowHeight = (int)(child.getAlpha() * mRowHeight);
+// child.layout(0, y, width, y + thisRowHeight);
+ child.layout(0, y, width, y + mRowHeight);
+ y += thisRowHeight;
+ }
+ }
+
+ public void setForcedHeight(int h) {
+ //if (DEBUG) Slog.d(TAG, "forcedHeight: " + h);
+ if (h != mHeight) {
+ mHeight = h;
+ requestLayout();
+ }
+ }
+
+ public int getForcedHeight() {
+ return mHeight;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
index e9db998..339e3f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java
@@ -422,9 +422,8 @@ public class InputMethodsPanel extends LinearLayout implements StatusBarPanel,
Log.d(TAG, "Get text from: " + imi.getPackageName() + subtype.getNameResId()
+ imi.getServiceInfo().applicationInfo);
}
- // TODO: Change the language of subtype name according to subtype's locale.
- return mPackageManager.getText(
- imi.getPackageName(), subtype.getNameResId(), imi.getServiceInfo().applicationInfo);
+ return subtype.getDisplayName(
+ mContext, imi.getPackageName(), imi.getServiceInfo().applicationInfo);
}
private Drawable getSubtypeIcon(InputMethodInfo imi, InputMethodSubtype subtype) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 79d50df..fe279c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -75,7 +75,7 @@ import com.android.systemui.statusbar.policy.CompatModeButton;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.Prefs;
-import com.android.systemui.recent.RecentApplicationsActivity;
+import com.android.systemui.recent.RecentsPanelView;
public class TabletStatusBar extends StatusBar implements
HeightReceiver.OnBarHeightChangedListener,
@@ -171,7 +171,7 @@ public class TabletStatusBar extends StatusBar implements
// for disabling the status bar
int mDisabled = 0;
- private RecentAppsPanel mRecentsPanel;
+ private RecentsPanelView mRecentsPanel;
private InputMethodsPanel mInputMethodsPanel;
private CompatModePanel mCompatModePanel;
@@ -266,7 +266,7 @@ public class TabletStatusBar extends StatusBar implements
WindowManagerImpl.getDefault().addView(mNotificationPeekWindow, lp);
// Recents Panel
- mRecentsPanel = (RecentAppsPanel) View.inflate(context,
+ mRecentsPanel = (RecentsPanelView) View.inflate(context,
R.layout.status_bar_recent_panel, null);
mRecentsPanel.setVisibility(View.GONE);
mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
@@ -1172,20 +1172,12 @@ public class TabletStatusBar extends StatusBar implements
public void onClickRecentButton() {
if (DEBUG) Slog.d(TAG, "clicked recent apps; disabled=" + mDisabled);
- if (mRecentsPanel == null) {
- Intent intent = new Intent();
- intent.setClass(mContext, RecentApplicationsActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- mContext.startActivity(intent);
- } else {
- if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
- int msg = (mRecentsPanel.getVisibility() == View.GONE)
- ? MSG_OPEN_RECENTS_PANEL
- : MSG_CLOSE_RECENTS_PANEL;
- mHandler.removeMessages(msg);
- mHandler.sendEmptyMessage(msg);
- }
+ if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
+ int msg = (mRecentsPanel.getVisibility() == View.GONE)
+ ? MSG_OPEN_RECENTS_PANEL
+ : MSG_CLOSE_RECENTS_PANEL;
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
}
}
@@ -1322,7 +1314,7 @@ public class TabletStatusBar extends StatusBar implements
if (mVT != null) {
if (action == MotionEvent.ACTION_UP
// was this a sloppy tap?
- && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
+ && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
&& Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3)
// dragging off the bottom doesn't count
&& (int)event.getY() < v.getBottom()) {
@@ -1425,7 +1417,7 @@ public class TabletStatusBar extends StatusBar implements
if (!peeking) {
if (action == MotionEvent.ACTION_UP
// was this a sloppy tap?
- && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
+ && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
&& Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3)
// dragging off the bottom doesn't count
&& (int)event.getY() < v.getBottom()) {
@@ -1694,6 +1686,16 @@ public class TabletStatusBar extends StatusBar implements
return true;
}
+ public void userActivity() {
+ }
+
+ public void toggleRecentApps() {
+ int msg = (mRecentsPanel.getVisibility() == View.GONE)
+ ? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL;
+ mHandler.removeMessages(msg);
+ mHandler.sendEmptyMessage(msg);
+ }
+
public class TouchOutsideListener implements View.OnTouchListener {
private int mMsg;
private StatusBarPanel mPanel;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
new file mode 100644
index 0000000..60906a1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPreferenceActivity.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2011 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.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.util.Log;
+import android.widget.Button;
+
+import java.io.File;
+
+import com.android.systemui.R;
+
+public class UsbPreferenceActivity extends Activity implements View.OnClickListener {
+
+ private static final String TAG = "UsbPreferenceActivity";
+
+ private UsbManager mUsbManager;
+ private String mCurrentFunction;
+ private String[] mFunctions;
+ private String mInstallerImagePath;
+ private AlertDialog mDialog;
+ private Button mMtpPtpButton;
+ private Button mInstallerCdButton;
+ private boolean mPtpActive;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
+ dialogBuilder.setTitle(getString(R.string.usb_preference_title));
+
+ LayoutInflater inflater = (LayoutInflater)getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ View buttonView = inflater.inflate(R.layout.usb_preference_buttons, null);
+ dialogBuilder.setView(buttonView);
+ mMtpPtpButton = (Button)buttonView.findViewById(R.id.mtp_ptp_button);
+ mInstallerCdButton = (Button)buttonView.findViewById(R.id.installer_cd_button);
+ mMtpPtpButton.setOnClickListener(this);
+ mInstallerCdButton.setOnClickListener(this);
+
+ mPtpActive = mUsbManager.isFunctionEnabled(UsbManager.USB_FUNCTION_PTP);
+ if (mPtpActive) {
+ mMtpPtpButton.setText(R.string.use_mtp_button_title);
+ }
+
+ mInstallerImagePath = getString(com.android.internal.R.string.config_isoImagePath);
+ if (!(new File(mInstallerImagePath)).exists()) {
+ mInstallerCdButton.setVisibility(View.GONE);
+ }
+
+ mDialog = dialogBuilder.show();
+ }
+
+ public void onClick(View v) {
+ if (v.equals(mMtpPtpButton)) {
+ if (mPtpActive) {
+ mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MTP, true);
+ } else {
+ mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_PTP, true);
+ }
+ } else if (v.equals(mInstallerCdButton)) {
+ // installer CD is never default
+ mUsbManager.setCurrentFunction(UsbManager.USB_FUNCTION_MASS_STORAGE, false);
+ mUsbManager.setMassStorageBackingFile(mInstallerImagePath);
+ }
+
+ if (mDialog != null) {
+ mDialog.dismiss();
+ }
+ finish();
+ }
+}
diff --git a/packages/TtsService/Android.mk b/packages/TtsService/Android.mk
deleted file mode 100644
index a1a3b9f..0000000
--- a/packages/TtsService/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files) \
-
-LOCAL_PACKAGE_NAME := TtsService
-LOCAL_CERTIFICATE := platform
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/TtsService/AndroidManifest.xml b/packages/TtsService/AndroidManifest.xml
deleted file mode 100755
index 46e0ad1..0000000
--- a/packages/TtsService/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.tts">
- <application android:label="TTS Service"
- android:icon="@drawable/ic_launcher_text_to_speech">
- <service android:enabled="true"
- android:name=".TtsService"
- android:label="TTS Service">
- <intent-filter>
- <action android:name="android.intent.action.START_TTS_SERVICE"/>
- <category android:name="android.intent.category.TTS"/>
- </intent-filter>
- </service>
- </application>
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-</manifest>
diff --git a/packages/TtsService/MODULE_LICENSE_APACHE2 b/packages/TtsService/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/packages/TtsService/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/packages/TtsService/NOTICE b/packages/TtsService/NOTICE
deleted file mode 100644
index 64aaa8d..0000000
--- a/packages/TtsService/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/packages/TtsService/jni/Android.mk b/packages/TtsService/jni/Android.mk
deleted file mode 100755
index 5dc0c30..0000000
--- a/packages/TtsService/jni/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- android_tts_SynthProxy.cpp
-
-LOCAL_C_INCLUDES += \
- frameworks/base/native/include \
- $(JNI_H_INCLUDE)
-
-LOCAL_SHARED_LIBRARIES := \
- libandroid_runtime \
- libnativehelper \
- libmedia \
- libutils \
- libcutils
-
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -ldl
-else
- LOCAL_SHARED_LIBRARIES += libdl
-endif
-
-
-LOCAL_MODULE:= libttssynthproxy
-
-LOCAL_ARM_MODE := arm
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
deleted file mode 100644
index 27d1fc0..0000000
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ /dev/null
@@ -1,1073 +0,0 @@
-/*
- * Copyright (C) 2009-2010 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.
- */
-
-#include <stdio.h>
-#include <unistd.h>
-
-#define LOG_TAG "SynthProxyJNI"
-
-#include <utils/Log.h>
-#include <nativehelper/jni.h>
-#include <nativehelper/JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
-#include <android/tts.h>
-#include <media/AudioTrack.h>
-#include <math.h>
-
-#include <dlfcn.h>
-
-#define DEFAULT_TTS_RATE 16000
-#define DEFAULT_TTS_FORMAT AudioSystem::PCM_16_BIT
-#define DEFAULT_TTS_NB_CHANNELS 1
-#define DEFAULT_TTS_BUFFERSIZE 2048
-#define DEFAULT_TTS_STREAM_TYPE AudioSystem::MUSIC
-#define DEFAULT_VOLUME 1.0f
-
-// EQ + BOOST parameters
-#define FILTER_LOWSHELF_ATTENUATION -18.0f // in dB
-#define FILTER_TRANSITION_FREQ 1100.0f // in Hz
-#define FILTER_SHELF_SLOPE 1.0f // Q
-#define FILTER_GAIN 5.5f // linear gain
-
-#define USAGEMODE_PLAY_IMMEDIATELY 0
-#define USAGEMODE_WRITE_TO_FILE 1
-
-#define SYNTHPLAYSTATE_IS_STOPPED 0
-#define SYNTHPLAYSTATE_IS_PLAYING 1
-
-using namespace android;
-
-// ----------------------------------------------------------------------------
-struct fields_t {
- jfieldID synthProxyFieldJniData;
- jclass synthProxyClass;
- jmethodID synthProxyMethodPost;
-};
-
-// structure to hold the data that is used each time the TTS engine has synthesized more data
-struct afterSynthData_t {
- jint jniStorage;
- int usageMode;
- FILE* outputFile;
- AudioSystem::stream_type streamType;
-};
-
-// ----------------------------------------------------------------------------
-// EQ data
-double amp;
-double w;
-double sinw;
-double cosw;
-double beta;
-double a0, a1, a2, b0, b1, b2;
-double m_fa, m_fb, m_fc, m_fd, m_fe;
-double x0; // x[n]
-double x1; // x[n-1]
-double x2; // x[n-2]
-double out0;// y[n]
-double out1;// y[n-1]
-double out2;// y[n-2]
-
-static float fFilterLowshelfAttenuation = FILTER_LOWSHELF_ATTENUATION;
-static float fFilterTransitionFreq = FILTER_TRANSITION_FREQ;
-static float fFilterShelfSlope = FILTER_SHELF_SLOPE;
-static float fFilterGain = FILTER_GAIN;
-static bool bUseFilter = false;
-
-void initializeEQ() {
-
- amp = float(pow(10.0, fFilterLowshelfAttenuation / 40.0));
- w = 2.0 * M_PI * (fFilterTransitionFreq / DEFAULT_TTS_RATE);
- sinw = float(sin(w));
- cosw = float(cos(w));
- beta = float(sqrt(amp)/fFilterShelfSlope);
-
- // initialize low-shelf parameters
- b0 = amp * ((amp+1.0F) - ((amp-1.0F)*cosw) + (beta*sinw));
- b1 = 2.0F * amp * ((amp-1.0F) - ((amp+1.0F)*cosw));
- b2 = amp * ((amp+1.0F) - ((amp-1.0F)*cosw) - (beta*sinw));
- a0 = (amp+1.0F) + ((amp-1.0F)*cosw) + (beta*sinw);
- a1 = 2.0F * ((amp-1.0F) + ((amp+1.0F)*cosw));
- a2 = -((amp+1.0F) + ((amp-1.0F)*cosw) - (beta*sinw));
-
- m_fa = fFilterGain * b0/a0;
- m_fb = fFilterGain * b1/a0;
- m_fc = fFilterGain * b2/a0;
- m_fd = a1/a0;
- m_fe = a2/a0;
-}
-
-void initializeFilter() {
- x0 = 0.0f;
- x1 = 0.0f;
- x2 = 0.0f;
- out0 = 0.0f;
- out1 = 0.0f;
- out2 = 0.0f;
-}
-
-void applyFilter(int16_t* buffer, size_t sampleCount) {
-
- for (size_t i=0 ; i<sampleCount ; i++) {
-
- x0 = (double) buffer[i];
-
- out0 = (m_fa*x0) + (m_fb*x1) + (m_fc*x2) + (m_fd*out1) + (m_fe*out2);
-
- x2 = x1;
- x1 = x0;
-
- out2 = out1;
- out1 = out0;
-
- if (out0 > 32767.0f) {
- buffer[i] = 32767;
- } else if (out0 < -32768.0f) {
- buffer[i] = -32768;
- } else {
- buffer[i] = (int16_t) out0;
- }
- }
-}
-
-
-// ----------------------------------------------------------------------------
-static fields_t javaTTSFields;
-
-// TODO move to synth member once we have multiple simultaneous engines running
-static Mutex engineMutex;
-
-// ----------------------------------------------------------------------------
-class SynthProxyJniStorage {
- public :
- jobject tts_ref;
- android_tts_engine_t* mEngine;
- void* mEngineLibHandle;
- AudioTrack* mAudioOut;
- int8_t mPlayState;
- Mutex mPlayLock;
- AudioSystem::stream_type mStreamType;
- uint32_t mSampleRate;
- uint32_t mAudFormat;
- int mNbChannels;
- int8_t * mBuffer;
- size_t mBufferSize;
- float mVolume[2];
-
- SynthProxyJniStorage() {
- tts_ref = NULL;
- mEngine = NULL;
- mEngineLibHandle = NULL;
- mAudioOut = NULL;
- mPlayState = SYNTHPLAYSTATE_IS_STOPPED;
- mStreamType = DEFAULT_TTS_STREAM_TYPE;
- mSampleRate = DEFAULT_TTS_RATE;
- mAudFormat = DEFAULT_TTS_FORMAT;
- mNbChannels = DEFAULT_TTS_NB_CHANNELS;
- mBufferSize = DEFAULT_TTS_BUFFERSIZE;
- mBuffer = new int8_t[mBufferSize];
- memset(mBuffer, 0, mBufferSize);
- mVolume[AudioTrack::LEFT] = DEFAULT_VOLUME;
- mVolume[AudioTrack::RIGHT] = DEFAULT_VOLUME;
- }
-
- ~SynthProxyJniStorage() {
- //LOGV("entering ~SynthProxyJniStorage()");
- killAudio();
- if (mEngine) {
- mEngine->funcs->shutdown(mEngine);
- mEngine = NULL;
- }
- if (mEngineLibHandle) {
- //LOGV("~SynthProxyJniStorage(): before close library");
- int res = dlclose(mEngineLibHandle);
- LOGE_IF( res != 0, "~SynthProxyJniStorage(): dlclose returned %d", res);
- }
- delete mBuffer;
- }
-
- void killAudio() {
- if (mAudioOut) {
- mAudioOut->stop();
- delete mAudioOut;
- mAudioOut = NULL;
- }
- }
-
- void createAudioOut(AudioSystem::stream_type streamType, uint32_t rate,
- AudioSystem::audio_format format, int channel) {
- mSampleRate = rate;
- mAudFormat = format;
- mNbChannels = channel;
- mStreamType = streamType;
-
- // retrieve system properties to ensure successful creation of the
- // AudioTrack object for playback
- int afSampleRate;
- if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
- afSampleRate = 44100;
- }
- int afFrameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
- afFrameCount = 2048;
- }
- uint32_t afLatency;
- if (AudioSystem::getOutputLatency(&afLatency, mStreamType) != NO_ERROR) {
- afLatency = 500;
- }
- uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
- if (minBufCount < 2) minBufCount = 2;
- int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate;
-
- mPlayLock.lock();
- mAudioOut = new AudioTrack(mStreamType, rate, format,
- (channel == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
- minFrameCount > 4096 ? minFrameCount : 4096,
- 0, 0, 0, 0); // not using an AudioTrack callback
-
- if (mAudioOut->initCheck() != NO_ERROR) {
- LOGE("createAudioOut(): AudioTrack error");
- delete mAudioOut;
- mAudioOut = NULL;
- } else {
- //LOGI("AudioTrack OK");
- mAudioOut->setVolume(mVolume[AudioTrack::LEFT], mVolume[AudioTrack::RIGHT]);
- LOGV("AudioTrack ready");
- }
- mPlayLock.unlock();
- }
-};
-
-
-// ----------------------------------------------------------------------------
-void prepAudioTrack(SynthProxyJniStorage* pJniData, AudioSystem::stream_type streamType,
- uint32_t rate, AudioSystem::audio_format format, int channel) {
- // Don't bother creating a new audiotrack object if the current
- // object is already initialized with the same audio parameters.
- if ( pJniData->mAudioOut &&
- (rate == pJniData->mSampleRate) &&
- (format == pJniData->mAudFormat) &&
- (channel == pJniData->mNbChannels) &&
- (streamType == pJniData->mStreamType) ){
- return;
- }
- if (pJniData->mAudioOut){
- pJniData->killAudio();
- }
- pJniData->createAudioOut(streamType, rate, format, channel);
-}
-
-
-// ----------------------------------------------------------------------------
-/*
- * Callback from TTS engine.
- * Directly speaks using AudioTrack or write to file
- */
-extern "C" android_tts_callback_status_t
-__ttsSynthDoneCB(void ** pUserdata, uint32_t rate,
- android_tts_audio_format_t format, int channel,
- int8_t **pWav, size_t *pBufferSize,
- android_tts_synth_status_t status)
-{
- //LOGV("ttsSynthDoneCallback: %d bytes", bufferSize);
- AudioSystem::audio_format encoding;
-
- if (*pUserdata == NULL){
- LOGE("userdata == NULL");
- return ANDROID_TTS_CALLBACK_HALT;
- }
- switch (format) {
- case ANDROID_TTS_AUDIO_FORMAT_PCM_8_BIT:
- encoding = AudioSystem::PCM_8_BIT;
- break;
- case ANDROID_TTS_AUDIO_FORMAT_PCM_16_BIT:
- encoding = AudioSystem::PCM_16_BIT;
- break;
- default:
- LOGE("Can't play, bad format");
- return ANDROID_TTS_CALLBACK_HALT;
- }
- afterSynthData_t* pForAfter = (afterSynthData_t*) *pUserdata;
- SynthProxyJniStorage* pJniData = (SynthProxyJniStorage*)(pForAfter->jniStorage);
-
- if (pForAfter->usageMode == USAGEMODE_PLAY_IMMEDIATELY){
- //LOGV("Direct speech");
-
- if (*pWav == NULL) {
- delete pForAfter;
- pForAfter = NULL;
- LOGV("Null: speech has completed");
- return ANDROID_TTS_CALLBACK_HALT;
- }
-
- if (*pBufferSize > 0) {
- prepAudioTrack(pJniData, pForAfter->streamType, rate, encoding, channel);
- if (pJniData->mAudioOut) {
- pJniData->mPlayLock.lock();
- if(pJniData->mAudioOut->stopped()
- && (pJniData->mPlayState == SYNTHPLAYSTATE_IS_PLAYING)) {
- pJniData->mAudioOut->start();
- }
- pJniData->mPlayLock.unlock();
- if (bUseFilter) {
- applyFilter((int16_t*)*pWav, *pBufferSize/2);
- }
- pJniData->mAudioOut->write(*pWav, *pBufferSize);
- memset(*pWav, 0, *pBufferSize);
- //LOGV("AudioTrack wrote: %d bytes", bufferSize);
- } else {
- LOGE("Can't play, null audiotrack");
- delete pForAfter;
- pForAfter = NULL;
- return ANDROID_TTS_CALLBACK_HALT;
- }
- }
- } else if (pForAfter->usageMode == USAGEMODE_WRITE_TO_FILE) {
- //LOGV("Save to file");
- if (*pWav == NULL) {
- delete pForAfter;
- LOGV("Null: speech has completed");
- return ANDROID_TTS_CALLBACK_HALT;
- }
- if (*pBufferSize > 0){
- if (bUseFilter) {
- applyFilter((int16_t*)*pWav, *pBufferSize/2);
- }
- fwrite(*pWav, 1, *pBufferSize, pForAfter->outputFile);
- memset(*pWav, 0, *pBufferSize);
- }
- }
- // Future update:
- // For sync points in the speech, call back into the SynthProxy class through the
- // javaTTSFields.synthProxyMethodPost methode to notify
- // playback has completed if the synthesis is done or if a marker has been reached.
-
- if (status == ANDROID_TTS_SYNTH_DONE) {
- // this struct was allocated in the original android_tts_SynthProxy_speak call,
- // all processing matching this call is now done.
- LOGV("Speech synthesis done.");
- if (pForAfter->usageMode == USAGEMODE_PLAY_IMMEDIATELY) {
- // only delete for direct playback. When writing to a file, we still have work to do
- // in android_tts_SynthProxy_synthesizeToFile. The struct will be deleted there.
- delete pForAfter;
- pForAfter = NULL;
- }
- return ANDROID_TTS_CALLBACK_HALT;
- }
-
- // we don't update the wav (output) parameter as we'll let the next callback
- // write at the same location, we've consumed the data already, but we need
- // to update bufferSize to let the TTS engine know how much it can write the
- // next time it calls this function.
- *pBufferSize = pJniData->mBufferSize;
-
- return ANDROID_TTS_CALLBACK_CONTINUE;
-}
-
-
-// ----------------------------------------------------------------------------
-static int
-android_tts_SynthProxy_setLowShelf(JNIEnv *env, jobject thiz, jboolean applyFilter,
- jfloat filterGain, jfloat attenuationInDb, jfloat freqInHz, jfloat slope)
-{
- int result = ANDROID_TTS_SUCCESS;
-
- bUseFilter = applyFilter;
- if (applyFilter) {
- fFilterLowshelfAttenuation = attenuationInDb;
- fFilterTransitionFreq = freqInHz;
- fFilterShelfSlope = slope;
- fFilterGain = filterGain;
-
- if (fFilterShelfSlope != 0.0f) {
- initializeEQ();
- } else {
- LOGE("Invalid slope, can't be null");
- result = ANDROID_TTS_FAILURE;
- }
- }
-
- return result;
-}
-
-// ----------------------------------------------------------------------------
-static int
-android_tts_SynthProxy_native_setup(JNIEnv *env, jobject thiz,
- jobject weak_this, jstring nativeSoLib, jstring engConfig)
-{
- int result = ANDROID_TTS_FAILURE;
-
- bUseFilter = false;
-
- SynthProxyJniStorage* pJniStorage = new SynthProxyJniStorage();
-
- prepAudioTrack(pJniStorage,
- DEFAULT_TTS_STREAM_TYPE, DEFAULT_TTS_RATE, DEFAULT_TTS_FORMAT, DEFAULT_TTS_NB_CHANNELS);
-
- const char *nativeSoLibNativeString = env->GetStringUTFChars(nativeSoLib, 0);
- const char *engConfigString = env->GetStringUTFChars(engConfig, 0);
-
- void *engine_lib_handle = dlopen(nativeSoLibNativeString,
- RTLD_NOW | RTLD_LOCAL);
- if (engine_lib_handle == NULL) {
- LOGE("android_tts_SynthProxy_native_setup(): engine_lib_handle == NULL");
- } else {
- android_tts_engine_t * (*get_TtsEngine)() =
- reinterpret_cast<android_tts_engine_t* (*)()>(dlsym(engine_lib_handle, "android_getTtsEngine"));
-
- // Support obsolete/legacy binary modules
- if (get_TtsEngine == NULL) {
- get_TtsEngine =
- reinterpret_cast<android_tts_engine_t* (*)()>(dlsym(engine_lib_handle, "getTtsEngine"));
- }
-
- pJniStorage->mEngine = (*get_TtsEngine)();
- pJniStorage->mEngineLibHandle = engine_lib_handle;
-
- android_tts_engine_t *engine = pJniStorage->mEngine;
- if (engine) {
- Mutex::Autolock l(engineMutex);
- engine->funcs->init(
- engine,
- __ttsSynthDoneCB,
- engConfigString);
- }
-
- result = ANDROID_TTS_SUCCESS;
- }
-
- // we use a weak reference so the SynthProxy object can be garbage collected.
- pJniStorage->tts_ref = env->NewGlobalRef(weak_this);
-
- // save the JNI resources so we can use them (and free them) later
- env->SetIntField(thiz, javaTTSFields.synthProxyFieldJniData, (int)pJniStorage);
-
- env->ReleaseStringUTFChars(nativeSoLib, nativeSoLibNativeString);
- env->ReleaseStringUTFChars(engConfig, engConfigString);
-
- return result;
-}
-
-
-static void
-android_tts_SynthProxy_native_finalize(JNIEnv *env, jobject thiz, jint jniData)
-{
- //LOGV("entering android_tts_SynthProxy_finalize()");
- if (jniData == 0) {
- //LOGE("android_tts_SynthProxy_native_finalize(): invalid JNI data");
- return;
- }
-
- Mutex::Autolock l(engineMutex);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- env->DeleteGlobalRef(pSynthData->tts_ref);
- delete pSynthData;
-
- env->SetIntField(thiz, javaTTSFields.synthProxyFieldJniData, 0);
-}
-
-
-static void
-android_tts_SynthProxy_shutdown(JNIEnv *env, jobject thiz, jint jniData)
-{
- //LOGV("entering android_tts_SynthProxy_shutdown()");
-
- // do everything a call to finalize would
- android_tts_SynthProxy_native_finalize(env, thiz, jniData);
-}
-
-
-static int
-android_tts_SynthProxy_isLanguageAvailable(JNIEnv *env, jobject thiz, jint jniData,
- jstring language, jstring country, jstring variant)
-{
- int result = ANDROID_TTS_LANG_NOT_SUPPORTED;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_isLanguageAvailable(): invalid JNI data");
- return result;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- const char *langNativeString = env->GetStringUTFChars(language, 0);
- const char *countryNativeString = env->GetStringUTFChars(country, 0);
- const char *variantNativeString = env->GetStringUTFChars(variant, 0);
-
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->isLanguageAvailable(engine,langNativeString,
- countryNativeString, variantNativeString);
- }
- env->ReleaseStringUTFChars(language, langNativeString);
- env->ReleaseStringUTFChars(country, countryNativeString);
- env->ReleaseStringUTFChars(variant, variantNativeString);
- return result;
-}
-
-static int
-android_tts_SynthProxy_setConfig(JNIEnv *env, jobject thiz, jint jniData, jstring engineConfig)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_setConfig(): invalid JNI data");
- return result;
- }
-
- Mutex::Autolock l(engineMutex);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- const char *engineConfigNativeString = env->GetStringUTFChars(engineConfig, 0);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->setProperty(engine,ANDROID_TTS_ENGINE_PROPERTY_CONFIG,
- engineConfigNativeString, strlen(engineConfigNativeString));
- }
- env->ReleaseStringUTFChars(engineConfig, engineConfigNativeString);
-
- return result;
-}
-
-static int
-android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
- jstring language, jstring country, jstring variant)
-{
- int result = ANDROID_TTS_LANG_NOT_SUPPORTED;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_setLanguage(): invalid JNI data");
- return result;
- }
-
- Mutex::Autolock l(engineMutex);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- const char *langNativeString = env->GetStringUTFChars(language, 0);
- const char *countryNativeString = env->GetStringUTFChars(country, 0);
- const char *variantNativeString = env->GetStringUTFChars(variant, 0);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->setLanguage(engine, langNativeString,
- countryNativeString, variantNativeString);
- }
- env->ReleaseStringUTFChars(language, langNativeString);
- env->ReleaseStringUTFChars(country, countryNativeString);
- env->ReleaseStringUTFChars(variant, variantNativeString);
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_loadLanguage(JNIEnv *env, jobject thiz, jint jniData,
- jstring language, jstring country, jstring variant)
-{
- int result = ANDROID_TTS_LANG_NOT_SUPPORTED;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_loadLanguage(): invalid JNI data");
- return result;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- const char *langNativeString = env->GetStringUTFChars(language, 0);
- const char *countryNativeString = env->GetStringUTFChars(country, 0);
- const char *variantNativeString = env->GetStringUTFChars(variant, 0);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->loadLanguage(engine, langNativeString,
- countryNativeString, variantNativeString);
- }
- env->ReleaseStringUTFChars(language, langNativeString);
- env->ReleaseStringUTFChars(country, countryNativeString);
- env->ReleaseStringUTFChars(variant, variantNativeString);
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_setSpeechRate(JNIEnv *env, jobject thiz, jint jniData,
- jint speechRate)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_setSpeechRate(): invalid JNI data");
- return result;
- }
-
- int bufSize = 12;
- char buffer [bufSize];
- sprintf(buffer, "%d", speechRate);
-
- Mutex::Autolock l(engineMutex);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- //LOGI("setting speech rate to %d", speechRate);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->setProperty(engine, "rate", buffer, bufSize);
- }
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_setPitch(JNIEnv *env, jobject thiz, jint jniData,
- jint pitch)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_setPitch(): invalid JNI data");
- return result;
- }
-
- Mutex::Autolock l(engineMutex);
-
- int bufSize = 12;
- char buffer [bufSize];
- sprintf(buffer, "%d", pitch);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- //LOGI("setting pitch to %d", pitch);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->setProperty(engine, "pitch", buffer, bufSize);
- }
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData,
- jstring textJavaString, jstring filenameJavaString)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_synthesizeToFile(): invalid JNI data");
- return result;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- if (!pSynthData->mEngine) {
- LOGE("android_tts_SynthProxy_synthesizeToFile(): invalid engine handle");
- return result;
- }
-
- initializeFilter();
-
- Mutex::Autolock l(engineMutex);
-
- // Retrieve audio parameters before writing the file header
- AudioSystem::audio_format encoding;
- uint32_t rate = DEFAULT_TTS_RATE;
- int channels = DEFAULT_TTS_NB_CHANNELS;
- android_tts_engine_t *engine = pSynthData->mEngine;
- android_tts_audio_format_t format = ANDROID_TTS_AUDIO_FORMAT_DEFAULT;
-
- engine->funcs->setAudioFormat(engine, &format, &rate, &channels);
-
- switch (format) {
- case ANDROID_TTS_AUDIO_FORMAT_PCM_16_BIT:
- encoding = AudioSystem::PCM_16_BIT;
- break;
- case ANDROID_TTS_AUDIO_FORMAT_PCM_8_BIT:
- encoding = AudioSystem::PCM_8_BIT;
- break;
- default:
- LOGE("android_tts_SynthProxy_synthesizeToFile(): engine uses invalid format");
- return result;
- }
-
- const char *filenameNativeString =
- env->GetStringUTFChars(filenameJavaString, 0);
- const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
-
- afterSynthData_t* pForAfter = new (afterSynthData_t);
- pForAfter->jniStorage = jniData;
- pForAfter->usageMode = USAGEMODE_WRITE_TO_FILE;
-
- pForAfter->outputFile = fopen(filenameNativeString, "wb");
-
- if (pForAfter->outputFile == NULL) {
- LOGE("android_tts_SynthProxy_synthesizeToFile(): error creating output file");
- delete pForAfter;
- return result;
- }
-
- // Write 44 blank bytes for WAV header, then come back and fill them in
- // after we've written the audio data
- char header[44];
- fwrite(header, 1, 44, pForAfter->outputFile);
-
- unsigned int unique_identifier;
-
- memset(pSynthData->mBuffer, 0, pSynthData->mBufferSize);
-
- result = engine->funcs->synthesizeText(engine, textNativeString,
- pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter);
-
- long filelen = ftell(pForAfter->outputFile);
-
- int samples = (((int)filelen) - 44) / 2;
- header[0] = 'R';
- header[1] = 'I';
- header[2] = 'F';
- header[3] = 'F';
- ((uint32_t *)(&header[4]))[0] = filelen - 8;
- header[8] = 'W';
- header[9] = 'A';
- header[10] = 'V';
- header[11] = 'E';
-
- header[12] = 'f';
- header[13] = 'm';
- header[14] = 't';
- header[15] = ' ';
-
- ((uint32_t *)(&header[16]))[0] = 16; // size of fmt
-
- int sampleSizeInByte = (encoding == AudioSystem::PCM_16_BIT ? 2 : 1);
-
- ((unsigned short *)(&header[20]))[0] = 1; // format
- ((unsigned short *)(&header[22]))[0] = channels; // channels
- ((uint32_t *)(&header[24]))[0] = rate; // samplerate
- ((uint32_t *)(&header[28]))[0] = rate * sampleSizeInByte * channels;// byterate
- ((unsigned short *)(&header[32]))[0] = sampleSizeInByte * channels; // block align
- ((unsigned short *)(&header[34]))[0] = sampleSizeInByte * 8; // bits per sample
-
- header[36] = 'd';
- header[37] = 'a';
- header[38] = 't';
- header[39] = 'a';
-
- ((uint32_t *)(&header[40]))[0] = samples * 2; // size of data
-
- // Skip back to the beginning and rewrite the header
- fseek(pForAfter->outputFile, 0, SEEK_SET);
- fwrite(header, 1, 44, pForAfter->outputFile);
-
- fflush(pForAfter->outputFile);
- fclose(pForAfter->outputFile);
-
- delete pForAfter;
- pForAfter = NULL;
-
- env->ReleaseStringUTFChars(textJavaString, textNativeString);
- env->ReleaseStringUTFChars(filenameJavaString, filenameNativeString);
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData,
- jstring textJavaString, jint javaStreamType, jfloat volume, jfloat pan)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_speak(): invalid JNI data");
- return result;
- }
-
- initializeFilter();
-
- Mutex::Autolock l(engineMutex);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-
- {//scope for lock on mPlayLock
- Mutex::Autolock _l(pSynthData->mPlayLock);
-
- pSynthData->mPlayState = SYNTHPLAYSTATE_IS_PLAYING;
-
- // clip volume and pan
- float vol = (volume > 1.0f) ? 1.0f : (volume < 0.0f) ? 0.0f : volume;
- float panning = (pan > 1.0f) ? 1.0f : (pan < -1.0f) ? -1.0f : pan;
- // compute playback volume based on volume and pan, using balance rule, in order to avoid
- // lowering volume when panning in center
- pSynthData->mVolume[AudioTrack::LEFT] = vol;
- pSynthData->mVolume[AudioTrack::RIGHT] = vol;
- if (panning > 0.0f) {
- pSynthData->mVolume[AudioTrack::LEFT] *= (1.0f - panning);
- } else if (panning < 0.0f) {
- pSynthData->mVolume[AudioTrack::RIGHT] *= (1.0f + panning);
- }
-
- // apply the volume if there is an output
- if (NULL != pSynthData->mAudioOut) {
- pSynthData->mAudioOut->setVolume(pSynthData->mVolume[AudioTrack::LEFT],
- pSynthData->mVolume[AudioTrack::RIGHT]);
- }
-
- //LOGV("android_tts_SynthProxy_speak() vol=%.3f pan=%.3f, mVolume=[%.1f %.1f]",
- // volume, pan,
- // pSynthData->mVolume[AudioTrack::LEFT], pSynthData->mVolume[AudioTrack::RIGHT]);
- }
-
- afterSynthData_t* pForAfter = new (afterSynthData_t);
- pForAfter->jniStorage = jniData;
- pForAfter->usageMode = USAGEMODE_PLAY_IMMEDIATELY;
- pForAfter->streamType = (AudioSystem::stream_type) javaStreamType;
-
- if (pSynthData->mEngine) {
- const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
- memset(pSynthData->mBuffer, 0, pSynthData->mBufferSize);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- result = engine->funcs->synthesizeText(engine, textNativeString,
- pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter);
- env->ReleaseStringUTFChars(textJavaString, textNativeString);
- }
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_stop(JNIEnv *env, jobject thiz, jint jniData)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_stop(): invalid JNI data");
- return result;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-
- pSynthData->mPlayLock.lock();
- pSynthData->mPlayState = SYNTHPLAYSTATE_IS_STOPPED;
- if (pSynthData->mAudioOut) {
- pSynthData->mAudioOut->stop();
- }
- pSynthData->mPlayLock.unlock();
-
- android_tts_engine_t *engine = pSynthData->mEngine;
- if (engine) {
- result = engine->funcs->stop(engine);
- }
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_stopSync(JNIEnv *env, jobject thiz, jint jniData)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_stop(): invalid JNI data");
- return result;
- }
-
- // perform a regular stop
- result = android_tts_SynthProxy_stop(env, thiz, jniData);
- // but wait on the engine having released the engine mutex which protects
- // the synthesizer resources.
- engineMutex.lock();
- engineMutex.unlock();
-
- return result;
-}
-
-
-static jobjectArray
-android_tts_SynthProxy_getLanguage(JNIEnv *env, jobject thiz, jint jniData)
-{
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_getLanguage(): invalid JNI data");
- return NULL;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-
- if (pSynthData->mEngine) {
- size_t bufSize = 100;
- char lang[bufSize];
- char country[bufSize];
- char variant[bufSize];
- memset(lang, 0, bufSize);
- memset(country, 0, bufSize);
- memset(variant, 0, bufSize);
- jobjectArray retLocale = (jobjectArray)env->NewObjectArray(3,
- env->FindClass("java/lang/String"), env->NewStringUTF(""));
-
- android_tts_engine_t *engine = pSynthData->mEngine;
- engine->funcs->getLanguage(engine, lang, country, variant);
- env->SetObjectArrayElement(retLocale, 0, env->NewStringUTF(lang));
- env->SetObjectArrayElement(retLocale, 1, env->NewStringUTF(country));
- env->SetObjectArrayElement(retLocale, 2, env->NewStringUTF(variant));
- return retLocale;
- } else {
- return NULL;
- }
-}
-
-
-JNIEXPORT int JNICALL
-android_tts_SynthProxy_getRate(JNIEnv *env, jobject thiz, jint jniData)
-{
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_getRate(): invalid JNI data");
- return 0;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- size_t bufSize = 100;
-
- char buf[bufSize];
- memset(buf, 0, bufSize);
- // TODO check return codes
- android_tts_engine_t *engine = pSynthData->mEngine;
- if (engine) {
- engine->funcs->getProperty(engine,"rate", buf, &bufSize);
- }
- return atoi(buf);
-}
-
-// Dalvik VM type signatures
-static JNINativeMethod gMethods[] = {
- { "native_stop",
- "(I)I",
- (void*)android_tts_SynthProxy_stop
- },
- { "native_stopSync",
- "(I)I",
- (void*)android_tts_SynthProxy_stopSync
- },
- { "native_speak",
- "(ILjava/lang/String;IFF)I",
- (void*)android_tts_SynthProxy_speak
- },
- { "native_synthesizeToFile",
- "(ILjava/lang/String;Ljava/lang/String;)I",
- (void*)android_tts_SynthProxy_synthesizeToFile
- },
- { "native_isLanguageAvailable",
- "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
- (void*)android_tts_SynthProxy_isLanguageAvailable
- },
- { "native_setConfig",
- "(ILjava/lang/String;)I",
- (void*)android_tts_SynthProxy_setConfig
- },
- { "native_setLanguage",
- "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
- (void*)android_tts_SynthProxy_setLanguage
- },
- { "native_loadLanguage",
- "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
- (void*)android_tts_SynthProxy_loadLanguage
- },
- { "native_setSpeechRate",
- "(II)I",
- (void*)android_tts_SynthProxy_setSpeechRate
- },
- { "native_setPitch",
- "(II)I",
- (void*)android_tts_SynthProxy_setPitch
- },
- { "native_getLanguage",
- "(I)[Ljava/lang/String;",
- (void*)android_tts_SynthProxy_getLanguage
- },
- { "native_getRate",
- "(I)I",
- (void*)android_tts_SynthProxy_getRate
- },
- { "native_shutdown",
- "(I)V",
- (void*)android_tts_SynthProxy_shutdown
- },
- { "native_setup",
- "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)I",
- (void*)android_tts_SynthProxy_native_setup
- },
- { "native_setLowShelf",
- "(ZFFFF)I",
- (void*)android_tts_SynthProxy_setLowShelf
- },
- { "native_finalize",
- "(I)V",
- (void*)android_tts_SynthProxy_native_finalize
- }
-};
-
-#define SP_JNIDATA_FIELD_NAME "mJniData"
-#define SP_POSTSPEECHSYNTHESIZED_METHOD_NAME "postNativeSpeechSynthesizedInJava"
-
-static const char* const kClassPathName = "android/tts/SynthProxy";
-
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
-{
- JNIEnv* env = NULL;
- jint result = -1;
- jclass clazz;
-
- if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- LOGE("ERROR: GetEnv failed\n");
- goto bail;
- }
- assert(env != NULL);
-
- clazz = env->FindClass(kClassPathName);
- if (clazz == NULL) {
- LOGE("Can't find %s", kClassPathName);
- goto bail;
- }
-
- javaTTSFields.synthProxyClass = clazz;
- javaTTSFields.synthProxyFieldJniData = NULL;
- javaTTSFields.synthProxyMethodPost = NULL;
-
- javaTTSFields.synthProxyFieldJniData = env->GetFieldID(clazz,
- SP_JNIDATA_FIELD_NAME, "I");
- if (javaTTSFields.synthProxyFieldJniData == NULL) {
- LOGE("Can't find %s.%s field", kClassPathName, SP_JNIDATA_FIELD_NAME);
- goto bail;
- }
-
- javaTTSFields.synthProxyMethodPost = env->GetStaticMethodID(clazz,
- SP_POSTSPEECHSYNTHESIZED_METHOD_NAME, "(Ljava/lang/Object;II)V");
- if (javaTTSFields.synthProxyMethodPost == NULL) {
- LOGE("Can't find %s.%s method", kClassPathName, SP_POSTSPEECHSYNTHESIZED_METHOD_NAME);
- goto bail;
- }
-
- if (jniRegisterNativeMethods(
- env, kClassPathName, gMethods, NELEM(gMethods)) < 0)
- goto bail;
-
- /* success -- return valid version number */
- result = JNI_VERSION_1_4;
-
- bail:
- return result;
-}
diff --git a/packages/TtsService/proguard.flags b/packages/TtsService/proguard.flags
deleted file mode 100644
index e8bee6b..0000000
--- a/packages/TtsService/proguard.flags
+++ /dev/null
@@ -1,5 +0,0 @@
--keep class android.tts.SynthProxy {
- int mJniData;
- # keep all declarations for native methods
- <methods>;
-}
diff --git a/packages/TtsService/res/drawable-hdpi/ic_launcher_text_to_speech.png b/packages/TtsService/res/drawable-hdpi/ic_launcher_text_to_speech.png
deleted file mode 100644
index f075e0f..0000000
--- a/packages/TtsService/res/drawable-hdpi/ic_launcher_text_to_speech.png
+++ /dev/null
Binary files differ
diff --git a/packages/TtsService/res/drawable-mdpi/ic_launcher_text_to_speech.png b/packages/TtsService/res/drawable-mdpi/ic_launcher_text_to_speech.png
deleted file mode 100644
index cbae7de..0000000
--- a/packages/TtsService/res/drawable-mdpi/ic_launcher_text_to_speech.png
+++ /dev/null
Binary files differ
diff --git a/packages/TtsService/src/android/tts/SynthProxy.java b/packages/TtsService/src/android/tts/SynthProxy.java
deleted file mode 100755
index f5f5fcf..0000000
--- a/packages/TtsService/src/android/tts/SynthProxy.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-package android.tts;
-
-import android.media.AudioManager;
-import android.media.AudioSystem;
-import android.util.Log;
-import java.lang.ref.WeakReference;
-
-/**
- * @hide
- *
- * The SpeechSynthesis class provides a high-level api to create and play
- * synthesized speech. This class is used internally to talk to a native
- * TTS library that implements the interface defined in
- * frameworks/base/include/tts/TtsEngine.h
- *
- */
-@SuppressWarnings("unused")
-public class SynthProxy {
-
- // Default parameters of a filter to be applied when using the Pico engine.
- // Such a huge filter gain is justified by how much energy in the low frequencies is "wasted" at
- // the output of the synthesis. The low shelving filter removes it, leaving room for
- // amplification.
- private final static float PICO_FILTER_GAIN = 5.0f; // linear gain
- private final static float PICO_FILTER_LOWSHELF_ATTENUATION = -18.0f; // in dB
- private final static float PICO_FILTER_TRANSITION_FREQ = 1100.0f; // in Hz
- private final static float PICO_FILTER_SHELF_SLOPE = 1.0f; // Q
-
- //
- // External API
- //
-
- /**
- * Constructor; pass the location of the native TTS .so to use.
- */
- public SynthProxy(String nativeSoLib, String engineConfig) {
- boolean applyFilter = nativeSoLib.toLowerCase().contains("pico");
- Log.v(TtsService.SERVICE_TAG, "About to load "+ nativeSoLib + ", applyFilter="+applyFilter);
- native_setup(new WeakReference<SynthProxy>(this), nativeSoLib, engineConfig);
- native_setLowShelf(applyFilter, PICO_FILTER_GAIN, PICO_FILTER_LOWSHELF_ATTENUATION,
- PICO_FILTER_TRANSITION_FREQ, PICO_FILTER_SHELF_SLOPE);
- }
-
- /**
- * Stops and clears the AudioTrack.
- */
- public int stop() {
- return native_stop(mJniData);
- }
-
- /**
- * Synchronous stop of the synthesizer. This method returns when the synth
- * has completed the stop procedure and doesn't use any of the resources it
- * was using while synthesizing.
- *
- * @return {@link android.speech.tts.TextToSpeech.SUCCESS} or
- * {@link android.speech.tts.TextToSpeech.ERROR}
- */
- public int stopSync() {
- return native_stopSync(mJniData);
- }
-
- /**
- * Synthesize speech and speak it directly using AudioTrack.
- */
- public int speak(String text, int streamType, float volume, float pan) {
- Log.i(TAG, "speak() on stream "+ streamType);
- if ((streamType > -1) && (streamType < AudioSystem.getNumStreamTypes())) {
- return native_speak(mJniData, text, streamType, volume, pan);
- } else {
- Log.e("SynthProxy", "Trying to speak with invalid stream type " + streamType);
- return native_speak(mJniData, text, AudioManager.STREAM_MUSIC, volume, pan);
- }
- }
-
- /**
- * Synthesize speech to a file. The current implementation writes a valid
- * WAV file to the given path, assuming it is writable. Something like
- * "/sdcard/???.wav" is recommended.
- */
- public int synthesizeToFile(String text, String filename) {
- Log.i(TAG, "synthesizeToFile() to file "+ filename);
- return native_synthesizeToFile(mJniData, text, filename);
- }
-
- /**
- * Queries for language support.
- * Return codes are defined in android.speech.tts.TextToSpeech
- */
- public int isLanguageAvailable(String language, String country, String variant) {
- return native_isLanguageAvailable(mJniData, language, country, variant);
- }
-
- /**
- * Updates the engine configuration.
- */
- public int setConfig(String engineConfig) {
- return native_setConfig(mJniData, engineConfig);
- }
-
- /**
- * Sets the language.
- */
- public int setLanguage(String language, String country, String variant) {
- return native_setLanguage(mJniData, language, country, variant);
- }
-
- /**
- * Loads the language: it's not set, but prepared for use later.
- */
- public int loadLanguage(String language, String country, String variant) {
- return native_loadLanguage(mJniData, language, country, variant);
- }
-
- /**
- * Sets the speech rate.
- */
- public final int setSpeechRate(int speechRate) {
- return native_setSpeechRate(mJniData, speechRate);
- }
-
- /**
- * Sets the pitch of the synthesized voice.
- */
- public final int setPitch(int pitch) {
- return native_setPitch(mJniData, pitch);
- }
-
- /**
- * Returns the currently set language, country and variant information.
- */
- public String[] getLanguage() {
- return native_getLanguage(mJniData);
- }
-
- /**
- * Gets the currently set rate.
- */
- public int getRate() {
- return native_getRate(mJniData);
- }
-
- /**
- * Shuts down the native synthesizer.
- */
- public void shutdown() {
- native_shutdown(mJniData);
- }
-
- //
- // Internal
- //
-
- protected void finalize() {
- native_finalize(mJniData);
- mJniData = 0;
- }
-
- static {
- System.loadLibrary("ttssynthproxy");
- }
-
- private final static String TAG = "SynthProxy";
-
- /**
- * Accessed by native methods
- */
- private int mJniData = 0;
-
- private native final int native_setup(Object weak_this, String nativeSoLib,
- String engineConfig);
-
- private native final int native_setLowShelf(boolean applyFilter, float filterGain,
- float attenuationInDb, float freqInHz, float slope);
-
- private native final void native_finalize(int jniData);
-
- private native final int native_stop(int jniData);
-
- private native final int native_stopSync(int jniData);
-
- private native final int native_speak(int jniData, String text, int streamType, float volume,
- float pan);
-
- private native final int native_synthesizeToFile(int jniData, String text, String filename);
-
- private native final int native_isLanguageAvailable(int jniData, String language,
- String country, String variant);
-
- private native final int native_setLanguage(int jniData, String language, String country,
- String variant);
-
- private native final int native_loadLanguage(int jniData, String language, String country,
- String variant);
-
- private native final int native_setConfig(int jniData, String engineConfig);
-
- private native final int native_setSpeechRate(int jniData, int speechRate);
-
- private native final int native_setPitch(int jniData, int speechRate);
-
- private native final String[] native_getLanguage(int jniData);
-
- private native final int native_getRate(int jniData);
-
- private native final void native_shutdown(int jniData);
-
-
- /**
- * Callback from the C layer
- */
- @SuppressWarnings("unused")
- private static void postNativeSpeechSynthesizedInJava(Object tts_ref,
- int bufferPointer, int bufferSize) {
-
- Log.i("TTS plugin debug", "bufferPointer: " + bufferPointer
- + " bufferSize: " + bufferSize);
-
- SynthProxy nativeTTS = (SynthProxy)((WeakReference)tts_ref).get();
- // TODO notify TTS service of synthesis/playback completion,
- // method definition to be changed.
- }
-}
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
deleted file mode 100755
index c562327..0000000
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ /dev/null
@@ -1,1503 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-package android.tts;
-
-import android.app.Service;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.database.Cursor;
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.net.Uri;
-import android.os.IBinder;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.preference.PreferenceManager;
-import android.speech.tts.ITts.Stub;
-import android.speech.tts.ITtsCallback;
-import android.speech.tts.TextToSpeech;
-import android.util.Log;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.TimeUnit;
-
-
-/**
- * @hide Synthesizes speech from text. This is implemented as a service so that
- * other applications can call the TTS without needing to bundle the TTS
- * in the build.
- *
- */
-public class TtsService extends Service implements OnCompletionListener {
-
- private static class SpeechItem {
- public static final int TEXT = 0;
- public static final int EARCON = 1;
- public static final int SILENCE = 2;
- public static final int TEXT_TO_FILE = 3;
- public String mText = "";
- public ArrayList<String> mParams = null;
- public int mType = TEXT;
- public long mDuration = 0;
- public String mFilename = null;
- public String mCallingApp = "";
-
- public SpeechItem(String source, String text, ArrayList<String> params, int itemType) {
- mText = text;
- mParams = params;
- mType = itemType;
- mCallingApp = source;
- }
-
- public SpeechItem(String source, long silenceTime, ArrayList<String> params) {
- mDuration = silenceTime;
- mParams = params;
- mType = SILENCE;
- mCallingApp = source;
- }
-
- public SpeechItem(String source, String text, ArrayList<String> params,
- int itemType, String filename) {
- mText = text;
- mParams = params;
- mType = itemType;
- mFilename = filename;
- mCallingApp = source;
- }
-
- }
-
- /**
- * Contains the information needed to access a sound resource; the name of
- * the package that contains the resource and the resID of the resource
- * within that package.
- */
- private static class SoundResource {
- public String mSourcePackageName = null;
- public int mResId = -1;
- public String mFilename = null;
-
- public SoundResource(String packageName, int id) {
- mSourcePackageName = packageName;
- mResId = id;
- mFilename = null;
- }
-
- public SoundResource(String file) {
- mSourcePackageName = null;
- mResId = -1;
- mFilename = file;
- }
- }
- // If the speech queue is locked for more than 5 seconds, something has gone
- // very wrong with processSpeechQueue.
- private static final int SPEECHQUEUELOCK_TIMEOUT = 5000;
- private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000;
- private static final int MAX_FILENAME_LENGTH = 250;
- private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_MUSIC;
- // TODO use TextToSpeech.DEFAULT_SYNTH once it is unhidden
- private static final String DEFAULT_SYNTH = "com.svox.pico";
- private static final String ACTION = "android.intent.action.START_TTS_SERVICE";
- private static final String CATEGORY = "android.intent.category.TTS";
- private static final String PKGNAME = "android.tts";
- protected static final String SERVICE_TAG = "TtsService";
-
- private final RemoteCallbackList<ITtsCallback> mCallbacks
- = new RemoteCallbackList<ITtsCallback>();
-
- private HashMap<String, ITtsCallback> mCallbacksMap;
-
- private Boolean mIsSpeaking;
- private Boolean mSynthBusy;
- private ArrayList<SpeechItem> mSpeechQueue;
- private HashMap<String, SoundResource> mEarcons;
- private HashMap<String, SoundResource> mUtterances;
- private MediaPlayer mPlayer;
- private SpeechItem mCurrentSpeechItem;
- private HashMap<SpeechItem, Boolean> mKillList; // Used to ensure that in-flight synth calls
- // are killed when stop is used.
- private TtsService mSelf;
-
- private ContentResolver mResolver;
-
- // lock for the speech queue (mSpeechQueue) and the current speech item (mCurrentSpeechItem)
- private final ReentrantLock speechQueueLock = new ReentrantLock();
- private final ReentrantLock synthesizerLock = new ReentrantLock();
-
- private static SynthProxy sNativeSynth = null;
- private String currentSpeechEngineSOFile = "";
-
- @Override
- public void onCreate() {
- super.onCreate();
- Log.v("TtsService", "TtsService.onCreate()");
-
- mResolver = getContentResolver();
-
- currentSpeechEngineSOFile = "";
- setEngine(getDefaultEngine());
-
- mSelf = this;
- mIsSpeaking = false;
- mSynthBusy = false;
-
- mEarcons = new HashMap<String, SoundResource>();
- mUtterances = new HashMap<String, SoundResource>();
- mCallbacksMap = new HashMap<String, android.speech.tts.ITtsCallback>();
-
- mSpeechQueue = new ArrayList<SpeechItem>();
- mPlayer = null;
- mCurrentSpeechItem = null;
- mKillList = new HashMap<SpeechItem, Boolean>();
-
- setDefaultSettings();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- killAllUtterances();
-
- // Don't hog the media player
- cleanUpPlayer();
-
- if (sNativeSynth != null) {
- sNativeSynth.shutdown();
- }
- sNativeSynth = null;
-
- // Unregister all callbacks.
- mCallbacks.kill();
-
- Log.v(SERVICE_TAG, "onDestroy() completed");
- }
-
-
- private int setEngine(String enginePackageName) {
- String soFilename = "";
- if (isDefaultEnforced()) {
- enginePackageName = getDefaultEngine();
- }
-
- // Make sure that the engine has been allowed by the user
- if (!enginePackageName.equals(DEFAULT_SYNTH)) {
- String[] enabledEngines = android.provider.Settings.Secure.getString(mResolver,
- android.provider.Settings.Secure.TTS_ENABLED_PLUGINS).split(" ");
- boolean isEnabled = false;
- for (int i=0; i<enabledEngines.length; i++) {
- if (enabledEngines[i].equals(enginePackageName)) {
- isEnabled = true;
- break;
- }
- }
- if (!isEnabled) {
- // Do not use an engine that the user has not enabled; fall back
- // to using the default synthesizer.
- enginePackageName = DEFAULT_SYNTH;
- }
- }
-
- // The SVOX TTS is an exception to how the TTS packaging scheme works
- // because it is part of the system and not a 3rd party add-on; thus
- // its binary is actually located under /system/lib/
- if (enginePackageName.equals(DEFAULT_SYNTH)) {
- soFilename = "/system/lib/libttspico.so";
- } else {
- // Find the package
- Intent intent = new Intent("android.intent.action.START_TTS_ENGINE");
- intent.setPackage(enginePackageName);
- ResolveInfo[] enginesArray = new ResolveInfo[0];
- PackageManager pm = getPackageManager();
- List <ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
- if ((resolveInfos == null) || resolveInfos.isEmpty()) {
- Log.e(SERVICE_TAG, "Invalid TTS Engine Package: " + enginePackageName);
- return TextToSpeech.ERROR;
- }
- enginesArray = resolveInfos.toArray(enginesArray);
- // Generate the TTS .so filename from the package
- ActivityInfo aInfo = enginesArray[0].activityInfo;
- soFilename = aInfo.name.replace(aInfo.packageName + ".", "") + ".so";
- soFilename = soFilename.toLowerCase();
- soFilename = "/data/data/" + aInfo.packageName + "/lib/libtts" + soFilename;
- }
-
- if (currentSpeechEngineSOFile.equals(soFilename)) {
- return TextToSpeech.SUCCESS;
- }
-
- File f = new File(soFilename);
- if (!f.exists()) {
- Log.e(SERVICE_TAG, "Invalid TTS Binary: " + soFilename);
- return TextToSpeech.ERROR;
- }
-
- if (sNativeSynth != null) {
- sNativeSynth.stopSync();
- sNativeSynth.shutdown();
- sNativeSynth = null;
- }
-
- // Load the engineConfig from the plugin if it has any special configuration
- // to be loaded. By convention, if an engine wants the TTS framework to pass
- // in any configuration, it must put it into its content provider which has the URI:
- // content://<packageName>.providers.SettingsProvider
- // That content provider must provide a Cursor which returns the String that
- // is to be passed back to the native .so file for the plugin when getString(0) is
- // called on it.
- // Note that the TTS framework does not care what this String data is: it is something
- // that comes from the engine plugin and is consumed only by the engine plugin itself.
- String engineConfig = "";
- Cursor c = getContentResolver().query(Uri.parse("content://" + enginePackageName
- + ".providers.SettingsProvider"), null, null, null, null);
- if (c != null){
- c.moveToFirst();
- engineConfig = c.getString(0);
- c.close();
- }
- sNativeSynth = new SynthProxy(soFilename, engineConfig);
- currentSpeechEngineSOFile = soFilename;
- return TextToSpeech.SUCCESS;
- }
-
-
-
- private void setDefaultSettings() {
- setLanguage("", this.getDefaultLanguage(), getDefaultCountry(), getDefaultLocVariant());
-
- // speech rate
- setSpeechRate("", getDefaultRate());
- }
-
-
- private boolean isDefaultEnforced() {
- return (android.provider.Settings.Secure.getInt(mResolver,
- android.provider.Settings.Secure.TTS_USE_DEFAULTS,
- TextToSpeech.Engine.USE_DEFAULTS)
- == 1 );
- }
-
- private String getDefaultEngine() {
- String defaultEngine = android.provider.Settings.Secure.getString(mResolver,
- android.provider.Settings.Secure.TTS_DEFAULT_SYNTH);
- if (defaultEngine == null) {
- return TextToSpeech.Engine.DEFAULT_SYNTH;
- } else {
- return defaultEngine;
- }
- }
-
- private int getDefaultRate() {
- return android.provider.Settings.Secure.getInt(mResolver,
- android.provider.Settings.Secure.TTS_DEFAULT_RATE,
- TextToSpeech.Engine.DEFAULT_RATE);
- }
-
- private int getDefaultPitch() {
- // Pitch is not user settable; the default pitch is always 100.
- return 100;
- }
-
- private String getDefaultLanguage() {
- String defaultLang = android.provider.Settings.Secure.getString(mResolver,
- android.provider.Settings.Secure.TTS_DEFAULT_LANG);
- if (defaultLang == null) {
- // no setting found, use the current Locale to determine the default language
- return Locale.getDefault().getISO3Language();
- } else {
- return defaultLang;
- }
- }
-
-
- private String getDefaultCountry() {
- String defaultCountry = android.provider.Settings.Secure.getString(mResolver,
- android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY);
- if (defaultCountry == null) {
- // no setting found, use the current Locale to determine the default country
- return Locale.getDefault().getISO3Country();
- } else {
- return defaultCountry;
- }
- }
-
-
- private String getDefaultLocVariant() {
- String defaultVar = android.provider.Settings.Secure.getString(mResolver,
- android.provider.Settings.Secure.TTS_DEFAULT_VARIANT);
- if (defaultVar == null) {
- // no setting found, use the current Locale to determine the default variant
- return Locale.getDefault().getVariant();
- } else {
- return defaultVar;
- }
- }
-
-
- private int setSpeechRate(String callingApp, int rate) {
- int res = TextToSpeech.ERROR;
- try {
- if (isDefaultEnforced()) {
- res = sNativeSynth.setSpeechRate(getDefaultRate());
- } else {
- res = sNativeSynth.setSpeechRate(rate);
- }
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- res = TextToSpeech.ERROR;
- }
- return res;
- }
-
-
- private int setPitch(String callingApp, int pitch) {
- int res = TextToSpeech.ERROR;
- try {
- res = sNativeSynth.setPitch(pitch);
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- res = TextToSpeech.ERROR;
- }
- return res;
- }
-
-
- private int isLanguageAvailable(String lang, String country, String variant) {
- int res = TextToSpeech.LANG_NOT_SUPPORTED;
- try {
- res = sNativeSynth.isLanguageAvailable(lang, country, variant);
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- res = TextToSpeech.LANG_NOT_SUPPORTED;
- }
- return res;
- }
-
-
- private String[] getLanguage() {
- try {
- return sNativeSynth.getLanguage();
- } catch (Exception e) {
- return null;
- }
- }
-
-
- private int setLanguage(String callingApp, String lang, String country, String variant) {
- Log.v(SERVICE_TAG, "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
- int res = TextToSpeech.ERROR;
- try {
- if (isDefaultEnforced()) {
- res = sNativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(),
- getDefaultLocVariant());
- } else {
- res = sNativeSynth.setLanguage(lang, country, variant);
- }
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- res = TextToSpeech.ERROR;
- }
- return res;
- }
-
-
- /**
- * Adds a sound resource to the TTS.
- *
- * @param text
- * The text that should be associated with the sound resource
- * @param packageName
- * The name of the package which has the sound resource
- * @param resId
- * The resource ID of the sound within its package
- */
- private void addSpeech(String callingApp, String text, String packageName, int resId) {
- mUtterances.put(text, new SoundResource(packageName, resId));
- }
-
- /**
- * Adds a sound resource to the TTS.
- *
- * @param text
- * The text that should be associated with the sound resource
- * @param filename
- * The filename of the sound resource. This must be a complete
- * path like: (/sdcard/mysounds/mysoundbite.mp3).
- */
- private void addSpeech(String callingApp, String text, String filename) {
- mUtterances.put(text, new SoundResource(filename));
- }
-
- /**
- * Adds a sound resource to the TTS as an earcon.
- *
- * @param earcon
- * The text that should be associated with the sound resource
- * @param packageName
- * The name of the package which has the sound resource
- * @param resId
- * The resource ID of the sound within its package
- */
- private void addEarcon(String callingApp, String earcon, String packageName, int resId) {
- mEarcons.put(earcon, new SoundResource(packageName, resId));
- }
-
- /**
- * Adds a sound resource to the TTS as an earcon.
- *
- * @param earcon
- * The text that should be associated with the sound resource
- * @param filename
- * The filename of the sound resource. This must be a complete
- * path like: (/sdcard/mysounds/mysoundbite.mp3).
- */
- private void addEarcon(String callingApp, String earcon, String filename) {
- mEarcons.put(earcon, new SoundResource(filename));
- }
-
- /**
- * Speaks the given text using the specified queueing mode and parameters.
- *
- * @param text
- * The text that should be spoken
- * @param queueMode
- * TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances),
- * TextToSpeech.TTS_QUEUE_ADD for queued
- * @param params
- * An ArrayList of parameters. This is not implemented for all
- * engines.
- */
- private int speak(String callingApp, String text, int queueMode, ArrayList<String> params) {
- // Log.v(SERVICE_TAG, "TTS service received " + text);
- if (queueMode == TextToSpeech.QUEUE_FLUSH) {
- stop(callingApp);
- } else if (queueMode == 2) {
- stopAll(callingApp);
- }
- mSpeechQueue.add(new SpeechItem(callingApp, text, params, SpeechItem.TEXT));
- if (!mIsSpeaking) {
- processSpeechQueue();
- }
- return TextToSpeech.SUCCESS;
- }
-
- /**
- * Plays the earcon using the specified queueing mode and parameters.
- *
- * @param earcon
- * The earcon that should be played
- * @param queueMode
- * TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances),
- * TextToSpeech.TTS_QUEUE_ADD for queued
- * @param params
- * An ArrayList of parameters. This is not implemented for all
- * engines.
- */
- private int playEarcon(String callingApp, String earcon, int queueMode,
- ArrayList<String> params) {
- if (queueMode == TextToSpeech.QUEUE_FLUSH) {
- stop(callingApp);
- } else if (queueMode == 2) {
- stopAll(callingApp);
- }
- mSpeechQueue.add(new SpeechItem(callingApp, earcon, params, SpeechItem.EARCON));
- if (!mIsSpeaking) {
- processSpeechQueue();
- }
- return TextToSpeech.SUCCESS;
- }
-
- /**
- * Stops all speech output and removes any utterances still in the queue for the calling app.
- */
- private int stop(String callingApp) {
- int result = TextToSpeech.ERROR;
- boolean speechQueueAvailable = false;
- try{
- speechQueueAvailable =
- speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
- if (speechQueueAvailable) {
- Log.i(SERVICE_TAG, "Stopping");
- for (int i = mSpeechQueue.size() - 1; i > -1; i--){
- if (mSpeechQueue.get(i).mCallingApp.equals(callingApp)){
- mSpeechQueue.remove(i);
- }
- }
- if ((mCurrentSpeechItem != null) &&
- mCurrentSpeechItem.mCallingApp.equals(callingApp)) {
- try {
- result = sNativeSynth.stop();
- } catch (NullPointerException e1) {
- // synth will become null during onDestroy()
- result = TextToSpeech.ERROR;
- }
- mKillList.put(mCurrentSpeechItem, true);
- if (mPlayer != null) {
- try {
- mPlayer.stop();
- } catch (IllegalStateException e) {
- // Do nothing, the player is already stopped.
- }
- }
- mIsSpeaking = false;
- mCurrentSpeechItem = null;
- } else {
- result = TextToSpeech.SUCCESS;
- }
- Log.i(SERVICE_TAG, "Stopped");
- } else {
- Log.e(SERVICE_TAG, "TTS stop(): queue locked longer than expected");
- result = TextToSpeech.ERROR;
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS stop: tryLock interrupted");
- e.printStackTrace();
- } finally {
- // This check is needed because finally will always run; even if the
- // method returns somewhere in the try block.
- if (speechQueueAvailable) {
- speechQueueLock.unlock();
- }
- return result;
- }
- }
-
-
- /**
- * Stops all speech output, both rendered to a file and directly spoken, and removes any
- * utterances still in the queue globally. Files that were being written are deleted.
- */
- @SuppressWarnings("finally")
- private int killAllUtterances() {
- int result = TextToSpeech.ERROR;
- boolean speechQueueAvailable = false;
-
- try {
- speechQueueAvailable = speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT,
- TimeUnit.MILLISECONDS);
- if (speechQueueAvailable) {
- // remove every single entry in the speech queue
- mSpeechQueue.clear();
-
- // clear the current speech item
- if (mCurrentSpeechItem != null) {
- result = sNativeSynth.stopSync();
- mKillList.put(mCurrentSpeechItem, true);
- mIsSpeaking = false;
-
- // was the engine writing to a file?
- if (mCurrentSpeechItem.mType == SpeechItem.TEXT_TO_FILE) {
- // delete the file that was being written
- if (mCurrentSpeechItem.mFilename != null) {
- File tempFile = new File(mCurrentSpeechItem.mFilename);
- Log.v(SERVICE_TAG, "Leaving behind " + mCurrentSpeechItem.mFilename);
- if (tempFile.exists()) {
- Log.v(SERVICE_TAG, "About to delete "
- + mCurrentSpeechItem.mFilename);
- if (tempFile.delete()) {
- Log.v(SERVICE_TAG, "file successfully deleted");
- }
- }
- }
- }
-
- mCurrentSpeechItem = null;
- }
- } else {
- Log.e(SERVICE_TAG, "TTS killAllUtterances(): queue locked longer than expected");
- result = TextToSpeech.ERROR;
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS killAllUtterances(): tryLock interrupted");
- result = TextToSpeech.ERROR;
- } finally {
- // This check is needed because finally will always run, even if the
- // method returns somewhere in the try block.
- if (speechQueueAvailable) {
- speechQueueLock.unlock();
- }
- return result;
- }
- }
-
-
- /**
- * Stops all speech output and removes any utterances still in the queue globally, except
- * those intended to be synthesized to file.
- */
- private int stopAll(String callingApp) {
- int result = TextToSpeech.ERROR;
- boolean speechQueueAvailable = false;
- try{
- speechQueueAvailable =
- speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
- if (speechQueueAvailable) {
- for (int i = mSpeechQueue.size() - 1; i > -1; i--){
- if (mSpeechQueue.get(i).mType != SpeechItem.TEXT_TO_FILE){
- mSpeechQueue.remove(i);
- }
- }
- if ((mCurrentSpeechItem != null) &&
- ((mCurrentSpeechItem.mType != SpeechItem.TEXT_TO_FILE) ||
- mCurrentSpeechItem.mCallingApp.equals(callingApp))) {
- try {
- result = sNativeSynth.stop();
- } catch (NullPointerException e1) {
- // synth will become null during onDestroy()
- result = TextToSpeech.ERROR;
- }
- mKillList.put(mCurrentSpeechItem, true);
- if (mPlayer != null) {
- try {
- mPlayer.stop();
- } catch (IllegalStateException e) {
- // Do nothing, the player is already stopped.
- }
- }
- mIsSpeaking = false;
- mCurrentSpeechItem = null;
- } else {
- result = TextToSpeech.SUCCESS;
- }
- Log.i(SERVICE_TAG, "Stopped all");
- } else {
- Log.e(SERVICE_TAG, "TTS stopAll(): queue locked longer than expected");
- result = TextToSpeech.ERROR;
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS stopAll: tryLock interrupted");
- e.printStackTrace();
- } finally {
- // This check is needed because finally will always run; even if the
- // method returns somewhere in the try block.
- if (speechQueueAvailable) {
- speechQueueLock.unlock();
- }
- return result;
- }
- }
-
- public void onCompletion(MediaPlayer arg0) {
- // mCurrentSpeechItem may become null if it is stopped at the same
- // time it completes.
- SpeechItem currentSpeechItemCopy = mCurrentSpeechItem;
- if (currentSpeechItemCopy != null) {
- String callingApp = currentSpeechItemCopy.mCallingApp;
- ArrayList<String> params = currentSpeechItemCopy.mParams;
- String utteranceId = "";
- if (params != null) {
- for (int i = 0; i < params.size() - 1; i = i + 2) {
- String param = params.get(i);
- if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)) {
- utteranceId = params.get(i + 1);
- }
- }
- }
- if (utteranceId.length() > 0) {
- dispatchUtteranceCompletedCallback(utteranceId, callingApp);
- }
- }
- processSpeechQueue();
- }
-
- private int playSilence(String callingApp, long duration, int queueMode,
- ArrayList<String> params) {
- if (queueMode == TextToSpeech.QUEUE_FLUSH) {
- stop(callingApp);
- }
- mSpeechQueue.add(new SpeechItem(callingApp, duration, params));
- if (!mIsSpeaking) {
- processSpeechQueue();
- }
- return TextToSpeech.SUCCESS;
- }
-
- private void silence(final SpeechItem speechItem) {
- class SilenceThread implements Runnable {
- public void run() {
- String utteranceId = "";
- if (speechItem.mParams != null){
- for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
- String param = speechItem.mParams.get(i);
- if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
- utteranceId = speechItem.mParams.get(i+1);
- }
- }
- }
- try {
- Thread.sleep(speechItem.mDuration);
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- if (utteranceId.length() > 0){
- dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
- }
- processSpeechQueue();
- }
- }
- }
- Thread slnc = (new Thread(new SilenceThread()));
- slnc.setPriority(Thread.MIN_PRIORITY);
- slnc.start();
- }
-
- private void speakInternalOnly(final SpeechItem speechItem) {
- class SynthThread implements Runnable {
- public void run() {
- boolean synthAvailable = false;
- String utteranceId = "";
- try {
- synthAvailable = synthesizerLock.tryLock();
- if (!synthAvailable) {
- mSynthBusy = true;
- Thread.sleep(100);
- Thread synth = (new Thread(new SynthThread()));
- synth.start();
- mSynthBusy = false;
- return;
- }
- int streamType = DEFAULT_STREAM_TYPE;
- String language = "";
- String country = "";
- String variant = "";
- String speechRate = "";
- String engine = "";
- String pitch = "";
- float volume = TextToSpeech.Engine.DEFAULT_VOLUME;
- float pan = TextToSpeech.Engine.DEFAULT_PAN;
- if (speechItem.mParams != null){
- for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
- String param = speechItem.mParams.get(i);
- if (param != null) {
- if (param.equals(TextToSpeech.Engine.KEY_PARAM_RATE)) {
- speechRate = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_LANGUAGE)){
- language = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_COUNTRY)){
- country = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VARIANT)){
- variant = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
- utteranceId = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_STREAM)) {
- try {
- streamType
- = Integer.parseInt(speechItem.mParams.get(i + 1));
- } catch (NumberFormatException e) {
- streamType = DEFAULT_STREAM_TYPE;
- }
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_ENGINE)) {
- engine = speechItem.mParams.get(i + 1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_PITCH)) {
- pitch = speechItem.mParams.get(i + 1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VOLUME)) {
- try {
- volume = Float.parseFloat(speechItem.mParams.get(i + 1));
- } catch (NumberFormatException e) {
- volume = TextToSpeech.Engine.DEFAULT_VOLUME;
- }
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_PAN)) {
- try {
- pan = Float.parseFloat(speechItem.mParams.get(i + 1));
- } catch (NumberFormatException e) {
- pan = TextToSpeech.Engine.DEFAULT_PAN;
- }
- }
- }
- }
- }
- // Only do the synthesis if it has not been killed by a subsequent utterance.
- if (mKillList.get(speechItem) == null) {
- if (engine.length() > 0) {
- setEngine(engine);
- } else {
- setEngine(getDefaultEngine());
- }
- if (language.length() > 0){
- setLanguage("", language, country, variant);
- } else {
- setLanguage("", getDefaultLanguage(), getDefaultCountry(),
- getDefaultLocVariant());
- }
- if (speechRate.length() > 0){
- setSpeechRate("", Integer.parseInt(speechRate));
- } else {
- setSpeechRate("", getDefaultRate());
- }
- if (pitch.length() > 0){
- setPitch("", Integer.parseInt(pitch));
- } else {
- setPitch("", getDefaultPitch());
- }
- try {
- sNativeSynth.speak(speechItem.mText, streamType, volume, pan);
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- Log.v(SERVICE_TAG, " null synth, can't speak");
- }
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS speakInternalOnly(): tryLock interrupted");
- e.printStackTrace();
- } finally {
- // This check is needed because finally will always run;
- // even if the
- // method returns somewhere in the try block.
- if (utteranceId.length() > 0){
- dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
- }
- if (synthAvailable) {
- synthesizerLock.unlock();
- processSpeechQueue();
- }
- }
- }
- }
- Thread synth = (new Thread(new SynthThread()));
- synth.setPriority(Thread.MAX_PRIORITY);
- synth.start();
- }
-
- private void synthToFileInternalOnly(final SpeechItem speechItem) {
- class SynthThread implements Runnable {
- public void run() {
- boolean synthAvailable = false;
- String utteranceId = "";
- Log.i(SERVICE_TAG, "Synthesizing to " + speechItem.mFilename);
- try {
- synthAvailable = synthesizerLock.tryLock();
- if (!synthAvailable) {
- synchronized (this) {
- mSynthBusy = true;
- }
- Thread.sleep(100);
- Thread synth = (new Thread(new SynthThread()));
- synth.start();
- synchronized (this) {
- mSynthBusy = false;
- }
- return;
- }
- String language = "";
- String country = "";
- String variant = "";
- String speechRate = "";
- String engine = "";
- String pitch = "";
- if (speechItem.mParams != null){
- for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
- String param = speechItem.mParams.get(i);
- if (param != null) {
- if (param.equals(TextToSpeech.Engine.KEY_PARAM_RATE)) {
- speechRate = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_LANGUAGE)){
- language = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_COUNTRY)){
- country = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VARIANT)){
- variant = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
- utteranceId = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_ENGINE)) {
- engine = speechItem.mParams.get(i + 1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_PITCH)) {
- pitch = speechItem.mParams.get(i + 1);
- }
- }
- }
- }
- // Only do the synthesis if it has not been killed by a subsequent utterance.
- if (mKillList.get(speechItem) == null){
- if (engine.length() > 0) {
- setEngine(engine);
- } else {
- setEngine(getDefaultEngine());
- }
- if (language.length() > 0){
- setLanguage("", language, country, variant);
- } else {
- setLanguage("", getDefaultLanguage(), getDefaultCountry(),
- getDefaultLocVariant());
- }
- if (speechRate.length() > 0){
- setSpeechRate("", Integer.parseInt(speechRate));
- } else {
- setSpeechRate("", getDefaultRate());
- }
- if (pitch.length() > 0){
- setPitch("", Integer.parseInt(pitch));
- } else {
- setPitch("", getDefaultPitch());
- }
- try {
- sNativeSynth.synthesizeToFile(speechItem.mText, speechItem.mFilename);
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- Log.v(SERVICE_TAG, " null synth, can't synthesize to file");
- }
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS synthToFileInternalOnly(): tryLock interrupted");
- e.printStackTrace();
- } finally {
- // This check is needed because finally will always run;
- // even if the
- // method returns somewhere in the try block.
- if (utteranceId.length() > 0){
- dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
- }
- if (synthAvailable) {
- synthesizerLock.unlock();
- processSpeechQueue();
- }
- }
- }
- }
- Thread synth = (new Thread(new SynthThread()));
- synth.setPriority(Thread.MAX_PRIORITY);
- synth.start();
- }
-
- private SoundResource getSoundResource(SpeechItem speechItem) {
- SoundResource sr = null;
- String text = speechItem.mText;
- if (speechItem.mType == SpeechItem.SILENCE) {
- // Do nothing if this is just silence
- } else if (speechItem.mType == SpeechItem.EARCON) {
- sr = mEarcons.get(text);
- } else {
- sr = mUtterances.get(text);
- }
- return sr;
- }
-
- private void broadcastTtsQueueProcessingCompleted(){
- Intent i = new Intent(TextToSpeech.ACTION_TTS_QUEUE_PROCESSING_COMPLETED);
- sendBroadcast(i);
- }
-
-
- private void dispatchUtteranceCompletedCallback(String utteranceId, String packageName) {
- ITtsCallback cb = mCallbacksMap.get(packageName);
- if (cb == null){
- return;
- }
- Log.v(SERVICE_TAG, "TTS callback: dispatch started");
- // Broadcast to all clients the new value.
- final int N = mCallbacks.beginBroadcast();
- try {
- cb.utteranceCompleted(utteranceId);
- } catch (RemoteException e) {
- // The RemoteCallbackList will take care of removing
- // the dead object for us.
- }
- mCallbacks.finishBroadcast();
- Log.v(SERVICE_TAG, "TTS callback: dispatch completed to " + N);
- }
-
- private SpeechItem splitCurrentTextIfNeeded(SpeechItem currentSpeechItem){
- if (currentSpeechItem.mText.length() < MAX_SPEECH_ITEM_CHAR_LENGTH){
- return currentSpeechItem;
- } else {
- String callingApp = currentSpeechItem.mCallingApp;
- ArrayList<SpeechItem> splitItems = new ArrayList<SpeechItem>();
- int start = 0;
- int end = start + MAX_SPEECH_ITEM_CHAR_LENGTH - 1;
- String splitText;
- SpeechItem splitItem;
- while (end < currentSpeechItem.mText.length()){
- splitText = currentSpeechItem.mText.substring(start, end);
- splitItem = new SpeechItem(callingApp, splitText, null, SpeechItem.TEXT);
- splitItems.add(splitItem);
- start = end;
- end = start + MAX_SPEECH_ITEM_CHAR_LENGTH - 1;
- }
- splitText = currentSpeechItem.mText.substring(start);
- splitItem = new SpeechItem(callingApp, splitText, null, SpeechItem.TEXT);
- splitItems.add(splitItem);
- mSpeechQueue.remove(0);
- for (int i = splitItems.size() - 1; i >= 0; i--){
- mSpeechQueue.add(0, splitItems.get(i));
- }
- return mSpeechQueue.get(0);
- }
- }
-
- private void processSpeechQueue() {
- boolean speechQueueAvailable = false;
- synchronized (this) {
- if (mSynthBusy){
- // There is already a synth thread waiting to run.
- return;
- }
- }
- try {
- speechQueueAvailable =
- speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
- if (!speechQueueAvailable) {
- Log.e(SERVICE_TAG, "processSpeechQueue - Speech queue is unavailable.");
- return;
- }
- if (mSpeechQueue.size() < 1) {
- mIsSpeaking = false;
- mKillList.clear();
- broadcastTtsQueueProcessingCompleted();
- return;
- }
-
- mCurrentSpeechItem = mSpeechQueue.get(0);
- mIsSpeaking = true;
- SoundResource sr = getSoundResource(mCurrentSpeechItem);
- // Synth speech as needed - synthesizer should call
- // processSpeechQueue to continue running the queue
- // Log.v(SERVICE_TAG, "TTS processing: " + mCurrentSpeechItem.mText);
- if (sr == null) {
- if (mCurrentSpeechItem.mType == SpeechItem.TEXT) {
- mCurrentSpeechItem = splitCurrentTextIfNeeded(mCurrentSpeechItem);
- speakInternalOnly(mCurrentSpeechItem);
- } else if (mCurrentSpeechItem.mType == SpeechItem.TEXT_TO_FILE) {
- synthToFileInternalOnly(mCurrentSpeechItem);
- } else {
- // This is either silence or an earcon that was missing
- silence(mCurrentSpeechItem);
- }
- } else {
- cleanUpPlayer();
- if (sr.mSourcePackageName == PKGNAME) {
- // Utterance is part of the TTS library
- mPlayer = MediaPlayer.create(this, sr.mResId);
- } else if (sr.mSourcePackageName != null) {
- // Utterance is part of the app calling the library
- Context ctx;
- try {
- ctx = this.createPackageContext(sr.mSourcePackageName, 0);
- } catch (NameNotFoundException e) {
- e.printStackTrace();
- mSpeechQueue.remove(0); // Remove it from the queue and
- // move on
- mIsSpeaking = false;
- return;
- }
- mPlayer = MediaPlayer.create(ctx, sr.mResId);
- } else {
- // Utterance is coming from a file
- mPlayer = MediaPlayer.create(this, Uri.parse(sr.mFilename));
- }
-
- // Check if Media Server is dead; if it is, clear the queue and
- // give up for now - hopefully, it will recover itself.
- if (mPlayer == null) {
- mSpeechQueue.clear();
- mIsSpeaking = false;
- return;
- }
- mPlayer.setOnCompletionListener(this);
- try {
- mPlayer.setAudioStreamType(getStreamTypeFromParams(mCurrentSpeechItem.mParams));
- mPlayer.start();
- } catch (IllegalStateException e) {
- mSpeechQueue.clear();
- mIsSpeaking = false;
- cleanUpPlayer();
- return;
- }
- }
- if (mSpeechQueue.size() > 0) {
- mSpeechQueue.remove(0);
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS processSpeechQueue: tryLock interrupted");
- e.printStackTrace();
- } finally {
- // This check is needed because finally will always run; even if the
- // method returns somewhere in the try block.
- if (speechQueueAvailable) {
- speechQueueLock.unlock();
- }
- }
- }
-
- private int getStreamTypeFromParams(ArrayList<String> paramList) {
- int streamType = DEFAULT_STREAM_TYPE;
- if (paramList == null) {
- return streamType;
- }
- for (int i = 0; i < paramList.size() - 1; i = i + 2) {
- String param = paramList.get(i);
- if ((param != null) && (param.equals(TextToSpeech.Engine.KEY_PARAM_STREAM))) {
- try {
- streamType = Integer.parseInt(paramList.get(i + 1));
- } catch (NumberFormatException e) {
- streamType = DEFAULT_STREAM_TYPE;
- }
- }
- }
- return streamType;
- }
-
- private void cleanUpPlayer() {
- if (mPlayer != null) {
- mPlayer.release();
- mPlayer = null;
- }
- }
-
- /**
- * Synthesizes the given text to a file using the specified parameters.
- *
- * @param text
- * The String of text that should be synthesized
- * @param params
- * An ArrayList of parameters. The first element of this array
- * controls the type of voice to use.
- * @param filename
- * The string that gives the full output filename; it should be
- * something like "/sdcard/myappsounds/mysound.wav".
- * @return A boolean that indicates if the synthesis can be started
- */
- private boolean synthesizeToFile(String callingApp, String text, ArrayList<String> params,
- String filename) {
- // Don't allow a filename that is too long
- if (filename.length() > MAX_FILENAME_LENGTH) {
- return false;
- }
- // Don't allow anything longer than the max text length; since this
- // is synthing to a file, don't even bother splitting it.
- if (text.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH){
- return false;
- }
- // Check that the output file can be created
- try {
- File tempFile = new File(filename);
- if (tempFile.exists()) {
- Log.v("TtsService", "File " + filename + " exists, deleting.");
- tempFile.delete();
- }
- if (!tempFile.createNewFile()) {
- Log.e("TtsService", "Unable to synthesize to file: can't create " + filename);
- return false;
- }
- tempFile.delete();
- } catch (IOException e) {
- Log.e("TtsService", "Can't create " + filename + " due to exception " + e);
- return false;
- }
- mSpeechQueue.add(new SpeechItem(callingApp, text, params, SpeechItem.TEXT_TO_FILE, filename));
- if (!mIsSpeaking) {
- processSpeechQueue();
- }
- return true;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- if (ACTION.equals(intent.getAction())) {
- for (String category : intent.getCategories()) {
- if (category.equals(CATEGORY)) {
- return mBinder;
- }
- }
- }
- return null;
- }
-
- private final android.speech.tts.ITts.Stub mBinder = new Stub() {
-
- public int registerCallback(String packageName, ITtsCallback cb) {
- if (cb != null) {
- mCallbacks.register(cb);
- mCallbacksMap.put(packageName, cb);
- return TextToSpeech.SUCCESS;
- }
- return TextToSpeech.ERROR;
- }
-
- public int unregisterCallback(String packageName, ITtsCallback cb) {
- if (cb != null) {
- mCallbacksMap.remove(packageName);
- mCallbacks.unregister(cb);
- return TextToSpeech.SUCCESS;
- }
- return TextToSpeech.ERROR;
- }
-
- /**
- * Speaks the given text using the specified queueing mode and
- * parameters.
- *
- * @param text
- * The text that should be spoken
- * @param queueMode
- * TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
- * TextToSpeech.TTS_QUEUE_ADD for queued
- * @param params
- * An ArrayList of parameters. The first element of this
- * array controls the type of voice to use.
- */
- public int speak(String callingApp, String text, int queueMode, String[] params) {
- ArrayList<String> speakingParams = new ArrayList<String>();
- if (params != null) {
- speakingParams = new ArrayList<String>(Arrays.asList(params));
- }
- return mSelf.speak(callingApp, text, queueMode, speakingParams);
- }
-
- /**
- * Plays the earcon using the specified queueing mode and parameters.
- *
- * @param earcon
- * The earcon that should be played
- * @param queueMode
- * TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
- * TextToSpeech.TTS_QUEUE_ADD for queued
- * @param params
- * An ArrayList of parameters.
- */
- public int playEarcon(String callingApp, String earcon, int queueMode, String[] params) {
- ArrayList<String> speakingParams = new ArrayList<String>();
- if (params != null) {
- speakingParams = new ArrayList<String>(Arrays.asList(params));
- }
- return mSelf.playEarcon(callingApp, earcon, queueMode, speakingParams);
- }
-
- /**
- * Plays the silence using the specified queueing mode and parameters.
- *
- * @param duration
- * The duration of the silence that should be played
- * @param queueMode
- * TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
- * TextToSpeech.TTS_QUEUE_ADD for queued
- * @param params
- * An ArrayList of parameters.
- */
- public int playSilence(String callingApp, long duration, int queueMode, String[] params) {
- ArrayList<String> speakingParams = new ArrayList<String>();
- if (params != null) {
- speakingParams = new ArrayList<String>(Arrays.asList(params));
- }
- return mSelf.playSilence(callingApp, duration, queueMode, speakingParams);
- }
-
- /**
- * Stops all speech output and removes any utterances still in the
- * queue.
- */
- public int stop(String callingApp) {
- return mSelf.stop(callingApp);
- }
-
- /**
- * Returns whether or not the TTS is speaking.
- *
- * @return Boolean to indicate whether or not the TTS is speaking
- */
- public boolean isSpeaking() {
- return (mSelf.mIsSpeaking && (mSpeechQueue.size() < 1));
- }
-
- /**
- * Adds a sound resource to the TTS.
- *
- * @param text
- * The text that should be associated with the sound resource
- * @param packageName
- * The name of the package which has the sound resource
- * @param resId
- * The resource ID of the sound within its package
- */
- public void addSpeech(String callingApp, String text, String packageName, int resId) {
- mSelf.addSpeech(callingApp, text, packageName, resId);
- }
-
- /**
- * Adds a sound resource to the TTS.
- *
- * @param text
- * The text that should be associated with the sound resource
- * @param filename
- * The filename of the sound resource. This must be a
- * complete path like: (/sdcard/mysounds/mysoundbite.mp3).
- */
- public void addSpeechFile(String callingApp, String text, String filename) {
- mSelf.addSpeech(callingApp, text, filename);
- }
-
- /**
- * Adds a sound resource to the TTS as an earcon.
- *
- * @param earcon
- * The text that should be associated with the sound resource
- * @param packageName
- * The name of the package which has the sound resource
- * @param resId
- * The resource ID of the sound within its package
- */
- public void addEarcon(String callingApp, String earcon, String packageName, int resId) {
- mSelf.addEarcon(callingApp, earcon, packageName, resId);
- }
-
- /**
- * Adds a sound resource to the TTS as an earcon.
- *
- * @param earcon
- * The text that should be associated with the sound resource
- * @param filename
- * The filename of the sound resource. This must be a
- * complete path like: (/sdcard/mysounds/mysoundbite.mp3).
- */
- public void addEarconFile(String callingApp, String earcon, String filename) {
- mSelf.addEarcon(callingApp, earcon, filename);
- }
-
- /**
- * Sets the speech rate for the TTS. Note that this will only have an
- * effect on synthesized speech; it will not affect pre-recorded speech.
- *
- * @param speechRate
- * The speech rate that should be used
- */
- public int setSpeechRate(String callingApp, int speechRate) {
- return mSelf.setSpeechRate(callingApp, speechRate);
- }
-
- /**
- * Sets the pitch for the TTS. Note that this will only have an
- * effect on synthesized speech; it will not affect pre-recorded speech.
- *
- * @param pitch
- * The pitch that should be used for the synthesized voice
- */
- public int setPitch(String callingApp, int pitch) {
- return mSelf.setPitch(callingApp, pitch);
- }
-
- /**
- * Returns the level of support for the specified language.
- *
- * @param lang the three letter ISO language code.
- * @param country the three letter ISO country code.
- * @param variant the variant code associated with the country and language pair.
- * @return one of TTS_LANG_NOT_SUPPORTED, TTS_LANG_MISSING_DATA, TTS_LANG_AVAILABLE,
- * TTS_LANG_COUNTRY_AVAILABLE, TTS_LANG_COUNTRY_VAR_AVAILABLE as defined in
- * android.speech.tts.TextToSpeech.
- */
- public int isLanguageAvailable(String lang, String country, String variant,
- String[] params) {
- for (int i = 0; i < params.length - 1; i = i + 2){
- String param = params[i];
- if (param != null) {
- if (param.equals(TextToSpeech.Engine.KEY_PARAM_ENGINE)) {
- mSelf.setEngine(params[i + 1]);
- break;
- }
- }
- }
- return mSelf.isLanguageAvailable(lang, country, variant);
- }
-
- /**
- * Returns the currently set language / country / variant strings representing the
- * language used by the TTS engine.
- * @return null is no language is set, or an array of 3 string containing respectively
- * the language, country and variant.
- */
- public String[] getLanguage() {
- return mSelf.getLanguage();
- }
-
- /**
- * Sets the speech rate for the TTS, which affects the synthesized voice.
- *
- * @param lang the three letter ISO language code.
- * @param country the three letter ISO country code.
- * @param variant the variant code associated with the country and language pair.
- */
- public int setLanguage(String callingApp, String lang, String country, String variant) {
- return mSelf.setLanguage(callingApp, lang, country, variant);
- }
-
- /**
- * Synthesizes the given text to a file using the specified
- * parameters.
- *
- * @param text
- * The String of text that should be synthesized
- * @param params
- * An ArrayList of parameters. The first element of this
- * array controls the type of voice to use.
- * @param filename
- * The string that gives the full output filename; it should
- * be something like "/sdcard/myappsounds/mysound.wav".
- * @return A boolean that indicates if the synthesis succeeded
- */
- public boolean synthesizeToFile(String callingApp, String text, String[] params,
- String filename) {
- ArrayList<String> speakingParams = new ArrayList<String>();
- if (params != null) {
- speakingParams = new ArrayList<String>(Arrays.asList(params));
- }
- return mSelf.synthesizeToFile(callingApp, text, speakingParams, filename);
- }
-
- /**
- * Sets the speech synthesis engine for the TTS by specifying its packagename
- *
- * @param packageName the packageName of the speech synthesis engine (ie, "com.svox.pico")
- *
- * @return SUCCESS or ERROR as defined in android.speech.tts.TextToSpeech.
- */
- public int setEngineByPackageName(String packageName) {
- return mSelf.setEngine(packageName);
- }
-
- /**
- * Returns the packagename of the default speech synthesis engine.
- *
- * @return Packagename of the TTS engine that the user has chosen as their default.
- */
- public String getDefaultEngine() {
- return mSelf.getDefaultEngine();
- }
-
- /**
- * Returns whether or not the user is forcing their defaults to override the
- * Text-To-Speech settings set by applications.
- *
- * @return Whether or not defaults are enforced.
- */
- public boolean areDefaultsEnforced() {
- return mSelf.isDefaultEnforced();
- }
-
- };
-
-}
diff --git a/packages/VpnDialogs/Android.mk b/packages/VpnDialogs/Android.mk
new file mode 100644
index 0000000..89f010a
--- /dev/null
+++ b/packages/VpnDialogs/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2011 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := VpnDialogs
+
+include $(BUILD_PACKAGE)
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
new file mode 100644
index 0000000..4e6784c
--- /dev/null
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.vpndialogs">
+
+ <application android:label="VpnDialogs">
+ <activity android:name=".ConfirmDialog"
+ android:theme="@style/transparent">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".ManageDialog"
+ android:theme="@style/transparent"
+ android:noHistory="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/packages/VpnDialogs/res/layout/confirm.xml b/packages/VpnDialogs/res/layout/confirm.xml
new file mode 100644
index 0000000..249b6e6
--- /dev/null
+++ b/packages/VpnDialogs/res/layout/confirm.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <ImageView android:id="@+id/icon"
+ android:layout_width="@android:dimen/app_icon_size"
+ android:layout_height="@android:dimen/app_icon_size"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_marginRight="1mm"/>
+
+ <TextView android:id="@+id/warning"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/icon"
+ android:padding="2mm"
+ android:text="@string/warning"
+ android:textSize="18sp"/>
+
+ <TextView android:id="@+id/prompt"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:layout_toRightOf="@id/icon"
+ android:layout_above="@id/warning"
+ android:gravity="center_vertical"
+ android:textSize="20sp"/>
+
+ <CheckBox android:id="@+id/check"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentRight="true"
+ android:layout_below="@id/warning"
+ android:text="@string/accept"
+
+
+ android:textSize="18sp"
+ android:checked="false"/>
+
+</RelativeLayout>
diff --git a/packages/VpnDialogs/res/layout/manage.xml b/packages/VpnDialogs/res/layout/manage.xml
new file mode 100644
index 0000000..330b8e3
--- /dev/null
+++ b/packages/VpnDialogs/res/layout/manage.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:stretchColumns="0,1">
+
+ <TableRow>
+ <TextView android:text="@string/session" style="@style/label"/>
+ <TextView android:id="@+id/session" style="@style/value"/>
+ </TableRow>
+
+ <TableRow>
+ <TextView android:text="@string/duration" style="@style/label"/>
+ <TextView android:id="@+id/duration" style="@style/value"/>
+ </TableRow>
+
+ <TableRow>
+ <TextView android:text="@string/data_transmitted" style="@style/label"/>
+ <TextView android:id="@+id/data_transmitted" style="@style/value"/>
+ </TableRow>
+
+ <TableRow>
+ <TextView android:text="@string/data_received" style="@style/label"/>
+ <TextView android:id="@+id/data_received" style="@style/value"/>
+ </TableRow>
+
+</TableLayout>
diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml
new file mode 100644
index 0000000..8186e26
--- /dev/null
+++ b/packages/VpnDialogs/res/values/strings.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <string name="prompt"><xliff:g id="app">%s</xliff:g>
+ attempts to create a VPN connection.
+ </string>
+
+ <string name="warning">By proceeding, you are giving the application
+ permission to intercept all network traffic.
+ <b>Do NOT accept unless you trust the application.</b> Otherwise,
+ you run the risk of having your data compromised by a malicious
+ software.
+ </string>
+
+ <string name="accept">I trust this application.</string>
+
+ <string name="configure">Configure</string>
+ <string name="disconnect">Disconnect</string>
+
+ <string name="session">Session:</string>
+ <string name="duration">Duration:</string>
+ <string name="data_transmitted">Data Transmitted:</string>
+ <string name="data_received">Data Received:</string>
+
+ <string name="blank_value">--</string>
+ <string name="data_value_format">
+ <xliff:g id="number">%1$s</xliff:g> bytes /
+ <xliff:g id="number">%2$s</xliff:g> packets
+ </string>
+</resources>
diff --git a/packages/VpnDialogs/res/values/styles.xml b/packages/VpnDialogs/res/values/styles.xml
new file mode 100644
index 0000000..6eae218
--- /dev/null
+++ b/packages/VpnDialogs/res/values/styles.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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>
+
+ <style name="transparent">
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowIsFloating">true</item>
+ </style>
+
+ <style name="label">
+ <item name="android:gravity">center_vertical|right</item>
+ <item name="android:paddingRight">5mm</item>
+ <item name="android:textSize">16sp</item>
+ </style>
+
+ <style name="value">
+ <item name="android:gravity">center_vertical|left</item>
+ <item name="android:textSize">18sp</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:text">@string/blank_value</item>
+ </style>
+</resources>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
new file mode 100644
index 0000000..c54e719
--- /dev/null
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2011 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.vpndialogs;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.net.IConnectivityManager;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class ConfirmDialog extends Activity implements CompoundButton.OnCheckedChangeListener,
+ DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+ private static final String TAG = "VpnConfirm";
+
+ private String mPackageName;
+
+ private IConnectivityManager mService;
+
+ private AlertDialog mDialog;
+ private Button mButton;
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ try {
+ mPackageName = getCallingPackage();
+
+ mService = IConnectivityManager.Stub.asInterface(
+ ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+
+ if (mPackageName.equals(mService.prepareVpn(null))) {
+ setResult(RESULT_OK);
+ finish();
+ return;
+ }
+
+ PackageManager pm = getPackageManager();
+ ApplicationInfo app = pm.getApplicationInfo(mPackageName, 0);
+
+ View view = View.inflate(this, R.layout.confirm, null);
+ ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(app.loadIcon(pm));
+ ((TextView) view.findViewById(R.id.prompt)).setText(
+ getString(R.string.prompt, app.loadLabel(pm)));
+ ((CompoundButton) view.findViewById(R.id.check)).setOnCheckedChangeListener(this);
+
+ mDialog = new AlertDialog.Builder(this)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setTitle(android.R.string.dialog_alert_title)
+ .setView(view)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .setCancelable(false)
+ .create();
+ mDialog.setOnDismissListener(this);
+ mDialog.show();
+
+ mButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ mButton.setEnabled(false);
+ } catch (Exception e) {
+ Log.e(TAG, "onResume", e);
+ finish();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (mDialog != null) {
+ mDialog.setOnDismissListener(null);
+ mDialog.dismiss();
+ }
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton button, boolean checked) {
+ mButton.setEnabled(checked);
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ try {
+ if (which == AlertDialog.BUTTON_POSITIVE &&
+ mPackageName.equals(mService.prepareVpn(mPackageName))) {
+ setResult(RESULT_OK);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "onClick", e);
+ }
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ finish();
+ }
+}
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
new file mode 100644
index 0000000..ba3f344
--- /dev/null
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2011 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.vpndialogs;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.net.IConnectivityManager;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.net.VpnConfig;
+
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+
+public class ManageDialog extends Activity implements Handler.Callback,
+ DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+ private static final String TAG = "VpnManage";
+
+ private VpnConfig mConfig;
+
+ private IConnectivityManager mService;
+
+ private AlertDialog mDialog;
+ private TextView mDuration;
+ private TextView mDataTransmitted;
+ private TextView mDataReceived;
+
+ private Handler mHandler;
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ try {
+ mConfig = getIntent().getParcelableExtra("config");
+
+ mService = IConnectivityManager.Stub.asInterface(
+ ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+
+ PackageManager pm = getPackageManager();
+ ApplicationInfo app = pm.getApplicationInfo(mConfig.packageName, 0);
+
+ View view = View.inflate(this, R.layout.manage, null);
+ if (mConfig.sessionName != null) {
+ ((TextView) view.findViewById(R.id.session)).setText(mConfig.sessionName);
+ }
+ mDuration = (TextView) view.findViewById(R.id.duration);
+ mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted);
+ mDataReceived = (TextView) view.findViewById(R.id.data_received);
+
+ mDialog = new AlertDialog.Builder(this)
+ .setIcon(app.loadIcon(pm))
+ .setTitle(app.loadLabel(pm))
+ .setView(view)
+ .setNeutralButton(R.string.disconnect, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .create();
+
+ if (mConfig.configureActivity != null) {
+ mDialog.setButton(DialogInterface.BUTTON_POSITIVE,
+ getText(R.string.configure), this);
+ }
+ mDialog.setOnDismissListener(this);
+ mDialog.show();
+
+ if (mHandler == null) {
+ mHandler = new Handler(this);
+ }
+ mHandler.sendEmptyMessage(0);
+ } catch (Exception e) {
+ Log.e(TAG, "onResume", e);
+ finish();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (mDialog != null) {
+ mDialog.setOnDismissListener(null);
+ mDialog.dismiss();
+ }
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ try {
+ if (which == AlertDialog.BUTTON_POSITIVE) {
+ Intent intent = new Intent();
+ intent.setClassName(mConfig.packageName, mConfig.configureActivity);
+ startActivity(intent);
+ } else if (which == AlertDialog.BUTTON_NEUTRAL) {
+ mService.prepareVpn("");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "onClick", e);
+ finish();
+ }
+ }
+
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ finish();
+ }
+
+ @Override
+ public boolean handleMessage(Message message) {
+ mHandler.removeMessages(0);
+
+ if (mDialog.isShowing()) {
+ if (mConfig.startTime != 0) {
+ long seconds = (SystemClock.elapsedRealtime() - mConfig.startTime) / 1000;
+ mDuration.setText(String.format("%02d:%02d:%02d",
+ seconds / 3600, seconds / 60 % 60, seconds % 60));
+ }
+
+ String[] numbers = getStatistics();
+ if (numbers != null) {
+ // [1] and [2] are received data in bytes and packets.
+ mDataReceived.setText(getString(R.string.data_value_format,
+ numbers[1], numbers[2]));
+
+ // [9] and [10] are transmitted data in bytes and packets.
+ mDataTransmitted.setText(getString(R.string.data_value_format,
+ numbers[9], numbers[10]));
+ }
+ mHandler.sendEmptyMessageDelayed(0, 1000);
+ }
+ return true;
+ }
+
+ private String[] getStatistics() {
+ DataInputStream in = null;
+ try {
+ // See dev_seq_printf_stats() in net/core/dev.c.
+ in = new DataInputStream(new FileInputStream("/proc/net/dev"));
+ String prefix = mConfig.interfaceName + ':';
+
+ while (true) {
+ String line = in.readLine().trim();
+ if (line.startsWith(prefix)) {
+ String[] numbers = line.substring(prefix.length()).split(" +");
+ if (numbers.length == 17) {
+ return numbers;
+ }
+ break;
+ }
+ }
+ } catch (Exception e) {
+ // ignore
+ } finally {
+ try {
+ in.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ return null;
+ }
+}
diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
index 9b0a36b..f436cb4 100644
--- a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
+++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
@@ -26,7 +26,6 @@ import android.os.RemoteException;
import android.provider.Telephony.Sms.Intents;
import android.test.ServiceTestCase;
import android.util.Log;
-import android.util.Config;
import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.IWapPushManager;
@@ -2051,7 +2050,7 @@ public class WapPushTest extends ServiceTestCase<WapPushManager> {
*/
public int dispatchWapPdu(byte[] pdu, IWapPushManager wapPushMan) {
- if (Config.DEBUG) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu));
+ if (false) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu));
int index = 0;
int transactionId = pdu[index++] & 0xFF;
@@ -2060,7 +2059,7 @@ public class WapPushTest extends ServiceTestCase<WapPushManager> {
if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH) &&
(pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
- if (Config.DEBUG) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
+ if (false) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
return Intents.RESULT_SMS_HANDLED;
}
@@ -2073,7 +2072,7 @@ public class WapPushTest extends ServiceTestCase<WapPushManager> {
* So it will be encoded in no more than 5 octets.
*/
if (pduDecoder.decodeUintvarInteger(index) == false) {
- if (Config.DEBUG) Log.w(LOG_TAG, "Received PDU. Header Length error.");
+ if (false) Log.w(LOG_TAG, "Received PDU. Header Length error.");
return Intents.RESULT_SMS_GENERIC_ERROR;
}
headerLength = (int) pduDecoder.getValue32();
@@ -2094,7 +2093,7 @@ public class WapPushTest extends ServiceTestCase<WapPushManager> {
* Length = Uintvar-integer
*/
if (pduDecoder.decodeContentType(index) == false) {
- if (Config.DEBUG) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
+ if (false) Log.w(LOG_TAG, "Received PDU. Header Content-Type error.");
return Intents.RESULT_SMS_GENERIC_ERROR;
}
@@ -2131,13 +2130,13 @@ public class WapPushTest extends ServiceTestCase<WapPushManager> {
String contentType = ((mimeType == null) ?
Long.toString(binaryContentType) : mimeType);
- if (Config.DEBUG) Log.v(LOG_TAG, "appid found: " + wapAppId + ":" + contentType);
+ if (false) Log.v(LOG_TAG, "appid found: " + wapAppId + ":" + contentType);
try {
boolean processFurther = true;
// IWapPushManager wapPushMan = mWapConn.getWapPushManager();
if (wapPushMan == null) {
- if (Config.DEBUG) Log.w(LOG_TAG, "wap push manager not found!");
+ if (false) Log.w(LOG_TAG, "wap push manager not found!");
} else {
Intent intent = new Intent();
intent.putExtra("transactionId", transactionId);
@@ -2148,7 +2147,7 @@ public class WapPushTest extends ServiceTestCase<WapPushManager> {
pduDecoder.getContentParameters());
int procRet = wapPushMan.processMessage(wapAppId, contentType, intent);
- if (Config.DEBUG) Log.v(LOG_TAG, "procRet:" + procRet);
+ if (false) Log.v(LOG_TAG, "procRet:" + procRet);
if ((procRet & WapPushManagerParams.MESSAGE_HANDLED) > 0
&& (procRet & WapPushManagerParams.FURTHER_PROCESSING) == 0) {
processFurther = false;
@@ -2158,10 +2157,10 @@ public class WapPushTest extends ServiceTestCase<WapPushManager> {
return Intents.RESULT_SMS_HANDLED;
}
} catch (RemoteException e) {
- if (Config.DEBUG) Log.w(LOG_TAG, "remote func failed...");
+ if (false) Log.w(LOG_TAG, "remote func failed...");
}
}
- if (Config.DEBUG) Log.v(LOG_TAG, "fall back to existing handler");
+ if (false) Log.v(LOG_TAG, "fall back to existing handler");
return Activity.RESULT_OK;
}