diff options
Diffstat (limited to 'core/java')
70 files changed, 1712 insertions, 463 deletions
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index b459320..9712b2b 100644 --- a/core/java/android/app/AlertDialog.java +++ b/core/java/android/app/AlertDialog.java @@ -265,12 +265,22 @@ public class AlertDialog extends Dialog implements DialogInterface { public static class Builder { private final AlertController.AlertParams P; + private int mTheme; /** * Constructor using a context for this builder and the {@link AlertDialog} it creates. */ public Builder(Context context) { + this(context, com.android.internal.R.style.Theme_Dialog_Alert); + } + + /** + * Constructor using a context and theme for this builder and + * the {@link AlertDialog} it creates. + */ + public Builder(Context context, int theme) { P = new AlertController.AlertParams(context); + mTheme = theme; } /** @@ -783,7 +793,7 @@ public class AlertDialog extends Dialog implements DialogInterface { * to do and want this to be created and displayed. */ public AlertDialog create() { - final AlertDialog dialog = new AlertDialog(P.mContext); + final AlertDialog dialog = new AlertDialog(P.mContext, mTheme); P.apply(dialog.mAlert); dialog.setCancelable(P.mCancelable); dialog.setOnCancelListener(P.mOnCancelListener); diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java index 8f940d5..2382596 100644 --- a/core/java/android/app/ApplicationErrorReport.java +++ b/core/java/android/app/ApplicationErrorReport.java @@ -188,7 +188,7 @@ public class ApplicationErrorReport implements Parcelable { /** * Return activity in receiverPackage that handles ACTION_APP_ERROR. * - * @param pm PackageManager isntance + * @param pm PackageManager instance * @param errorPackage package which caused the error * @param receiverPackage candidate package to receive the error * @return activity component within receiverPackage which handles diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 50ec34f..f535d61 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -53,7 +53,6 @@ import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; -import android.content.pm.PackageParser.Package; import android.content.res.AssetManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; @@ -86,11 +85,9 @@ import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.StatFs; import android.os.Vibrator; import android.os.FileUtils.FileStatus; import android.os.storage.StorageManager; -import android.provider.Settings; import android.telephony.TelephonyManager; import android.text.ClipboardManager; import android.util.AndroidRuntimeException; @@ -264,18 +261,18 @@ class ContextImpl extends Context { public Looper getMainLooper() { return mMainThread.getLooper(); } - + @Override public Context getApplicationContext() { return (mPackageInfo != null) ? mPackageInfo.getApplication() : mMainThread.getApplication(); } - + @Override public void setTheme(int resid) { mThemeResource = resid; } - + @Override public Resources.Theme getTheme() { if (mTheme == null) { @@ -441,7 +438,7 @@ class ContextImpl extends Context { } if (!mFilesDir.exists()) { if(!mFilesDir.mkdirs()) { - Log.w(TAG, "Unable to create files directory"); + Log.w(TAG, "Unable to create files directory " + mFilesDir.getPath()); return null; } FileUtils.setPermissions( @@ -452,7 +449,7 @@ class ContextImpl extends Context { return mFilesDir; } } - + @Override public File getExternalFilesDir(String type) { synchronized (mSync) { @@ -484,7 +481,7 @@ class ContextImpl extends Context { return dir; } } - + @Override public File getCacheDir() { synchronized (mSync) { @@ -504,7 +501,7 @@ class ContextImpl extends Context { } return mCacheDir; } - + @Override public File getExternalCacheDir() { synchronized (mSync) { @@ -526,7 +523,7 @@ class ContextImpl extends Context { return mExternalCacheDir; } } - + @Override public File getFileStreamPath(String name) { return makeFilename(getFilesDir(), name); @@ -567,7 +564,7 @@ class ContextImpl extends Context { return (list != null) ? list : EMPTY_FILE_LIST; } - + private File getDatabasesDir() { synchronized (mSync) { if (mDatabasesDir == null) { @@ -579,7 +576,7 @@ class ContextImpl extends Context { return mDatabasesDir; } } - + @Override public Drawable getWallpaper() { return getWallpaperManager().getDrawable(); @@ -647,7 +644,7 @@ class ContextImpl extends Context { } catch (RemoteException e) { } } - + @Override public void sendBroadcast(Intent intent) { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); @@ -1571,15 +1568,15 @@ class ContextImpl extends Context { final void setActivityToken(IBinder token) { mActivityToken = token; } - + final void setOuterContext(Context context) { mOuterContext = context; } - + final Context getOuterContext() { return mOuterContext; } - + final IBinder getActivityToken() { return mActivityToken; } @@ -1657,7 +1654,7 @@ class ContextImpl extends Context { public boolean releaseProvider(IContentProvider provider) { return mMainThread.releaseProvider(provider); } - + private final ActivityThread mMainThread; } @@ -1690,7 +1687,7 @@ class ContextImpl extends Context { throw new RuntimeException("Package manager has died", e); } } - + @Override public String[] canonicalToCurrentPackageNames(String[] names) { try { @@ -1699,7 +1696,7 @@ class ContextImpl extends Context { throw new RuntimeException("Package manager has died", e); } } - + @Override public Intent getLaunchIntentForPackage(String packageName) { // First see if the package has an INFO activity; the existence of @@ -1721,8 +1718,9 @@ class ContextImpl extends Context { if (resolveInfo == null) { return null; } - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setClassName(packageName, resolveInfo.activityInfo.name); + Intent intent = new Intent(intentToResolve); + intent.setClassName(resolveInfo.activityInfo.applicationInfo.packageName, + resolveInfo.activityInfo.name); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); return intent; } @@ -1888,7 +1886,7 @@ class ContextImpl extends Context { throw new RuntimeException("Package manager has died", e); } } - + @Override public boolean hasSystemFeature(String name) { try { @@ -1897,7 +1895,7 @@ class ContextImpl extends Context { throw new RuntimeException("Package manager has died", e); } } - + @Override public int checkPermission(String permName, String pkgName) { try { @@ -1969,9 +1967,9 @@ class ContextImpl extends Context { throw new RuntimeException("Package manager has died", e); } } - + @Override - public int getUidForSharedUser(String sharedUserName) + public int getUidForSharedUser(String sharedUserName) throws NameNotFoundException { try { int uid = mPM.getUidForSharedUser(sharedUserName); @@ -2375,7 +2373,7 @@ class ContextImpl extends Context { } } } - + private static final class ResourceName { final String packageName; final int iconId; @@ -2547,7 +2545,7 @@ class ContextImpl extends Context { } } @Override - public void clearApplicationUserData(String packageName, + public void clearApplicationUserData(String packageName, IPackageDataObserver observer) { try { mPM.clearApplicationUserData(packageName, observer); @@ -2556,7 +2554,7 @@ class ContextImpl extends Context { } } @Override - public void deleteApplicationCacheFiles(String packageName, + public void deleteApplicationCacheFiles(String packageName, IPackageDataObserver observer) { try { mPM.deleteApplicationCacheFiles(packageName, observer); @@ -2581,9 +2579,9 @@ class ContextImpl extends Context { // Should never happen! } } - + @Override - public void getPackageSizeInfo(String packageName, + public void getPackageSizeInfo(String packageName, IPackageStatsObserver observer) { try { mPM.getPackageSizeInfo(packageName, observer); @@ -2628,7 +2626,7 @@ class ContextImpl extends Context { // Should never happen! } } - + @Override public void replacePreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) { @@ -2647,7 +2645,7 @@ class ContextImpl extends Context { // Should never happen! } } - + @Override public int getPreferredActivities(List<IntentFilter> outFilters, List<ComponentName> outActivities, String packageName) { @@ -2658,7 +2656,7 @@ class ContextImpl extends Context { } return 0; } - + @Override public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags) { @@ -2688,7 +2686,7 @@ class ContextImpl extends Context { // Should never happen! } } - + @Override public int getApplicationEnabledSetting(String packageName) { try { diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java index 009671f..8ba480d 100644 --- a/core/java/android/app/DatePickerDialog.java +++ b/core/java/android/app/DatePickerDialog.java @@ -21,7 +21,6 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.os.Bundle; import android.text.TextUtils.TruncateAt; -import android.text.format.DateFormat; import android.view.LayoutInflater; import android.view.View; import android.widget.DatePicker; @@ -39,13 +38,13 @@ import java.util.Calendar; * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-datepicker.html">Date Picker * tutorial</a>.</p> */ -public class DatePickerDialog extends AlertDialog implements OnClickListener, +public class DatePickerDialog extends AlertDialog implements OnClickListener, OnDateChangedListener { private static final String YEAR = "year"; private static final String MONTH = "month"; private static final String DAY = "day"; - + private final DatePicker mDatePicker; private final OnDateSetListener mCallBack; private final Calendar mCalendar; @@ -83,7 +82,7 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener, int year, int monthOfYear, int dayOfMonth) { - this(context, com.android.internal.R.style.Theme_Dialog_Alert, + this(context, com.android.internal.R.style.Theme_Dialog_Alert, callBack, year, monthOfYear, dayOfMonth); } @@ -109,17 +108,17 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener, mInitialDay = dayOfMonth; DateFormatSymbols symbols = new DateFormatSymbols(); mWeekDays = symbols.getShortWeekdays(); - + mTitleDateFormat = java.text.DateFormat. getDateInstance(java.text.DateFormat.FULL); mCalendar = Calendar.getInstance(); updateTitle(mInitialYear, mInitialMonth, mInitialDay); - - setButton(context.getText(R.string.date_time_set), this); - setButton2(context.getText(R.string.cancel), (OnClickListener) null); + + setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this); + setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel), (OnClickListener) null); setIcon(R.drawable.ic_dialog_time); - - LayoutInflater inflater = + + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.date_picker_dialog, null); setView(view); @@ -139,20 +138,20 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener, title.setSingleLine(); title.setEllipsize(TruncateAt.END); } - + public void onClick(DialogInterface dialog, int which) { if (mCallBack != null) { mDatePicker.clearFocus(); - mCallBack.onDateSet(mDatePicker, mDatePicker.getYear(), + mCallBack.onDateSet(mDatePicker, mDatePicker.getYear(), mDatePicker.getMonth(), mDatePicker.getDayOfMonth()); } } - + public void onDateChanged(DatePicker view, int year, int month, int day) { updateTitle(year, month, day); } - + public void updateDate(int year, int monthOfYear, int dayOfMonth) { mInitialYear = year; mInitialMonth = monthOfYear; @@ -166,7 +165,7 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener, mCalendar.set(Calendar.DAY_OF_MONTH, day); setTitle(mTitleDateFormat.format(mCalendar.getTime())); } - + @Override public Bundle onSaveInstanceState() { Bundle state = super.onSaveInstanceState(); @@ -175,7 +174,7 @@ public class DatePickerDialog extends AlertDialog implements OnClickListener, state.putInt(DAY, mDatePicker.getDayOfMonth()); return state; } - + @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 1fae516..e3242c1 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -39,13 +39,17 @@ import android.util.Log; * </ul> * * <p> - * Each of the notify methods takes an int id parameter. This id identifies - * this notification from your app to the system, so that id should be unique - * within your app. If you call one of the notify methods with an id that is - * currently active and a new set of notification parameters, it will be - * updated. For example, if you pass a new status bar icon, the old icon in - * the status bar will be replaced with the new one. This is also the same - * id you pass to the {@link #cancel} method to clear this notification. + * Each of the notify methods takes an int id parameter and optionally a + * {@link String} tag parameter, which may be {@code null}. These parameters + * are used to form a pair (tag, id), or ({@code null}, id) if tag is + * unspecified. This pair identifies this notification from your app to the + * system, so that pair should be unique within your app. If you call one + * of the notify methods with a (tag, id) pair that is currently active and + * a new set of notification parameters, it will be updated. For example, + * if you pass a new status bar icon, the old icon in the status bar will + * be replaced with the new one. This is also the same tag and id you pass + * to the {@link #cancel(int)} or {@link #cancel(String, int)} method to clear + * this notification. * * <p> * You do not instantiate this class directly; instead, retrieve it through @@ -94,12 +98,11 @@ public class NotificationManager /** * Persistent notification on the status bar, * - * @param tag An string identifier for this notification unique within your - * application. + * @param tag A string identifier for this notification. May be {@code null}. + * @param id An identifier for this notification. The pair (tag, id) must be unique + * within your application. * @param notification A {@link Notification} object describing how to * notify the user, other than the view you're providing. Must not be null. - * @return the id of the notification that is associated with the string identifier that - * can be used to cancel the notification */ public void notify(String tag, int id, Notification notification) { diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index cd22fa1..4eb89ae 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -1109,6 +1109,9 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS * @return true if a successful launch, false if could not (e.g. bad position). */ protected boolean launchSuggestion(int position, int actionKey, String actionMsg) { + if (mSuggestionsAdapter == null) { + return false; + } Cursor c = mSuggestionsAdapter.getCursor(); if ((c != null) && c.moveToPosition(position)) { @@ -1133,7 +1136,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS try { // If the intent was created from a suggestion, it will always have an explicit // component here. - Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toURI()); + Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toUri(0)); getContext().startActivity(intent); // If the search switches to a different activity, // SearchDialogWrapper#performActivityResuming diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java index 62d3f7d..521d41c 100644 --- a/core/java/android/app/TimePickerDialog.java +++ b/core/java/android/app/TimePickerDialog.java @@ -36,7 +36,7 @@ import java.util.Calendar; * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-timepicker.html">Time Picker * tutorial</a>.</p> */ -public class TimePickerDialog extends AlertDialog implements OnClickListener, +public class TimePickerDialog extends AlertDialog implements OnClickListener, OnTimeChangedListener { /** @@ -56,12 +56,12 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener, private static final String HOUR = "hour"; private static final String MINUTE = "minute"; private static final String IS_24_HOUR = "is24hour"; - + private final TimePicker mTimePicker; private final OnTimeSetListener mCallback; private final Calendar mCalendar; private final java.text.DateFormat mDateFormat; - + int mInitialHourOfDay; int mInitialMinute; boolean mIs24HourView; @@ -101,12 +101,13 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener, mDateFormat = DateFormat.getTimeFormat(context); mCalendar = Calendar.getInstance(); updateTitle(mInitialHourOfDay, mInitialMinute); - - setButton(context.getText(R.string.date_time_set), this); - setButton2(context.getText(R.string.cancel), (OnClickListener) null); + + setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this); + setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel), + (OnClickListener) null); setIcon(R.drawable.ic_dialog_time); - - LayoutInflater inflater = + + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.time_picker_dialog, null); setView(view); @@ -118,11 +119,11 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener, mTimePicker.setIs24HourView(mIs24HourView); mTimePicker.setOnTimeChangedListener(this); } - + public void onClick(DialogInterface dialog, int which) { if (mCallback != null) { mTimePicker.clearFocus(); - mCallback.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(), + mCallback.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(), mTimePicker.getCurrentMinute()); } } @@ -130,7 +131,7 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener, public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { updateTitle(hourOfDay, minute); } - + public void updateTime(int hourOfDay, int minutOfHour) { mTimePicker.setCurrentHour(hourOfDay); mTimePicker.setCurrentMinute(minutOfHour); @@ -141,7 +142,7 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener, mCalendar.set(Calendar.MINUTE, minute); setTitle(mDateFormat.format(mCalendar.getTime())); } - + @Override public Bundle onSaveInstanceState() { Bundle state = super.onSaveInstanceState(); @@ -150,7 +151,7 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener, state.putBoolean(IS_24_HOUR, mTimePicker.is24HourView()); return state; } - + @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index e455a59..92b7cf5 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -235,8 +235,13 @@ public class WallpaperManager { if (width <= 0 || height <= 0) { // Degenerate case: no size requested, just load // bitmap as-is. - Bitmap bm = BitmapFactory.decodeFileDescriptor( - fd.getFileDescriptor(), null, null); + Bitmap bm = null; + try { + bm = BitmapFactory.decodeFileDescriptor( + fd.getFileDescriptor(), null, null); + } catch (OutOfMemoryError e) { + Log.w(TAG, "Can't decode file", e); + } try { fd.close(); } catch (IOException e) { @@ -277,7 +282,12 @@ public class WallpaperManager { if (width <= 0 || height <= 0) { // Degenerate case: no size requested, just load // bitmap as-is. - Bitmap bm = BitmapFactory.decodeStream(is, null, null); + Bitmap bm = null; + try { + bm = BitmapFactory.decodeStream(is, null, null); + } catch (OutOfMemoryError e) { + Log.w(TAG, "Can't decode stream", e); + } try { is.close(); } catch (IOException e) { diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index d4ce6a1..d2ab85e 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -22,7 +22,6 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.DisplayMetrics; -import android.util.Log; import android.util.TypedValue; import android.widget.RemoteViews; @@ -149,7 +148,7 @@ public class AppWidgetManager { * instances as possible.</td> * </tr> * </table> - * + * * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) */ public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE"; @@ -163,7 +162,7 @@ public class AppWidgetManager { /** * Sent when an instance of an AppWidget is removed from the last host. - * + * * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context) */ public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED"; @@ -172,7 +171,7 @@ public class AppWidgetManager { * Sent when an instance of an AppWidget is added to a host for the first time. * This broadcast is sent at boot time if there is a AppWidgetHost installed with * an instance for this provider. - * + * * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context) */ public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED"; @@ -183,20 +182,21 @@ public class AppWidgetManager { * @see AppWidgetProviderInfo */ public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider"; - + /** * Field for the manifest meta-data tag used to indicate any previous name for the * app widget receiver. * * @see AppWidgetProviderInfo - * + * * @hide Pending API approval */ public static final String META_DATA_APPWIDGET_OLD_NAME = "android.appwidget.oldName"; - static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache = new WeakHashMap(); + static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache = + new WeakHashMap<Context, WeakReference<AppWidgetManager>>(); static IAppWidgetService sService; - + Context mContext; private DisplayMetrics mDisplayMetrics; @@ -219,7 +219,7 @@ public class AppWidgetManager { } if (result == null) { result = new AppWidgetManager(context); - sManagerCache.put(context, new WeakReference(result)); + sManagerCache.put(context, new WeakReference<AppWidgetManager>(result)); } return result; } @@ -310,7 +310,7 @@ public class AppWidgetManager { AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId); if (info != null) { // Converting complex to dp. - info.minWidth = + info.minWidth = TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics); info.minHeight = TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics); @@ -344,7 +344,7 @@ public class AppWidgetManager { /** * Get the list of appWidgetIds that have been bound to the given AppWidget * provider. - * + * * @param provider The {@link android.content.BroadcastReceiver} that is the * AppWidget provider to find appWidgetIds for. */ diff --git a/core/java/android/bluetooth/AtCommandHandler.java b/core/java/android/bluetooth/AtCommandHandler.java index 8de2133..6deab34 100644 --- a/core/java/android/bluetooth/AtCommandHandler.java +++ b/core/java/android/bluetooth/AtCommandHandler.java @@ -73,7 +73,7 @@ public abstract class AtCommandHandler { * least one element in this array. * @return The result of this command. */ - // Typically used to set this paramter + // Typically used to set this parameter public AtCommandResult handleSetCommand(Object[] args) { return new AtCommandResult(AtCommandResult.ERROR); } @@ -83,11 +83,12 @@ public abstract class AtCommandHandler { * Test commands are part of the Extended command syntax, and are typically * used to request an indication of the range of legal values that "FOO" * can take.<p> - * By defualt we return an OK result, to indicate that this command is at + * By default we return an OK result, to indicate that this command is at * least recognized.<p> * @return The result of this command. */ public AtCommandResult handleTestCommand() { return new AtCommandResult(AtCommandResult.OK); } + } diff --git a/core/java/android/bluetooth/BluetoothAssignedNumbers.java b/core/java/android/bluetooth/BluetoothAssignedNumbers.java new file mode 100644 index 0000000..55bc814 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothAssignedNumbers.java @@ -0,0 +1,523 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +/** + * Bluetooth Assigned Numbers. + * <p> + * For now we only include Company ID values. + * @see <a href="https://www.bluetooth.org/technical/assignednumbers/identifiers.htm"> + * The Official Bluetooth SIG Member Website | Company Identifiers</a> + * + * @hide + */ +public class BluetoothAssignedNumbers { + + //// Bluetooth SIG Company ID values + + /* + * Ericsson Technology Licensing. + */ + public static final int ERICSSON_TECHNOLOGY = 0x0000; + + /* + * Nokia Mobile Phones. + */ + public static final int NOKIA_MOBILE_PHONES = 0x0001; + + /* + * Intel Corp. + */ + public static final int INTEL = 0x0002; + + /* + * IBM Corp. + */ + public static final int IBM = 0x0003; + + /* + * Toshiba Corp. + */ + public static final int TOSHIBA = 0x0004; + + /* + * 3Com. + */ + public static final int THREECOM = 0x0005; + + /* + * Microsoft. + */ + public static final int MICROSOFT = 0x0006; + + /* + * Lucent. + */ + public static final int LUCENT = 0x0007; + + /* + * Motorola. + */ + public static final int MOTOROLA = 0x0008; + + /* + * Infineon Technologies AG. + */ + public static final int INFINEON_TECHNOLOGIES = 0x0009; + + /* + * Cambridge Silicon Radio. + */ + public static final int CAMBRIDGE_SILICON_RADIO = 0x000A; + + /* + * Silicon Wave. + */ + public static final int SILICON_WAVE = 0x000B; + + /* + * Digianswer A/S. + */ + public static final int DIGIANSWER = 0x000C; + + /* + * Texas Instruments Inc. + */ + public static final int TEXAS_INSTRUMENTS = 0x000D; + + /* + * Parthus Technologies Inc. + */ + public static final int PARTHUS_TECHNOLOGIES = 0x000E; + + /* + * Broadcom Corporation. + */ + public static final int BROADCOM = 0x000F; + + /* + * Mitel Semiconductor. + */ + public static final int MITEL_SEMICONDUCTOR = 0x0010; + + /* + * Widcomm, Inc. + */ + public static final int WIDCOMM = 0x0011; + + /* + * Zeevo, Inc. + */ + public static final int ZEEVO = 0x0012; + + /* + * Atmel Corporation. + */ + public static final int ATMEL = 0x0013; + + /* + * Mitsubishi Electric Corporation. + */ + public static final int MITSUBISHI_ELECTRIC = 0x0014; + + /* + * RTX Telecom A/S. + */ + public static final int RTX_TELECOM = 0x0015; + + /* + * KC Technology Inc. + */ + public static final int KC_TECHNOLOGY = 0x0016; + + /* + * Newlogic. + */ + public static final int NEWLOGIC = 0x0017; + + /* + * Transilica, Inc. + */ + public static final int TRANSILICA = 0x0018; + + /* + * Rohde & Schwarz GmbH & Co. KG. + */ + public static final int ROHDE_AND_SCHWARZ = 0x0019; + + /* + * TTPCom Limited. + */ + public static final int TTPCOM = 0x001A; + + /* + * Signia Technologies, Inc. + */ + public static final int SIGNIA_TECHNOLOGIES = 0x001B; + + /* + * Conexant Systems Inc. + */ + public static final int CONEXANT_SYSTEMS = 0x001C; + + /* + * Qualcomm. + */ + public static final int QUALCOMM = 0x001D; + + /* + * Inventel. + */ + public static final int INVENTEL = 0x001E; + + /* + * AVM Berlin. + */ + public static final int AVM_BERLIN = 0x001F; + + /* + * BandSpeed, Inc. + */ + public static final int BANDSPEED = 0x0020; + + /* + * Mansella Ltd. + */ + public static final int MANSELLA = 0x0021; + + /* + * NEC Corporation. + */ + public static final int NEC = 0x0022; + + /* + * WavePlus Technology Co., Ltd. + */ + public static final int WAVEPLUS_TECHNOLOGY = 0x0023; + + /* + * Alcatel. + */ + public static final int ALCATEL = 0x0024; + + /* + * Philips Semiconductors. + */ + public static final int PHILIPS_SEMICONDUCTORS = 0x0025; + + /* + * C Technologies. + */ + public static final int C_TECHNOLOGIES = 0x0026; + + /* + * Open Interface. + */ + public static final int OPEN_INTERFACE = 0x0027; + + /* + * R F Micro Devices. + */ + public static final int RF_MICRO_DEVICES = 0x0028; + + /* + * Hitachi Ltd. + */ + public static final int HITACHI = 0x0029; + + /* + * Symbol Technologies, Inc. + */ + public static final int SYMBOL_TECHNOLOGIES = 0x002A; + + /* + * Tenovis. + */ + public static final int TENOVIS = 0x002B; + + /* + * Macronix International Co. Ltd. + */ + public static final int MACRONIX = 0x002C; + + /* + * GCT Semiconductor. + */ + public static final int GCT_SEMICONDUCTOR = 0x002D; + + /* + * Norwood Systems. + */ + public static final int NORWOOD_SYSTEMS = 0x002E; + + /* + * MewTel Technology Inc. + */ + public static final int MEWTEL_TECHNOLOGY = 0x002F; + + /* + * ST Microelectronics. + */ + public static final int ST_MICROELECTRONICS = 0x0030; + + /* + * Synopsys. + */ + public static final int SYNOPSYS = 0x0031; + + /* + * Red-M (Communications) Ltd. + */ + public static final int RED_M = 0x0032; + + /* + * Commil Ltd. + */ + public static final int COMMIL = 0x0033; + + /* + * Computer Access Technology Corporation (CATC). + */ + public static final int CATC = 0x0034; + + /* + * Eclipse (HQ Espana) S.L. + */ + public static final int ECLIPSE = 0x0035; + + /* + * Renesas Technology Corp. + */ + public static final int RENESAS_TECHNOLOGY = 0x0036; + + /* + * Mobilian Corporation. + */ + public static final int MOBILIAN_CORPORATION = 0x0037; + + /* + * Terax. + */ + public static final int TERAX = 0x0038; + + /* + * Integrated System Solution Corp. + */ + public static final int INTEGRATED_SYSTEM_SOLUTION = 0x0039; + + /* + * Matsushita Electric Industrial Co., Ltd. + */ + public static final int MATSUSHITA_ELECTRIC = 0x003A; + + /* + * Gennum Corporation. + */ + public static final int GENNUM = 0x003B; + + /* + * Research In Motion. + */ + public static final int RESEARCH_IN_MOTION = 0x003C; + + /* + * IPextreme, Inc. + */ + public static final int IPEXTREME = 0x003D; + + /* + * Systems and Chips, Inc. + */ + public static final int SYSTEMS_AND_CHIPS = 0x003E; + + /* + * Bluetooth SIG, Inc. + */ + public static final int BLUETOOTH_SIG = 0x003F; + + /* + * Seiko Epson Corporation. + */ + public static final int SEIKO_EPSON = 0x0040; + + /* + * Integrated Silicon Solution Taiwan, Inc. + */ + public static final int INTEGRATED_SILICON_SOLUTION = 0x0041; + + /* + * CONWISE Technology Corporation Ltd. + */ + public static final int CONWISE_TECHNOLOGY = 0x0042; + + /* + * PARROT SA. + */ + public static final int PARROT = 0x0043; + + /* + * Socket Mobile. + */ + public static final int SOCKET_MOBILE = 0x0044; + + /* + * Atheros Communications, Inc. + */ + public static final int ATHEROS_COMMUNICATIONS = 0x0045; + + /* + * MediaTek, Inc. + */ + public static final int MEDIATEK = 0x0046; + + /* + * Bluegiga. + */ + public static final int BLUEGIGA = 0x0047; + + /* + * Marvell Technology Group Ltd. + */ + public static final int MARVELL = 0x0048; + + /* + * 3DSP Corporation. + */ + public static final int THREE_DSP = 0x0049; + + /* + * Accel Semiconductor Ltd. + */ + public static final int ACCEL_SEMICONDUCTOR = 0x004A; + + /* + * Continental Automotive Systems. + */ + public static final int CONTINENTAL_AUTOMOTIVE = 0x004B; + + /* + * Apple, Inc. + */ + public static final int APPLE = 0x004C; + + /* + * Staccato Communications, Inc. + */ + public static final int STACCATO_COMMUNICATIONS = 0x004D; + + /* + * Avago Technologies. + */ + public static final int AVAGO = 0x004E; + + /* + * APT Licensing Ltd. + */ + public static final int APT_LICENSING = 0x004F; + + /* + * SiRF Technology, Inc. + */ + public static final int SIRF_TECHNOLOGY = 0x0050; + + /* + * Tzero Technologies, Inc. + */ + public static final int TZERO_TECHNOLOGIES = 0x0051; + + /* + * J&M Corporation. + */ + public static final int J_AND_M = 0x0052; + + /* + * Free2move AB. + */ + public static final int FREE2MOVE = 0x0053; + + /* + * 3DiJoy Corporation. + */ + public static final int THREE_DIJOY = 0x0054; + + /* + * Plantronics, Inc. + */ + public static final int PLANTRONICS = 0x0055; + + /* + * Sony Ericsson Mobile Communications. + */ + public static final int SONY_ERICSSON = 0x0056; + + /* + * Harman International Industries, Inc. + */ + public static final int HARMAN_INTERNATIONAL = 0x0057; + + /* + * Vizio, Inc. + */ + public static final int VIZIO = 0x0058; + + /* + * Nordic Semiconductor ASA. + */ + public static final int NORDIC_SEMICONDUCTOR = 0x0059; + + /* + * EM Microelectronic-Marin SA. + */ + public static final int EM_MICROELECTRONIC_MARIN = 0x005A; + + /* + * Ralink Technology Corporation. + */ + public static final int RALINK_TECHNOLOGY = 0x005B; + + /* + * Belkin International, Inc. + */ + public static final int BELKIN_INTERNATIONAL = 0x005C; + + /* + * Realtek Semiconductor Corporation. + */ + public static final int REALTEK_SEMICONDUCTOR = 0x005D; + + /* + * Stonestreet One, LLC. + */ + public static final int STONESTREET_ONE = 0x005E; + + /* + * Wicentric, Inc. + */ + public static final int WICENTRIC = 0x005F; + + /* + * RivieraWaves S.A.S. + */ + public static final int RIVIERAWAVES = 0x0060; + + /* + * You can't instantiate one of these. + */ + private BluetoothAssignedNumbers() { + } + +} diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 197b022..da1aa45 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -85,6 +85,43 @@ public final class BluetoothHeadset { "android.bluetooth.headset.extra.DISCONNECT_INITIATOR"; /** + * Broadcast Action: Indicates a headset has posted a vendor-specific event. + * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, + * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD}, and + * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS}. + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT = + "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT"; + + /** + * A String extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} + * intents that contains the name of the vendor-specific command. + */ + public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD = + "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD"; + + /** + * An int extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} + * intents that contains the Company ID of the vendor defining the vendor-specific + * command. + * @see <a href="https://www.bluetooth.org/Technical/AssignedNumbers/identifiers.htm"> + * Bluetooth SIG Assigned Numbers - Company Identifiers</a> + */ + public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID = + "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID"; + + /** + * A Parcelable String array extra field in + * {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} intents that contains + * the arguments to the vendor-specific command. + */ + public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS = + "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_ARGS"; + + + /** * TODO(API release): Consider incorporating as new state in * HEADSET_STATE_CHANGED */ diff --git a/core/java/android/bluetooth/HeadsetBase.java b/core/java/android/bluetooth/HeadsetBase.java index 22495a7..9ef2eb5 100644 --- a/core/java/android/bluetooth/HeadsetBase.java +++ b/core/java/android/bluetooth/HeadsetBase.java @@ -74,8 +74,8 @@ public final class HeadsetBase { private native void cleanupNativeDataNative(); - public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device, - int rfcommChannel) { + public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, + BluetoothDevice device, int rfcommChannel) { mDirection = DIRECTION_OUTGOING; mConnectTimestamp = System.currentTimeMillis(); mAdapter = adapter; @@ -89,9 +89,10 @@ public final class HeadsetBase { initializeNativeDataNative(-1); } - /* Create from an already existing rfcomm connection */ - public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, BluetoothDevice device, - int socketFd, int rfcommChannel, Handler handler) { + /* Create from an existing rfcomm connection */ + public HeadsetBase(PowerManager pm, BluetoothAdapter adapter, + BluetoothDevice device, + int socketFd, int rfcommChannel, Handler handler) { mDirection = DIRECTION_INCOMING; mConnectTimestamp = System.currentTimeMillis(); mAdapter = adapter; @@ -142,8 +143,9 @@ public final class HeadsetBase { */ protected void initializeAtParser() { mAtParser = new AtParser(); - //TODO(): Get rid of this as there are no parsers registered. But because of dependencies, - //it needs to be done as part of refactoring HeadsetBase and BluetoothHandsfree + + //TODO(): Get rid of this as there are no parsers registered. But because of dependencies + // it needs to be done as part of refactoring HeadsetBase and BluetoothHandsfree } public AtParser getAtParser() { @@ -159,8 +161,7 @@ public final class HeadsetBase { String input = readNative(500); if (input != null) { handleInput(input); - } - else { + } else { last_read_error = getLastReadStatusNative(); if (last_read_error != 0) { Log.i(TAG, "headset read error " + last_read_error); @@ -179,8 +180,6 @@ public final class HeadsetBase { mEventThread.start(); } - - private native String readNative(int timeout_ms); private native int getLastReadStatusNative(); diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 81ff414..d16b3d8 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -201,6 +201,7 @@ public abstract class ContentResolver { } catch (RemoteException e) { return null; } catch (java.lang.Exception e) { + Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")"); return null; } finally { releaseProvider(provider); @@ -216,6 +217,9 @@ public abstract class ContentResolver { return type; } catch (RemoteException e) { return null; + } catch (java.lang.Exception e) { + Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")"); + return null; } } @@ -1394,9 +1398,11 @@ public abstract class ContentResolver { @Override protected void finalize() throws Throwable { + // TODO: integrate CloseGuard support. try { if(!mCloseFlag) { - ContentResolver.this.releaseProvider(mContentProvider); + Log.w(TAG, "Cursor finalized without prior close()"); + close(); } } finally { super.finalize(); diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java index 72ec469..841c8f4 100644 --- a/core/java/android/content/UriMatcher.java +++ b/core/java/android/content/UriMatcher.java @@ -25,8 +25,8 @@ import java.util.regex.Pattern; /** Utility class to aid in matching URIs in content providers. -<p>To use this class, build up a tree of UriMatcher objects. -Typically, it looks something like this: +<p>To use this class, build up a tree of <code>UriMatcher</code> objects. +For example: <pre> private static final int PEOPLE = 1; private static final int PEOPLE_ID = 2; @@ -48,36 +48,35 @@ Typically, it looks something like this: private static final int CALLS_ID = 12; private static final int CALLS_FILTER = 15; - private static final UriMatcher sURIMatcher = new UriMatcher(); + private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { - sURIMatcher.addURI("contacts", "/people", PEOPLE); - sURIMatcher.addURI("contacts", "/people/#", PEOPLE_ID); - sURIMatcher.addURI("contacts", "/people/#/phones", PEOPLE_PHONES); - sURIMatcher.addURI("contacts", "/people/#/phones/#", PEOPLE_PHONES_ID); - sURIMatcher.addURI("contacts", "/people/#/contact_methods", PEOPLE_CONTACTMETHODS); - sURIMatcher.addURI("contacts", "/people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID); - sURIMatcher.addURI("contacts", "/deleted_people", DELETED_PEOPLE); - sURIMatcher.addURI("contacts", "/phones", PHONES); - sURIMatcher.addURI("contacts", "/phones/filter/*", PHONES_FILTER); - sURIMatcher.addURI("contacts", "/phones/#", PHONES_ID); - sURIMatcher.addURI("contacts", "/contact_methods", CONTACTMETHODS); - sURIMatcher.addURI("contacts", "/contact_methods/#", CONTACTMETHODS_ID); - sURIMatcher.addURI("call_log", "/calls", CALLS); - sURIMatcher.addURI("call_log", "/calls/filter/*", CALLS_FILTER); - sURIMatcher.addURI("call_log", "/calls/#", CALLS_ID); + sURIMatcher.addURI("contacts", "people", PEOPLE); + sURIMatcher.addURI("contacts", "people/#", PEOPLE_ID); + sURIMatcher.addURI("contacts", "people/#/phones", PEOPLE_PHONES); + sURIMatcher.addURI("contacts", "people/#/phones/#", PEOPLE_PHONES_ID); + sURIMatcher.addURI("contacts", "people/#/contact_methods", PEOPLE_CONTACTMETHODS); + sURIMatcher.addURI("contacts", "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID); + sURIMatcher.addURI("contacts", "deleted_people", DELETED_PEOPLE); + sURIMatcher.addURI("contacts", "phones", PHONES); + sURIMatcher.addURI("contacts", "phones/filter/*", PHONES_FILTER); + sURIMatcher.addURI("contacts", "phones/#", PHONES_ID); + sURIMatcher.addURI("contacts", "contact_methods", CONTACTMETHODS); + sURIMatcher.addURI("contacts", "contact_methods/#", CONTACTMETHODS_ID); + sURIMatcher.addURI("call_log", "calls", CALLS); + sURIMatcher.addURI("call_log", "calls/filter/*", CALLS_FILTER); + sURIMatcher.addURI("call_log", "calls/#", CALLS_ID); } </pre> -<p>Then when you need to match match against a URI, call {@link #match}, providing -the tokenized url you've been given, and the value you want if there isn't -a match. You can use the result to build a query, return a type, insert or -delete a row, or whatever you need, without duplicating all of the if-else -logic you'd otherwise need. Like this: +<p>Then when you need to match against a URI, call {@link #match}, providing +the URL that you have been given. You can use the result to build a query, +return a type, insert or delete a row, or whatever you need, without duplicating +all of the if-else logic that you would otherwise need. For example: <pre> - public String getType(String[] url) + public String getType(Uri url) { - int match = sURIMatcher.match(url, NO_MATCH); + int match = sURIMatcher.match(url); switch (match) { case PEOPLE: @@ -93,19 +92,20 @@ logic you'd otherwise need. Like this: } } </pre> -instead of +instead of: <pre> - public String getType(String[] url) + public String getType(Uri url) { - if (url.length >= 2) { - if (url[1].equals("people")) { - if (url.length == 2) { + List<String> pathSegments = url.getPathSegments(); + if (pathSegments.size() >= 2) { + if ("people".equals(pathSegments.get(1))) { + if (pathSegments.size() == 2) { return "vnd.android.cursor.dir/person"; - } else if (url.length == 3) { + } else if (pathSegments.size() == 3) { return "vnd.android.cursor.item/person"; ... snip ... return "vnd.android.cursor.dir/snail-mail"; - } else if (url.length == 3) { + } else if (pathSegments.size() == 3) { return "vnd.android.cursor.item/snail-mail"; } } diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 9bb3b75..e9a2929 100644..100755 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -25,6 +25,7 @@ import org.xmlpull.v1.XmlPullParserException; import android.graphics.Movie; import android.graphics.drawable.Drawable; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable.ConstantState; import android.os.Build; import android.os.Bundle; import android.os.SystemProperties; @@ -66,6 +67,8 @@ public class Resources { = new LongSparseArray<Drawable.ConstantState>(); private static final SparseArray<ColorStateList> mPreloadedColorStateLists = new SparseArray<ColorStateList>(); + private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables + = new LongSparseArray<Drawable.ConstantState>(); private static boolean mPreloaded; /*package*/ final TypedValue mTmpValue = new TypedValue(); @@ -75,6 +78,8 @@ public class Resources { = new LongSparseArray<WeakReference<Drawable.ConstantState> >(); private final SparseArray<WeakReference<ColorStateList> > mColorStateListCache = new SparseArray<WeakReference<ColorStateList> >(); + private final LongSparseArray<WeakReference<Drawable.ConstantState> > mColorDrawableCache + = new LongSparseArray<WeakReference<Drawable.ConstantState> >(); private boolean mPreloading; /*package*/ TypedArray mCachedStyledAttributes = null; @@ -1299,37 +1304,13 @@ public class Resources { (int)(mMetrics.density*160), mConfiguration.keyboard, keyboardHidden, mConfiguration.navigation, width, height, mConfiguration.screenLayout, mConfiguration.uiMode, sSdkVersion); - int N = mDrawableCache.size(); - if (DEBUG_CONFIG) { - Log.d(TAG, "Cleaning up drawables config changes: 0x" - + Integer.toHexString(configChanges)); - } - for (int i=0; i<N; i++) { - WeakReference<Drawable.ConstantState> ref = mDrawableCache.valueAt(i); - if (ref != null) { - Drawable.ConstantState cs = ref.get(); - if (cs != null) { - if (Configuration.needNewResources( - configChanges, cs.getChangingConfigurations())) { - if (DEBUG_CONFIG) { - Log.d(TAG, "FLUSHING #0x" - + Long.toHexString(mDrawableCache.keyAt(i)) - + " / " + cs + " with changes: 0x" - + Integer.toHexString(cs.getChangingConfigurations())); - } - mDrawableCache.setValueAt(i, null); - } else if (DEBUG_CONFIG) { - Log.d(TAG, "(Keeping #0x" - + Long.toHexString(mDrawableCache.keyAt(i)) - + " / " + cs + " with changes: 0x" - + Integer.toHexString(cs.getChangingConfigurations()) - + ")"); - } - } - } - } - mDrawableCache.clear(); + + clearDrawableCache(mDrawableCache, configChanges); + clearDrawableCache(mColorDrawableCache, configChanges); + mColorStateListCache.clear(); + + flushLayoutCache(); } synchronized (mSync) { @@ -1339,6 +1320,40 @@ public class Resources { } } + private void clearDrawableCache( + LongSparseArray<WeakReference<ConstantState>> cache, + int configChanges) { + int N = cache.size(); + if (DEBUG_CONFIG) { + Log.d(TAG, "Cleaning up drawables config changes: 0x" + + Integer.toHexString(configChanges)); + } + for (int i=0; i<N; i++) { + WeakReference<Drawable.ConstantState> ref = cache.valueAt(i); + if (ref != null) { + Drawable.ConstantState cs = ref.get(); + if (cs != null) { + if (Configuration.needNewResources( + configChanges, cs.getChangingConfigurations())) { + if (DEBUG_CONFIG) { + Log.d(TAG, "FLUSHING #0x" + + Long.toHexString(mDrawableCache.keyAt(i)) + + " / " + cs + " with changes: 0x" + + Integer.toHexString(cs.getChangingConfigurations())); + } + cache.setValueAt(i, null); + } else if (DEBUG_CONFIG) { + Log.d(TAG, "(Keeping #0x" + + Long.toHexString(cache.keyAt(i)) + + " / " + cs + " with changes: 0x" + + Integer.toHexString(cs.getChangingConfigurations()) + + ")"); + } + } + } + } + } + /** * Update the system resources configuration if they have previously * been initialized. @@ -1661,13 +1676,18 @@ public class Resources { } final long key = (((long) value.assetCookie) << 32) | value.data; - Drawable dr = getCachedDrawable(key); + boolean isColorDrawable = false; + if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT && + value.type <= TypedValue.TYPE_LAST_COLOR_INT) { + isColorDrawable = true; + } + Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key); if (dr != null) { return dr; } - Drawable.ConstantState cs = sPreloadedDrawables.get(key); + Drawable.ConstantState cs = isColorDrawable ? sPreloadedColorDrawables.get(key) : sPreloadedDrawables.get(key); if (cs != null) { dr = cs.newDrawable(this); } else { @@ -1726,13 +1746,21 @@ public class Resources { cs = dr.getConstantState(); if (cs != null) { if (mPreloading) { - sPreloadedDrawables.put(key, cs); + if (isColorDrawable) { + sPreloadedColorDrawables.put(key, cs); + } else { + sPreloadedDrawables.put(key, cs); + } } else { synchronized (mTmpValue) { //Log.i(TAG, "Saving cached drawable @ #" + // Integer.toHexString(key.intValue()) // + " in " + this + ": " + cs); - mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs)); + if (isColorDrawable) { + mColorDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs)); + } else { + mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs)); + } } } } @@ -1741,9 +1769,11 @@ public class Resources { return dr; } - private Drawable getCachedDrawable(long key) { + private Drawable getCachedDrawable( + LongSparseArray<WeakReference<ConstantState>> drawableCache, + long key) { synchronized (mTmpValue) { - WeakReference<Drawable.ConstantState> wr = mDrawableCache.get(key); + WeakReference<Drawable.ConstantState> wr = drawableCache.get(key); if (wr != null) { // we have the key Drawable.ConstantState entry = wr.get(); if (entry != null) { @@ -1753,7 +1783,7 @@ public class Resources { return entry.newDrawable(this); } else { // our entry has been purged - mDrawableCache.delete(key); + drawableCache.delete(key); } } } diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java index 5e90b91..23a6f97 100644 --- a/core/java/android/content/res/StringBlock.java +++ b/core/java/android/content/res/StringBlock.java @@ -87,21 +87,48 @@ final class StringBlock { if (style != null) { if (mStyleIDs == null) { mStyleIDs = new StyleIDs(); - mStyleIDs.boldId = nativeIndexOfString(mNative, "b"); - mStyleIDs.italicId = nativeIndexOfString(mNative, "i"); - mStyleIDs.underlineId = nativeIndexOfString(mNative, "u"); - mStyleIDs.ttId = nativeIndexOfString(mNative, "tt"); - mStyleIDs.bigId = nativeIndexOfString(mNative, "big"); - mStyleIDs.smallId = nativeIndexOfString(mNative, "small"); - mStyleIDs.supId = nativeIndexOfString(mNative, "sup"); - mStyleIDs.subId = nativeIndexOfString(mNative, "sub"); - mStyleIDs.strikeId = nativeIndexOfString(mNative, "strike"); - mStyleIDs.listItemId = nativeIndexOfString(mNative, "li"); - mStyleIDs.marqueeId = nativeIndexOfString(mNative, "marquee"); - - if (localLOGV) Log.v(TAG, "BoldId=" + mStyleIDs.boldId - + ", ItalicId=" + mStyleIDs.italicId - + ", UnderlineId=" + mStyleIDs.underlineId); + } + + // the style array is a flat array of <type, start, end> hence + // the magic constant 3. + for (int styleIndex = 0; styleIndex < style.length; styleIndex += 3) { + int styleId = style[styleIndex]; + + if (styleId == mStyleIDs.boldId || styleId == mStyleIDs.italicId + || styleId == mStyleIDs.underlineId || styleId == mStyleIDs.ttId + || styleId == mStyleIDs.bigId || styleId == mStyleIDs.smallId + || styleId == mStyleIDs.subId || styleId == mStyleIDs.supId + || styleId == mStyleIDs.strikeId || styleId == mStyleIDs.listItemId + || styleId == mStyleIDs.marqueeId) { + // id already found skip to next style + continue; + } + + String styleTag = nativeGetString(mNative, styleId); + + if (styleTag.equals("b")) { + mStyleIDs.boldId = styleId; + } else if (styleTag.equals("i")) { + mStyleIDs.italicId = styleId; + } else if (styleTag.equals("u")) { + mStyleIDs.underlineId = styleId; + } else if (styleTag.equals("tt")) { + mStyleIDs.ttId = styleId; + } else if (styleTag.equals("big")) { + mStyleIDs.bigId = styleId; + } else if (styleTag.equals("small")) { + mStyleIDs.smallId = styleId; + } else if (styleTag.equals("sup")) { + mStyleIDs.supId = styleId; + } else if (styleTag.equals("sub")) { + mStyleIDs.subId = styleId; + } else if (styleTag.equals("strike")) { + mStyleIDs.strikeId = styleId; + } else if (styleTag.equals("li")) { + mStyleIDs.listItemId = styleId; + } else if (styleTag.equals("marquee")) { + mStyleIDs.marqueeId = styleId; + } } res = applyStyles(str, style, mStyleIDs); @@ -119,17 +146,17 @@ final class StringBlock { } static final class StyleIDs { - private int boldId; - private int italicId; - private int underlineId; - private int ttId; - private int bigId; - private int smallId; - private int subId; - private int supId; - private int strikeId; - private int listItemId; - private int marqueeId; + private int boldId = -1; + private int italicId = -1; + private int underlineId = -1; + private int ttId = -1; + private int bigId = -1; + private int smallId = -1; + private int subId = -1; + private int supId = -1; + private int strikeId = -1; + private int listItemId = -1; + private int marqueeId = -1; } private CharSequence applyStyles(String str, int[] style, StyleIDs ids) { @@ -403,6 +430,5 @@ final class StringBlock { private static final native int nativeGetSize(int obj); private static final native String nativeGetString(int obj, int idx); private static final native int[] nativeGetStyle(int obj, int idx); - private static final native int nativeIndexOfString(int obj, String str); private static final native void nativeDestroy(int obj); } diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java index 038eedf..a5e5e46 100644 --- a/core/java/android/database/AbstractCursor.java +++ b/core/java/android/database/AbstractCursor.java @@ -204,7 +204,7 @@ public abstract class AbstractCursor implements CrossProcessCursor { * @param window */ public void fillWindow(int position, CursorWindow window) { - if (position < 0 || position > getCount()) { + if (position < 0 || position >= getCount()) { return; } window.acquireReference(); diff --git a/core/java/android/database/Cursor.java b/core/java/android/database/Cursor.java index 6539156..e339a63 100644 --- a/core/java/android/database/Cursor.java +++ b/core/java/android/database/Cursor.java @@ -211,7 +211,9 @@ public interface Cursor { /** * Returns the value of the requested column as a byte array. * - * <p>If the native content of that column is not blob exception may throw + * <p>The result and whether this method throws an exception when the + * column value is null or the column type is not a blob type is + * implementation-defined. * * @param columnIndex the zero-based index of the target column. * @return the value of that column as a byte array. @@ -221,8 +223,9 @@ public interface Cursor { /** * Returns the value of the requested column as a String. * - * <p>If the native content of that column is not text the result will be - * the result of passing the column value to String.valueOf(x). + * <p>The result and whether this method throws an exception when the + * column value is null or the column type is not a string type is + * implementation-defined. * * @param columnIndex the zero-based index of the target column. * @return the value of that column as a String. @@ -242,8 +245,10 @@ public interface Cursor { /** * Returns the value of the requested column as a short. * - * <p>If the native content of that column is not numeric the result will be - * the result of passing the column value to Short.valueOf(x). + * <p>The result and whether this method throws an exception when the + * column value is null, the column type is not an integral type, or the + * integer value is outside the range [<code>Short.MIN_VALUE</code>, + * <code>Short.MAX_VALUE</code>] is implementation-defined. * * @param columnIndex the zero-based index of the target column. * @return the value of that column as a short. @@ -253,8 +258,10 @@ public interface Cursor { /** * Returns the value of the requested column as an int. * - * <p>If the native content of that column is not numeric the result will be - * the result of passing the column value to Integer.valueOf(x). + * <p>The result and whether this method throws an exception when the + * column value is null, the column type is not an integral type, or the + * integer value is outside the range [<code>Integer.MIN_VALUE</code>, + * <code>Integer.MAX_VALUE</code>] is implementation-defined. * * @param columnIndex the zero-based index of the target column. * @return the value of that column as an int. @@ -264,8 +271,10 @@ public interface Cursor { /** * Returns the value of the requested column as a long. * - * <p>If the native content of that column is not numeric the result will be - * the result of passing the column value to Long.valueOf(x). + * <p>The result and whether this method throws an exception when the + * column value is null, the column type is not an integral type, or the + * integer value is outside the range [<code>Long.MIN_VALUE</code>, + * <code>Long.MAX_VALUE</code>] is implementation-defined. * * @param columnIndex the zero-based index of the target column. * @return the value of that column as a long. @@ -275,8 +284,10 @@ public interface Cursor { /** * Returns the value of the requested column as a float. * - * <p>If the native content of that column is not numeric the result will be - * the result of passing the column value to Float.valueOf(x). + * <p>The result and whether this method throws an exception when the + * column value is null, the column type is not a floating-point type, or the + * floating-point value is not representable as a <code>float</code> value is + * implementation-defined. * * @param columnIndex the zero-based index of the target column. * @return the value of that column as a float. @@ -286,8 +297,10 @@ public interface Cursor { /** * Returns the value of the requested column as a double. * - * <p>If the native content of that column is not numeric the result will be - * the result of passing the column value to Double.valueOf(x). + * <p>The result and whether this method throws an exception when the + * column value is null, the column type is not a floating-point type, or the + * floating-point value is not representable as a <code>double</code> value is + * implementation-defined. * * @param columnIndex the zero-based index of the target column. * @return the value of that column as a double. @@ -573,7 +586,8 @@ public interface Cursor { * that are required to fetch data for the cursor. * * <p>These values may only change when requery is called. - * @return cursor-defined values, or Bundle.EMTPY if there are no values. Never null. + * @return cursor-defined values, or {@link android.os.Bundle#EMPTY Bundle.EMPTY} if there + * are no values. Never <code>null</code>. */ Bundle getExtras(); @@ -583,8 +597,10 @@ public interface Cursor { * * <p>One use of this is to tell a cursor that it should retry its network request after it * reported an error. - * @param extras extra values, or Bundle.EMTPY. Never null. - * @return extra values, or Bundle.EMTPY. Never null. + * @param extras extra values, or {@link android.os.Bundle#EMPTY Bundle.EMPTY}. + * Never <code>null</code>. + * @return extra values, or {@link android.os.Bundle#EMPTY Bundle.EMPTY}. + * Never <code>null</code>. */ Bundle respond(Bundle extras); } diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java index c756825..76b91f5 100644 --- a/core/java/android/database/CursorWindow.java +++ b/core/java/android/database/CursorWindow.java @@ -245,6 +245,15 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { } } + /** + * Returns the value at (<code>row</code>, <code>col</code>) as a <code>byte</code> array. + * + * <p>If the value is null, then <code>null</code> is returned. If the + * type of column <code>col</code> is a string type, then the result + * is the array of bytes that make up the internal representation of the + * string value. If the type of column <code>col</code> is integral or floating-point, + * then an {@link SQLiteException} is thrown. + */ private native byte[] getBlob_native(int row, int col); /** @@ -332,6 +341,19 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { } } + /** + * Returns the value at (<code>row</code>, <code>col</code>) as a <code>String</code>. + * + * <p>If the value is null, then <code>null</code> is returned. If the + * type of column <code>col</code> is integral, then the result is the string + * that is obtained by formatting the integer value with the <code>printf</code> + * family of functions using format specifier <code>%lld</code>. If the + * type of column <code>col</code> is floating-point, then the result is the string + * that is obtained by formatting the floating-point value with the + * <code>printf</code> family of functions using format specifier <code>%g</code>. + * If the type of column <code>col</code> is a blob type, then an + * {@link SQLiteException} is thrown. + */ private native String getString_native(int row, int col); /** @@ -383,6 +405,17 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { } } + /** + * Returns the value at (<code>row</code>, <code>col</code>) as a <code>long</code>. + * + * <p>If the value is null, then <code>0L</code> is returned. If the + * type of column <code>col</code> is a string type, then the result + * is the <code>long</code> that is obtained by parsing the string value with + * <code>strtoll</code>. If the type of column <code>col</code> is + * floating-point, then the result is the floating-point value casted to a <code>long</code>. + * If the type of column <code>col</code> is a blob type, then an + * {@link SQLiteException} is thrown. + */ private native long getLong_native(int row, int col); /** @@ -402,6 +435,17 @@ public class CursorWindow extends SQLiteClosable implements Parcelable { } } + /** + * Returns the value at (<code>row</code>, <code>col</code>) as a <code>double</code>. + * + * <p>If the value is null, then <code>0.0</code> is returned. If the + * type of column <code>col</code> is a string type, then the result + * is the <code>double</code> that is obtained by parsing the string value with + * <code>strtod</code>. If the type of column <code>col</code> is + * integral, then the result is the integer value casted to a <code>double</code>. + * If the type of column <code>col</code> is a blob type, then an + * {@link SQLiteException} is thrown. + */ private native double getDouble_native(int row, int col); /** diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index 66406ca..95fc1fd 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -50,8 +50,6 @@ public class DatabaseUtils { private static final boolean DEBUG = false; private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV; - private static final String[] countProjection = new String[]{"count(*)"}; - /** * Special function for writing an exception result at the header of * a parcel, to be used when returning an exception from a transaction. @@ -604,14 +602,40 @@ public class DatabaseUtils { * @return the number of rows in the table */ public static long queryNumEntries(SQLiteDatabase db, String table) { - Cursor cursor = db.query(table, countProjection, - null, null, null, null, null); - try { - cursor.moveToFirst(); - return cursor.getLong(0); - } finally { - cursor.close(); - } + return queryNumEntries(db, table, null, null); + } + + /** + * Query the table for the number of rows in the table. + * @param db the database the table is in + * @param table the name of the table to query + * @param selection A filter declaring which rows to return, + * formatted as an SQL WHERE clause (excluding the WHERE itself). + * Passing null will count all rows for the given table + * @return the number of rows in the table filtered by the selection + */ + public static long queryNumEntries(SQLiteDatabase db, String table, String selection) { + return queryNumEntries(db, table, selection, null); + } + + /** + * Query the table for the number of rows in the table. + * @param db the database the table is in + * @param table the name of the table to query + * @param selection A filter declaring which rows to return, + * formatted as an SQL WHERE clause (excluding the WHERE itself). + * Passing null will count all rows for the given table + * @param selectionArgs You may include ?s in selection, + * which will be replaced by the values from selectionArgs, + * in order that they appear in the selection. + * The values will be bound as Strings. + * @return the number of rows in the table filtered by the selection + */ + public static long queryNumEntries(SQLiteDatabase db, String table, String selection, + String[] selectionArgs) { + String s = (!TextUtils.isEmpty(selection)) ? " where " + selection : ""; + return longForQuery(db, "select count(*) from " + table + s, + selectionArgs); } /** diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java index d8dcaf7..c592134 100644 --- a/core/java/android/database/sqlite/SQLiteCursor.java +++ b/core/java/android/database/sqlite/SQLiteCursor.java @@ -132,11 +132,11 @@ public class SQLiteCursor extends AbstractWindowedCursor { // the cursor's state doesn't change while (true) { mLock.lock(); - if (mCursorState != mThreadState) { - mLock.unlock(); - break; - } try { + if (mCursorState != mThreadState) { + break; + } + int count = mQuery.fillWindow(cw, mMaxRead, mCount); // return -1 means not finished if (count != 0) { @@ -218,9 +218,8 @@ public class SQLiteCursor extends AbstractWindowedCursor { mColumnNameMap = null; mQuery = query; + db.lock(); try { - db.lock(); - // Setup the list of columns int columnCount = mQuery.columnCountLocked(); mColumns = new String[columnCount]; diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java index 610bf70..b6aca2b 100644 --- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java +++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java @@ -321,7 +321,7 @@ public class SQLiteQueryBuilder } String sql = buildQuery( - projectionIn, selection, selectionArgs, groupBy, having, + projectionIn, selection, groupBy, having, sortOrder, limit); if (Log.isLoggable(TAG, Log.DEBUG)) { @@ -345,10 +345,6 @@ public class SQLiteQueryBuilder * formatted as an SQL WHERE clause (excluding the WHERE * itself). Passing null will return all rows for the given * URL. - * @param selectionArgs You may include ?s in selection, which - * will be replaced by the values from selectionArgs, in order - * that they appear in the selection. The values will be bound - * as Strings. * @param groupBy A filter declaring how to group rows, formatted * as an SQL GROUP BY clause (excluding the GROUP BY itself). * Passing null will cause the rows to not be grouped. @@ -365,8 +361,8 @@ public class SQLiteQueryBuilder * @return the resulting SQL SELECT statement */ public String buildQuery( - String[] projectionIn, String selection, String[] selectionArgs, - String groupBy, String having, String sortOrder, String limit) { + String[] projectionIn, String selection, String groupBy, + String having, String sortOrder, String limit) { String[] projection = computeProjection(projectionIn); StringBuilder where = new StringBuilder(); @@ -394,6 +390,19 @@ public class SQLiteQueryBuilder } /** + * @deprecated This method's signature is misleading since no SQL parameter + * substitution is carried out. The selection arguments parameter does not get + * used at all. To avoid confusion, call + * {@link #buildQuery(String[], String, String, String, String, String)} instead. + */ + @Deprecated + public String buildQuery( + String[] projectionIn, String selection, String[] selectionArgs, + String groupBy, String having, String sortOrder, String limit) { + return buildQuery(projectionIn, selection, groupBy, having, sortOrder, limit); + } + + /** * Construct a SELECT statement suitable for use in a group of * SELECT statements that will be joined through UNION operators * in buildUnionQuery. @@ -422,10 +431,6 @@ public class SQLiteQueryBuilder * formatted as an SQL WHERE clause (excluding the WHERE * itself). Passing null will return all rows for the given * URL. - * @param selectionArgs You may include ?s in selection, which - * will be replaced by the values from selectionArgs, in order - * that they appear in the selection. The values will be bound - * as Strings. * @param groupBy A filter declaring how to group rows, formatted * as an SQL GROUP BY clause (excluding the GROUP BY itself). * Passing null will cause the rows to not be grouped. @@ -443,7 +448,6 @@ public class SQLiteQueryBuilder int computedColumnsOffset, String typeDiscriminatorValue, String selection, - String[] selectionArgs, String groupBy, String having) { int unionColumnsCount = unionColumns.length; @@ -463,12 +467,36 @@ public class SQLiteQueryBuilder } } return buildQuery( - projectionIn, selection, selectionArgs, groupBy, having, + projectionIn, selection, groupBy, having, null /* sortOrder */, null /* limit */); } /** + * @deprecated This method's signature is misleading since no SQL parameter + * substitution is carried out. The selection arguments parameter does not get + * used at all. To avoid confusion, call + * {@link #buildUnionSubQuery} + * instead. + */ + @Deprecated + public String buildUnionSubQuery( + String typeDiscriminatorColumn, + String[] unionColumns, + Set<String> columnsPresentInTable, + int computedColumnsOffset, + String typeDiscriminatorValue, + String selection, + String[] selectionArgs, + String groupBy, + String having) { + return buildUnionSubQuery( + typeDiscriminatorColumn, unionColumns, columnsPresentInTable, + computedColumnsOffset, typeDiscriminatorValue, selection, + groupBy, having); + } + + /** * Given a set of subqueries, all of which are SELECT statements, * construct a query that returns the union of what those * subqueries return. diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 39681912..1cfe419 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -21,6 +21,9 @@ import android.annotation.SdkConstant.SdkConstantType; import android.os.Binder; import android.os.RemoteException; +import java.net.InetAddress; +import java.net.UnknownHostException; + /** * Class that answers queries about the state of network connectivity. It also * notifies applications when network connectivity changes. Get an instance @@ -328,8 +331,29 @@ public class ConnectivityManager * @return {@code true} on success, {@code false} on failure */ public boolean requestRouteToHost(int networkType, int hostAddress) { + InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); + + if (inetAddress == null) { + return false; + } + + return requestRouteToHostAddress(networkType, inetAddress); + } + + /** + * Ensure that a network route exists to deliver traffic to the specified + * host via the specified network interface. An attempt to add a route that + * already exists is ignored, but treated as successful. + * @param networkType the type of the network over which traffic to the specified + * host is to be routed + * @param hostAddress the IP address of the host to which the route is desired + * @return {@code true} on success, {@code false} on failure + * @hide + */ + public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { + byte[] address = hostAddress.getAddress(); try { - return mService.requestRouteToHost(networkType, hostAddress); + return mService.requestRouteToHostAddress(networkType, address); } catch (RemoteException e) { return false; } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b734ac7..afccdd9 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -47,6 +47,8 @@ interface IConnectivityManager boolean requestRouteToHost(int networkType, int hostAddress); + boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress); + boolean getBackgroundDataSetting(); void setBackgroundDataSetting(boolean allowBackgroundData); diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index ffbd69d..8d18eba 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -16,6 +16,8 @@ package android.net; +import java.net.InetAddress; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -23,7 +25,6 @@ import android.content.IntentFilter; import android.os.RemoteException; import android.os.Handler; import android.os.ServiceManager; -import android.os.SystemProperties; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.Phone; import com.android.internal.telephony.TelephonyIntents; @@ -489,17 +490,16 @@ public class MobileDataStateTracker extends NetworkStateTracker { * Ensure that a network route exists to deliver traffic to the specified * host via the mobile data network. * @param hostAddress the IP address of the host to which the route is desired, - * in network byte order. * @return {@code true} on success, {@code false} on failure */ @Override - public boolean requestRouteToHost(int hostAddress) { + public boolean requestRouteToHost(InetAddress hostAddress) { if (DBG) { - Log.d(TAG, "Requested host route to " + Integer.toHexString(hostAddress) + + Log.d(TAG, "Requested host route to " + hostAddress.getHostAddress() + " for " + mApnType + "(" + mInterfaceName + ")"); } - if (mInterfaceName != null && hostAddress != -1) { - return NetworkUtils.addHostRoute(mInterfaceName, hostAddress) == 0; + if (mInterfaceName != null) { + return NetworkUtils.addHostRoute(mInterfaceName, hostAddress, null); } else { return false; } diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index d340a99..c161f3a 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -18,13 +18,14 @@ package android.net; import java.io.FileWriter; import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; import android.os.Handler; import android.os.Message; import android.os.SystemProperties; import android.content.Context; import android.text.TextUtils; -import android.util.Config; import android.util.Log; @@ -133,13 +134,18 @@ public abstract class NetworkStateTracker extends Handler { } if (mInterfaceName != null && !mPrivateDnsRouteSet) { for (String addrString : getNameServers()) { - int addr = NetworkUtils.lookupHost(addrString); - if (addr != -1 && addr != 0) { - if (DBG) Log.d(TAG, " adding "+addrString+" ("+addr+")"); - NetworkUtils.addHostRoute(mInterfaceName, addr); + if (addrString != null) { + try { + InetAddress inetAddress = InetAddress.getByName(addrString); + if (DBG) Log.d(TAG, " adding " + addrString); + if (NetworkUtils.addHostRoute(mInterfaceName, inetAddress, null)) { + mPrivateDnsRouteSet = true; + } + } catch (UnknownHostException e) { + if (DBG) Log.d(TAG, " DNS address " + addrString + " : Exception " + e); + } } } - mPrivateDnsRouteSet = true; } } @@ -162,7 +168,14 @@ public abstract class NetworkStateTracker extends Handler { Log.d(TAG, "addDefaultRoute for " + mNetworkInfo.getTypeName() + " (" + mInterfaceName + "), GatewayAddr=" + mDefaultGatewayAddr); } - NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr); + InetAddress inetAddress = NetworkUtils.intToInetAddress(mDefaultGatewayAddr); + if (inetAddress == null) { + if (DBG) Log.d(TAG, " Unable to add default route. mDefaultGatewayAddr Error"); + } else { + if (!NetworkUtils.addDefaultRoute(mInterfaceName, inetAddress) && DBG) { + Log.d(TAG, " Unable to add default route."); + } + } } } @@ -399,7 +412,7 @@ public abstract class NetworkStateTracker extends Handler { * @param hostAddress the IP address of the host to which the route is desired * @return {@code true} on success, {@code false} on failure */ - public boolean requestRouteToHost(int hostAddress) { + public boolean requestRouteToHost(InetAddress hostAddress) { return false; } diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index e4f3d5c..5d4b099 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -17,25 +17,39 @@ package android.net; import java.net.InetAddress; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.UnknownHostException; +import android.util.Log; + /** * Native methods for managing network interfaces. * * {@hide} */ public class NetworkUtils { + + private static final String TAG = "NetworkUtils"; + /** Bring the named network interface up. */ public native static int enableInterface(String interfaceName); /** Bring the named network interface down. */ public native static int disableInterface(String interfaceName); - /** Add a route to the specified host via the named interface. */ - public native static int addHostRoute(String interfaceName, int hostaddr); - - /** Add a default route for the named interface. */ - public native static int setDefaultRoute(String interfaceName, int gwayAddr); + /** + * Add a route to the routing table. + * + * @param interfaceName the interface to route through. + * @param dst the network or host to route to. May be IPv4 or IPv6, e.g. + * "0.0.0.0" or "2001:4860::". + * @param prefixLength the prefix length of the route. + * @param gw the gateway to use, e.g., "192.168.251.1". If null, + * indicates a directly-connected route. + */ + public native static int addRoute(String interfaceName, String dst, + int prefixLength, String gw); /** Return the gateway address for the default route for the named interface. */ public native static int getDefaultRoute(String interfaceName); @@ -106,27 +120,79 @@ public class NetworkUtils { String interfaceName, int ipAddress, int netmask, int gateway, int dns1, int dns2); /** - * Look up a host name and return the result as an int. Works if the argument - * is an IP address in dot notation. Obviously, this can only be used for IPv4 - * addresses. - * @param hostname the name of the host (or the IP address) - * @return the IP address as an {@code int} in network byte order + * Convert a IPv4 address from an integer to an InetAddress. + * @param hostAddr is an Int corresponding to the IPv4 address in network byte order + * @return the IP address as an {@code InetAddress}, returns null if + * unable to convert or if the int is an invalid address. */ - public static int lookupHost(String hostname) { + public static InetAddress intToInetAddress(int hostAddress) { InetAddress inetAddress; + byte[] addressBytes = { (byte)(0xff & hostAddress), + (byte)(0xff & (hostAddress >> 8)), + (byte)(0xff & (hostAddress >> 16)), + (byte)(0xff & (hostAddress >> 24)) }; + try { - inetAddress = InetAddress.getByName(hostname); - } catch (UnknownHostException e) { - return -1; + inetAddress = InetAddress.getByAddress(addressBytes); + } catch(UnknownHostException e) { + return null; + } + + return inetAddress; + } + + /** + * Add a default route through the specified gateway. + * @param interfaceName interface on which the route should be added + * @param gw the IP address of the gateway to which the route is desired, + * @return {@code true} on success, {@code false} on failure + */ + public static boolean addDefaultRoute(String interfaceName, InetAddress gw) { + String dstStr; + String gwStr = gw.getHostAddress(); + + if (gw instanceof Inet4Address) { + dstStr = "0.0.0.0"; + } else if (gw instanceof Inet6Address) { + dstStr = "::"; + } else { + Log.w(TAG, "addDefaultRoute failure: address is neither IPv4 nor IPv6" + + "(" + gwStr + ")"); + return false; + } + return addRoute(interfaceName, dstStr, 0, gwStr) == 0; + } + + /** + * Add a host route. + * @param interfaceName interface on which the route should be added + * @param dst the IP address of the host to which the route is desired, + * this should not be null. + * @param gw the IP address of the gateway to which the route is desired, + * if null, indicates a directly-connected route. + * @return {@code true} on success, {@code false} on failure + */ + public static boolean addHostRoute(String interfaceName, InetAddress dst, + InetAddress gw) { + if (dst == null) { + Log.w(TAG, "addHostRoute: dst should not be null"); + return false; + } + + int prefixLength; + String dstStr = dst.getHostAddress(); + String gwStr = (gw != null) ? gw.getHostAddress() : null; + + if (dst instanceof Inet4Address) { + prefixLength = 32; + } else if (dst instanceof Inet6Address) { + prefixLength = 128; + } else { + Log.w(TAG, "addHostRoute failure: address is neither IPv4 nor IPv6" + + "(" + dst + ")"); + return false; } - byte[] addrBytes; - int addr; - addrBytes = inetAddress.getAddress(); - addr = ((addrBytes[3] & 0xff) << 24) - | ((addrBytes[2] & 0xff) << 16) - | ((addrBytes[1] & 0xff) << 8) - | (addrBytes[0] & 0xff); - return addr; + return addRoute(interfaceName, dstStr, prefixLength, gwStr) == 0; } public static int v4StringToInt(String str) { diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index 66eefb2..c1fa5b4 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -16,12 +16,16 @@ package android.net; +import org.apache.http.HttpHost; + import android.content.ContentResolver; import android.content.Context; import android.os.SystemProperties; import android.provider.Settings; import android.util.Log; +import java.net.URI; + import junit.framework.Assert; /** @@ -120,4 +124,73 @@ final public class Proxy { } } + /** + * Returns the preferred proxy to be used by clients. This is a wrapper + * around {@link android.net.Proxy#getHost()}. Currently no proxy will + * be returned for localhost or if the active network is Wi-Fi. + * + * @param context the context which will be passed to + * {@link android.net.Proxy#getHost()} + * @param url the target URL for the request + * @note Calling this method requires permission + * android.permission.ACCESS_NETWORK_STATE + * @return The preferred proxy to be used by clients, or null if there + * is no proxy. + * + * {@hide} + */ + static final public HttpHost getPreferredHttpHost(Context context, + String url) { + if (!isLocalHost(url) && !isNetworkWifi(context)) { + final String proxyHost = Proxy.getHost(context); + if (proxyHost != null) { + return new HttpHost(proxyHost, Proxy.getPort(context), "http"); + } + } + + return null; + } + + static final private boolean isLocalHost(String url) { + if (url == null) { + return false; + } + + try { + final URI uri = URI.create(url); + final String host = uri.getHost(); + if (host != null) { + // TODO: InetAddress.isLoopbackAddress should be used to check + // for localhost. However no public factory methods exist which + // can be used without triggering DNS lookup if host is not localhost. + if (host.equalsIgnoreCase("localhost") || + host.equals("127.0.0.1") || + host.equals("[::1]")) { + return true; + } + } + } catch (IllegalArgumentException iex) { + // Ignore (URI.create) + } + + return false; + } + + static final private boolean isNetworkWifi(Context context) { + if (context == null) { + return false; + } + + final ConnectivityManager connectivity = (ConnectivityManager) + context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivity != null) { + final NetworkInfo info = connectivity.getActiveNetworkInfo(); + if (info != null && + info.getType() == ConnectivityManager.TYPE_WIFI) { + return true; + } + } + + return false; + } }; diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java index e07ee59..8dc2a86 100644 --- a/core/java/android/net/http/AndroidHttpClient.java +++ b/core/java/android/net/http/AndroidHttpClient.java @@ -79,6 +79,9 @@ public final class AndroidHttpClient implements HttpClient { // Gzip of data shorter than this probably won't be worthwhile public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256; + // Default connection and socket timeout of 60 seconds. Tweak to taste. + private static final int SOCKET_OPERATION_TIMEOUT = 60 * 1000; + private static final String TAG = "AndroidHttpClient"; @@ -107,9 +110,8 @@ public final class AndroidHttpClient implements HttpClient { // and it's not worth it to pay the penalty of checking every time. HttpConnectionParams.setStaleCheckingEnabled(params, false); - // Default connection and socket timeout of 20 seconds. Tweak to taste. - HttpConnectionParams.setConnectionTimeout(params, 20 * 1000); - HttpConnectionParams.setSoTimeout(params, 20 * 1000); + HttpConnectionParams.setConnectionTimeout(params, SOCKET_OPERATION_TIMEOUT); + HttpConnectionParams.setSoTimeout(params, SOCKET_OPERATION_TIMEOUT); HttpConnectionParams.setSocketBufferSize(params, 8192); // Don't handle redirects -- return them to the caller. Our code @@ -125,7 +127,8 @@ public final class AndroidHttpClient implements HttpClient { schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schemeRegistry.register(new Scheme("https", - SSLCertificateSocketFactory.getHttpSocketFactory(30 * 1000, sessionCache), 443)); + SSLCertificateSocketFactory.getHttpSocketFactory( + SOCKET_OPERATION_TIMEOUT, sessionCache), 443)); ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry); diff --git a/core/java/android/net/http/Headers.java b/core/java/android/net/http/Headers.java index 09f6f4f..74c0de8 100644 --- a/core/java/android/net/http/Headers.java +++ b/core/java/android/net/http/Headers.java @@ -262,7 +262,14 @@ public final class Headers { break; case HASH_CACHE_CONTROL: if (name.equals(CACHE_CONTROL)) { - mHeaders[IDX_CACHE_CONTROL] = val; + // In case where we receive more than one header, create a ',' separated list. + // This should be ok, according to RFC 2616 chapter 4.2 + if (mHeaders[IDX_CACHE_CONTROL] != null && + mHeaders[IDX_CACHE_CONTROL].length() > 0) { + mHeaders[IDX_CACHE_CONTROL] += (',' + val); + } else { + mHeaders[IDX_CACHE_CONTROL] = val; + } } break; case HASH_LAST_MODIFIED: diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java index b361dca..d77e9d9 100644 --- a/core/java/android/net/http/HttpsConnection.java +++ b/core/java/android/net/http/HttpsConnection.java @@ -205,10 +205,13 @@ public class HttpsConnection extends Connection { BasicHttpRequest proxyReq = new BasicHttpRequest ("CONNECT", mHost.toHostString()); - // add all 'proxy' headers from the original request + // add all 'proxy' headers from the original request, we also need + // to add 'host' header unless we want proxy to answer us with a + // 400 Bad Request for (Header h : req.mHttpRequest.getAllHeaders()) { String headerName = h.getName().toLowerCase(); - if (headerName.startsWith("proxy") || headerName.equals("keep-alive")) { + if (headerName.startsWith("proxy") || headerName.equals("keep-alive") + || headerName.equals("host")) { proxyReq.addHeader(h); } } diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java index 103fd94..2c48a04 100644 --- a/core/java/android/net/http/RequestHandle.java +++ b/core/java/android/net/http/RequestHandle.java @@ -308,7 +308,7 @@ public class RequestHandle { String A2 = mMethod + ":" + mUrl; // because we do not preemptively send authorization headers, nc is always 1 - String nc = "000001"; + String nc = "00000001"; String cnonce = computeCnonce(); String digest = computeDigest(A1, A2, nonce, QOP, nc, cnonce); diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index 44b73c5..bd57b33 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -99,6 +99,7 @@ public class BatteryManager { public static final int BATTERY_HEALTH_DEAD = 4; public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5; public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6; + public static final int BATTERY_HEALTH_COLD = 7; // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent. // These must be powers of 2. diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index f8260ca..a402c91 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -324,6 +324,10 @@ public class Binder implements IBinder { } catch (RuntimeException e) { reply.writeException(e); res = true; + } catch (OutOfMemoryError e) { + RuntimeException re = new RuntimeException("Out of memory", e); + reply.writeException(re); + res = true; } reply.recycle(); data.recycle(); diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 2e14667..86f9a6b 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -94,7 +94,8 @@ public final class Debug /** * Default trace file path and file */ - private static final String DEFAULT_TRACE_PATH_PREFIX = "/sdcard/"; + private static final String DEFAULT_TRACE_PATH_PREFIX = + Environment.getExternalStorageDirectory().getPath() + "/"; private static final String DEFAULT_TRACE_BODY = "dmtrace"; private static final String DEFAULT_TRACE_EXTENSION = ".trace"; private static final String DEFAULT_TRACE_FILE_PATH = @@ -127,7 +128,7 @@ public final class Debug public int otherPrivateDirty; /** The shared dirty pages used by everything else. */ public int otherSharedDirty; - + public MemoryInfo() { } @@ -137,21 +138,21 @@ public final class Debug public int getTotalPss() { return dalvikPss + nativePss + otherPss; } - + /** * Return total private dirty memory usage in kB. */ public int getTotalPrivateDirty() { return dalvikPrivateDirty + nativePrivateDirty + otherPrivateDirty; } - + /** * Return total shared dirty memory usage in kB. */ public int getTotalSharedDirty() { return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty; } - + public int describeContents() { return 0; } @@ -179,7 +180,7 @@ public final class Debug otherPrivateDirty = source.readInt(); otherSharedDirty = source.readInt(); } - + public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() { public MemoryInfo createFromParcel(Parcel source) { return new MemoryInfo(source); @@ -460,7 +461,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo * Like startMethodTracing(String, int, int), but taking an already-opened * FileDescriptor in which the trace is written. The file name is also * supplied simply for logging. Makes a dup of the file descriptor. - * + * * Not exposed in the SDK unless we are really comfortable with supporting * this and find it would be useful. * @hide @@ -1070,7 +1071,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo * static { * // Sets all the fields * Debug.setFieldsOn(MyDebugVars.class); - * + * * // Sets only the fields annotated with @Debug.DebugProperty * // Debug.setFieldsOn(MyDebugVars.class, true); * } diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java index a47c66a..e1c1678 100644 --- a/core/java/android/os/DropBoxManager.java +++ b/core/java/android/os/DropBoxManager.java @@ -58,6 +58,30 @@ public class DropBoxManager { private static final int HAS_BYTE_ARRAY = 8; /** + * Broadcast Action: This is broadcast when a new entry is added in the dropbox. + * You must hold the {@link android.Manifest.permission#READ_LOGS} permission + * in order to receive this broadcast. + * + * <p class="note">This is a protected intent that can only be sent + * by the system. + */ + public static final String ACTION_DROPBOX_ENTRY_ADDED = + "android.intent.action.DROPBOX_ENTRY_ADDED"; + + /** + * Extra for {@link android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED}: + * string containing the dropbox tag. + */ + public static final String EXTRA_TAG = "tag"; + + /** + * Extra for {@link android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED}: + * long integer value containing time (in milliseconds since January 1, 1970 00:00:00 UTC) + * when the entry was created. + */ + public static final String EXTRA_TIME = "time"; + + /** * A single entry retrieved from the drop box. * This may include a reference to a stream, so you must call * {@link #close()} when you are done using it. @@ -169,7 +193,12 @@ public class DropBoxManager { is = getInputStream(); if (is == null) return null; byte[] buf = new byte[maxBytes]; - return new String(buf, 0, Math.max(0, is.read(buf))); + int readBytes = 0; + int n = 0; + while (n >= 0 && (readBytes += n) < maxBytes) { + n = is.read(buf, readBytes, maxBytes - readBytes); + } + return new String(buf, 0, readBytes); } catch (IOException e) { return null; } finally { diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java index 49b72fe..7d128ec 100644 --- a/core/java/android/os/Message.java +++ b/core/java/android/os/Message.java @@ -85,9 +85,9 @@ public final class Message implements Parcelable { // sometimes we store linked lists of these things /*package*/ Message next; - private static Object mPoolSync = new Object(); - private static Message mPool; - private static int mPoolSize = 0; + private static final Object sPoolSync = new Object(); + private static Message sPool; + private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 10; @@ -96,11 +96,12 @@ public final class Message implements Parcelable { * avoid allocating new objects in many cases. */ public static Message obtain() { - synchronized (mPoolSync) { - if (mPool != null) { - Message m = mPool; - mPool = m.next; + synchronized (sPoolSync) { + if (sPool != null) { + Message m = sPool; + sPool = m.next; m.next = null; + sPoolSize--; return m; } } @@ -237,12 +238,12 @@ public final class Message implements Parcelable { * freed. */ public void recycle() { - synchronized (mPoolSync) { - if (mPoolSize < MAX_POOL_SIZE) { + synchronized (sPoolSync) { + if (sPoolSize < MAX_POOL_SIZE) { clearForRecycle(); - - next = mPool; - mPool = this; + next = sPool; + sPool = this; + sPoolSize++; } } } @@ -453,4 +454,3 @@ public final class Message implements Parcelable { replyTo = Messenger.readMessengerOrNullFromParcel(source); } } - diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java index bbad2b6..45c8174 100644 --- a/core/java/android/preference/DialogPreference.java +++ b/core/java/android/preference/DialogPreference.java @@ -322,7 +322,7 @@ public abstract class DialogPreference extends Preference implements private void requestInputMethod(Dialog dialog) { Window window = dialog.getWindow(); window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE | - WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); } /** diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java index f842d75..f44cbe4 100644 --- a/core/java/android/preference/ListPreference.java +++ b/core/java/android/preference/ListPreference.java @@ -39,6 +39,7 @@ public class ListPreference extends DialogPreference { private CharSequence[] mEntries; private CharSequence[] mEntryValues; private String mValue; + private String mSummary; private int mClickedDialogEntryIndex; public ListPreference(Context context, AttributeSet attrs) { @@ -49,8 +50,16 @@ public class ListPreference extends DialogPreference { mEntries = a.getTextArray(com.android.internal.R.styleable.ListPreference_entries); mEntryValues = a.getTextArray(com.android.internal.R.styleable.ListPreference_entryValues); a.recycle(); + + /* Retrieve the Preference summary attribute since it's private + * in the Preference class. + */ + a = context.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.Preference, 0, 0); + mSummary = a.getString(com.android.internal.R.styleable.Preference_summary); + a.recycle(); } - + public ListPreference(Context context) { this(context, null); } @@ -127,6 +136,43 @@ public class ListPreference extends DialogPreference { } /** + * Returns the summary of this ListPreference. If the summary + * has a {@linkplain java.lang.String#format String formatting} + * marker in it (i.e. "%s" or "%1$s"), then the current entry + * value will be substituted in its place. + * + * @return the summary with appropriate string substitution + */ + @Override + public CharSequence getSummary() { + final CharSequence entry = getEntry(); + if (mSummary == null || entry == null) { + return super.getSummary(); + } else { + return String.format(mSummary, entry); + } + } + + /** + * Sets the summary for this Preference with a CharSequence. + * If the summary has a + * {@linkplain java.lang.String#format String formatting} + * marker in it (i.e. "%s" or "%1$s"), then the current entry + * value will be substituted in its place when it's retrieved. + * + * @param summary The summary for the preference. + */ + @Override + public void setSummary(CharSequence summary) { + super.setSummary(summary); + if (summary == null && mSummary != null) { + mSummary = null; + } else if (summary != null && !summary.equals(mSummary)) { + mSummary = summary.toString(); + } + } + + /** * Sets the value to the given index from the entry values. * * @param index The index of the value to set. diff --git a/core/java/android/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java index 95e5432..fae5f1a 100644 --- a/core/java/android/preference/PreferenceScreen.java +++ b/core/java/android/preference/PreferenceScreen.java @@ -80,6 +80,8 @@ public final class PreferenceScreen extends PreferenceGroup implements AdapterVi private ListAdapter mRootAdapter; private Dialog mDialog; + + private ListView mListView; /** * Do NOT use this constructor, use {@link PreferenceManager#createPreferenceScreen(Context)}. @@ -145,15 +147,18 @@ public final class PreferenceScreen extends PreferenceGroup implements AdapterVi private void showDialog(Bundle state) { Context context = getContext(); - ListView listView = new ListView(context); - bind(listView); + if (mListView != null) { + mListView.setAdapter(null); + } + mListView = new ListView(context); + bind(mListView); // Set the title bar if title is available, else no title bar final CharSequence title = getTitle(); Dialog dialog = mDialog = new Dialog(context, TextUtils.isEmpty(title) ? com.android.internal.R.style.Theme_NoTitleBar : com.android.internal.R.style.Theme); - dialog.setContentView(listView); + dialog.setContentView(mListView); if (!TextUtils.isEmpty(title)) { dialog.setTitle(title); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5aa22fb..2a13d520 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3620,7 +3620,7 @@ public final class Settings { while (intent == null && c.moveToNext()) { try { String intentURI = c.getString(c.getColumnIndexOrThrow(INTENT)); - intent = Intent.getIntent(intentURI); + intent = Intent.parseUri(intentURI, 0); } catch (java.net.URISyntaxException e) { // The stored URL is bad... ignore it. } catch (IllegalArgumentException e) { @@ -3678,7 +3678,7 @@ public final class Settings { ContentValues values = new ContentValues(); if (title != null) values.put(TITLE, title); if (folder != null) values.put(FOLDER, folder); - values.put(INTENT, intent.toURI()); + values.put(INTENT, intent.toUri(0)); if (shortcut != 0) values.put(SHORTCUT, (int) shortcut); values.put(ORDERING, ordering); return cr.insert(CONTENT_URI, values); @@ -3730,7 +3730,7 @@ public final class Settings { Intent intent; try { - intent = Intent.getIntent(intentUri); + intent = Intent.parseUri(intentUri, 0); } catch (URISyntaxException e) { return ""; } diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 6d8bd9b..803446f 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -25,6 +25,7 @@ import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SqliteWrapper; import android.net.Uri; +import android.os.Environment; import android.telephony.SmsMessage; import android.text.TextUtils; import android.util.Config; @@ -561,15 +562,24 @@ public final class Telephony { * values:</p> * * <ul> - * <li><em>transactionId (Integer)</em> - The WAP transaction - * ID</li> + * <li><em>transactionId (Integer)</em> - The WAP transaction ID</li> * <li><em>pduType (Integer)</em> - The WAP PDU type</li> * <li><em>header (byte[])</em> - The header of the message</li> * <li><em>data (byte[])</em> - The data payload of the message</li> + * <li><em>contentTypeParameters (HashMap<String,String>)</em> + * - Any parameters associated with the content type + * (decoded from the WSP Content-Type header)</li> * </ul> * * <p>If a BroadcastReceiver encounters an error while processing * this intent it should set the result code appropriately.</p> + * + * <p>The contentTypeParameters extra value is map of content parameters keyed by + * their names.</p> + * + * <p>If any unassigned well-known parameters are encountered, the key of the map will + * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter. If + * a parameter has No-Value the value in the map will be null.</p> */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String WAP_PUSH_RECEIVED_ACTION = @@ -582,7 +592,7 @@ public final class Telephony { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String SIM_FULL_ACTION = - "android.provider.Telephony.SIM_FULL"; + "android.provider.Telephony.SIM_FULL"; /** * Broadcast Action: An incoming SMS has been rejected by the @@ -1525,7 +1535,8 @@ public final class Telephony { * which streams the captured image to the uri. Internally we write the media content * to this file. It's named '.temp.jpg' so Gallery won't pick it up. */ - public static final String SCRAP_FILE_PATH = "/sdcard/mms/scrapSpace/.temp.jpg"; + public static final String SCRAP_FILE_PATH = + Environment.getExternalStorageDirectory().getPath() + "/mms/scrapSpace/.temp.jpg"; } public static final class Intents { diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index c877c5c..80d6d30 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -30,6 +30,8 @@ import android.util.Log; import java.util.HashMap; import java.util.Set; +import android.os.PowerManager; + /** * TODO: Move this to @@ -51,6 +53,9 @@ class BluetoothEventLoop { private final BluetoothService mBluetoothService; private final BluetoothAdapter mAdapter; private final Context mContext; + // The WakeLock is used for bringing up the LCD during a pairing request + // from remote device when Android is in Suspend state. + private PowerManager.WakeLock mWakeLock; private static final int EVENT_RESTART_BLUETOOTH = 1; private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 2; @@ -105,6 +110,11 @@ class BluetoothEventLoop { mContext = context; mPasskeyAgentRequestData = new HashMap(); mAdapter = adapter; + //WakeLock instantiation in BluetoothEventLoop class + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP + | PowerManager.ON_AFTER_RELEASE, TAG); + mWakeLock.setReferenceCounted(false); initializeNativeDataNative(); } @@ -398,37 +408,46 @@ class BluetoothEventLoop { mHandler.sendMessageDelayed(message, 1500); return; } - + // Acquire wakelock during PIN code request to bring up LCD display + mWakeLock.acquire(); Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_CONSENT); mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); + // Release wakelock to allow the LCD to go off after the PIN popup notifcation. + mWakeLock.release(); return; } private void onRequestPasskeyConfirmation(String objectPath, int passkey, int nativeData) { String address = checkPairingRequestAndGetAddress(objectPath, nativeData); if (address == null) return; - + // Acquire wakelock during PIN code request to bring up LCD display + mWakeLock.acquire(); Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey); intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION); mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); + // Release wakelock to allow the LCD to go off after the PIN popup notifcation. + mWakeLock.release(); return; } private void onRequestPasskey(String objectPath, int nativeData) { String address = checkPairingRequestAndGetAddress(objectPath, nativeData); if (address == null) return; - + // Acquire wakelock during PIN code request to bring up LCD display + mWakeLock.acquire(); Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PASSKEY); mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); + // Release wakelock to allow the LCD to go off after the PIN popup notifcation. + mWakeLock.release(); return; } @@ -461,10 +480,14 @@ class BluetoothEventLoop { if (mBluetoothService.attemptAutoPair(address)) return; } } + // Acquire wakelock during PIN code request to bring up LCD display + mWakeLock.acquire(); Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN); mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); + // Release wakelock to allow the LCD to go off after the PIN popup notifcation. + mWakeLock.release(); return; } @@ -472,12 +495,16 @@ class BluetoothEventLoop { String address = checkPairingRequestAndGetAddress(objectPath, nativeData); if (address == null) return; + // Acquire wakelock during PIN code request to bring up LCD display + mWakeLock.acquire(); Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey); intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY); mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); + //Release wakelock to allow the LCD to go off after the PIN popup notifcation. + mWakeLock.release(); } private void onRequestOobData(String objectPath , int nativeData) { diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 26346d2..9f362d3 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -514,8 +514,11 @@ public abstract class WallpaperService extends Service { mLayout.windowAnimations = com.android.internal.R.style.Animation_Wallpaper; mInputChannel = new InputChannel(); - mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets, - mInputChannel); + if (mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets, + mInputChannel) < 0) { + Log.w(TAG, "Failed to add window while updating wallpaper surface."); + return; + } mCreated = true; InputQueue.registerInputChannel(mInputChannel, mInputHandler, diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 38ac9b7..4e197cd 100644..100755 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -749,6 +749,9 @@ public abstract class Layout { if (line == getLineCount() - 1) max++; + if (line != getLineCount() - 1) + max = TextUtils.getOffsetBefore(mText, getLineEnd(line)); + int best = min; float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz); @@ -893,7 +896,7 @@ public abstract class Layout { Directions dirs = getLineDirections(line); if (line != getLineCount() - 1) - end--; + end = TextUtils.getOffsetBefore(mText, end); float horiz = getPrimaryHorizontal(offset); @@ -993,7 +996,7 @@ public abstract class Layout { Directions dirs = getLineDirections(line); if (line != getLineCount() - 1) - end--; + end = TextUtils.getOffsetBefore(mText, end); float horiz = getPrimaryHorizontal(offset); @@ -1564,7 +1567,8 @@ public abstract class Layout { h = dir * nextTab(text, start, end, h * dir, tabs); } - if (bm != null) { + if (j != there && bm != null) { + if (offset == start + j) return h; workPaint.set(paint); Styled.measureText(paint, workPaint, text, j, j + 2, null); @@ -1958,4 +1962,3 @@ public abstract class Layout { new Directions(new short[] { 0, 32767 }); } - diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index f02ad2a..d0d2482 100644..100755 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -313,7 +313,9 @@ extends Layout class); if (spanned == null) { - paint.getTextWidths(sub, i, next, widths); + final int actualNum = paint.getTextWidths(sub, i, next, widths); + if (next - i > actualNum) + adjustTextWidths(widths, sub, i, next, actualNum); System.arraycopy(widths, 0, widths, end - start + (i - start), next - i); @@ -321,9 +323,11 @@ extends Layout } else { mWorkPaint.baselineShift = 0; - Styled.getTextWidths(paint, mWorkPaint, - spanned, i, next, - widths, fm); + final int actualNum = Styled.getTextWidths(paint, mWorkPaint, + spanned, i, next, + widths, fm); + if (next - i > actualNum) + adjustTextWidths(widths, spanned, i, next, actualNum); System.arraycopy(widths, 0, widths, end - start + (i - start), next - i); @@ -966,6 +970,22 @@ extends Layout return low; } + private static void adjustTextWidths(float[] widths, CharSequence text, + int curPos, int nextPos, int actualNum) { + try { + int dstIndex = nextPos - curPos - 1; + for (int srcIndex = actualNum - 1; srcIndex >= 0; srcIndex--) { + final char c = text.charAt(dstIndex + curPos); + if (c >= 0xD800 && c <= 0xDFFF) { + widths[dstIndex--] = 0.0f; + } + widths[dstIndex--] = widths[srcIndex]; + } + } catch (IndexOutOfBoundsException e) { + Log.e("text", "adjust text widths failed"); + } + } + private int out(CharSequence text, int start, int end, int above, int below, int top, int bottom, int v, float spacingmult, float spacingadd, diff --git a/core/java/android/text/Styled.java b/core/java/android/text/Styled.java index 513b2cd..13cc42c 100644..100755 --- a/core/java/android/text/Styled.java +++ b/core/java/android/text/Styled.java @@ -203,9 +203,10 @@ public class Styled } } + int result; if (replacement == null) { workPaint.getFontMetricsInt(fmi); - workPaint.getTextWidths(text, start, end, widths); + result = workPaint.getTextWidths(text, start, end, widths); } else { int wid = replacement.getSize(workPaint, text, start, end, fmi); @@ -214,8 +215,9 @@ public class Styled for (int i = start + 1; i < end; i++) widths[i - start] = 0; } + result = end - start; } - return end - start; + return result; } /** diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index 4e2c3c3..a95dad7 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -502,7 +502,7 @@ public class DateUtils } } } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) { - count = duration / DAY_IN_MILLIS; + count = getNumberOfDaysPassed(time, now); if (past) { if (abbrevRelative) { resId = com.android.internal.R.plurals.abbrev_num_days_ago; @@ -527,6 +527,24 @@ public class DateUtils } /** + * Returns the number of days passed between two dates. + * + * @param date1 first date + * @param date2 second date + * @return number of days passed between to dates. + */ + private synchronized static long getNumberOfDaysPassed(long date1, long date2) { + if (sThenTime == null) { + sThenTime = new Time(); + } + sThenTime.set(date1); + int day1 = Time.getJulianDay(date1, sThenTime.gmtoff); + sThenTime.set(date2); + int day2 = Time.getJulianDay(date2, sThenTime.gmtoff); + return Math.abs(day2 - day1); + } + + /** * Return string describing the elapsed time since startTime formatted like * "[relative time/date], [time]". * <p> @@ -1595,40 +1613,45 @@ public class DateUtils public static CharSequence getRelativeTimeSpanString(Context c, long millis, boolean withPreposition) { + String result; long now = System.currentTimeMillis(); long span = now - millis; - if (sNowTime == null) { - sNowTime = new Time(); - sThenTime = new Time(); - } + synchronized (DateUtils.class) { + if (sNowTime == null) { + sNowTime = new Time(); + } - sNowTime.set(now); - sThenTime.set(millis); + if (sThenTime == null) { + sThenTime = new Time(); + } - String result; - int prepositionId; - if (span < DAY_IN_MILLIS && sNowTime.weekDay == sThenTime.weekDay) { - // Same day - int flags = FORMAT_SHOW_TIME; - result = formatDateRange(c, millis, millis, flags); - prepositionId = R.string.preposition_for_time; - } else if (sNowTime.year != sThenTime.year) { - // Different years - int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE; - result = formatDateRange(c, millis, millis, flags); - - // This is a date (like "10/31/2008" so use the date preposition) - prepositionId = R.string.preposition_for_date; - } else { - // Default - int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH; - result = formatDateRange(c, millis, millis, flags); - prepositionId = R.string.preposition_for_date; - } - if (withPreposition) { - Resources res = c.getResources(); - result = res.getString(prepositionId, result); + sNowTime.set(now); + sThenTime.set(millis); + + int prepositionId; + if (span < DAY_IN_MILLIS && sNowTime.weekDay == sThenTime.weekDay) { + // Same day + int flags = FORMAT_SHOW_TIME; + result = formatDateRange(c, millis, millis, flags); + prepositionId = R.string.preposition_for_time; + } else if (sNowTime.year != sThenTime.year) { + // Different years + int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE; + result = formatDateRange(c, millis, millis, flags); + + // This is a date (like "10/31/2008" so use the date preposition) + prepositionId = R.string.preposition_for_date; + } else { + // Default + int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH; + result = formatDateRange(c, millis, millis, flags); + prepositionId = R.string.preposition_for_date; + } + if (withPreposition) { + Resources res = c.getResources(); + result = res.getString(prepositionId, result); + } } return result; } diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java index 8eae111..c05a8fe 100644 --- a/core/java/android/text/format/Time.java +++ b/core/java/android/text/format/Time.java @@ -32,7 +32,7 @@ public class Time { private static final String Y_M_D_T_H_M_S_000 = "%Y-%m-%dT%H:%M:%S.000"; private static final String Y_M_D_T_H_M_S_000_Z = "%Y-%m-%dT%H:%M:%S.000Z"; private static final String Y_M_D = "%Y-%m-%d"; - + public static final String TIMEZONE_UTC = "UTC"; /** @@ -170,11 +170,11 @@ public class Time { public Time() { this(TimeZone.getDefault().getID()); } - + /** * A copy constructor. Construct a Time object by copying the given * Time object. No normalization occurs. - * + * * @param other */ public Time(Time other) { @@ -185,17 +185,17 @@ public class Time { * Ensures the values in each field are in range. For example if the * current value of this calendar is March 32, normalize() will convert it * to April 1. It also fills in weekDay, yearDay, isDst and gmtoff. - * + * * <p> * If "ignoreDst" is true, then this method sets the "isDst" field to -1 * (the "unknown" value) before normalizing. It then computes the * correct value for "isDst". - * + * * <p> * See {@link #toMillis(boolean)} for more information about when to * use <tt>true</tt> or <tt>false</tt> for "ignoreDst". - * - * @return the UTC milliseconds since the epoch + * + * @return the UTC milliseconds since the epoch */ native public long normalize(boolean ignoreDst); @@ -379,13 +379,13 @@ public class Time { * Parses a date-time string in either the RFC 2445 format or an abbreviated * format that does not include the "time" field. For example, all of the * following strings are valid: - * + * * <ul> * <li>"20081013T160000Z"</li> * <li>"20081013T160000"</li> * <li>"20081013"</li> * </ul> - * + * * Returns whether or not the time is in UTC (ends with Z). If the string * ends with "Z" then the timezone is set to UTC. If the date-time string * included only a date and no time field, then the <code>allDay</code> @@ -396,10 +396,10 @@ public class Time { * <code>yearDay</code>, and <code>gmtoff</code> are always set to zero, * and the field <code>isDst</code> is set to -1 (unknown). To set those * fields, call {@link #normalize(boolean)} after parsing. - * + * * To parse a date-time string and convert it to UTC milliseconds, do * something like this: - * + * * <pre> * Time time = new Time(); * String date = "20081013T160000Z"; @@ -428,25 +428,25 @@ public class Time { * Parse a time in RFC 3339 format. This method also parses simple dates * (that is, strings that contain no time or time offset). For example, * all of the following strings are valid: - * + * * <ul> * <li>"2008-10-13T16:00:00.000Z"</li> * <li>"2008-10-13T16:00:00.000+07:00"</li> * <li>"2008-10-13T16:00:00.000-07:00"</li> * <li>"2008-10-13"</li> * </ul> - * + * * <p> * If the string contains a time and time offset, then the time offset will * be used to convert the time value to UTC. * </p> - * + * * <p> * If the given string contains just a date (with no time field), then * the {@link #allDay} field is set to true and the {@link #hour}, * {@link #minute}, and {@link #second} fields are set to zero. * </p> - * + * * <p> * Returns true if the resulting time value is in UTC time. * </p> @@ -462,7 +462,7 @@ public class Time { } return false; } - + native private boolean nativeParse3339(String s); /** @@ -484,13 +484,13 @@ public class Time { * <em>not</em> change any of the fields in this Time object. If you want * to normalize the fields in this Time object and also get the milliseconds * then use {@link #normalize(boolean)}. - * + * * <p> * If "ignoreDst" is false, then this method uses the current setting of the * "isDst" field and will adjust the returned time if the "isDst" field is * wrong for the given time. See the sample code below for an example of * this. - * + * * <p> * If "ignoreDst" is true, then this method ignores the current setting of * the "isDst" field in this Time object and will instead figure out the @@ -499,27 +499,27 @@ public class Time { * correct value of the "isDst" field is when the time is inherently * ambiguous because it falls in the hour that is repeated when switching * from Daylight-Saving Time to Standard Time. - * + * * <p> * Here is an example where <tt>toMillis(true)</tt> adjusts the time, * assuming that DST changes at 2am on Sunday, Nov 4, 2007. - * + * * <pre> * Time time = new Time(); - * time.set(2007, 10, 4); // set the date to Nov 4, 2007, 12am + * time.set(4, 10, 2007); // set the date to Nov 4, 2007, 12am * time.normalize(); // this sets isDst = 1 * time.monthDay += 1; // changes the date to Nov 5, 2007, 12am * millis = time.toMillis(false); // millis is Nov 4, 2007, 11pm * millis = time.toMillis(true); // millis is Nov 5, 2007, 12am * </pre> - * + * * <p> * To avoid this problem, use <tt>toMillis(true)</tt> * after adding or subtracting days or explicitly setting the "monthDay" * field. On the other hand, if you are adding * or subtracting hours or minutes, then you should use * <tt>toMillis(false)</tt>. - * + * * <p> * You should also use <tt>toMillis(false)</tt> if you want * to read back the same milliseconds that you set with {@link #set(long)} @@ -531,14 +531,14 @@ public class Time { * Sets the fields in this Time object given the UTC milliseconds. After * this method returns, all the fields are normalized. * This also sets the "isDst" field to the correct value. - * + * * @param millis the time in UTC milliseconds since the epoch. */ native public void set(long millis); /** * Format according to RFC 2445 DATETIME type. - * + * * <p> * The same as format("%Y%m%dT%H%M%S"). */ @@ -584,7 +584,7 @@ public class Time { * Sets the date from the given fields. Also sets allDay to true. * Sets weekDay, yearDay and gmtoff to 0, and isDst to -1. * Call {@link #normalize(boolean)} if you need those. - * + * * @param monthDay the day of the month (in the range [1,31]) * @param month the zero-based month number (in the range [0,11]) * @param year the year @@ -606,7 +606,7 @@ public class Time { /** * Returns true if the time represented by this Time object occurs before * the given time. - * + * * @param that a given Time object to compare against * @return true if this time is less than the given time */ @@ -618,7 +618,7 @@ public class Time { /** * Returns true if the time represented by this Time object occurs after * the given time. - * + * * @param that a given Time object to compare against * @return true if this time is greater than the given time */ @@ -632,12 +632,12 @@ public class Time { * closest Thursday yearDay. */ private static final int[] sThursdayOffset = { -3, 3, 2, 1, 0, -1, -2 }; - + /** * Computes the week number according to ISO 8601. The current Time * object must already be normalized because this method uses the * yearDay and weekDay fields. - * + * * <p> * In IS0 8601, weeks start on Monday. * The first week of the year (week 1) is defined by ISO 8601 as the @@ -645,12 +645,12 @@ public class Time { * Or equivalently, the week containing January 4. Or equivalently, * the week with the year's first Thursday in it. * </p> - * + * * <p> * The week number can be calculated by counting Thursdays. Week N * contains the Nth Thursday of the year. * </p> - * + * * @return the ISO week number. */ public int getWeekNumber() { @@ -661,7 +661,7 @@ public class Time { if (closestThursday >= 0 && closestThursday <= 364) { return closestThursday / 7 + 1; } - + // The week crosses a year boundary. Time temp = new Time(this); temp.monthDay += sThursdayOffset[weekDay]; @@ -670,7 +670,7 @@ public class Time { } /** - * Return a string in the RFC 3339 format. + * Return a string in the RFC 3339 format. * <p> * If allDay is true, expresses the time as Y-M-D</p> * <p> @@ -691,13 +691,13 @@ public class Time { int offset = (int)Math.abs(gmtoff); int minutes = (offset % 3600) / 60; int hours = offset / 3600; - + return String.format("%s%s%02d:%02d", base, sign, hours, minutes); } } - + /** - * Returns true if the day of the given time is the epoch on the Julian Calendar + * Returns true if the day of the given time is the epoch on the Julian Calendar * (January 1, 1970 on the Gregorian calendar). * * @param time the time to test @@ -707,7 +707,7 @@ public class Time { long millis = time.toMillis(true); return getJulianDay(millis, 0) == EPOCH_JULIAN_DAY; } - + /** * Computes the Julian day number, given the UTC milliseconds * and the offset (in seconds) from UTC. The Julian day for a given @@ -716,10 +716,10 @@ public class Time { * what timezone is being used. The Julian day is useful for testing * if two events occur on the same day and for determining the relative * time of an event from the present ("yesterday", "3 days ago", etc.). - * + * * <p> * Use {@link #toMillis(boolean)} to get the milliseconds. - * + * * @param millis the time in UTC milliseconds * @param gmtoff the offset from UTC in seconds * @return the Julian day @@ -729,7 +729,7 @@ public class Time { long julianDay = (millis + offsetMillis) / DateUtils.DAY_IN_MILLIS; return (int) julianDay + EPOCH_JULIAN_DAY; } - + /** * <p>Sets the time from the given Julian day number, which must be based on * the same timezone that is set in this Time object. The "gmtoff" field @@ -738,7 +738,7 @@ public class Time { * After this method returns all the fields will be normalized and the time * will be set to 12am at the beginning of the given Julian day. * </p> - * + * * <p> * The only exception to this is if 12am does not exist for that day because * of daylight saving time. For example, Cairo, Eqypt moves time ahead one @@ -746,7 +746,7 @@ public class Time { * also change daylight saving time at 12am. In those cases, the time * will be set to 1am. * </p> - * + * * @param julianDay the Julian day in the timezone for this Time object * @return the UTC milliseconds for the beginning of the Julian day */ @@ -756,13 +756,13 @@ public class Time { // the day. long millis = (julianDay - EPOCH_JULIAN_DAY) * DateUtils.DAY_IN_MILLIS; set(millis); - + // Figure out how close we are to the requested Julian day. // We can't be off by more than a day. int approximateDay = getJulianDay(millis, gmtoff); int diff = julianDay - approximateDay; monthDay += diff; - + // Set the time to 12am and re-normalize. hour = 0; minute = 0; diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java index 15fb839..8ad9a62 100644 --- a/core/java/android/view/FocusFinder.java +++ b/core/java/android/view/FocusFinder.java @@ -266,7 +266,7 @@ public class FocusFinder { /** - * Do the "beams" w.r.t the given direcition's axos of rect1 and rect2 overlap? + * Do the "beams" w.r.t the given direcition's axis of rect1 and rect2 overlap? * @param direction the direction (up, down, left, right) * @param rect1 The first rectangle * @param rect2 The second rectangle diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 194c013..d5e411a 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -38,7 +38,7 @@ import java.util.HashMap; * for the device you are running on. For example: * * <pre>LayoutInflater inflater = (LayoutInflater)context.getSystemService - * Context.LAYOUT_INFLATER_SERVICE);</pre> + * (Context.LAYOUT_INFLATER_SERVICE);</pre> * * <p> * To create a new LayoutInflater with an additional {@link Factory} for your diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 1766345..232dd6a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3944,6 +3944,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility imm.focusOut(this); } removeLongPressCallback(); + removeTapCallback(); onFocusLost(); } else if (imm != null && (mPrivateFlags & FOCUSED) != 0) { imm.focusIn(this); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 091844e..d6dcd4c 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1050,14 +1050,6 @@ public interface WindowManager extends ViewManager { gravity = o.gravity; changes |= LAYOUT_CHANGED; } - if (horizontalMargin != o.horizontalMargin) { - horizontalMargin = o.horizontalMargin; - changes |= LAYOUT_CHANGED; - } - if (verticalMargin != o.verticalMargin) { - verticalMargin = o.verticalMargin; - changes |= LAYOUT_CHANGED; - } if (format != o.format) { format = o.format; changes |= FORMAT_CHANGED; diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java index 7fd993a..021b53c 100644 --- a/core/java/android/webkit/FrameLoader.java +++ b/core/java/android/webkit/FrameLoader.java @@ -18,6 +18,7 @@ package android.webkit; import android.net.http.EventHandler; import android.net.http.RequestHandle; +import android.os.Build; import android.util.Log; import android.webkit.CacheManager.CacheResult; @@ -35,6 +36,7 @@ class FrameLoader { private int mCacheMode; private String mReferrer; private String mContentType; + private final String mUaprofHeader; private static final int URI_PROTOCOL = 0x100; @@ -57,6 +59,8 @@ class FrameLoader { mMethod = method; mCacheMode = WebSettings.LOAD_NORMAL; mSettings = settings; + mUaprofHeader = mListener.getContext().getResources().getString( + com.android.internal.R.string.config_useragentprofile_url, Build.MODEL); } public void setReferrer(String ref) { @@ -356,6 +360,11 @@ class FrameLoader { } mHeaders.put("User-Agent", mSettings.getUserAgentString()); + + // Set the x-wap-profile header + if (mUaprofHeader != null && mUaprofHeader.length() > 0) { + mHeaders.put("x-wap-profile", mUaprofHeader); + } } /** diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java index ca9ad53..c1ac180 100644 --- a/core/java/android/webkit/MimeTypeMap.java +++ b/core/java/android/webkit/MimeTypeMap.java @@ -369,10 +369,13 @@ public class MimeTypeMap { sMimeTypeMap.loadEntry("application/x-xfig", "fig"); sMimeTypeMap.loadEntry("application/xhtml+xml", "xhtml"); sMimeTypeMap.loadEntry("audio/3gpp", "3gpp"); + sMimeTypeMap.loadEntry("audio/amr", "amr"); sMimeTypeMap.loadEntry("audio/basic", "snd"); sMimeTypeMap.loadEntry("audio/midi", "mid"); sMimeTypeMap.loadEntry("audio/midi", "midi"); sMimeTypeMap.loadEntry("audio/midi", "kar"); + sMimeTypeMap.loadEntry("audio/midi", "xmf"); + sMimeTypeMap.loadEntry("audio/mobile-xmf", "mxmf"); sMimeTypeMap.loadEntry("audio/mpeg", "mpga"); sMimeTypeMap.loadEntry("audio/mpeg", "mpega"); sMimeTypeMap.loadEntry("audio/mpeg", "mp2"); diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 1915425..7f7a25e 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -313,6 +313,10 @@ public class WebView extends AbsoluteLayout // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK private boolean mAutoRedraw; + // Reference to the AlertDialog displayed by InvokeListBox. + // It's used to dismiss the dialog in destroy if not done before. + private AlertDialog mListBoxDialog = null; + static final String LOGTAG = "webview"; private static class ExtendedZoomControls extends FrameLayout { @@ -1301,6 +1305,10 @@ public class WebView extends AbsoluteLayout */ public void destroy() { clearHelpers(); + if (mListBoxDialog != null) { + mListBoxDialog.dismiss(); + mListBoxDialog = null; + } if (mWebViewCore != null) { // Set the handlers to null before destroying WebViewCore so no // more messages will be posted. @@ -4173,6 +4181,16 @@ public class WebView extends AbsoluteLayout } } + if (keyCode == KeyEvent.KEYCODE_PAGE_UP) { + pageUp(false); + return true; + } + + if (keyCode == KeyEvent.KEYCODE_PAGE_DOWN) { + pageDown(false); + return true; + } + if (keyCode >= KeyEvent.KEYCODE_DPAD_UP && keyCode <= KeyEvent.KEYCODE_DPAD_RIGHT) { switchOutDrawHistory(); @@ -7540,7 +7558,7 @@ public class WebView extends AbsoluteLayout EventHub.SINGLE_LISTBOX_CHOICE, -2, 0); }}); } - final AlertDialog dialog = b.create(); + mListBoxDialog = b.create(); listView.setAdapter(adapter); listView.setFocusableInTouchMode(true); // There is a bug (1250103) where the checks in a ListView with @@ -7562,7 +7580,8 @@ public class WebView extends AbsoluteLayout int position, long id) { mWebViewCore.sendMessage( EventHub.SINGLE_LISTBOX_CHOICE, (int)id, 0); - dialog.dismiss(); + mListBoxDialog.dismiss(); + mListBoxDialog = null; } }); if (mSelection != -1) { @@ -7574,13 +7593,14 @@ public class WebView extends AbsoluteLayout adapter.registerDataSetObserver(observer); } } - dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { + mListBoxDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { mWebViewCore.sendMessage( EventHub.SINGLE_LISTBOX_CHOICE, -2, 0); + mListBoxDialog = null; } }); - dialog.show(); + mListBoxDialog.show(); } } diff --git a/core/java/android/widget/AbsoluteLayout.java b/core/java/android/widget/AbsoluteLayout.java index b829655..970cbe3 100644 --- a/core/java/android/widget/AbsoluteLayout.java +++ b/core/java/android/widget/AbsoluteLayout.java @@ -187,7 +187,7 @@ public class AbsoluteLayout extends ViewGroup { * </ul> * * @param c the application environment - * @param attrs the set of attributes fom which to extract the layout + * @param attrs the set of attributes from which to extract the layout * parameters values */ public LayoutParams(Context c, AttributeSet attrs) { diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java index 32e5504..03ada94 100644 --- a/core/java/android/widget/ArrayAdapter.java +++ b/core/java/android/widget/ArrayAdapter.java @@ -24,6 +24,7 @@ import android.view.ViewGroup; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Comparator; import java.util.Collections; @@ -83,7 +84,7 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable { */ private boolean mNotifyOnChange = true; - private Context mContext; + private Context mContext; private ArrayList<T> mOriginalValues; private ArrayFilter mFilter; @@ -181,6 +182,44 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable { } /** + * Adds the specified Collection at the end of the array. + * + * @param collection The Collection to add at the end of the array. + */ + public void addAll(Collection<? extends T> collection) { + if (mOriginalValues != null) { + synchronized (mLock) { + mOriginalValues.addAll(collection); + if (mNotifyOnChange) notifyDataSetChanged(); + } + } else { + mObjects.addAll(collection); + if (mNotifyOnChange) notifyDataSetChanged(); + } + } + + /** + * Adds the specified items at the end of the array. + * + * @param items The items to add at the end of the array. + */ + public void addAll(T ... items) { + if (mOriginalValues != null) { + synchronized (mLock) { + for (T item : items) { + mOriginalValues.add(item); + } + if (mNotifyOnChange) notifyDataSetChanged(); + } + } else { + for (T item : items) { + mObjects.add(item); + } + if (mNotifyOnChange) notifyDataSetChanged(); + } + } + + /** * Inserts the specified object at the specified index in the array. * * @param object The object to insert into the array. @@ -236,7 +275,7 @@ public class ArrayAdapter<T> extends BaseAdapter implements Filterable { */ public void sort(Comparator<? super T> comparator) { Collections.sort(mObjects, comparator); - if (mNotifyOnChange) notifyDataSetChanged(); + if (mNotifyOnChange) notifyDataSetChanged(); } /** diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index 54c4b36..aa68a74 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -154,6 +154,11 @@ class FastScroller { int textColorNormal = textColor.getDefaultColor(); mPaint.setColor(textColorNormal); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + // to show mOverlayDrawable properly + if (mList.getWidth() > 0 && mList.getHeight() > 0) { + onSizeChanged(mList.getWidth(), mList.getHeight(), 0, 0); + } mState = STATE_NONE; } diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index 4482b5b..10e7634 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -66,7 +66,8 @@ public class NumberPicker extends LinearLayout { public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() { final StringBuilder mBuilder = new StringBuilder(); - final java.util.Formatter mFmt = new java.util.Formatter(mBuilder); + final java.util.Formatter mFmt = new java.util.Formatter( + mBuilder, java.util.Locale.US); final Object[] mArgs = new Object[1]; public String toString(int value) { mArgs[0] = value; diff --git a/core/java/android/widget/NumberPickerButton.java b/core/java/android/widget/NumberPickerButton.java index 1c8579c..292b668 100644 --- a/core/java/android/widget/NumberPickerButton.java +++ b/core/java/android/widget/NumberPickerButton.java @@ -85,4 +85,12 @@ class NumberPickerButton extends ImageButton { mNumberPicker.cancelDecrement(); } } + + public void onWindowFocusChanged(boolean hasWindowFocus) { + super.onWindowFocusChanged(hasWindowFocus); + if (!hasWindowFocus) { + cancelLongpress(); + } + } + } diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java index afae7ef..b4b355a 100644 --- a/core/java/android/widget/TabWidget.java +++ b/core/java/android/widget/TabWidget.java @@ -109,7 +109,6 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { } private void initTabWidget() { - setOrientation(LinearLayout.HORIZONTAL); mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER; final Context context = mContext; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 41c9736..bdc5014 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -976,6 +976,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener setTypeface(tf, styleIndex); } + @Override + public void setEnabled(boolean enabled) { + if (enabled == isEnabled()) { + return; + } + + if (!enabled) { + // Hide the soft input if the currently active TextView is disabled + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null && imm.isActive(this)) { + imm.hideSoftInputFromWindow(getWindowToken(), 0); + } + } + super.setEnabled(enabled); + } + /** * Sets the typeface and style in which the text should be displayed, * and turns on the fake bold and italic bits in the Paint if the @@ -4571,7 +4587,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { - if (onCheckIsTextEditor()) { + if (onCheckIsTextEditor() && isEnabled()) { if (mInputMethodState == null) { mInputMethodState = new InputMethodState(); } @@ -4645,6 +4661,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener partialStartOffset = 0; partialEndOffset = N; } else { + // Now use the delta to determine the actual amount of text + // we need. + partialEndOffset += delta; // Adjust offsets to ensure we contain full spans. if (content instanceof Spanned) { Spanned spanned = (Spanned)content; @@ -4660,10 +4679,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } outText.partialStartOffset = partialStartOffset; - outText.partialEndOffset = partialEndOffset; - // Now use the delta to determine the actual amount of text - // we need. - partialEndOffset += delta; + outText.partialEndOffset = partialEndOffset - delta; + if (partialStartOffset > N) { partialStartOffset = N; } else if (partialStartOffset < 0) { @@ -4727,6 +4744,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener + ": " + ims.mTmpExtracted.text); imm.updateExtractedText(this, req.token, mInputMethodState.mTmpExtracted); + ims.mChangedStart = EXTRACT_UNKNOWN; + ims.mChangedEnd = EXTRACT_UNKNOWN; + ims.mChangedDelta = 0; + ims.mContentChanged = false; return true; } } @@ -6327,8 +6348,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener ims.mChangedStart = start; ims.mChangedEnd = start+before; } else { - if (ims.mChangedStart > start) ims.mChangedStart = start; - if (ims.mChangedEnd < (start+before)) ims.mChangedEnd = start+before; + ims.mChangedStart = Math.min(ims.mChangedStart, start); + ims.mChangedEnd = Math.max(ims.mChangedEnd, start + before - ims.mChangedDelta); } ims.mChangedDelta += after-before; } @@ -6826,7 +6847,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return superResult; } - if ((mMovement != null || onCheckIsTextEditor()) && mText instanceof Spannable && mLayout != null) { + if ((mMovement != null || onCheckIsTextEditor()) && isEnabled() && + mText instanceof Spannable && mLayout != null) { if (hasInsertionController()) { getInsertionController().onTouchEvent(event); } diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 81ca912..fefdcea 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -434,6 +434,7 @@ public class AlertController { View titleTemplate = mWindow.findViewById(R.id.title_template); titleTemplate.setVisibility(View.GONE); mIconView.setVisibility(View.GONE); + topPanel.setVisibility(View.GONE); hasTitle = false; } } diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java index 36f45b2..6039cc2 100755 --- a/core/java/com/android/internal/app/NetInitiatedActivity.java +++ b/core/java/com/android/internal/app/NetInitiatedActivity.java @@ -26,6 +26,8 @@ import android.os.Bundle; import android.widget.Toast; import android.util.Log; import android.location.LocationManager; + +import com.android.internal.R; import com.android.internal.location.GpsNetInitiatedHandler; /** @@ -42,10 +44,6 @@ public class NetInitiatedActivity extends AlertActivity implements DialogInterfa private static final int POSITIVE_BUTTON = AlertDialog.BUTTON_POSITIVE; private static final int NEGATIVE_BUTTON = AlertDialog.BUTTON_NEGATIVE; - // Dialog button text - public static final String BUTTON_TEXT_ACCEPT = "Accept"; - public static final String BUTTON_TEXT_DENY = "Deny"; - // Received ID from intent, -1 when no notification is in progress private int notificationId = -1; @@ -67,12 +65,13 @@ public class NetInitiatedActivity extends AlertActivity implements DialogInterfa // Set up the "dialog" final Intent intent = getIntent(); final AlertController.AlertParams p = mAlertParams; + Context context = getApplicationContext(); p.mIconId = com.android.internal.R.drawable.ic_dialog_usb; p.mTitle = intent.getStringExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_TITLE); p.mMessage = intent.getStringExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_MESSAGE); - p.mPositiveButtonText = BUTTON_TEXT_ACCEPT; + p.mPositiveButtonText = String.format(context.getString(R.string.gpsVerifYes)); p.mPositiveButtonListener = this; - p.mNegativeButtonText = BUTTON_TEXT_DENY; + p.mNegativeButtonText = String.format(context.getString(R.string.gpsVerifNo)); p.mNegativeButtonListener = this; notificationId = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_NOTIF_ID, -1); diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java index b7255bb..cd1b569 100644 --- a/core/java/com/android/internal/app/ShutdownThread.java +++ b/core/java/com/android/internal/app/ShutdownThread.java @@ -71,7 +71,8 @@ public final class ShutdownThread extends Thread { private boolean mActionDone; private Context mContext; private PowerManager mPowerManager; - private PowerManager.WakeLock mWakeLock; + private PowerManager.WakeLock mCpuWakeLock; + private PowerManager.WakeLock mScreenWakeLock; private Handler mHandler; private ShutdownThread() { @@ -138,7 +139,7 @@ public final class ShutdownThread extends Thread { private static void beginShutdownSequence(Context context) { synchronized (sIsStartedGuard) { if (sIsStarted) { - Log.d(TAG, "Request to shutdown already running, returning."); + Log.d(TAG, "Shutdown sequence already running, returning."); return; } sIsStarted = true; @@ -159,20 +160,36 @@ public final class ShutdownThread extends Thread { pd.show(); - // start the thread that initiates shutdown sInstance.mContext = context; sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - sInstance.mWakeLock = null; + + // make sure we never fall asleep again + sInstance.mCpuWakeLock = null; + try { + sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu"); + sInstance.mCpuWakeLock.setReferenceCounted(false); + sInstance.mCpuWakeLock.acquire(); + } catch (SecurityException e) { + Log.w(TAG, "No permission to acquire wake lock", e); + sInstance.mCpuWakeLock = null; + } + + // also make sure the screen stays on for better user experience + sInstance.mScreenWakeLock = null; if (sInstance.mPowerManager.isScreenOn()) { try { - sInstance.mWakeLock = sInstance.mPowerManager.newWakeLock( - PowerManager.FULL_WAKE_LOCK, "Shutdown"); - sInstance.mWakeLock.acquire(); + sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock( + PowerManager.FULL_WAKE_LOCK, TAG + "-screen"); + sInstance.mScreenWakeLock.setReferenceCounted(false); + sInstance.mScreenWakeLock.acquire(); } catch (SecurityException e) { Log.w(TAG, "No permission to acquire wake lock", e); - sInstance.mWakeLock = null; + sInstance.mScreenWakeLock = null; } } + + // start the thread that initiates shutdown sInstance.mHandler = new Handler() { }; sInstance.start(); diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index f020a06..9ec9610 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -978,7 +978,7 @@ public final class BatteryStatsImpl extends BatteryStats { private final Map<String, KernelWakelockStats> readKernelWakelockStats() { - byte[] buffer = new byte[4096]; + byte[] buffer = new byte[8192]; int len; try { @@ -1025,9 +1025,11 @@ public final class BatteryStatsImpl extends BatteryStats { for (endIndex=startIndex; endIndex < len && wlBuffer[endIndex] != '\n' && wlBuffer[endIndex] != '\0'; endIndex++); - // Don't go over the end of the buffer - if (endIndex < len) { - endIndex++; // endIndex is an exclusive upper bound. + endIndex++; // endIndex is an exclusive upper bound. + // Don't go over the end of the buffer, Process.parseProcLine might + // write to wlBuffer[endIndex] + if (endIndex >= (len - 1) ) { + return m; } String[] nameStringArray = mProcWakelocksName; diff --git a/core/java/com/android/internal/os/SamplingProfilerIntegration.java b/core/java/com/android/internal/os/SamplingProfilerIntegration.java index a3efbc8..ea278a6 100644 --- a/core/java/com/android/internal/os/SamplingProfilerIntegration.java +++ b/core/java/com/android/internal/os/SamplingProfilerIntegration.java @@ -96,7 +96,8 @@ public class SamplingProfilerIntegration { pending = true; snapshotWriter.execute(new Runnable() { public void run() { - String dir = "/sdcard/snapshots"; + String dir = + Environment.getExternalStorageDirectory().getPath() + "/snapshots"; if (!dirMade) { new File(dir).mkdirs(); if (new File(dir).isDirectory()) { diff --git a/core/java/com/google/android/mms/pdu/PduParser.java b/core/java/com/google/android/mms/pdu/PduParser.java index 21f0c93..8edfe52 100644 --- a/core/java/com/google/android/mms/pdu/PduParser.java +++ b/core/java/com/google/android/mms/pdu/PduParser.java @@ -163,6 +163,13 @@ public class PduParser { // or "application/vnd.wap.multipart.related" // or "application/vnd.wap.multipart.alternative" return retrieveConf; + } else if (ctTypeStr.equals(ContentType.MULTIPART_ALTERNATIVE)) { + // "application/vnd.wap.multipart.alternative" + // should take only the first part. + PduPart firstPart = mBody.getPart(0); + mBody.removeAll(); + mBody.addPart(0, firstPart); + return retrieveConf; } return null; case PduHeaders.MESSAGE_TYPE_DELIVERY_IND: |
