Merge change 1063 into donut

* changes:
  Refactor SearchableInfo.
diff --git a/api/current.xml b/api/current.xml
index 2bab739..509abe1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -63668,7 +63668,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="mode" type="int">
@@ -63879,7 +63879,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="mode" type="int">
@@ -68595,6 +68595,17 @@
  visibility="public"
 >
 </field>
+<field name="TONE_SUP_CONFIRM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TONE_SUP_CONGESTION"
  type="int"
  transient="false"
@@ -68606,6 +68617,17 @@
  visibility="public"
 >
 </field>
+<field name="TONE_SUP_CONGESTION_ABBREV"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="31"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TONE_SUP_DIAL"
  type="int"
  transient="false"
@@ -68628,6 +68650,39 @@
  visibility="public"
 >
 </field>
+<field name="TONE_SUP_INTERCEPT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="29"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_SUP_INTERCEPT_ABBREV"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="30"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TONE_SUP_PIP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="33"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TONE_SUP_RADIO_ACK"
  type="int"
  transient="false"
diff --git a/core/java/android/backup/BackupService.java b/core/java/android/backup/BackupService.java
index 879b544..5a6886d 100644
--- a/core/java/android/backup/BackupService.java
+++ b/core/java/android/backup/BackupService.java
@@ -39,7 +39,7 @@
  *      &lt;!-- Use the class "MyBackupService" to perform backups for my app --&gt;
  *      &lt;service android:name=".MyBackupService"&gt;
  *          &lt;intent-filter&gt;
- *              &lt;action android:name="android.service.action.BACKUP" /&gt;
+ *              &lt;action android:name="android.backup.BackupService.SERVICE" /&gt;
  *          &lt;/intent-filter&gt;
  *      &lt;/service&gt;</pre>
  * 
@@ -54,19 +54,18 @@
      * IntentFilter} that accepts this action. 
      */
     @SdkConstant(SdkConstantType.SERVICE_ACTION)
-    public static final String SERVICE_ACTION = "android.backup.BackupService";
+    public static final String SERVICE_ACTION = "android.backup.BackupService.SERVICE";
 
     /**
      * The application is being asked to write any data changed since the
      * last time it performed a backup operation.  The state data recorded
-     * during the last backup pass is provided in the oldStateFd file descriptor.
-     * If oldState.getStatSize() is zero or negative, no old state is available
-     * and the application should perform a full backup.  In both cases, a representation
-     * of the final backup state after this pass should be written to the file pointed
-     * to by the newStateFd file descriptor.
+     * during the last backup pass is provided in the oldState file descriptor.
+     * If oldState is null, no old state is available and the application should perform
+     * a full backup.  In both cases, a representation of the final backup state after
+     * this pass should be written to the file pointed to by the newStateFd file descriptor.
      *
      * @param oldState An open, read-only ParcelFileDescriptor pointing to the last backup
-     *                 state provided by the application.  May be empty or invalid, in which
+     *                 state provided by the application.  May be null, in which
      *                 case no prior state is being provided and the application should
      *                 perform a full backup.
      * @param data An open, read/write ParcelFileDescriptor pointing to the backup data
diff --git a/core/java/android/backup/IBackupManager.aidl b/core/java/android/backup/IBackupManager.aidl
index 7efaf58..cf22798 100644
--- a/core/java/android/backup/IBackupManager.aidl
+++ b/core/java/android/backup/IBackupManager.aidl
@@ -29,7 +29,13 @@
 interface IBackupManager {
     /**
      * Tell the system service that the caller has made changes to its
-     * data, and therefore needs to undergo a backup pass.
+     * data, and therefore needs to undergo an incremental backup pass.
      */
     oneway void dataChanged(String packageName);
+
+    /**
+     * Schedule a full backup of the given package.
+     * !!! TODO: protect with a signature-or-system permission?
+     */
+    oneway void scheduleFullBackup(String packageName);
 }
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index 093c24e..9dd4d15 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -25,6 +25,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.WeakHashMap;
 
 /**
  * An easy adapter to map static data to views defined in an XML file. You can specify the data
@@ -57,6 +58,7 @@
     private int mResource;
     private int mDropDownResource;
     private LayoutInflater mInflater;
+    private final WeakHashMap<View, View[]> mHolders = new WeakHashMap<View, View[]>();
 
     private SimpleFilter mFilter;
     private ArrayList<Map<String, ?>> mUnfilteredData;
@@ -128,7 +130,7 @@
                 holder[i] = v.findViewById(to[i]);
             }
 
-            v.setTag(holder);
+            mHolders.put(v, holder);
         } else {
             v = convertView;
         }
@@ -160,7 +162,7 @@
         }
 
         final ViewBinder binder = mViewBinder;
-        final View[] holder = (View[]) view.getTag();
+        final View[] holder = mHolders.get(view);
         final String[] from = mFrom;
         final int[] to = mTo;
         final int count = to.length;
diff --git a/core/java/android/widget/SimpleCursorAdapter.java b/core/java/android/widget/SimpleCursorAdapter.java
index c1bcd42..b6a49e5 100644
--- a/core/java/android/widget/SimpleCursorAdapter.java
+++ b/core/java/android/widget/SimpleCursorAdapter.java
@@ -22,6 +22,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import java.util.WeakHashMap;
+
 /**
  * An easy adapter to map columns from a cursor to TextViews or ImageViews
  * defined in an XML file. You can specify which columns you want, which
@@ -64,6 +66,7 @@
     private CursorToStringConverter mCursorToStringConverter;
     private ViewBinder mViewBinder;
     private String[] mOriginalFrom;
+    private final WeakHashMap<View, View[]> mHolders = new WeakHashMap<View, View[]>();
 
     /**
      * Constructor.
@@ -106,7 +109,7 @@
         for (int i = 0; i < count; i++) {
             holder[i] = v.findViewById(to[i]);
         }
-        v.setTag(holder);
+        mHolders.put(v, holder);
 
         return v;
     }
@@ -137,7 +140,7 @@
      */
     @Override
     public void bindView(View view, Context context, Cursor cursor) {
-        final View[] holder = (View[]) view.getTag();
+        final View[] holder = mHolders.get(view);
         final ViewBinder binder = mViewBinder;
         final int count = mTo.length;
         final int[] from = mFrom;
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index ec64e4d..6b0cc8a 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -18,7 +18,7 @@
 #define ANDROID_TONEGENERATOR_H_
 
 #include <utils/RefBase.h>
-#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
 #include <utils/threads.h>
 #include <media/AudioSystem.h>
 #include <media/AudioTrack.h>
@@ -49,21 +49,30 @@
         TONE_DTMF_C,  // C key: 1633Hz, 852Hz
         TONE_DTMF_D,  // D key: 1633Hz, 941Hz
         // Call supervisory tones:  3GPP TS 22.001 (CEPT)
-        TONE_SUP_DIAL,  // Dial tone: 425Hz, continuous
-        TONE_SUP_BUSY,  // Busy tone: 425Hz, 500ms ON, 500ms OFF...
-        TONE_SUP_CONGESTION,  // Congestion tone: 425Hz, 200ms ON, 200ms OFF...
-        TONE_SUP_RADIO_ACK,  // Radio path acknowlegment: 425Hz, 200ms ON
+        TONE_SUP_DIAL,  // Dial tone: CEPT: 425Hz, continuous
+        FIRST_SUP_TONE = TONE_SUP_DIAL,
+        TONE_SUP_BUSY,  // Busy tone, CEPT: 425Hz, 500ms ON, 500ms OFF...
+        TONE_SUP_CONGESTION,  // Congestion tone CEPT, JAPAN: 425Hz, 200ms ON, 200ms OFF...
+        TONE_SUP_RADIO_ACK,  // Radio path acknowlegment, CEPT, ANSI: 425Hz, 200ms ON
         TONE_SUP_RADIO_NOTAVAIL,  // Radio path not available: 425Hz, 200ms ON, 200 OFF 3 bursts
         TONE_SUP_ERROR,  // Error/Special info:  950Hz+1400Hz+1800Hz, 330ms ON, 1s OFF...
-        TONE_SUP_CALL_WAITING,  // Call Waiting:  425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
-        TONE_SUP_RINGTONE,  // Ring Tone:  425Hz, 1s ON, 4s OFF...
+        TONE_SUP_CALL_WAITING,  // Call Waiting CEPT,JAPAN:  425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
+        TONE_SUP_RINGTONE,  // Ring Tone CEPT, JAPAN:  425Hz, 1s ON, 4s OFF...
+        LAST_SUP_TONE = TONE_SUP_RINGTONE,
         // Proprietary tones:  3GPP TS 31.111
         TONE_PROP_BEEP,  // General beep: 400Hz+1200Hz, 35ms ON
         TONE_PROP_ACK,  // Positive Acknowlgement: 1200Hz, 100ms ON, 100ms OFF 2 bursts
-        TONE_PROP_NACK,  // Negative Acknowlgement: 300Hz+400Hz+500Hz, 400ms ON 
+        TONE_PROP_NACK,  // Negative Acknowlgement: 300Hz+400Hz+500Hz, 400ms ON
         TONE_PROP_PROMPT,  // Prompt tone: 400Hz+1200Hz, 200ms ON
         TONE_PROP_BEEP2,  // General double beep: 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms on
-        NUM_TONES
+        // Additional call supervisory tones: specified by IS-95 only
+        TONE_SUP_INTERCEPT, // Intercept tone: alternating 440 Hz and 620 Hz tones, each on for 250 ms.
+        TONE_SUP_INTERCEPT_ABBREV, // Abbreviated intercept: intercept tone limited to 4 seconds
+        TONE_SUP_CONGESTION_ABBREV, // Abbreviated congestion: congestion tone limited to 4 seconds
+        TONE_SUP_CONFIRM, // Confirm tone: a 350 Hz tone added to a 440 Hz tone repeated 3 times in a 100 ms on, 100 ms off cycle.
+        TONE_SUP_PIP, // Pip tone: four bursts of 480 Hz tone (0.1 s on, 0.1 s off).
+        NUM_TONES,
+        NUM_SUP_TONES = LAST_SUP_TONE-FIRST_SUP_TONE+1
     };
 
     ToneGenerator(int streamType, float volume);
@@ -85,13 +94,45 @@
         TONE_RESTARTING  //
     };
 
-    static const unsigned int TONEGEN_MAX_WAVES = 3;
-    static const unsigned int TONEGEN_MAX_SEGMENTS = 4;  // Maximun number of elenemts in
+
+    // Region specific tones.
+    // These supervisory tones are different depending on the region (USA/CANADA, JAPAN, rest of the world).
+    // When a tone in the range [FIRST_SUP_TONE, LAST_SUP_TONE] is requested, the region is determined
+    // from system property gsm.operator.iso-country and the proper tone descriptor is selected with the
+    // help of sToneMappingTable[]
+    enum regional_tone_type {
+        // ANSI supervisory tones
+        TONE_ANSI_DIAL = NUM_TONES, // Dial tone: a continuous 350 Hz + 440 Hz tone.
+        TONE_ANSI_BUSY,             // Busy tone on:  a 480 Hz + 620 Hz tone repeated in a 500 ms on, 500 ms off cycle.
+        TONE_ANSI_CONGESTION,       // Network congestion (reorder) tone on:  a 480 Hz + 620 Hz tone repeated in a 250 ms on, 250 ms off cycle.
+        TONE_ANSI_CALL_WAITING,     // Call waiting tone on: 440 Hz, on for 300 ms, 9,7 s off followed by
+                                    // (440 Hz, on for 100 ms off for 100 ms, on for 100 ms, 9,7s off and repeated as necessary).
+        TONE_ANSI_RINGTONE,         // Ring Tone:  a 440 Hz + 480 Hz tone repeated in a 2 s on, 4 s off pattern.
+        // JAPAN Supervisory tones
+        TONE_JAPAN_DIAL,            // Dial tone: 400Hz, continuous
+        TONE_JAPAN_BUSY,            // Busy tone: 400Hz, 500ms ON, 500ms OFF...
+        TONE_JAPAN_RADIO_ACK,       // Radio path acknowlegment: 400Hz, 1s ON, 2s OFF...
+        NUM_ALTERNATE_TONES
+    };
+
+    enum region {
+        ANSI,
+        JAPAN,
+        CEPT,
+        NUM_REGIONS
+    };
+
+    static const unsigned char sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES];
+
+    static const unsigned int TONEGEN_MAX_WAVES = 3;     // Maximun number of sine waves in a tone segment
+    static const unsigned int TONEGEN_MAX_SEGMENTS = 5;  // Maximun number of segments in a tone descriptor
     static const unsigned int TONEGEN_INF = 0xFFFFFFFF;  // Represents infinite time duration
     static const float TONEGEN_GAIN = 0.9;  // Default gain passed to  WaveGenerator().
 
     // ToneDescriptor class contains all parameters needed to generate a tone:
-    //    - The array waveFreq[] contains the frequencies of all individual waves making the multi-tone.
+    //    - The array waveFreq[]:
+    //         1 for static tone descriptors: contains the frequencies of all individual waves making the multi-tone.
+    //         2 for active tone descritors: contains the indexes of the WaveGenerator objects in mWaveGens
     //        The number of sine waves varies from 1 to TONEGEN_MAX_WAVES.
     //        The first null value indicates that no more waves are needed.
     //    - The array segments[] is used to generate the tone pulses. A segment is a period of time
@@ -100,17 +141,25 @@
     //        The data stored in segments[] is the duration of the corresponding period in ms.
     //        The first segment encountered with a 0 duration    indicates that no more segment follows.
     //    - repeatCnt indicates the number of times the sequence described by segments[] array must be repeated.
-    //        When the tone generator    encounters the first 0 duration segment, it will compare repeatCnt to mCurCount.
-    //        If mCurCount > repeatCnt, the tone is stopped automatically.
+    //        When the tone generator encounters the first 0 duration segment, it will compare repeatCnt to mCurCount.
+    //        If mCurCount > repeatCnt, the tone is stopped automatically. Otherwise, tone sequence will be
+    //        restarted from segment repeatSegment.
+    //    - repeatSegment number of the first repeated segment when repeatCnt is not null
+
+    class ToneSegment {
+    public:
+        unsigned int duration;
+        unsigned short waveFreq[TONEGEN_MAX_WAVES+1];
+    };
 
     class ToneDescriptor {
     public:
-        unsigned short waveFreq[TONEGEN_MAX_WAVES+1];
-        unsigned long segments[TONEGEN_MAX_SEGMENTS+1];
+        ToneSegment segments[TONEGEN_MAX_SEGMENTS+1];
         unsigned long repeatCnt;
+        unsigned long repeatSegment;
     };
 
-    static const ToneDescriptor toneDescriptors[NUM_TONES];
+    static const ToneDescriptor sToneDescriptors[];
 
     unsigned int mTotalSmp;  // Total number of audio samples played (gives current time)
     unsigned int mNextSegSmp;  // Position of next segment transition expressed in samples
@@ -121,6 +170,7 @@
     unsigned short mCurSegment;  // Current segment index in ToneDescriptor segments[]
     unsigned short mCurCount;  // Current sequence repeat count
     volatile unsigned short mState;  // ToneGenerator state (tone_state)
+    unsigned short mRegion;
     const ToneDescriptor *mpToneDesc;  // pointer to active tone descriptor
     const ToneDescriptor *mpNewToneDesc;  // pointer to next active tone descriptor
 
@@ -136,8 +186,9 @@
     bool initAudioTrack();
     static void audioCallback(int event, void* user, void *info);
     bool prepareWave();
-    unsigned int numWaves();
+    unsigned int numWaves(unsigned int segmentIdx);
     void clearWaveGens();
+    int getToneForRegion(int toneType);
 
     // WaveGenerator generates a single sine wave
     class WaveGenerator {
@@ -167,7 +218,7 @@
         short mAmplitude_Q15;  // Q15 amplitude
     };
 
-    Vector<WaveGenerator *> mWaveGens;  // list of active wave generators.
+    KeyedVector<unsigned short, WaveGenerator *> mWaveGens;  // list of active wave generators.
 };
 
 }
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index a40b1fb2..2cda7fa 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -25,7 +25,7 @@
  * This class is used in conjunction with the {@link Listener} interface.
  */
 public final class GpsStatus {
-    private static final int NUM_SATELLITES = 32;
+    private static final int NUM_SATELLITES = 255;
 
     /* These package private values are modified by the LocationManager class */
     private int mTimeToFirstFix;
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 5877dd1..97b6a62 100644
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.location;
 
+import android.app.AlarmManager;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -59,6 +61,9 @@
 public class GpsLocationProvider extends ILocationProvider.Stub {
 
     private static final String TAG = "GpsLocationProvider";
+
+    private static final boolean DEBUG = true;
+    private static final boolean VERBOSE = false;
     
     /**
      * Broadcast intent action indicating that the GPS has either been
@@ -151,6 +156,9 @@
     
     // turn off GPS fix icon if we haven't received a fix in 10 seconds
     private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
+    
+    // number of fixes to receive before disabling GPS
+    private static final int MIN_FIX_COUNT = 10;
 
     // true if we are enabled
     private boolean mEnabled;
@@ -164,6 +172,9 @@
     // requested frequency of fixes, in seconds
     private int mFixInterval = 1;
 
+    // number of fixes we have received since we started navigating
+    private int mFixCount;
+
     private int mPositionMode = GPS_POSITION_MODE_STANDALONE;
 
     // true if we started navigation
@@ -196,6 +207,11 @@
     private int mSuplDataConnectionState;
     private final ConnectivityManager mConnMgr;
 
+    // Alarms
+    private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
+    private final AlarmManager mAlarmManager;
+    private final PendingIntent mWakeupIntent;
+
     private final IBatteryStats mBatteryStats;
     private final SparseIntArray mClientUids = new SparseIntArray();
 
@@ -257,11 +273,14 @@
         return mGpsStatusProvider;
     }
 
-    private class TelephonyBroadcastReceiver extends BroadcastReceiver {
+    private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
         @Override public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
 
-            if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
+            if (action.equals(ALARM_WAKEUP)) {
+                if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
+                startNavigating();
+            } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
                 String state = intent.getStringExtra(Phone.STATE_KEY);
                 String apnName = intent.getStringExtra(Phone.DATA_APN_KEY);
                 String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY);
@@ -278,7 +297,7 @@
                 }
             }
         }
-    }
+    };
 
     public static boolean isSupported() {
         return native_is_supported();
@@ -288,10 +307,13 @@
         mContext = context;
         mLocationManager = locationManager;
 
-        TelephonyBroadcastReceiver receiver = new TelephonyBroadcastReceiver();
+        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
+
         IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ALARM_WAKEUP);
         intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
-        context.registerReceiver(receiver, intentFilter);
+        context.registerReceiver(mBroadcastReciever, intentFilter);
 
         mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
 
@@ -512,11 +534,11 @@
 
     public void enableLocationTracking(boolean enable) {
         if (enable) {
-            mFixRequestTime = System.currentTimeMillis();
             mTTFF = 0;
             mLastFixTime = 0;
             startNavigating();
         } else {
+            mAlarmManager.cancel(mWakeupIntent);
             stopNavigating();
         }
     }
@@ -622,7 +644,7 @@
 
     public void startNavigating() {
         if (!mStarted) {
-            if (Config.LOGV) Log.v(TAG, "startNavigating");
+            if (DEBUG) Log.d(TAG, "startNavigating");
             mStarted = true;
             if (!native_start(mPositionMode, false, mFixInterval)) {
                 mStarted = false;
@@ -631,11 +653,13 @@
 
             // reset SV count to zero
             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
+            mFixCount = 0;
+            mFixRequestTime = System.currentTimeMillis();
         }
     }
 
     public void stopNavigating() {
-        if (Config.LOGV) Log.v(TAG, "stopNavigating");
+        if (DEBUG) Log.d(TAG, "stopNavigating");
         if (mStarted) {
             mStarted = false;
             native_stop();
@@ -653,7 +677,7 @@
      */
     private void reportLocation(int flags, double latitude, double longitude, double altitude,
             float speed, float bearing, float accuracy, long timestamp) {
-        if (Config.LOGV) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
+        if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
                 " timestamp: " + timestamp);
 
         mLastFixTime = System.currentTimeMillis();
@@ -721,13 +745,23 @@
             mContext.sendBroadcast(intent);
             updateStatus(LocationProvider.AVAILABLE, mSvCount);
         }
+
+        if (mFixCount++ >= MIN_FIX_COUNT && mFixInterval > 1) {
+            if (DEBUG) Log.d(TAG, "exceeded MIN_FIX_COUNT");
+            stopNavigating();
+            mFixCount = 0;
+            mAlarmManager.cancel(mWakeupIntent);
+            long now = SystemClock.elapsedRealtime();
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    SystemClock.elapsedRealtime() + mFixInterval * 1000, mWakeupIntent);
+        }
    }
 
     /**
      * called from native code to update our status
      */
     private void reportStatus(int status) {
-        if (Config.LOGV) Log.v(TAG, "reportStatus status: " + status);
+        if (VERBOSE) Log.v(TAG, "reportStatus status: " + status);
 
         boolean wasNavigating = mNavigating;
         mNavigating = (status == GPS_STATUS_SESSION_BEGIN);
@@ -797,12 +831,12 @@
             }
         }
 
-        if (Config.LOGD) {
-            if (Config.LOGV) Log.v(TAG, "SV count: " + svCount +
+        if (VERBOSE) {
+            Log.v(TAG, "SV count: " + svCount +
                     " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
                     " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
             for (int i = 0; i < svCount; i++) {
-                if (Config.LOGV) Log.v(TAG, "sv: " + mSvs[i] +
+                Log.v(TAG, "sv: " + mSvs[i] +
                         " snr: " + (float)mSnrs[i]/10 +
                         " elev: " + mSvElevations[i] +
                         " azimuth: " + mSvAzimuths[i] +
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f509fb5..e43c9c4 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -642,7 +642,9 @@
      *           <var>false</var> to turn it off
      */
     public void setSpeakerphoneOn(boolean on){
-        setRouting(MODE_IN_CALL, on ? ROUTE_SPEAKER : ROUTE_EARPIECE, ROUTE_ALL);
+        // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
+        // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
+        setRoutingP(MODE_INVALID, on ? ROUTE_SPEAKER: 0, ROUTE_SPEAKER);
     }
 
     /**
@@ -651,7 +653,7 @@
      * @return true if speakerphone is on, false if it's off
      */
     public boolean isSpeakerphoneOn() {
-        return (getRouting(MODE_IN_CALL) & ROUTE_SPEAKER) == 0 ? false : true;
+        return (getRoutingP(MODE_IN_CALL) & ROUTE_SPEAKER) == 0 ? false : true;
      }
 
     /**
@@ -661,14 +663,9 @@
      *           headset; <var>false</var> to route audio to/from phone earpiece
      */
     public void setBluetoothScoOn(boolean on){
-        // Don't disable A2DP when turning off SCO.
-        // A2DP does not affect in-call routing.
-        setRouting(MODE_RINGTONE,
-               on ? ROUTE_BLUETOOTH_SCO: ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP);
-        setRouting(MODE_NORMAL,
-                on ? ROUTE_BLUETOOTH_SCO: ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP);
-        setRouting(MODE_IN_CALL,
-                on ? ROUTE_BLUETOOTH_SCO: ROUTE_EARPIECE, ROUTE_ALL);
+        // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
+        // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
+        setRoutingP(MODE_INVALID, on ? ROUTE_BLUETOOTH_SCO: 0, ROUTE_BLUETOOTH_SCO);
     }
 
     /**
@@ -678,7 +675,7 @@
      *         false if otherwise
      */
     public boolean isBluetoothScoOn() {
-        return (getRouting(MODE_IN_CALL) & ROUTE_BLUETOOTH_SCO) == 0 ? false : true;
+        return (getRoutingP(MODE_IN_CALL) & ROUTE_BLUETOOTH_SCO) == 0 ? false : true;
     }
 
     /**
@@ -688,12 +685,9 @@
      *           headset; <var>false</var> disable A2DP audio
      */
     public void setBluetoothA2dpOn(boolean on){
-        // the audio flinger chooses A2DP as a higher priority,
-        // so there is no need to disable other routes.
-        setRouting(MODE_RINGTONE,
-               on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP);
-        setRouting(MODE_NORMAL,
-                on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP);
+        // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
+        // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
+        setRoutingP(MODE_INVALID, on ? ROUTE_BLUETOOTH_A2DP: 0, ROUTE_BLUETOOTH_A2DP);
     }
 
     /**
@@ -703,7 +697,7 @@
      *         false if otherwise
      */
     public boolean isBluetoothA2dpOn() {
-        return (getRouting(MODE_NORMAL) & ROUTE_BLUETOOTH_A2DP) == 0 ? false : true;
+        return (getRoutingP(MODE_NORMAL) & ROUTE_BLUETOOTH_A2DP) == 0 ? false : true;
     }
 
     /**
@@ -714,14 +708,9 @@
      * @hide
      */
     public void setWiredHeadsetOn(boolean on){
-        // A2DP has higher priority than wired headset, so headset connect/disconnect events
-        // should not affect A2DP routing
-        setRouting(MODE_NORMAL,
-                on ? ROUTE_HEADSET : ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP);
-        setRouting(MODE_RINGTONE,
-                on ? ROUTE_HEADSET | ROUTE_SPEAKER : ROUTE_SPEAKER, ROUTE_ALL & ~ROUTE_BLUETOOTH_A2DP);
-        setRouting(MODE_IN_CALL,
-                on ? ROUTE_HEADSET : ROUTE_EARPIECE, ROUTE_ALL);
+        // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
+        // MODE_INVALID indicates to AudioService that setRouting() was initiated by AudioManager
+        setRoutingP(MODE_INVALID, on ? ROUTE_HEADSET: 0, ROUTE_HEADSET);
     }
 
     /**
@@ -732,7 +721,7 @@
      * @hide
      */
     public boolean isWiredHeadsetOn() {
-        return (getRouting(MODE_NORMAL) & ROUTE_HEADSET) == 0 ? false : true;
+        return (getRoutingP(MODE_NORMAL) & ROUTE_HEADSET) == 0 ? false : true;
     }
 
     /**
@@ -860,7 +849,11 @@
      *               more of ROUTE_xxx types. Set bits indicate that route should be on
      * @param mask   bit vector of routes to change, created from one or more of
      * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
+     *
+     * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
+     * setBluetoothScoOn(), setBluetoothA2dpOn() and setWiredHeadsetOn() methods instead.
      */
+
     public void setRouting(int mode, int routes, int mask) {
         IAudioService service = getService();
         try {
@@ -876,7 +869,10 @@
      * @param mode audio mode to get route (e.g., MODE_RINGTONE)
      * @return an audio route bit vector that can be compared with ROUTE_xxx
      * bits
+     * @deprecated   Do not query audio routing directly, use isSpeakerphoneOn(),
+     * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
      */
+    @Deprecated
     public int getRouting(int mode) {
         IAudioService service = getService();
         try {
@@ -1076,4 +1072,31 @@
       * {@hide}
       */
      private IBinder mICallBack = new Binder();
+
+     /**
+      * {@hide}
+      */
+     private void setRoutingP(int mode, int routes, int mask) {
+         IAudioService service = getService();
+         try {
+             service.setRouting(mode, routes, mask);
+         } catch (RemoteException e) {
+             Log.e(TAG, "Dead object in setRouting", e);
+         }
+     }
+
+
+     /**
+      * {@hide}
+      */
+     private int getRoutingP(int mode) {
+         IAudioService service = getService();
+         try {
+             return service.getRouting(mode);
+         } catch (RemoteException e) {
+             Log.e(TAG, "Dead object in getRouting", e);
+             return -1;
+         }
+     }
+
 }
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 2e3e460..881de4d 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -100,6 +100,10 @@
     private int[] mRoutes = new int[AudioSystem.NUM_MODES];
     private Object mSettingsLock = new Object();
     private boolean mMediaServerOk;
+    private boolean mSpeakerIsOn;
+    private boolean mBluetoothScoIsConnected;
+    private boolean mHeadsetIsConnected;
+    private boolean mBluetoothA2dpIsConnected;
 
     private SoundPool mSoundPool;
     private Object mSoundEffectsLock = new Object();
@@ -189,6 +193,10 @@
         mMediaServerOk = true;
         AudioSystem.setErrorCallback(mAudioSystemCallback);
         loadSoundEffects();
+        mSpeakerIsOn = false;
+        mBluetoothScoIsConnected = false;
+        mHeadsetIsConnected = false;
+        mBluetoothA2dpIsConnected = false;
     }
 
     private void createAudioSystemThread() {
@@ -606,8 +614,9 @@
         }
         synchronized (mSettingsLock) {
             if (mode != mMode) {
-                AudioSystem.setMode(mode);
-                mMode = mode;
+                if (AudioSystem.setMode(mode) == AudioSystem.AUDIO_STATUS_OK) {
+                    mMode = mode;
+                }
             }
             int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
             int index = mStreamStates[streamType].mIndex;
@@ -623,18 +632,167 @@
 
     /** @see AudioManager#setRouting(int, int, int) */
     public void setRouting(int mode, int routes, int mask) {
+        int incallMask = 0;
+        int ringtoneMask = 0;
+        int normalMask = 0;
+
         if (!checkAudioSettingsPermission("setRouting()")) {
             return;
         }
         synchronized (mSettingsLock) {
-            if ((mRoutes[mode] & mask) != (routes & mask)) {
-                AudioSystem.setRouting(mode, routes, mask);
-                mRoutes[mode] = (mRoutes[mode] & ~mask) | (routes & mask);
+            // Temporary fix for issue #1713090 until audio routing is refactored in eclair release.
+            // mode AudioSystem.MODE_INVALID is used only by the following AudioManager methods:
+            // setWiredHeadsetOn(), setBluetoothA2dpOn(), setBluetoothScoOn() and setSpeakerphoneOn().
+            // If applications are using AudioManager.setRouting() that is now deprecated, the routing
+            // command will be ignored.
+            if (mode == AudioSystem.MODE_INVALID) {
+                switch (mask) {
+                case AudioSystem.ROUTE_SPEAKER:
+                    // handle setSpeakerphoneOn()
+                    if (routes != 0 && !mSpeakerIsOn) {
+                        mSpeakerIsOn = true;
+                        mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
+                        incallMask = AudioSystem.ROUTE_ALL;
+                    } else if (mSpeakerIsOn) {
+                        mSpeakerIsOn = false;
+                        if (mBluetoothScoIsConnected) {
+                            mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_BLUETOOTH_SCO;
+                        } else if (mHeadsetIsConnected) {
+                            mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
+                        } else {
+                            mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
+                        }
+                        incallMask = AudioSystem.ROUTE_ALL;
+                    }
+                    break;
+
+                case AudioSystem.ROUTE_BLUETOOTH_SCO:
+                    // handle setBluetoothScoOn()
+                    if (routes != 0 && !mBluetoothScoIsConnected) {
+                        mBluetoothScoIsConnected = true;
+                        mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_BLUETOOTH_SCO;
+                        mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+                                                              AudioSystem.ROUTE_BLUETOOTH_SCO;
+                        mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+                                                            AudioSystem.ROUTE_BLUETOOTH_SCO;
+                        incallMask = AudioSystem.ROUTE_ALL;
+                        // A2DP has higher priority than SCO headset, so headset connect/disconnect events
+                        // should not affect A2DP routing
+                        ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                        normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                    } else if (mBluetoothScoIsConnected) {
+                        mBluetoothScoIsConnected = false;
+                        if (mHeadsetIsConnected) {
+                            mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
+                            mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+                                                                 (AudioSystem.ROUTE_HEADSET|AudioSystem.ROUTE_SPEAKER);
+                            mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+                                                               AudioSystem.ROUTE_HEADSET;
+                        } else {
+                            if (mSpeakerIsOn) {
+                                mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
+                            } else {
+                                mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
+                            }
+                            mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+                                                                 AudioSystem.ROUTE_SPEAKER;
+                            mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+                                                               AudioSystem.ROUTE_SPEAKER;
+                        }
+                        incallMask = AudioSystem.ROUTE_ALL;
+                        // A2DP has higher priority than SCO headset, so headset connect/disconnect events
+                        // should not affect A2DP routing
+                        ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                        normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                    }
+                    break;
+
+                case AudioSystem.ROUTE_HEADSET:
+                    // handle setWiredHeadsetOn()
+                    if (routes != 0 && !mHeadsetIsConnected) {
+                        mHeadsetIsConnected = true;
+                        // do not act upon headset connection if bluetooth SCO is connected to match phone app behavior
+                        if (!mBluetoothScoIsConnected) {
+                            mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_HEADSET;
+                            mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+                                                                 (AudioSystem.ROUTE_HEADSET|AudioSystem.ROUTE_SPEAKER);
+                            mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+                                                               AudioSystem.ROUTE_HEADSET;
+                            incallMask = AudioSystem.ROUTE_ALL;
+                            // A2DP has higher priority than wired headset, so headset connect/disconnect events
+                            // should not affect A2DP routing
+                            ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                            normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                        }
+                    } else if (mHeadsetIsConnected) {
+                        mHeadsetIsConnected = false;
+                        // do not act upon headset disconnection if bluetooth SCO is connected to match phone app behavior
+                        if (!mBluetoothScoIsConnected) {
+                            if (mSpeakerIsOn) {
+                                mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_SPEAKER;
+                            } else {
+                                mRoutes[AudioSystem.MODE_IN_CALL] = AudioSystem.ROUTE_EARPIECE;
+                            }
+                            mRoutes[AudioSystem.MODE_RINGTONE] = (mRoutes[AudioSystem.MODE_RINGTONE] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+                                                                 AudioSystem.ROUTE_SPEAKER;
+                            mRoutes[AudioSystem.MODE_NORMAL] = (mRoutes[AudioSystem.MODE_NORMAL] & AudioSystem.ROUTE_BLUETOOTH_A2DP) |
+                                                               AudioSystem.ROUTE_SPEAKER;
+
+                            incallMask = AudioSystem.ROUTE_ALL;
+                            // A2DP has higher priority than wired headset, so headset connect/disconnect events
+                            // should not affect A2DP routing
+                            ringtoneMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                            normalMask = AudioSystem.ROUTE_ALL & ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                        }
+                    }
+                    break;
+
+                case AudioSystem.ROUTE_BLUETOOTH_A2DP:
+                    // handle setBluetoothA2dpOn()
+                    if (routes != 0 && !mBluetoothA2dpIsConnected) {
+                        mBluetoothA2dpIsConnected = true;
+                        mRoutes[AudioSystem.MODE_RINGTONE] |= AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                        mRoutes[AudioSystem.MODE_NORMAL] |= AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                        // the audio flinger chooses A2DP as a higher priority,
+                        // so there is no need to disable other routes.
+                        ringtoneMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                        normalMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                    } else if (mBluetoothA2dpIsConnected) {
+                        mBluetoothA2dpIsConnected = false;
+                        mRoutes[AudioSystem.MODE_RINGTONE] &= ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                        mRoutes[AudioSystem.MODE_NORMAL] &= ~AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                        // the audio flinger chooses A2DP as a higher priority,
+                        // so there is no need to disable other routes.
+                        ringtoneMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                        normalMask = AudioSystem.ROUTE_BLUETOOTH_A2DP;
+                    }
+                    break;
+                }
+                
+                // incallMask is != 0 means we must apply ne routing to MODE_IN_CALL mode
+                if (incallMask != 0) {
+                    AudioSystem.setRouting(AudioSystem.MODE_IN_CALL,
+                                           mRoutes[AudioSystem.MODE_IN_CALL],
+                                           incallMask);
+                }
+                // ringtoneMask is != 0 means we must apply ne routing to MODE_RINGTONE mode
+                if (ringtoneMask != 0) {
+                    AudioSystem.setRouting(AudioSystem.MODE_RINGTONE,
+                                           mRoutes[AudioSystem.MODE_RINGTONE],
+                                           ringtoneMask);
+                }
+                // normalMask is != 0 means we must apply ne routing to MODE_NORMAL mode
+                if (normalMask != 0) {
+                    AudioSystem.setRouting(AudioSystem.MODE_NORMAL,
+                                           mRoutes[AudioSystem.MODE_NORMAL],
+                                           normalMask);
+                }
+
+                int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
+                int index = mStreamStates[streamType].mIndex;
+                syncRingerAndNotificationStreamVolume(streamType, index, true);
+                setStreamVolumeInt(streamType, index, true);
             }
-            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
-            int index = mStreamStates[streamType].mIndex;
-            syncRingerAndNotificationStreamVolume(streamType, index, true);
-            setStreamVolumeInt(streamType, index, true);
         }
     }
 
diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java
index 0901fbf..4b53756 100644
--- a/media/java/android/media/ToneGenerator.java
+++ b/media/java/android/media/ToneGenerator.java
@@ -130,25 +130,35 @@
      */
     public static final int TONE_DTMF_D = 15;
     /**
-     * Call supervisory tone, Dial tone: 425Hz, continuous
-     * 
+     * Call supervisory tone, Dial tone:
+     *      CEPT:           425Hz, continuous
+     *      ANSI (IS-95):   350Hz+440Hz, continuous
+     *      JAPAN:          400Hz, continuous
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_SUP_DIAL = 16;
     /**
-     * Call supervisory tone, Busy: 425Hz, 500ms ON, 500ms OFF...
-     * 
+     * Call supervisory tone, Busy:
+     *      CEPT:           425Hz, 500ms ON, 500ms OFF...
+     *      ANSI (IS-95):   480Hz+620Hz, 500ms ON, 500ms OFF...
+     *      JAPAN:          400Hz, 500ms ON, 500ms OFF...
+     *
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_SUP_BUSY = 17;
     /**
-     * Call supervisory tone, Congestion: 425Hz, 200ms ON, 200ms OFF...
+     * Call supervisory tone, Congestion:
+     *      CEPT, JAPAN:    425Hz, 200ms ON, 200ms OFF...
+     *      ANSI (IS-95):   480Hz+620Hz, 250ms ON, 250ms OFF...
      * 
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_SUP_CONGESTION = 18;
     /**
-     * Call supervisory tone, Radio path acknowlegment : 425Hz, 200ms ON
+     * Call supervisory tone, Radio path acknowlegment :
+     *      CEPT, ANSI:    425Hz, 200ms ON
+     *      JAPAN:         400Hz, 1s ON, 2s OFF...
      * 
      * @see #ToneGenerator(int, int)
      */
@@ -166,13 +176,17 @@
      */
     public static final int TONE_SUP_ERROR = 21;
     /**
-     * Call supervisory tone, Call Waiting: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
+     * Call supervisory tone, Call Waiting:
+     *      CEPT, JAPAN:    425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF...
+     *      ANSI (IS-95):   440 Hz, 300 ms ON, 9.7 s OFF, (100 ms ON, 100 ms OFF, 100 ms ON, 9.7s OFF ...)
      * 
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_SUP_CALL_WAITING = 22;
     /**
-     * Call supervisory tone, Ring Tone: 425Hz, 1s ON, 4s OFF...
+     * Call supervisory tone, Ring Tone:
+     *      CEPT, JAPAN:    425Hz, 1s ON, 4s OFF...
+     *      ANSI (IS-95):   440Hz + 480Hz, 2s ON, 4s OFF...
      * 
      * @see #ToneGenerator(int, int)
      */
@@ -207,6 +221,37 @@
      * @see #ToneGenerator(int, int)
      */
     public static final int TONE_PROP_BEEP2 = 28;
+    /**
+     * Call supervisory tone (IS-95), intercept tone: alternating 440 Hz and 620 Hz tones, each on for 250 ms
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_SUP_INTERCEPT = 29;
+    /**
+     * Call supervisory tone (IS-95), abbreviated intercept: intercept tone limited to 4 seconds
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_SUP_INTERCEPT_ABBREV = 30;
+    /**
+     * Call supervisory tone (IS-95), abbreviated congestion: congestion tone limited to 4 seconds
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_SUP_CONGESTION_ABBREV = 31;
+    /**
+     * Call supervisory tone (IS-95), confirm tone: a 350 Hz tone added to a 440 Hz tone repeated 3 times in a 100 ms on, 100 ms off cycle
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_SUP_CONFIRM = 32;
+    /**
+     * Call supervisory tone (IS-95), pip tone: four bursts of 480 Hz tone (0.1 s on, 0.1 s off).
+     *
+     * @see #ToneGenerator(int, int)
+     */
+    public static final int TONE_SUP_PIP = 33;
+
 
     /** Maximum volume, for use with {@link #ToneGenerator(int,int)} */
     public static final int MAX_VOLUME = AudioSystem.MAX_VOLUME;
@@ -258,6 +303,11 @@
      * <li>{@link #TONE_PROP_NACK}
      * <li>{@link #TONE_PROP_PROMPT}
      * <li>{@link #TONE_PROP_BEEP2}
+     * <li>{@link #TONE_SUP_INTERCEPT}
+     * <li>{@link #TONE_SUP_INTERCEPT_ABBREV}
+     * <li>{@link #TONE_SUP_CONGESTION_ABBREV}
+     * <li>{@link #TONE_SUP_CONFIRM}
+     * <li>{@link #TONE_SUP_PIP}
      * </ul>
      * @see #ToneGenerator(int, int)
     */
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 8560593..d1789ad 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -24,44 +24,235 @@
 #include <sys/resource.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
+#include <cutils/properties.h>
 #include "media/ToneGenerator.h"
 
+
 namespace android {
 
+
 // Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
-const ToneGenerator::ToneDescriptor
-    ToneGenerator::toneDescriptors[NUM_TONES] = {
-    // waveFreq[]                     segments[]                         repeatCnt
-        { { 1336, 941, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_0
-        { { 1209, 697, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_1
-        { { 1336, 697, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_2
-        { { 1477, 697, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_3
-        { { 1209, 770, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_4
-        { { 1336, 770, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_5
-        { { 1477, 770, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_6
-        { { 1209, 852, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_7
-        { { 1336, 852, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_8
-        { { 1477, 852, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_9
-        { { 1209, 941, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_S
-        { { 1477, 941, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_P
-        { { 1633, 697, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_A
-        { { 1633, 770, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_B
-        { { 1633, 852, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_C
-        { { 1633, 941, 0 },       { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_DTMF_D
-        { { 425, 0 },             { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF },  // TONE_SUP_DIAL
-        { { 425, 0 },             { 500, 500, 0 },                   ToneGenerator::TONEGEN_INF },  // TONE_SUP_BUSY
-        { { 425, 0 },             { 200, 200, 0 },                   ToneGenerator::TONEGEN_INF },  // TONE_SUP_CONGESTION
-        { { 425, 0 },             { 200, 0 },                        0 },                           // TONE_SUP_RADIO_ACK
-        { { 425, 0 },             { 200, 200, 0 },                   2 },                           // TONE_SUP_RADIO_NOTAVAIL
-        { { 950, 1400, 1800, 0 }, { 330, 1000, 0 },                  ToneGenerator::TONEGEN_INF },  // TONE_SUP_ERROR
-        { { 425, 0 },             { 200, 600, 200, 3000, 0 },        ToneGenerator::TONEGEN_INF },  // TONE_SUP_CALL_WAITING
-        { { 425, 0 },             { 1000, 4000, 0 },                 ToneGenerator::TONEGEN_INF },  // TONE_SUP_RINGTONE
-        { { 400, 1200, 0 },       { 40, 0 },                         0 },                           // TONE_PROP_BEEP
-        { { 1200, 0 },            { 100, 100, 0 },                   1 },                           // TONE_PROP_ACK
-        { { 300, 400, 500, 0 },   { 400, 0 },                        0 },                           // TONE_PROP_NACK
-        { { 400, 1200, 0 },       { 200, 0 },                        0 },                           // TONE_PROP_PROMPT
-        { { 400, 1200, 0 },       { 40, 200, 40, 0 },                0 }                            // TONE_PROP_BEEP2
-    };
+const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = {
+        { segments: {{ duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 941, 0 }},
+                     { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_0
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 697, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_1
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 697, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_2
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 697, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_3
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 770, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_4
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 770, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_5
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 770, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_6
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 852, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_7
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1336, 852, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_8
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 852, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_9
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1209, 941, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_S
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1477, 941, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_P
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 697, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_A
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 770, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                             // TONE_DTMF_B
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 852, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_C
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 1633, 941, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_DTMF_D
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 425, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_SUP_DIAL
+        { segments: { { duration: 500 , waveFreq: { 425, 0 }},
+                      { duration: 500, waveFreq: { 0 }},
+                         { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_SUP_BUSY
+        { segments: { { duration: 200, waveFreq: { 425, 0 } },
+                      { duration: 200, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_SUP_CONGESTION
+        { segments: { { duration: 200, waveFreq: { 425, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: 0,
+          repeatSegment: 0 },                              // TONE_SUP_RADIO_ACK
+        { segments: { { duration: 200, waveFreq: { 425, 0 }},
+                      { duration: 200, waveFreq: { 0 }},
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: 2,
+          repeatSegment: 0 },                              // TONE_SUP_RADIO_NOTAVAIL
+        { segments: { { duration: 330, waveFreq: { 950, 1400, 1800, 0 }},
+                      { duration: 1000, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_SUP_ERROR
+        { segments: { { duration: 200, waveFreq: { 425, 0 } },
+                      { duration: 600, waveFreq: { 0 } },
+                      { duration: 200, waveFreq: { 425, 0 } },
+                      { duration: 3000, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_SUP_CALL_WAITING
+        { segments: { { duration: 1000, waveFreq: { 425, 0 } },
+                      { duration: 4000, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_SUP_RINGTONE
+        { segments: { { duration: 40, waveFreq: { 400, 1200, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: 0,
+          repeatSegment: 0 },                              // TONE_PROP_BEEP
+        { segments: { { duration: 100, waveFreq: { 1200, 0 } },
+                      { duration: 100, waveFreq: { 0 }  },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: 1,
+          repeatSegment: 0 },                              // TONE_PROP_ACK
+        { segments: { { duration: 400, waveFreq: { 300, 400, 500, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: 0,
+          repeatSegment: 0 },                              // TONE_PROP_NACK
+        { segments: { { duration: 200, waveFreq: { 400, 1200, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: 0,
+          repeatSegment: 0 },                              // TONE_PROP_PROMPT
+        { segments: { { duration: 40, waveFreq: { 400, 1200, 0 } },
+                      { duration: 200, waveFreq: { 0 } },
+                      { duration: 40, waveFreq: { 400, 1200, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: 0,
+          repeatSegment: 0 },                             // TONE_PROP_BEEP2
+        { segments: { { duration: 250, waveFreq: { 440, 0 } },
+                      { duration: 250, waveFreq: { 620, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_SUP_INTERCEPT
+        { segments: { { duration: 250, waveFreq: { 440, 0 } },
+                      { duration: 250, waveFreq: { 620, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: 7,
+          repeatSegment: 0 },                             // TONE_SUP_INTERCEPT_ABBREV
+        { segments: { { duration: 250, waveFreq: { 480, 620, 0 } },
+                      { duration: 250, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: 7,
+          repeatSegment: 0 },                             // TONE_SUP_CONGESTION_ABBREV
+        { segments: { { duration: 100, waveFreq: { 350, 440, 0 } },
+                      { duration: 100, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: 2,
+          repeatSegment: 0 },                             // TONE_SUP_CONFIRM
+        { segments: { { duration: 100, waveFreq: { 480, 0 } },
+                      { duration: 100, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: 3,
+          repeatSegment: 0 },                              // TONE_SUP_PIP
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 350, 440, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_ANSI_DIAL
+        { segments: { { duration: 500, waveFreq: { 480, 620, 0 } },
+                      { duration: 500, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_ANSI_BUSY
+        { segments: { { duration: 250, waveFreq: { 480, 620, 0 } },
+                      { duration: 250, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_ANSI_CONGESTION
+        { segments: { { duration: 300, waveFreq: { 440, 0 } },
+                      { duration: 9700, waveFreq: { 0 } },
+                      { duration: 100, waveFreq: { 440, 0 } },
+                      { duration: 100, waveFreq: { 0 } },
+                      { duration: 100, waveFreq: { 440, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 1 },                              // TONE_ANSI_CALL_WAITING
+        { segments: { { duration: 2000, waveFreq: { 440, 480, 0 } },
+                      { duration: 4000, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_ANSI_RINGTONE
+        { segments: { { duration: ToneGenerator::TONEGEN_INF, waveFreq: { 400, 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_JAPAN_DIAL
+        { segments: { { duration: 500, waveFreq: { 400, 0 } },
+                      { duration: 500, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_JAPAN_BUSY
+        { segments: { { duration: 1000, waveFreq: { 400, 0 } },
+                      { duration: 2000, waveFreq: { 0 } },
+                      { duration: 0 , waveFreq: { 0 }}},
+          repeatCnt: ToneGenerator::TONEGEN_INF,
+          repeatSegment: 0 },                              // TONE_JAPAN_RADIO_ACK
+};
+
+// Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type
+// to actual tone for current region.
+const unsigned char ToneGenerator::sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES] = {
+        {   // ANSI
+            TONE_ANSI_DIAL,             // TONE_SUP_DIAL
+            TONE_ANSI_BUSY,             // TONE_SUP_BUSY
+            TONE_ANSI_CONGESTION,       // TONE_SUP_CONGESTION
+            TONE_SUP_RADIO_ACK,         // TONE_SUP_RADIO_ACK
+            TONE_SUP_RADIO_NOTAVAIL,    // TONE_SUP_RADIO_NOTAVAIL
+            TONE_SUP_ERROR,             // TONE_SUP_ERROR
+            TONE_ANSI_CALL_WAITING,     // TONE_SUP_CALL_WAITING
+            TONE_ANSI_RINGTONE          // TONE_SUP_RINGTONE
+        },
+        {   // JAPAN
+            TONE_JAPAN_DIAL,             // TONE_SUP_DIAL
+            TONE_JAPAN_BUSY,             // TONE_SUP_BUSY
+            TONE_SUP_CONGESTION,         // TONE_SUP_CONGESTION
+            TONE_JAPAN_RADIO_ACK,        // TONE_SUP_RADIO_ACK
+            TONE_SUP_RADIO_NOTAVAIL,     // TONE_SUP_RADIO_NOTAVAIL
+            TONE_SUP_ERROR,              // TONE_SUP_ERROR
+            TONE_SUP_CALL_WAITING,       // TONE_SUP_CALL_WAITING
+            TONE_SUP_RINGTONE            // TONE_SUP_RINGTONE
+        }
+};
+
 
 ////////////////////////////////////////////////////////////////////////////////
 //                           ToneGenerator class Implementation
@@ -105,6 +296,17 @@
     // Generate tone by chunks of 20 ms to keep cadencing precision
     mProcessSize = (mSamplingRate * 20) / 1000;
 
+    char value[PROPERTY_VALUE_MAX];
+    property_get("gsm.operator.iso-country", value, "");
+    if (strcmp(value,"us") == 0 ||
+        strcmp(value,"ca") == 0) {
+        mRegion = ANSI;
+    } else if (strcmp(value,"jp") == 0) {
+        mRegion = JAPAN;
+    } else {
+        mRegion = CEPT;
+    }
+
     if (initAudioTrack()) {
         LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
     } else {
@@ -170,7 +372,8 @@
     mLock.lock();
 
     // Get descriptor for requested tone
-    mpNewToneDesc = &toneDescriptors[toneType];
+    toneType = getToneForRegion(toneType);
+    mpNewToneDesc = &sToneDescriptors[toneType];
 
     if (mState == TONE_INIT) {
         if (prepareWave()) {
@@ -333,6 +536,7 @@
     ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user);
     short *lpOut = buffer->i16;
     unsigned int lNumSmp = buffer->size/sizeof(short);
+    const ToneDescriptor *lpToneDesc = lpToneGen->mpToneDesc;
 
     if (buffer->size == 0) return;
 
@@ -377,7 +581,7 @@
         
     
         // Exit if tone sequence is over
-        if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) {
+        if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
             if (lpToneGen->mState == TONE_PLAYING) {
                 lpToneGen->mState = TONE_STOPPING;            
             }
@@ -390,52 +594,64 @@
             LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
     
             lGenSmp = lReqSmp;
-    
-            if (lpToneGen->mCurSegment & 0x0001) {
-                // If odd segment,  OFF -> ON transition : reset wave generator
-                lWaveCmd = WaveGenerator::WAVEGEN_START;
-    
-                LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
-            } else {
-                // If even segment,  ON -> OFF transition : ramp volume down
+
+            // If segment,  ON -> OFF transition : ramp volume down
+            if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
                 lWaveCmd = WaveGenerator::WAVEGEN_STOP;
-    
+                unsigned int lFreqIdx = 0;
+                unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx];
+
+                while (lFrequency != 0) {
+                    WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency);
+                    lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
+                    lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
+                }
                 LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
             }
-    
-            // Pre increment segment index and handle loop if last segment reached
-            if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) {
+
+            // Go to next segment
+            lpToneGen->mCurSegment++;
+
+            // Handle loop if last segment reached
+            if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
                 LOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
     
                 // Pre increment loop count and restart if total count not reached. Stop sequence otherwise
-                if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) {
+                if (++lpToneGen->mCurCount <= lpToneDesc->repeatCnt) {
                     LOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
     
-                    lpToneGen->mCurSegment = 0;
+                    lpToneGen->mCurSegment = lpToneDesc->repeatSegment;
+                    if (lpToneDesc->segments[lpToneDesc->repeatSegment].waveFreq[0] != 0) {
+                        lWaveCmd = WaveGenerator::WAVEGEN_START;
+                    }
     
                     LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
                             (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
     
                 } else {
+                    lGenSmp = 0;
                     LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
-    
-                    // Cancel OFF->ON transition in case previous segment tone state was OFF
-                    if (!(lpToneGen->mCurSegment & 0x0001)) {
-                        lGenSmp = 0;
-                    }
                 }
             } else {
                 LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
                         (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
+                if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
+                    // If next segment is not silent,  OFF -> ON transition : reset wave generator
+                    lWaveCmd = WaveGenerator::WAVEGEN_START;
+
+                    LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+                } else {
+                    lGenSmp = 0;
+                }
             }
     
             // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
             lpToneGen->mNextSegSmp
-                    += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000;
+                    += (lpToneDesc->segments[lpToneGen->mCurSegment].duration * lpToneGen->mSamplingRate) / 1000;
     
         } else {
             // Inside a segment keep tone ON or OFF
-            if (lpToneGen->mCurSegment & 0x0001) {
+            if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] == 0) {
                 lGenSmp = 0;  // If odd segment, tone is currently OFF
             } else {
                 lGenSmp = lReqSmp;  // If event segment, tone is currently ON
@@ -444,11 +660,13 @@
     
         if (lGenSmp) {
             // If samples must be generated, call all active wave generators and acumulate waves in lpOut
-            unsigned int lWaveIdx;
+            unsigned int lFreqIdx = 0;
+            unsigned short lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[lFreqIdx];
     
-            for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) {
-                WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx];
+            while (lFrequency != 0) {
+                WaveGenerator *lpWaveGen = lpToneGen->mWaveGens.valueFor(lFrequency);
                 lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
+                lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
             }
         }
         
@@ -501,7 +719,7 @@
 //    Method:        ToneGenerator::prepareWave()
 //
 //    Description:    Prepare wave generators and reset tone sequencer state machine.
-//      mpNewToneDesc must have been initialized befoire calling this function.
+//      mpNewToneDesc must have been initialized before calling this function.
 //    Input:
 //        none
 //
@@ -510,40 +728,48 @@
 //
 ////////////////////////////////////////////////////////////////////////////////
 bool ToneGenerator::prepareWave() {
-    unsigned int lCnt = 0;
-    unsigned int lNumWaves;
+    unsigned int segmentIdx = 0;
 
     if (!mpNewToneDesc) {
         return false;
     }
+
     // Remove existing wave generators if any
     clearWaveGens();
 
     mpToneDesc = mpNewToneDesc;
 
-    // Get total number of sine waves: needed to adapt sine wave gain.
-    lNumWaves = numWaves();
-
-    // Instantiate as many wave generators as listed in descriptor
-    while (lCnt < lNumWaves) {
-        ToneGenerator::WaveGenerator *lpWaveGen =
-                new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate,
-                        mpToneDesc->waveFreq[lCnt],
-                        TONEGEN_GAIN/lNumWaves);
-        if (lpWaveGen == 0) {
-            goto prepareWave_exit;
+    while (mpToneDesc->segments[segmentIdx].duration) {
+        // Get total number of sine waves: needed to adapt sine wave gain.
+        unsigned int lNumWaves = numWaves(segmentIdx);
+        unsigned int freqIdx = 0;
+        unsigned int frequency = mpToneDesc->segments[segmentIdx].waveFreq[freqIdx];
+        while (frequency) {
+            // Instantiate a wave generator if  ot already done for this frequency
+            if (mWaveGens.indexOfKey(frequency) == NAME_NOT_FOUND) {
+                ToneGenerator::WaveGenerator *lpWaveGen =
+                        new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate,
+                                frequency,
+                                TONEGEN_GAIN/lNumWaves);
+                if (lpWaveGen == 0) {
+                    goto prepareWave_exit;
+                }
+                mWaveGens.add(frequency, lpWaveGen);
+            }
+            frequency = mpNewToneDesc->segments[segmentIdx].waveFreq[++freqIdx];
         }
-
-        mWaveGens.push(lpWaveGen);
-        LOGV("Create sine: %d\n", mpToneDesc->waveFreq[lCnt]);
-        lCnt++;
+        segmentIdx++;
     }
 
     // Initialize tone sequencer
     mTotalSmp = 0;
     mCurSegment = 0;
     mCurCount = 0;
-    mNextSegSmp = (mpToneDesc->segments[0] * mSamplingRate) / 1000;
+    if (mpToneDesc->segments[0].duration == TONEGEN_INF) {
+        mNextSegSmp = TONEGEN_INF;
+    } else{
+        mNextSegSmp = (mpToneDesc->segments[0].duration * mSamplingRate) / 1000;
+    }
 
     return true;
 
@@ -559,19 +785,22 @@
 //
 //    Method:        ToneGenerator::numWaves()
 //
-//    Description:    Count number of sine waves needed to generate tone (e.g 2 for DTMF).
+//    Description:    Count number of sine waves needed to generate a tone segment (e.g 2 for DTMF).
 //
 //    Input:
-//        none
+//        segmentIdx        tone segment index
 //
 //    Output:
 //        returned value:    nummber of sine waves
 //
 ////////////////////////////////////////////////////////////////////////////////
-unsigned int ToneGenerator::numWaves() {
+unsigned int ToneGenerator::numWaves(unsigned int segmentIdx) {
     unsigned int lCnt = 0;
 
-    while (mpToneDesc->waveFreq[lCnt]) {
+    if (mpToneDesc->segments[segmentIdx].duration) {
+        while (mpToneDesc->segments[segmentIdx].waveFreq[lCnt]) {
+            lCnt++;
+        }
         lCnt++;
     }
 
@@ -595,10 +824,38 @@
 void ToneGenerator::clearWaveGens() {
     LOGV("Clearing mWaveGens:");
 
-    while (!mWaveGens.isEmpty()) {
-        delete mWaveGens.top();
-        mWaveGens.pop();
+    for (size_t lIdx = 0; lIdx < mWaveGens.size(); lIdx++) {
+        delete mWaveGens.valueAt(lIdx);
     }
+    mWaveGens.clear();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Method:       ToneGenerator::getToneForRegion()
+//
+//    Description:  Get correct ringtone type according to current region.
+//      The corrected ring tone type is the tone descriptor index in sToneDescriptors[].
+//
+//    Input:
+//        none
+//
+//    Output:
+//        none
+//
+////////////////////////////////////////////////////////////////////////////////
+int ToneGenerator::getToneForRegion(int toneType) {
+    int regionTone;
+
+    if (mRegion == CEPT || toneType < FIRST_SUP_TONE || toneType > LAST_SUP_TONE) {
+        regionTone = toneType;
+    } else {
+        regionTone = sToneMappingTable[mRegion][toneType - FIRST_SUP_TONE];
+    }
+
+    LOGV("getToneForRegion, tone %d, region %d, regionTone %d", toneType, mRegion, regionTone);
+
+    return regionTone;
 }
 
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java
index da18e74..c75b96b 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/TonesAutoTest.java
@@ -74,7 +74,19 @@
               break;
           }
       }
-      
+
+      for (type = ToneGenerator.TONE_SUP_INTERCEPT;
+      type <= ToneGenerator.TONE_SUP_PIP; type++) {
+          if (toneGen.startTone(type)) {
+              Thread.sleep(5000);
+              toneGen.stopTone();
+              Thread.sleep(200);
+          } else {
+              result = false;
+              break;
+          }
+      }
+
       toneGen.release();
       return result;
     }
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 04cd53f..56caeea 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -58,7 +58,16 @@
     private SparseArray<HashSet<ServiceInfo>> mBackupParticipants
         = new SparseArray<HashSet<ServiceInfo>>();
     // set of backup services that have pending changes
-    private HashSet<ServiceInfo> mPendingBackups = new HashSet<ServiceInfo>();
+    private class BackupRequest {
+        public ServiceInfo service;
+        public boolean fullBackup;
+        
+        BackupRequest(ServiceInfo svc, boolean isFull) {
+            service = svc;
+            fullBackup = isFull;
+        }
+    }
+    private HashSet<BackupRequest> mPendingBackups = new HashSet<BackupRequest>();
     private final Object mQueueLock = new Object();
 
     private File mStateDir;
@@ -77,21 +86,21 @@
             case MSG_RUN_BACKUP:
             {
                 // snapshot the pending-backup set and work on that
-                HashSet<ServiceInfo> queue;
+                HashSet<BackupRequest> queue;
                 synchronized (mQueueLock) {
                     queue = mPendingBackups;
-                    mPendingBackups = new HashSet<ServiceInfo>();
+                    mPendingBackups = new HashSet<BackupRequest>();
                     // !!! TODO: start a new backup-queue journal file too
                 }
                 
                 // Walk the set of pending backups, setting up the relevant files and
                 // invoking the backup service in each participant
                 Intent backupIntent = new Intent(BackupService.SERVICE_ACTION);
-                for (ServiceInfo service : queue) {
+                for (BackupRequest request : queue) {
                     mBinding = true;
                     mTargetService = null;
 
-                    backupIntent.setClassName(service.packageName, service.name);
+                    backupIntent.setClassName(request.service.packageName, request.service.name);
                     Log.d(TAG, "binding to " + backupIntent);
                     if (mContext.bindService(backupIntent, this, 0)) {
                         synchronized (mBindSignaller) {
@@ -106,15 +115,22 @@
                             try {
                                 Log.d(TAG, "invoking doBackup() on " + backupIntent);
 
-                                File savedStateName = new File(mStateDir, service.packageName);
-                                File backupDataName = new File(mDataDir, service.packageName + ".data");
-                                File newStateName = new File(mStateDir, service.packageName + ".new");
+                                // !!! TODO right now these naming schemes limit applications to
+                                // one backup service per package
+                                File savedStateName = new File(mStateDir,
+                                        request.service.packageName);
+                                File backupDataName = new File(mDataDir,
+                                        request.service.packageName + ".data");
+                                File newStateName = new File(mStateDir,
+                                        request.service.packageName + ".new");
                                 
-                                ParcelFileDescriptor savedState =
-                                        ParcelFileDescriptor.open(savedStateName,
-                                                ParcelFileDescriptor.MODE_READ_ONLY |
-                                                ParcelFileDescriptor.MODE_CREATE);
-                                
+                                // In a full backup, we pass a null ParcelFileDescriptor as
+                                // the saved-state "file"
+                                ParcelFileDescriptor savedState = (request.fullBackup) ? null
+                                        : ParcelFileDescriptor.open(savedStateName,
+                                            ParcelFileDescriptor.MODE_READ_ONLY |
+                                            ParcelFileDescriptor.MODE_CREATE);
+
                                 backupDataName.delete();
                                 ParcelFileDescriptor backupData =
                                         ParcelFileDescriptor.open(backupDataName,
@@ -231,7 +247,7 @@
                     // packages associated with this uid
                     if (service.packageName.equals(packageName)) {
                         // add the caller to the set of pending backups
-                        if (mPendingBackups.add(service)) {
+                        if (mPendingBackups.add(new BackupRequest(service, false))) {
                             // !!! TODO: write to the pending-backup journal file in case of crash
                         }
                     }
@@ -240,9 +256,27 @@
                 // Schedule a backup pass in a few minutes.  As backup-eligible data
                 // keeps changing, continue to defer the backup pass until things
                 // settle down, to avoid extra overhead.
-                mBackupHandler.removeMessages(MSG_RUN_BACKUP);
                 mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, COLLECTION_INTERVAL);
             }
         }
     }
+
+    // Schedule a backup pass for a given package, even if the caller is not part of
+    // that uid or package itself.
+    public void scheduleFullBackup(String packageName) throws RemoteException {
+        // !!! TODO: protect with a signature-or-system permission?
+        HashSet<ServiceInfo> targets = new HashSet<ServiceInfo>();
+        synchronized (mQueueLock) {
+            int numKeys = mBackupParticipants.size();
+            for (int index = 0; index < numKeys; index++) {
+                int uid = mBackupParticipants.keyAt(index);
+                HashSet<ServiceInfo> servicesAtUid = mBackupParticipants.get(uid);
+                for (ServiceInfo service: servicesAtUid) {
+                    if (service.packageName.equals(packageName)) {
+                        mPendingBackups.add(new BackupRequest(service, true));
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 20c54fb..1ff0f7e 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -490,7 +490,7 @@
         if (null == language) {
             return; // no match possible
         }
-        language.toLowerCase();
+        language = language.toLowerCase();
         if (null == country) {
             country = "";
         }
@@ -503,13 +503,12 @@
                 final int N = locales.length;
                 String bestMatch = null;
                 for(int i = 0; i < N; i++) {
-                    if (locales[i]!=null && locales[i].length() >= 2 &&
+                    // only match full (lang + country) locales
+                    if (locales[i]!=null && locales[i].length() >= 5 &&
                             locales[i].substring(0,2).equals(language)) {
-                        if (locales[i].length() >= 5) {
-                            if (locales[i].substring(3,5).equals(country)) {
-                                bestMatch = locales[i];
-                                break;
-                            }
+                        if (locales[i].substring(3,5).equals(country)) {
+                            bestMatch = locales[i];
+                            break;
                         } else if (null == bestMatch) {
                             bestMatch = locales[i];
                         }
@@ -518,12 +517,8 @@
                 if (null != bestMatch) {
                     IActivityManager am = ActivityManagerNative.getDefault();
                     Configuration config = am.getConfiguration();
-                    if (bestMatch.length() >= 5) {
-                        config.locale = new Locale(bestMatch.substring(0,2),
-                                                   bestMatch.substring(3,5));
-                    } else {
-                        config.locale = new Locale(bestMatch.substring(0,2));
-                    }
+                    config.locale = new Locale(bestMatch.substring(0,2),
+                                               bestMatch.substring(3,5));
                     config.userSetLocale = true;
                     am.updateConfiguration(config);
                 }