summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/RecoverySystem.java4
-rw-r--r--core/java/android/server/BluetoothEventLoop.java12
-rw-r--r--core/res/res/drawable-hdpi/overscroll_edge.pngbin4515 -> 4861 bytes
-rw-r--r--core/res/res/drawable-hdpi/overscroll_glow.pngbin44675 -> 54467 bytes
-rwxr-xr-x[-rw-r--r--]core/res/res/values/strings.xml103
-rwxr-xr-xpackages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.pngbin4089 -> 1822 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.pngbin1021 -> 210 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.pngbin1058 -> 313 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.pngbin4468 -> 1331 bytes
-rw-r--r--[-rwxr-xr-x]packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.pngbin4491 -> 1359 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.pngbin809 -> 199 bytes
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java19
-rw-r--r--packages/TtsService/Android.mk2
-rw-r--r--services/java/com/android/server/PowerManagerService.java2
-rw-r--r--telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java94
-rwxr-xr-xtelephony/java/com/android/internal/telephony/sip/SipPhone.java66
-rw-r--r--voip/java/android/net/rtp/AudioCodec.java3
-rw-r--r--voip/java/android/net/sip/SipManager.java4
-rw-r--r--voip/java/com/android/server/sip/SipService.java131
-rw-r--r--voip/java/com/android/server/sip/SipSessionGroup.java17
-rw-r--r--voip/jni/rtp/AmrCodec.cpp268
-rw-r--r--voip/jni/rtp/Android.mk12
-rw-r--r--voip/jni/rtp/AudioCodec.cpp4
-rw-r--r--voip/jni/rtp/AudioGroup.cpp51
24 files changed, 623 insertions, 169 deletions
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index e56e257..6d19f41 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -68,6 +68,7 @@ public class RecoverySystem {
private static File RECOVERY_DIR = new File("/cache/recovery");
private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
private static File LOG_FILE = new File(RECOVERY_DIR, "log");
+ private static String LAST_LOG_FILENAME = "last_log";
// Length limits for reading files.
private static int LOG_FILE_MAX_LENGTH = 64 * 1024;
@@ -399,9 +400,10 @@ public class RecoverySystem {
Log.e(TAG, "Error reading recovery log", e);
}
- // Delete everything in RECOVERY_DIR
+ // Delete everything in RECOVERY_DIR except LAST_LOG_FILENAME
String[] names = RECOVERY_DIR.list();
for (int i = 0; names != null && i < names.length; i++) {
+ if (names[i].equals(LAST_LOG_FILENAME)) continue;
File f = new File(RECOVERY_DIR, names[i]);
if (!f.delete()) {
Log.e(TAG, "Can't delete: " + f);
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index e05fe7b..bcb151a 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -225,10 +225,10 @@ class BluetoothEventLoop {
}
String name = propValues[0];
if (name.equals("Name")) {
+ mBluetoothService.setProperty(name, propValues[1]);
Intent intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, propValues[1]);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- mBluetoothService.setProperty(name, propValues[1]);
} else if (name.equals("Pairable") || name.equals("Discoverable")) {
String pairable = name.equals("Pairable") ? propValues[1] :
mBluetoothService.getPropertyInternal("Pairable");
@@ -239,6 +239,7 @@ class BluetoothEventLoop {
if (pairable == null || discoverable == null)
return;
+ mBluetoothService.setProperty(name, propValues[1]);
int mode = BluetoothService.bluezStringToScanMode(
pairable.equals("true"),
discoverable.equals("true"));
@@ -248,9 +249,9 @@ class BluetoothEventLoop {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
}
- mBluetoothService.setProperty(name, propValues[1]);
} else if (name.equals("Discovering")) {
Intent intent;
+ mBluetoothService.setProperty(name, propValues[1]);
if (propValues[1].equals("true")) {
mBluetoothService.setIsDiscovering(true);
intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
@@ -261,7 +262,6 @@ class BluetoothEventLoop {
intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
}
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- mBluetoothService.setProperty(name, propValues[1]);
} else if (name.equals("Devices")) {
String value = null;
int len = Integer.valueOf(propValues[1]);
@@ -294,19 +294,20 @@ class BluetoothEventLoop {
}
BluetoothDevice device = mAdapter.getRemoteDevice(address);
if (name.equals("Name")) {
+ mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothDevice.EXTRA_NAME, propValues[1]);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
} else if (name.equals("Class")) {
+ mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
Intent intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothDevice.EXTRA_CLASS,
new BluetoothClass(Integer.valueOf(propValues[1])));
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
} else if (name.equals("Connected")) {
+ mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
Intent intent = null;
if (propValues[1].equals("true")) {
intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED);
@@ -320,7 +321,6 @@ class BluetoothEventLoop {
}
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
} else if (name.equals("UUIDs")) {
String uuid = null;
int len = Integer.valueOf(propValues[1]);
diff --git a/core/res/res/drawable-hdpi/overscroll_edge.png b/core/res/res/drawable-hdpi/overscroll_edge.png
index f8e40ec..e8c1aa3 100644
--- a/core/res/res/drawable-hdpi/overscroll_edge.png
+++ b/core/res/res/drawable-hdpi/overscroll_edge.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/overscroll_glow.png b/core/res/res/drawable-hdpi/overscroll_glow.png
index a8a62c4..3418384 100644
--- a/core/res/res/drawable-hdpi/overscroll_glow.png
+++ b/core/res/res/drawable-hdpi/overscroll_glow.png
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7832f83..d9177e7 100644..100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -381,8 +381,10 @@
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_storage">Storage</string>
+ <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+ <string name="permgroupdesc_storage" product="nosdcard">Access the shared storage.</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permgroupdesc_storage">Access the SD card.</string>
+ <string name="permgroupdesc_storage" product="default">Access the SD card.</string>
<!-- Permissions -->
@@ -1224,10 +1226,14 @@
<string name="permdesc_writeDictionary">Allows an application to write new words into the
user dictionary.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+ <string name="permlab_sdcardWrite" product="nosdcard">modify/delete shared storage contents</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_sdcardWrite">modify/delete SD card contents</string>
+ <string name="permlab_sdcardWrite" product="default">modify/delete SD card contents</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
+ <string name="permdesc_sdcardWrite" product="nosdcard">Allows an application to write to the shared storage.</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_sdcardWrite">Allows an application to write to the SD card.</string>
+ <string name="permdesc_sdcardWrite" product="default">Allows an application to write to the SD card.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_cache_filesystem">access the cache filesystem</string>
@@ -1237,31 +1243,28 @@
<!-- Policy administration -->
<!-- Title of policy access to limiting the user's password choices -->
- <string name="policylab_limitPassword">Limit password</string>
+ <string name="policylab_limitPassword">Set password rules</string>
<!-- Description of policy access to limiting the user's password choices -->
- <string name="policydesc_limitPassword">Restrict the types of passwords you
- are allowed to use.</string>
+ <string name="policydesc_limitPassword">Control the length and the characters allowed in
+ screen-unlock passwords</string>
<!-- Title of policy access to watch user login attempts -->
- <string name="policylab_watchLogin">Watch login attempts</string>
+ <string name="policylab_watchLogin">Monitor screen-unlock attempts</string>
<!-- Description of policy access to watch user login attempts -->
- <string name="policydesc_watchLogin">Monitor failed attempts to login to
- the device, to perform some action.</string>
+ <string name="policydesc_watchLogin">Monitor the number of incorrect passwords entered when unlocking
+ the screen, and lock the phone or erase all the phone\'s data if too many incorrect passwords are entered
+ </string>
<!-- Title of policy access to reset user's password -->
- <string name="policylab_resetPassword">Reset password</string>
+ <string name="policylab_resetPassword">Change the screen-unlock password</string>
<!-- Description of policy access to reset user's password -->
- <string name="policydesc_resetPassword">Force your password
- to a new value, requiring the administrator give it to you
- before you can log in.</string>
+ <string name="policydesc_resetPassword">Change the screen-unlock password</string>
<!-- Title of policy access to force lock the device -->
- <string name="policylab_forceLock">Force lock</string>
+ <string name="policylab_forceLock">Lock the screen</string>
<!-- Description of policy access to limiting the user's password choices -->
- <string name="policydesc_forceLock">Control when device locks,
- requiring you re-enter its password.</string>
+ <string name="policydesc_forceLock">Control how and when the screen locks</string>
<!-- Title of policy access to wipe the user's data -->
<string name="policylab_wipeData">Erase all data</string>
<!-- Description of policy access to wipe the user's data -->
- <string name="policydesc_wipeData">Perform a factory reset, deleting
- all of your data without any confirmation.</string>
+ <string name="policydesc_wipeData">Erase the phone\'s data without warning, by performing a factory data reset</string>
<!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
<!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
@@ -2082,12 +2085,16 @@
<!-- See USB_STORAGE. USB_STORAGE_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to mount. This is the title. -->
<string name="usb_storage_title">USB connected</string>
+ <!-- See USB_STORAGE. This is the message. [CHAR LIMIT=NONE] -->
+ <string name="usb_storage_message" product="nosdcard">You have connected your phone to your computer via USB. Select the button below if you want to copy files between your computer and your Android\u2018s shared storage.</string>
<!-- See USB_STORAGE. This is the message. -->
- <string name="usb_storage_message">You have connected your phone to your computer via USB. Select the button below if you want to copy files between your computer and your Android\u2018s SD card.</string>
+ <string name="usb_storage_message" product="default">You have connected your phone to your computer via USB. Select the button below if you want to copy files between your computer and your Android\u2018s SD card.</string>
<!-- See USB_STORAGE. This is the button text to mount the phone on the computer. -->
<string name="usb_storage_button_mount">Turn on USB storage</string>
+ <!-- See USB_STORAGE_DIALOG. If there was an error mounting, this is the text. [CHAR LIMIT=NONE] -->
+ <string name="usb_storage_error_message" product="nosdcard">There is a problem using your shared storage for USB storage.</string>
<!-- See USB_STORAGE_DIALOG. If there was an error mounting, this is the text. -->
- <string name="usb_storage_error_message">There is a problem using your SD card for USB storage.</string>
+ <string name="usb_storage_error_message" product="default">There is a problem using your SD card for USB storage.</string>
<!-- USB_STORAGE: When the user connects the phone to a computer via USB, we show a notification asking if he wants to share files across. This is the title -->
<string name="usb_storage_notification_title">USB connected</string>
<!-- See USB_STORAGE. This is the message. -->
@@ -2102,8 +2109,10 @@
<!-- This is the label for the activity, and should never be visible to the user. -->
<!-- See USB_STORAGE_STOP. USB_STORAGE_STOP_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to stop usb storage. This is the title. -->
<string name="usb_storage_stop_title">USB storage in use</string>
+ <!-- See USB_STORAGE_STOP. This is the message. [CHAR LIMIT=NONE] -->
+ <string name="usb_storage_stop_message" product="nosdcard">Before turning off USB storage, make sure you have unmounted (\u201cejected\u201d) your Android\u2018s shared storage from your computer.</string>
<!-- See USB_STORAGE_STOP. This is the message. -->
- <string name="usb_storage_stop_message">Before turning off USB storage, make sure you have unmounted (\u201cejected\u201d) your Android\u2018s SD card from your computer.</string>
+ <string name="usb_storage_stop_message" product="default">Before turning off USB storage, make sure you have unmounted (\u201cejected\u201d) your Android\u2018s SD card from your computer.</string>
<!-- See USB_STORAGE_STOP. This is the button text to stop usb storage. -->
<string name="usb_storage_stop_button_mount">Turn off USB storage</string>
<!-- See USB_STORAGE_STOP_DIALOG. If there was an error stopping, this is the text. -->
@@ -2120,10 +2129,14 @@
<!-- External media format dialog strings -->
<!-- This is the label for the activity, and should never be visible to the user. -->
+ <!-- See EXTMEDIA_FORMAT. EXTMEDIA_FORMAT_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to format the SD card. This is the title. [CHAR LIMIT=20] -->
+ <string name="extmedia_format_title" product="nosdcard">Format shared storage</string>
<!-- See EXTMEDIA_FORMAT. EXTMEDIA_FORMAT_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to format the SD card. This is the title. -->
- <string name="extmedia_format_title">Format SD card</string>
+ <string name="extmedia_format_title" product="default">Format SD card</string>
+ <!-- See EXTMEDIA_FORMAT. This is the message. [CHAR LIMIT=NONE] -->
+ <string name="extmedia_format_message" product="nosdcard">Format shared storage, erasing all files stored there? Action cannot be reversed!</string>
<!-- See EXTMEDIA_FORMAT. This is the message. -->
- <string name="extmedia_format_message">Are you sure you want to format the SD card? All data on your card will be lost.</string>
+ <string name="extmedia_format_message" product="default">Are you sure you want to format the SD card? All data on your card will be lost.</string>
<!-- See EXTMEDIA_FORMAT. This is the button text to format the sd card. -->
<string name="extmedia_format_button_format">Format</string>
@@ -2148,29 +2161,51 @@
<string name="candidates_style"><u>candidates</u></string>
<!-- External media notification strings -->
+ <!-- Shown when external media is being checked [CHAR LIMIT=30] -->
+ <string name="ext_media_checking_notification_title" product="nosdcard">Preparing shared storage</string>
<!-- Shown when external media is being checked -->
- <string name="ext_media_checking_notification_title">Preparing SD card</string>
+ <string name="ext_media_checking_notification_title" product="default">Preparing SD card</string>
<string name="ext_media_checking_notification_message">Checking for errors.</string>
+ <!-- Shown when external media is blank (or unsupported filesystem) [CHAR LIMIT=30] -->
+ <string name="ext_media_nofs_notification_title" product="nosdcard">Blank shared storage</string>
<!-- Shown when external media is blank (or unsupported filesystem) -->
- <string name="ext_media_nofs_notification_title">Blank SD card</string>
- <string name="ext_media_nofs_notification_message">SD card blank or has unsupported filesystem.</string>
+ <string name="ext_media_nofs_notification_title" product="default">Blank SD card</string>
+ <!-- Shown when shared storage cannot be read. [CHAR LIMIT=NONE] -->
+ <string name="ext_media_nofs_notification_message" product="nosdcard">Shared storage blank or has unsupported filesystem.</string>
+ <string name="ext_media_nofs_notification_message" product="default">SD card blank or has unsupported filesystem.</string>
+ <!-- Shown when external media is unmountable (corrupt)) [CHAR LIMIT=30] -->
+ <string name="ext_media_unmountable_notification_title" product="nosdcard">Damaged shared storage</string>
<!-- Shown when external media is unmountable (corrupt)) -->
- <string name="ext_media_unmountable_notification_title">Damaged SD card</string>
- <string name="ext_media_unmountable_notification_message">SD card damaged. You may have to reformat it.</string>
+ <string name="ext_media_unmountable_notification_title" product="default">Damaged SD card</string>
+ <!-- Shown when shared storage cannot be read. [CHAR LIMIT=NONE] -->
+ <string name="ext_media_unmountable_notification_message" product="nosdcard">Shared storage damaged. You may have to reformat it.</string>
+ <string name="ext_media_unmountable_notification_message" product="default">SD card damaged. You may have to reformat it.</string>
+ <!-- Shown when external media is unsafely removed [CHAR LIMIT=30] -->
+ <string name="ext_media_badremoval_notification_title" product="nosdcard">Shared storage unexpectedly removed</string>
<!-- Shown when external media is unsafely removed -->
- <string name="ext_media_badremoval_notification_title">SD card unexpectedly removed</string>
- <string name="ext_media_badremoval_notification_message">Unmount SD card before removing to avoid data loss.</string>
+ <string name="ext_media_badremoval_notification_title" product="default">SD card unexpectedly removed</string>
+ <!-- Shown when external media is unsafely removed. [CHAR LIMIT=NONE] -->
+ <string name="ext_media_badremoval_notification_message" product="nosdcard">Unmount shared storage before removing to avoid data loss.</string>
+ <string name="ext_media_badremoval_notification_message" product="default">Unmount SD card before removing to avoid data loss.</string>
+ <!-- Shown when external media has been safely removed [CHAR LIMIT=30] -->
+ <string name="ext_media_safe_unmount_notification_title" product="nosdcard">Shared storage safe to remove</string>
<!-- Shown when external media has been safely removed -->
- <string name="ext_media_safe_unmount_notification_title">SD card safe to remove</string>
- <string name="ext_media_safe_unmount_notification_message">You can safely remove SD card.</string>
+ <string name="ext_media_safe_unmount_notification_title" product="default">SD card safe to remove</string>
+ <!-- Shown when external media has been safely removed. [CHAR LIMIT=NONE] -->
+ <string name="ext_media_safe_unmount_notification_message" product="nosdcard">You can safely remove shared storage.</string>
+ <string name="ext_media_safe_unmount_notification_message" product="default">You can safely remove SD card.</string>
+ <!-- Shown when external media is missing [CHAR LIMIT=30] -->
+ <string name="ext_media_nomedia_notification_title" product="nosdcard">Removed shared storage</string>
<!-- Shown when external media is missing -->
- <string name="ext_media_nomedia_notification_title">Removed SD card</string>
- <string name="ext_media_nomedia_notification_message">SD card removed. Insert a new one.</string>
+ <string name="ext_media_nomedia_notification_title" product="default">Removed SD card</string>
+ <!-- Shown when external media is missing. [CHAR LIMIT=NONE] -->
+ <string name="ext_media_nomedia_notification_message" product="nosdcard">Shared storage removed. Insert new media.</string>
+ <string name="ext_media_nomedia_notification_message" product="default">SD card removed. Insert a new one.</string>
<!-- Shown in LauncherActivity when the requested target Intent didn't return any matching Activities, leaving the list empty. -->
<string name="activity_list_empty">No matching activities found</string>
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.png
index c299e12..ae90cc8 100755
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
index 157491e..a0e59cf 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
index 3e317dd..2f66b1d 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
index aea18ed..1626895 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
index 1a25a2c..3c2e2b9 100755..100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_wifi_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
index 2134d49..bb41db0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
Binary files differ
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index 70d4d6a..d4491d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -20,6 +20,8 @@ import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.View;
import android.widget.ImageView;
import android.widget.RemoteViews.RemoteView;
@@ -43,7 +45,7 @@ public class AnimatedImageView extends ImageView {
}
if (drawable instanceof AnimationDrawable) {
mAnim = (AnimationDrawable)drawable;
- if (mAttached) {
+ if (isShown()) {
mAnim.start();
}
} else {
@@ -67,9 +69,6 @@ public class AnimatedImageView extends ImageView {
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
- if (mAnim != null) {
- mAnim.start();
- }
mAttached = true;
}
@@ -81,5 +80,17 @@ public class AnimatedImageView extends ImageView {
}
mAttached = false;
}
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int vis) {
+ super.onVisibilityChanged(changedView, vis);
+ if (mAnim != null) {
+ if (isShown()) {
+ mAnim.start();
+ } else {
+ mAnim.stop();
+ }
+ }
+ }
}
diff --git a/packages/TtsService/Android.mk b/packages/TtsService/Android.mk
index 75b26a2..a1a3b9f 100644
--- a/packages/TtsService/Android.mk
+++ b/packages/TtsService/Android.mk
@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) \
LOCAL_PACKAGE_NAME := TtsService
LOCAL_CERTIFICATE := platform
-LOCAL_PROGUARD_FLAGS := -include $(LOCAL_PATH)/proguard.flags
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
include $(BUILD_PACKAGE)
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 5d32b74..71105f1 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -2105,6 +2105,7 @@ class PowerManagerService extends IPowerManager.Stub
}
public void userActivity(long time, boolean noChangeLights) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
userActivity(time, -1, noChangeLights, OTHER_EVENT, false);
}
@@ -2128,7 +2129,6 @@ class PowerManagerService extends IPowerManager.Stub
private void userActivity(long time, long timeoutOverride, boolean noChangeLights,
int eventType, boolean force) {
- //mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)
&& (eventType == CHEEK_EVENT || eventType == TOUCH_EVENT)) {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 798a5a5..25ca559 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -24,9 +24,10 @@ import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.provider.ContactsContract.CommonDataKinds.SipAddress;
+import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.PhoneLookup;
import android.telephony.PhoneNumberUtils;
-import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -36,7 +37,7 @@ import android.util.Log;
public class CallerInfoAsyncQuery {
- private static final boolean DBG = false;
+ private static final boolean DBG = true; // STOPSHIP: disable debugging before ship
private static final String LOG_TAG = "CallerInfoAsyncQuery";
private static final int EVENT_NEW_QUERY = 1;
@@ -189,7 +190,7 @@ public class CallerInfoAsyncQuery {
*/
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- if (DBG) log("query complete for token: " + token);
+ if (DBG) log("##### onQueryComplete() ##### query complete for token: " + token);
//get the cookie and notify the listener.
CookieWrapper cw = (CookieWrapper) cookie;
@@ -227,6 +228,8 @@ public class CallerInfoAsyncQuery {
mCallerInfo = new CallerInfo().markAsVoiceMail();
} else {
mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor);
+ if (DBG) log("==> Got mCallerInfo: " + mCallerInfo);
+
// Use the number entered by the user for display.
if (!TextUtils.isEmpty(cw.number)) {
mCallerInfo.phoneNumber = PhoneNumberUtils.formatNumber(cw.number);
@@ -238,7 +241,7 @@ public class CallerInfoAsyncQuery {
//notify that we can clean up the queue after this.
CookieWrapper endMarker = new CookieWrapper();
endMarker.event = EVENT_END_OF_QUEUE;
- startQuery (token, endMarker, null, null, null, null, null);
+ startQuery(token, endMarker, null, null, null, null, null);
}
//notify the listener that the query is complete.
@@ -274,24 +277,82 @@ public class CallerInfoAsyncQuery {
cw.cookie = cookie;
cw.event = EVENT_NEW_QUERY;
- c.mHandler.startQuery (token, cw, contactRef, null, null, null, null);
+ c.mHandler.startQuery(token, cw, contactRef, null, null, null, null);
return c;
}
/**
- * Factory method to start query with a number
+ * Factory method to start the query based on a number.
+ *
+ * Note: if the number contains an "@" character we treat it
+ * as a SIP address, and look it up directly in the Data table
+ * rather than using the PhoneLookup table.
+ * TODO: But eventually we should expose two separate methods, one for
+ * numbers and one for SIP addresses, and then have
+ * PhoneUtils.startGetCallerInfo() decide which one to call based on
+ * the phone type of the incoming connection.
*/
public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
OnQueryCompleteListener listener, Object cookie) {
- //construct the URI object and start Query.
- Uri contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
+ if (DBG) {
+ log("##### CallerInfoAsyncQuery startQuery()... #####");
+ log("- number: " + number);
+ log("- cookie: " + cookie);
+ }
+
+ // Construct the URI object and query params, and start the query.
+
+ Uri contactRef;
+ String selection;
+ String[] selectionArgs;
+
+ if (PhoneNumberUtils.isUriNumber(number)) {
+ // "number" is really a SIP address.
+ if (DBG) log(" - Treating number as a SIP address: " + number);
+
+ // We look up SIP addresses directly in the Data table:
+ contactRef = Data.CONTENT_URI;
+
+ // Note Data.DATA1 and SipAddress.SIP_ADDRESS are equivalent.
+ //
+ // Also note we use "upper(data1)" in the WHERE clause, and
+ // uppercase the incoming SIP address, in order to do a
+ // case-insensitive match.
+ //
+ // TODO: need to confirm that the use of upper() doesn't
+ // prevent us from using the index! (Linear scan of the whole
+ // contacts DB can be very slow.)
+ //
+ // TODO: May also need to normalize by adding "sip:" as a
+ // prefix, if we start storing SIP addresses that way in the
+ // database.
+
+ selection = "upper(" + Data.DATA1 + ")=?"
+ + " AND "
+ + Data.MIMETYPE + "='" + SipAddress.CONTENT_ITEM_TYPE + "'";
+ selectionArgs = new String[] { number.toUpperCase() };
+
+ } else {
+ // "number" is a regular phone number. Use the PhoneLookup table:
+ contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
+ selection = null;
+ selectionArgs = null;
+ }
+
+ if (DBG) {
+ log("==> contactRef: " + contactRef);
+ log("==> selection: " + selection);
+ if (selectionArgs != null) {
+ for (int i = 0; i < selectionArgs.length; i++) {
+ log("==> selectionArgs[" + i + "]: " + selectionArgs[i]);
+ }
+ }
+ }
CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
c.allocate(context, contactRef);
- if (DBG) log("starting query for number: " + number + " handler: " + c.toString());
-
//create cookieWrapper, start query
CookieWrapper cw = new CookieWrapper();
cw.listener = listener;
@@ -307,10 +368,15 @@ public class CallerInfoAsyncQuery {
cw.event = EVENT_NEW_QUERY;
}
- c.mHandler.startQuery (token, cw, contactRef, null, null, null, null);
-
+ c.mHandler.startQuery(token,
+ cw, // cookie
+ contactRef, // uri
+ null, // projection
+ selection, // selection
+ selectionArgs, // selectionArgs
+ null); // orderBy
return c;
- }
+ }
/**
* Method to add listeners to a currently running query
@@ -326,7 +392,7 @@ public class CallerInfoAsyncQuery {
cw.cookie = cookie;
cw.event = EVENT_ADD_LISTENER;
- mHandler.startQuery (token, cw, null, null, null, null, null);
+ mHandler.startQuery(token, cw, null, null, null, null, null);
}
/**
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index bceceda..af3e0886 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -126,14 +126,27 @@ public class SipPhone extends SipPhoneBase {
return false;
}
- SipAudioCall sipAudioCall = (SipAudioCall) incomingCall;
- Log.v(LOG_TAG, " ++++++ taking call from: "
- + sipAudioCall.getPeerProfile().getUriString());
- String localUri = sipAudioCall.getLocalProfile().getUriString();
- if (localUri.equals(mProfile.getUriString())) {
- boolean makeCallWait = foregroundCall.getState().isAlive();
- ringingCall.initIncomingCall(sipAudioCall, makeCallWait);
- return true;
+ try {
+ SipAudioCall sipAudioCall = (SipAudioCall) incomingCall;
+ Log.d(LOG_TAG, "+++ taking call from: "
+ + sipAudioCall.getPeerProfile().getUriString());
+ String localUri = sipAudioCall.getLocalProfile().getUriString();
+ if (localUri.equals(mProfile.getUriString())) {
+ boolean makeCallWait = foregroundCall.getState().isAlive();
+ ringingCall.initIncomingCall(sipAudioCall, makeCallWait);
+ if (sipAudioCall.getState()
+ != SipSession.State.INCOMING_CALL) {
+ // Peer cancelled the call!
+ Log.d(LOG_TAG, " call cancelled !!");
+ ringingCall.reset();
+ }
+ return true;
+ }
+ } catch (Exception e) {
+ // Peer may cancel the call at any time during the time we hook
+ // up ringingCall with sipAudioCall. Clean up ringingCall when
+ // that happens.
+ ringingCall.reset();
}
return false;
}
@@ -358,6 +371,11 @@ public class SipPhone extends SipPhoneBase {
}
private class SipCall extends SipCallBase {
+ void reset() {
+ connections.clear();
+ setState(Call.State.IDLE);
+ }
+
void switchWith(SipCall that) {
synchronized (SipPhone.class) {
SipCall tmp = new SipCall();
@@ -444,6 +462,7 @@ public class SipPhone extends SipPhoneBase {
if (state.isAlive()) {
Log.d(LOG_TAG, "hang up call: " + getState() + ": " + this
+ " on phone " + getPhone());
+ setState(State.DISCONNECTING);
CallStateException excp = null;
for (Connection c : connections) {
try {
@@ -453,7 +472,6 @@ public class SipPhone extends SipPhoneBase {
}
}
if (excp != null) throw excp;
- setState(State.DISCONNECTING);
} else {
Log.d(LOG_TAG, "hang up dead call: " + getState() + ": "
+ this + " on phone " + getPhone());
@@ -630,13 +648,20 @@ public class SipPhone extends SipPhoneBase {
}
synchronized (SipPhone.class) {
setState(Call.State.DISCONNECTED);
- mSipAudioCall.close();
- mOwner.onConnectionEnded(SipConnection.this);
- Log.v(LOG_TAG, "-------- connection ended: "
- + mPeer.getUriString() + ": "
- + mSipAudioCall.getState() + ", cause: "
- + getDisconnectCause() + ", on phone "
+ SipAudioCall sipAudioCall = mSipAudioCall;
+ mSipAudioCall = null;
+ String sessionState = (sipAudioCall == null)
+ ? ""
+ : (sipAudioCall.getState() + ", ");
+ Log.v(LOG_TAG, "--- connection ended: "
+ + mPeer.getUriString() + ": " + sessionState
+ + "cause: " + getDisconnectCause() + ", on phone "
+ getPhone());
+ if (sipAudioCall != null) {
+ sipAudioCall.setListener(null);
+ sipAudioCall.close();
+ }
+ mOwner.onConnectionEnded(SipConnection.this);
}
}
@@ -790,14 +815,17 @@ public class SipPhone extends SipPhoneBase {
synchronized (SipPhone.class) {
Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": "
+ mState + ": on phone " + getPhone().getPhoneName());
+ if (!mState.isAlive()) return;
try {
- if (mState.isAlive()) {
- if (mSipAudioCall != null) mSipAudioCall.endCall();
- setState(Call.State.DISCONNECTING);
- setDisconnectCause(DisconnectCause.LOCAL);
+ SipAudioCall sipAudioCall = mSipAudioCall;
+ if (sipAudioCall != null) {
+ sipAudioCall.setListener(null);
+ sipAudioCall.endCall();
}
} catch (SipException e) {
throw new CallStateException("hangup(): " + e);
+ } finally {
+ mAdapter.onCallEnded(DisconnectCause.LOCAL);
}
}
}
diff --git a/voip/java/android/net/rtp/AudioCodec.java b/voip/java/android/net/rtp/AudioCodec.java
index dfa6841..3877aeb 100644
--- a/voip/java/android/net/rtp/AudioCodec.java
+++ b/voip/java/android/net/rtp/AudioCodec.java
@@ -80,8 +80,7 @@ public class AudioCodec {
*/
public static final AudioCodec AMR = new AudioCodec(97, "AMR/8000", null);
- // TODO: add rest of the codecs when the native part is done.
- private static final AudioCodec[] sCodecs = {GSM, PCMU, PCMA};
+ private static final AudioCodec[] sCodecs = {GSM_EFR, AMR, GSM, PCMU, PCMA};
private AudioCodec(int type, String rtpmap, String fmtp) {
this.type = type;
diff --git a/voip/java/android/net/sip/SipManager.java b/voip/java/android/net/sip/SipManager.java
index 59631c1..52f5716 100644
--- a/voip/java/android/net/sip/SipManager.java
+++ b/voip/java/android/net/sip/SipManager.java
@@ -520,7 +520,9 @@ public class SipManager {
private String getUri(ISipSession session) {
try {
- return session.getLocalProfile().getUriString();
+ return ((session == null)
+ ? "no session"
+ : session.getLocalProfile().getUriString());
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index 0ff5586..130fe9f 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -510,31 +510,43 @@ public final class SipService extends ISipService.Stub {
}
}
+ // KeepAliveProcess is controlled by AutoRegistrationProcess.
+ // All methods will be invoked in sync with SipService.this except realRun()
private class KeepAliveProcess implements Runnable {
private static final String TAG = "\\KEEPALIVE/";
private static final int INTERVAL = 10;
private SipSessionGroup.SipSessionImpl mSession;
+ private boolean mRunning = false;
public KeepAliveProcess(SipSessionGroup.SipSessionImpl session) {
mSession = session;
}
public void start() {
+ if (mRunning) return;
+ mRunning = true;
mTimer.set(INTERVAL * 1000, this);
}
+ // timeout handler
public void run() {
+ if (!mRunning) return;
+ final SipSessionGroup.SipSessionImpl session = mSession;
+
// delegate to mExecutor
getExecutor().addTask(new Runnable() {
public void run() {
- realRun();
+ realRun(session);
}
});
}
- private void realRun() {
+ // real timeout handler
+ private void realRun(SipSessionGroup.SipSessionImpl session) {
synchronized (SipService.this) {
- SipSessionGroup.SipSessionImpl session = mSession.duplicate();
+ if (notCurrentSession(session)) return;
+
+ session = session.duplicate();
if (DEBUG) Log.d(TAG, "~~~ keepalive");
mTimer.cancel(this);
session.sendKeepAlive();
@@ -547,8 +559,14 @@ public final class SipService extends ISipService.Stub {
}
public void stop() {
+ mRunning = false;
+ mSession = null;
mTimer.cancel(this);
}
+
+ private boolean notCurrentSession(ISipSession session) {
+ return (session != mSession) || !mRunning;
+ }
}
private class AutoRegistrationProcess extends SipSessionAdapter
@@ -561,13 +579,15 @@ public final class SipService extends ISipService.Stub {
private long mExpiryTime;
private int mErrorCode;
private String mErrorMessage;
+ private boolean mRunning = false;
private String getAction() {
return toString();
}
public void start(SipSessionGroup group) {
- if (mSession == null) {
+ if (!mRunning) {
+ mRunning = true;
mBackoff = 1;
mSession = (SipSessionGroup.SipSessionImpl)
group.createSession(this);
@@ -584,35 +604,24 @@ public final class SipService extends ISipService.Stub {
}
public void stop() {
- stop(false);
- }
-
- private void stopButKeepStates() {
- stop(true);
- }
-
- private void stop(boolean keepStates) {
- if (mSession == null) return;
+ if (!mRunning) return;
+ mRunning = false;
+ mSession.setListener(null);
if (mConnected && mRegistered) mSession.unregister();
+
mTimer.cancel(this);
if (mKeepAliveProcess != null) {
mKeepAliveProcess.stop();
mKeepAliveProcess = null;
}
- if (!keepStates) {
- mSession = null;
- mRegistered = false;
- }
- }
- private boolean isStopped() {
- return (mSession == null);
+ mRegistered = false;
+ setListener(mProxy.getListener());
}
public void setListener(ISipSessionListener listener) {
synchronized (SipService.this) {
mProxy.setListener(listener);
- if (mSession == null) return;
try {
int state = (mSession == null)
@@ -632,6 +641,18 @@ public final class SipService extends ISipService.Stub {
mProxy.onRegistrationFailed(mSession, mErrorCode,
mErrorMessage);
}
+ } else if (!mConnected) {
+ mProxy.onRegistrationFailed(mSession,
+ SipErrorCode.DATA_CONNECTION_LOST,
+ "no data connection");
+ } else if (!mRunning) {
+ mProxy.onRegistrationFailed(mSession,
+ SipErrorCode.CLIENT_ERROR,
+ "registration not running");
+ } else {
+ mProxy.onRegistrationFailed(mSession,
+ SipErrorCode.IN_PROGRESS,
+ String.valueOf(state));
}
} catch (Throwable t) {
Log.w(TAG, "setListener(): " + t);
@@ -643,21 +664,29 @@ public final class SipService extends ISipService.Stub {
return mRegistered;
}
+ // timeout handler
public void run() {
- // delegate to mExecutor
- getExecutor().addTask(new Runnable() {
- public void run() {
- realRun();
- }
- });
+ synchronized (SipService.this) {
+ if (!mRunning) return;
+ final SipSessionGroup.SipSessionImpl session = mSession;
+
+ // delegate to mExecutor
+ getExecutor().addTask(new Runnable() {
+ public void run() {
+ realRun(session);
+ }
+ });
+ }
}
- private void realRun() {
- mErrorCode = SipErrorCode.NO_ERROR;
- mErrorMessage = null;
- if (DEBUG) Log.d(TAG, "~~~ registering");
+ // real timeout handler
+ private void realRun(SipSessionGroup.SipSessionImpl session) {
synchronized (SipService.this) {
- if (mConnected && !isStopped()) mSession.register(EXPIRY_TIME);
+ if (notCurrentSession(session)) return;
+ mErrorCode = SipErrorCode.NO_ERROR;
+ mErrorMessage = null;
+ if (DEBUG) Log.d(TAG, "~~~ registering");
+ if (mConnected) session.register(EXPIRY_TIME);
}
}
@@ -697,22 +726,29 @@ public final class SipService extends ISipService.Stub {
public void onRegistering(ISipSession session) {
if (DEBUG) Log.d(TAG, "onRegistering(): " + session);
synchronized (SipService.this) {
- if (!isStopped() && (session != mSession)) return;
+ if (notCurrentSession(session)) return;
+
mRegistered = false;
mProxy.onRegistering(session);
}
}
+ private boolean notCurrentSession(ISipSession session) {
+ if (session != mSession) {
+ ((SipSessionGroup.SipSessionImpl) session).setListener(null);
+ return true;
+ }
+ return !mRunning;
+ }
+
@Override
public void onRegistrationDone(ISipSession session, int duration) {
if (DEBUG) Log.d(TAG, "onRegistrationDone(): " + session);
synchronized (SipService.this) {
- if (!isStopped() && (session != mSession)) return;
+ if (notCurrentSession(session)) return;
mProxy.onRegistrationDone(session, duration);
- if (isStopped()) return;
-
if (duration > 0) {
mSession.clearReRegisterRequired();
mExpiryTime = SystemClock.elapsedRealtime()
@@ -751,17 +787,18 @@ public final class SipService extends ISipService.Stub {
if (DEBUG) Log.d(TAG, "onRegistrationFailed(): " + session + ": "
+ SipErrorCode.toString(errorCode) + ": " + message);
synchronized (SipService.this) {
- if (!isStopped() && (session != mSession)) return;
- mErrorCode = errorCode;
- mErrorMessage = message;
- mProxy.onRegistrationFailed(session, errorCode, message);
+ if (notCurrentSession(session)) return;
if (errorCode == SipErrorCode.INVALID_CREDENTIALS) {
if (DEBUG) Log.d(TAG, " pause auto-registration");
- stopButKeepStates();
- } else if (!isStopped()) {
+ stop();
+ } else {
onError();
}
+
+ mErrorCode = errorCode;
+ mErrorMessage = message;
+ mProxy.onRegistrationFailed(session, errorCode, message);
}
}
@@ -769,14 +806,11 @@ public final class SipService extends ISipService.Stub {
public void onRegistrationTimeout(ISipSession session) {
if (DEBUG) Log.d(TAG, "onRegistrationTimeout(): " + session);
synchronized (SipService.this) {
- if (!isStopped() && (session != mSession)) return;
+ if (notCurrentSession(session)) return;
+
mErrorCode = SipErrorCode.TIME_OUT;
mProxy.onRegistrationTimeout(session);
-
- if (!isStopped()) {
- mRegistered = false;
- onError();
- }
+ onError();
}
}
@@ -883,6 +917,7 @@ public final class SipService extends ISipService.Stub {
mConnected = connected;
}
+ // timeout handler
@Override
public void run() {
// delegate to mExecutor
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 4321d7b..c68fa1b 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -334,12 +334,12 @@ class SipSessionGroup implements SipListener {
if (isRequestEvent(Request.INVITE, evt)) {
RequestEvent event = (RequestEvent) evt;
SipSessionImpl newSession = new SipSessionImpl(mProxy);
+ newSession.mState = SipSession.State.INCOMING_CALL;
newSession.mServerTransaction = mSipHelper.sendRinging(event,
generateTag());
newSession.mDialog = newSession.mServerTransaction.getDialog();
newSession.mInviteReceived = event;
newSession.mPeerProfile = createPeerProfile(event.getRequest());
- newSession.mState = SipSession.State.INCOMING_CALL;
newSession.mPeerSessionDescription =
extractContent(event.getRequest());
addSipSession(newSession);
@@ -708,7 +708,6 @@ class SipSessionGroup implements SipListener {
case SipSession.State.PINGING:
reset();
mReRegisterFlag = true;
- mState = SipSession.State.READY_TO_CALL;
break;
default:
@@ -877,6 +876,7 @@ class SipSessionGroup implements SipListener {
private boolean readyForCall(EventObject evt) throws SipException {
// expect MakeCallCommand, RegisterCommand, DEREGISTER
if (evt instanceof MakeCallCommand) {
+ mState = SipSession.State.OUTGOING_CALL;
MakeCallCommand cmd = (MakeCallCommand) evt;
mPeerProfile = cmd.getPeerProfile();
mClientTransaction = mSipHelper.sendInvite(mLocalProfile,
@@ -884,25 +884,24 @@ class SipSessionGroup implements SipListener {
generateTag());
mDialog = mClientTransaction.getDialog();
addSipSession(this);
- mState = SipSession.State.OUTGOING_CALL;
mProxy.onCalling(this);
startSessionTimer(cmd.getTimeout());
return true;
} else if (evt instanceof RegisterCommand) {
+ mState = SipSession.State.REGISTERING;
int duration = ((RegisterCommand) evt).getDuration();
mClientTransaction = mSipHelper.sendRegister(mLocalProfile,
generateTag(), duration);
mDialog = mClientTransaction.getDialog();
addSipSession(this);
- mState = SipSession.State.REGISTERING;
mProxy.onRegistering(this);
return true;
} else if (DEREGISTER == evt) {
+ mState = SipSession.State.DEREGISTERING;
mClientTransaction = mSipHelper.sendRegister(mLocalProfile,
generateTag(), 0);
mDialog = mClientTransaction.getDialog();
addSipSession(this);
- mState = SipSession.State.DEREGISTERING;
mProxy.onRegistering(this);
return true;
}
@@ -913,11 +912,11 @@ class SipSessionGroup implements SipListener {
// expect MakeCallCommand(answering) , END_CALL cmd , Cancel
if (evt instanceof MakeCallCommand) {
// answer call
+ mState = SipSession.State.INCOMING_CALL_ANSWERING;
mServerTransaction = mSipHelper.sendInviteOk(mInviteReceived,
mLocalProfile,
((MakeCallCommand) evt).getSessionDescription(),
mServerTransaction);
- mState = SipSession.State.INCOMING_CALL_ANSWERING;
startSessionTimer(((MakeCallCommand) evt).getTimeout());
return true;
} else if (END_CALL == evt) {
@@ -1009,8 +1008,8 @@ class SipSessionGroup implements SipListener {
// RFC says that UA should not send out cancel when no
// response comes back yet. We are cheating for not checking
// response.
- mSipHelper.sendCancel(mClientTransaction);
mState = SipSession.State.OUTGOING_CALL_CANCELING;
+ mSipHelper.sendCancel(mClientTransaction);
startSessionTimer(CANCEL_CALL_TIMER);
return true;
}
@@ -1065,8 +1064,8 @@ class SipSessionGroup implements SipListener {
return true;
} else if (isRequestEvent(Request.INVITE, evt)) {
// got Re-INVITE
- RequestEvent event = mInviteReceived = (RequestEvent) evt;
mState = SipSession.State.INCOMING_CALL;
+ RequestEvent event = mInviteReceived = (RequestEvent) evt;
mPeerSessionDescription = extractContent(event.getRequest());
mServerTransaction = null;
mProxy.onRinging(this, mPeerProfile, mPeerSessionDescription);
@@ -1077,9 +1076,9 @@ class SipSessionGroup implements SipListener {
return true;
} else if (evt instanceof MakeCallCommand) {
// to change call
+ mState = SipSession.State.OUTGOING_CALL;
mClientTransaction = mSipHelper.sendReinvite(mDialog,
((MakeCallCommand) evt).getSessionDescription());
- mState = SipSession.State.OUTGOING_CALL;
startSessionTimer(((MakeCallCommand) evt).getTimeout());
return true;
}
diff --git a/voip/jni/rtp/AmrCodec.cpp b/voip/jni/rtp/AmrCodec.cpp
new file mode 100644
index 0000000..f3ecac2
--- /dev/null
+++ b/voip/jni/rtp/AmrCodec.cpp
@@ -0,0 +1,268 @@
+/*
+ * Copyrightm (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.
+ */
+
+#include <string.h>
+
+#include "AudioCodec.h"
+
+#include "gsmamr_dec.h"
+#include "gsmamr_enc.h"
+
+namespace {
+
+const int gFrameBits[8] = {95, 103, 118, 134, 148, 159, 204, 244};
+
+//------------------------------------------------------------------------------
+
+// See RFC 4867 for the encoding details.
+
+class AmrCodec : public AudioCodec
+{
+public:
+ AmrCodec() {
+ if (AMREncodeInit(&mEncoder, &mSidSync, false)) {
+ mEncoder = NULL;
+ }
+ if (GSMInitDecode(&mDecoder, (Word8 *)"RTP")) {
+ mDecoder = NULL;
+ }
+ }
+
+ ~AmrCodec() {
+ if (mEncoder) {
+ AMREncodeExit(&mEncoder, &mSidSync);
+ }
+ if (mDecoder) {
+ GSMDecodeFrameExit(&mDecoder);
+ }
+ }
+
+ int set(int sampleRate, const char *fmtp);
+ int encode(void *payload, int16_t *samples);
+ int decode(int16_t *samples, void *payload, int length);
+
+private:
+ void *mEncoder;
+ void *mSidSync;
+ void *mDecoder;
+
+ int mMode;
+ int mModeSet;
+ bool mOctetAligned;
+};
+
+int AmrCodec::set(int sampleRate, const char *fmtp)
+{
+ // These parameters are not supported.
+ if (strcasestr(fmtp, "crc=1") || strcasestr(fmtp, "robust-sorting=1") ||
+ strcasestr(fmtp, "interleaving=")) {
+ return -1;
+ }
+
+ // Handle mode-set and octet-align.
+ char *modes = strcasestr(fmtp, "mode-set=");
+ if (modes) {
+ mMode = 0;
+ mModeSet = 0;
+ for (char c = *modes; c && c != ' '; c = *++modes) {
+ if (c >= '0' && c <= '7') {
+ int mode = c - '0';
+ if (mode > mMode) {
+ mMode = mode;
+ }
+ mModeSet |= 1 << mode;
+ }
+ }
+ } else {
+ mMode = 7;
+ mModeSet = 0xFF;
+ }
+ mOctetAligned = (strcasestr(fmtp, "octet-align=1") != NULL);
+
+ // TODO: handle mode-change-*.
+
+ return (sampleRate == 8000 && mEncoder && mDecoder) ? 160 : -1;
+}
+
+int AmrCodec::encode(void *payload, int16_t *samples)
+{
+ unsigned char *bytes = (unsigned char *)payload;
+ Frame_Type_3GPP type;
+
+ int length = AMREncode(mEncoder, mSidSync, (Mode)mMode,
+ samples, bytes + 1, &type, AMR_TX_WMF);
+
+ if (type != mMode || length != (8 + gFrameBits[mMode] + 7) >> 3) {
+ return -1;
+ }
+
+ if (mOctetAligned) {
+ bytes[0] = 0xF0;
+ bytes[1] = (mMode << 3) | 0x04;
+ ++length;
+ } else {
+ // CMR = 15 (4-bit), F = 0 (1-bit), FT = mMode (4-bit), Q = 1 (1-bit).
+ bytes[0] = 0xFF;
+ bytes[1] = 0xC0 | (mMode << 1) | 1;
+
+ // Shift left 6 bits and update the length.
+ bytes[length + 1] = 0;
+ for (int i = 0; i <= length; ++i) {
+ bytes[i] = (bytes[i] << 6) | (bytes[i + 1] >> 2);
+ }
+ length = (10 + gFrameBits[mMode] + 7) >> 3;
+ }
+ return length;
+}
+
+int AmrCodec::decode(int16_t *samples, void *payload, int length)
+{
+ unsigned char *bytes = (unsigned char *)payload;
+ Frame_Type_3GPP type;
+ if (length < 2) {
+ return -1;
+ }
+ int request = bytes[0] >> 4;
+
+ if (mOctetAligned) {
+ if ((bytes[1] & 0xC4) != 0x04) {
+ return -1;
+ }
+ type = (Frame_Type_3GPP)(bytes[1] >> 3);
+ if (length != (16 + gFrameBits[type] + 7) >> 3) {
+ return -1;
+ }
+ length -= 2;
+ bytes += 2;
+ } else {
+ if ((bytes[0] & 0x0C) || !(bytes[1] & 0x40)) {
+ return -1;
+ }
+ type = (Frame_Type_3GPP)((bytes[0] << 1 | bytes[1] >> 7) & 0x07);
+ if (length != (10 + gFrameBits[type] + 7) >> 3) {
+ return -1;
+ }
+
+ // Shift left 2 bits and update the length.
+ --length;
+ for (int i = 1; i < length; ++i) {
+ bytes[i] = (bytes[i] << 2) | (bytes[i + 1] >> 6);
+ }
+ bytes[length] <<= 2;
+ length = (gFrameBits[type] + 7) >> 3;
+ ++bytes;
+ }
+
+ if (AMRDecode(mDecoder, type, bytes, samples, MIME_IETF) != length) {
+ return -1;
+ }
+
+ // Handle CMR
+ if (request < 8 && request != mMode) {
+ for (int i = request; i >= 0; --i) {
+ if (mModeSet & (1 << i)) {
+ mMode = request;
+ break;
+ }
+ }
+ }
+
+ return 160;
+}
+
+//------------------------------------------------------------------------------
+
+// See RFC 3551 for the encoding details.
+
+class GsmEfrCodec : public AudioCodec
+{
+public:
+ GsmEfrCodec() {
+ if (AMREncodeInit(&mEncoder, &mSidSync, false)) {
+ mEncoder = NULL;
+ }
+ if (GSMInitDecode(&mDecoder, (Word8 *)"RTP")) {
+ mDecoder = NULL;
+ }
+ }
+
+ ~GsmEfrCodec() {
+ if (mEncoder) {
+ AMREncodeExit(&mEncoder, &mSidSync);
+ }
+ if (mDecoder) {
+ GSMDecodeFrameExit(&mDecoder);
+ }
+ }
+
+ int set(int sampleRate, const char *fmtp) {
+ return (sampleRate == 8000 && mEncoder && mDecoder) ? 160 : -1;
+ }
+
+ int encode(void *payload, int16_t *samples);
+ int decode(int16_t *samples, void *payload, int length);
+
+private:
+ void *mEncoder;
+ void *mSidSync;
+ void *mDecoder;
+};
+
+int GsmEfrCodec::encode(void *payload, int16_t *samples)
+{
+ unsigned char *bytes = (unsigned char *)payload;
+ Frame_Type_3GPP type;
+
+ int length = AMREncode(mEncoder, mSidSync, MR122,
+ samples, bytes, &type, AMR_TX_WMF);
+
+ if (type == AMR_122 && length == 32) {
+ bytes[0] = 0xC0 | (bytes[1] >> 4);
+ for (int i = 1; i < 31; ++i) {
+ bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
+ }
+ return 31;
+ }
+ return -1;
+}
+
+int GsmEfrCodec::decode(int16_t *samples, void *payload, int length)
+{
+ unsigned char *bytes = (unsigned char *)payload;
+ if (length == 31 && (bytes[0] >> 4) == 0x0C) {
+ for (int i = 0; i < 30; ++i) {
+ bytes[i] = (bytes[i] << 4) | (bytes[i + 1] >> 4);
+ }
+ bytes[30] <<= 4;
+
+ if (AMRDecode(mDecoder, AMR_122, bytes, samples, MIME_IETF) == 31) {
+ return 160;
+ }
+ }
+ return -1;
+}
+
+} // namespace
+
+AudioCodec *newAmrCodec()
+{
+ return new AmrCodec;
+}
+
+AudioCodec *newGsmEfrCodec()
+{
+ return new GsmEfrCodec;
+}
diff --git a/voip/jni/rtp/Android.mk b/voip/jni/rtp/Android.mk
index 29683bd..5909c0d 100644
--- a/voip/jni/rtp/Android.mk
+++ b/voip/jni/rtp/Android.mk
@@ -27,6 +27,7 @@ LOCAL_SRC_FILES := \
rtp_jni.cpp
LOCAL_SRC_FILES += \
+ AmrCodec.cpp \
G711Codec.cpp \
GsmCodec.cpp
@@ -34,13 +35,20 @@ LOCAL_SHARED_LIBRARIES := \
libnativehelper \
libcutils \
libutils \
- libmedia
+ libmedia \
+ libstagefright
LOCAL_STATIC_LIBRARIES := libgsm
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
- external/libgsm/inc
+ external/libgsm/inc \
+ frameworks/base/media/libstagefright/codecs/amrnb/common/include \
+ frameworks/base/media/libstagefright/codecs/amrnb/common/ \
+ frameworks/base/media/libstagefright/codecs/amrnb/enc/include \
+ frameworks/base/media/libstagefright/codecs/amrnb/enc/src \
+ frameworks/base/media/libstagefright/codecs/amrnb/dec/include \
+ frameworks/base/media/libstagefright/codecs/amrnb/dec/src
LOCAL_CFLAGS += -fvisibility=hidden
diff --git a/voip/jni/rtp/AudioCodec.cpp b/voip/jni/rtp/AudioCodec.cpp
index fc33ef2..2267ea0 100644
--- a/voip/jni/rtp/AudioCodec.cpp
+++ b/voip/jni/rtp/AudioCodec.cpp
@@ -21,6 +21,8 @@
extern AudioCodec *newAlawCodec();
extern AudioCodec *newUlawCodec();
extern AudioCodec *newGsmCodec();
+extern AudioCodec *newAmrCodec();
+extern AudioCodec *newGsmEfrCodec();
struct AudioCodecType {
const char *name;
@@ -29,6 +31,8 @@ struct AudioCodecType {
{"PCMA", newAlawCodec},
{"PCMU", newUlawCodec},
{"GSM", newGsmCodec},
+ {"AMR", newAmrCodec},
+ {"GSM-EFR", newGsmEfrCodec},
{NULL, NULL},
};
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 72c882b..f09edb6 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -86,8 +86,6 @@ public:
void decode(int tick);
private:
- bool isNatAddress(struct sockaddr_storage *addr);
-
enum {
NORMAL = 0,
SEND_ONLY = 1,
@@ -101,6 +99,7 @@ private:
AudioCodec *mCodec;
uint32_t mCodecMagic;
uint32_t mDtmfMagic;
+ bool mFixRemote;
int mTick;
int mSampleRate;
@@ -181,6 +180,20 @@ bool AudioStream::set(int mode, int socket, sockaddr_storage *remote,
if (codec) {
mRemote = *remote;
mCodec = codec;
+
+ // Here we should never get an private address, but some buggy proxy
+ // servers do give us one. To solve this, we replace the address when
+ // the first time we successfully decode an incoming packet.
+ mFixRemote = false;
+ if (remote->ss_family == AF_INET) {
+ unsigned char *address =
+ (unsigned char *)&((sockaddr_in *)remote)->sin_addr;
+ if (address[0] == 10 ||
+ (address[0] == 172 && (address[1] >> 4) == 1) ||
+ (address[0] == 192 && address[1] == 168)) {
+ mFixRemote = true;
+ }
+ }
}
LOGD("stream[%d] is configured as %s %dkHz %dms", mSocket,
@@ -318,16 +331,6 @@ void AudioStream::encode(int tick, AudioStream *chain)
sizeof(mRemote));
}
-bool AudioStream::isNatAddress(struct sockaddr_storage *addr) {
- if (addr->ss_family != AF_INET) return false;
- struct sockaddr_in *s4 = (struct sockaddr_in *)addr;
- unsigned char *d = (unsigned char *) &s4->sin_addr;
- if ((d[0] == 10)
- || ((d[0] == 172) && (d[1] & 0x10))
- || ((d[0] == 192) && (d[1] == 168))) return true;
- return false;
-}
-
void AudioStream::decode(int tick)
{
char c;
@@ -375,21 +378,11 @@ void AudioStream::decode(int tick)
MSG_TRUNC | MSG_DONTWAIT) >> 1;
} else {
__attribute__((aligned(4))) uint8_t buffer[2048];
- struct sockaddr_storage src_addr;
- socklen_t addrlen;
+ sockaddr_storage remote;
+ socklen_t len = sizeof(remote);
+
length = recvfrom(mSocket, buffer, sizeof(buffer),
- MSG_TRUNC|MSG_DONTWAIT, (sockaddr*)&src_addr, &addrlen);
-
- // The following if clause is for fixing the target address if
- // proxy server did not replace the NAT address with its media
- // port in SDP. Although it is proxy server's responsibility for
- // replacing the connection address with correct one, we will change
- // the target address as we detect the difference for now until we
- // know the best way to get rid of this issue.
- if ((memcmp((void*)&src_addr, (void*)&mRemote, addrlen) != 0) &&
- isNatAddress(&mRemote)) {
- memcpy((void*)&mRemote, (void*)&src_addr, addrlen);
- }
+ MSG_TRUNC | MSG_DONTWAIT, (sockaddr *)&remote, &len);
// Do we need to check SSRC, sequence, and timestamp? They are not
// reliable but at least they can be used to identify duplicates?
@@ -409,8 +402,12 @@ void AudioStream::decode(int tick)
if (length >= 0) {
length = mCodec->decode(samples, &buffer[offset], length);
}
+ if (length > 0 && mFixRemote) {
+ mRemote = remote;
+ mFixRemote = false;
+ }
}
- if (length != mSampleCount) {
+ if (length <= 0) {
LOGD("stream[%d] decoder error", mSocket);
return;
}