diff options
65 files changed, 1889 insertions, 1218 deletions
diff --git a/api/current.xml b/api/current.xml index 442fc4fd8dee..fd8a18040b22 100644 --- a/api/current.xml +++ b/api/current.xml @@ -25564,6 +25564,17 @@ visibility="public" > </method> +<method name="getCurrentModeType" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getNightMode" return="int" abstract="false" @@ -25588,33 +25599,73 @@ <parameter name="mode" type="int"> </parameter> </method> -<field name="MODE_AUTO" +<field name="ACTION_ENTER_CAR_MODE" + type="java.lang.String" + transient="false" + volatile="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_ENTER_DESK_MODE" + type="java.lang.String" + transient="false" + volatile="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_EXIT_CAR_MODE" + type="java.lang.String" + transient="false" + volatile="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_EXIT_DESK_MODE" + type="java.lang.String" + transient="false" + volatile="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="MODE_NIGHT_AUTO" type="int" transient="false" volatile="false" - value="3" + value="0" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> -<field name="MODE_NIGHT" +<field name="MODE_NIGHT_NO" type="int" transient="false" volatile="false" - value="2" + value="1" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> -<field name="MODE_NOTNIGHT" +<field name="MODE_NIGHT_YES" type="int" transient="false" volatile="false" - value="1" + value="2" static="true" final="true" deprecated="not deprecated" @@ -39068,17 +39119,6 @@ visibility="public" > </field> -<field name="EXTRA_CAR_MODE_ENABLED" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.intent.extra.CAR_MODE_ENABLED"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="EXTRA_CC" type="java.lang.String" transient="false" @@ -39233,17 +39273,6 @@ visibility="public" > </field> -<field name="EXTRA_PHYSICAL_DOCK_STATE" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.intent.extra.PHYSICAL_DOCK_STATE"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="EXTRA_REMOTE_INTENT_TOKEN" type="java.lang.String" transient="false" @@ -47911,6 +47940,17 @@ type="int" transient="false" volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="UI_MODE_TYPE_DESK" + type="int" + transient="false" + volatile="false" value="2" static="true" final="true" @@ -71481,6 +71521,19 @@ visibility="public" > </method> +<method name="reconnect" + return="void" + abstract="false" + native="true" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<exception name="IOException" type="java.io.IOException"> +</exception> +</method> <method name="release" return="void" abstract="false" @@ -74110,7 +74163,7 @@ type="float" transient="false" volatile="false" - value="0.001f" + value="0.0010f" static="true" final="true" deprecated="not deprecated" @@ -82150,6 +82203,210 @@ </parameter> </method> </interface> +<class name="CamcorderProfile" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<method name="get" + return="android.media.CamcorderProfile" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="quality" type="android.media.CamcorderProfile.Quality"> +</parameter> +</method> +<method name="getMmsRecordingDurationInSeconds" + return="int" + abstract="false" + native="false" + synchronized="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</method> +<field name="mAudioBitRate" + type="int" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="mAudioChannels" + type="int" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="mAudioCodec" + type="int" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="mAudioSampleRate" + type="int" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="mFileFormat" + type="int" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="mQuality" + type="android.media.CamcorderProfile.Quality" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="mVideoBitRate" + type="int" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="mVideoCodec" + type="int" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="mVideoFrameHeight" + type="int" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="mVideoFrameRate" + type="int" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="mVideoFrameWidth" + type="int" + transient="false" + volatile="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +<class name="CamcorderProfile.Quality" + extends="java.lang.Enum" + abstract="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +<method name="valueOf" + return="android.media.CamcorderProfile.Quality" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="name" type="java.lang.String"> +</parameter> +</method> +<method name="values" + return="android.media.CamcorderProfile.Quality[]" + abstract="false" + native="false" + synchronized="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</method> +</class> +<class name="CameraProfile" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="CameraProfile" + type="android.media.CameraProfile" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<method name="getImageEncodingQualityLevels" + return="int[]" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +</class> <class name="ExifInterface" extends="java.lang.Object" abstract="false" @@ -175209,6 +175466,17 @@ visibility="public" > </method> +<method name="getOverscrollMode" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getPaddingBottom" return="int" abstract="false" @@ -177374,6 +177642,19 @@ <parameter name="l" type="android.view.View.OnTouchListener"> </parameter> </method> +<method name="setOverscrollMode" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="overscrollMode" type="int"> +</parameter> +</method> <method name="setPadding" return="void" abstract="false" @@ -177996,6 +178277,39 @@ visibility="public" > </field> +<field name="OVERSCROLL_ALWAYS" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="OVERSCROLL_IF_CONTENT_SCROLLS" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="OVERSCROLL_NEVER" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET" type="int[]" transient="false" @@ -213929,7 +214243,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="t" type="T"> +<parameter name="arg0" type="T"> </parameter> </method> </interface> diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl index 6ac8a2a6ad78..bd637b7ac801 100644 --- a/core/java/android/app/IUiModeManager.aidl +++ b/core/java/android/app/IUiModeManager.aidl @@ -33,6 +33,11 @@ interface IUiModeManager { void disableCarMode(); /** + * Return the current running mode. + */ + int getCurrentModeType(); + + /** * Sets the night mode. * The mode can be one of: * 1 - notnight mode diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java index 1ae93150d049..cb947b1e46b4 100644 --- a/core/java/android/app/SuggestionsAdapter.java +++ b/core/java/android/app/SuggestionsAdapter.java @@ -32,6 +32,7 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.StateListDrawable; import android.net.Uri; +import android.os.Bundle; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; @@ -80,7 +81,7 @@ class SuggestionsAdapter extends ResourceCursorAdapter { private int mIconName1Col; private int mIconName2Col; private int mBackgroundColorCol; - + static final int NONE = -1; private final Runnable mStartSpinnerRunnable; @@ -121,7 +122,7 @@ class SuggestionsAdapter extends ResourceCursorAdapter { mSearchDialog.setWorking(false); } }; - + // delay 500ms when deleting getFilter().setDelayer(new Filter.Delayer() { @@ -129,7 +130,7 @@ class SuggestionsAdapter extends ResourceCursorAdapter { public long getPostingDelay(CharSequence constraint) { if (constraint == null) return 0; - + long delay = constraint.length() < mPreviousLength ? DELETE_KEY_POST_DELAY : 0; mPreviousLength = constraint.length(); return delay; @@ -203,15 +204,16 @@ class SuggestionsAdapter extends ResourceCursorAdapter { } private void updateSpinnerState(Cursor cursor) { + Bundle extras = cursor != null ? cursor.getExtras() : null; if (DBG) { Log.d(LOG_TAG, "updateSpinnerState - extra = " - + (cursor != null - ? cursor.getExtras().getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS) + + (extras != null + ? extras.getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS) : null)); } // Check if the Cursor indicates that the query is not complete and show the spinner - if (cursor != null - && cursor.getExtras().getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS)) { + if (extras != null + && extras.getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS)) { mSearchDialog.getWindow().getDecorView().post(mStartSpinnerRunnable); return; } diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java index aca8ab4ad613..defe42149b23 100644 --- a/core/java/android/app/UiModeManager.java +++ b/core/java/android/app/UiModeManager.java @@ -1,5 +1,7 @@ package android.app; +import android.content.Context; +import android.content.res.Configuration; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; @@ -9,6 +11,22 @@ import android.util.Log; * allow applications to control UI modes of the device. * It provides functionality to disable the car mode and it gives access to the * night mode settings. + * + * <p>These facilities are built on top of the underlying + * {@link android.content.Intent#ACTION_DOCK_EVENT} broadcasts that are sent when the user + * physical places the device into and out of a dock. When that happens, + * the UiModeManager switches the system {@link android.content.res.Configuration} + * to the appropriate UI mode, sends broadcasts about the mode switch, and + * starts the corresponding mode activity if appropriate. See the + * broadcasts {@link #ACTION_ENTER_CAR_MODE} and + * {@link #ACTION_ENTER_DESK_MODE} for more information. + * + * <p>In addition, the user may manually switch the system to car mode without + * physically being in a dock. While in car mode -- whether by manual action + * from the user or being physically placed in a dock -- a notification is + * displayed allowing the user to exit dock mode. Thus the dock mode + * represented here may be different than the current state of the underlying + * dock event broadcast. * * <p>You do not instantiate this class directly; instead, retrieve it through * {@link android.content.Context#getSystemService @@ -17,19 +35,72 @@ import android.util.Log; public class UiModeManager { private static final String TAG = "UiModeManager"; - public static final int MODE_NOTNIGHT = 1; - public static final int MODE_NIGHT = 2; - public static final int MODE_AUTO = 3; + /** + * Broadcast sent when the device's UI has switched to car mode, either + * by being placed in a car dock or explicit action of the user. After + * sending the broadcast, the system will start the intent + * {@link android.content.Intent#ACTION_MAIN} with category + * {@link android.content.Intent#CATEGORY_CAR_DOCK} + * to display the car UI, which typically what an application would + * implement to provide their own interface. However, applications can + * also monitor this Intent in order to be informed of mode changes or + * prevent the normal car UI from being displayed by setting the result + * of the broadcast to {@link Activity#RESULT_CANCELED}. + */ + public static String ACTION_ENTER_CAR_MODE = "android.app.action.ENTER_CAR_MODE"; + + /** + * Broadcast sent when the device's UI has switch away from car mode back + * to normal mode. Typically used by a car mode app, to dismiss itself + * when the user exits car mode. + */ + public static String ACTION_EXIT_CAR_MODE = "android.app.action.EXIT_CAR_MODE"; + + /** + * Broadcast sent when the device's UI has switched to desk mode, + * by being placed in a desk dock. After + * sending the broadcast, the system will start the intent + * {@link android.content.Intent#ACTION_MAIN} with category + * {@link android.content.Intent#CATEGORY_DESK_DOCK} + * to display the desk UI, which typically what an application would + * implement to provide their own interface. However, applications can + * also monitor this Intent in order to be informed of mode changes or + * prevent the normal desk UI from being displayed by setting the result + * of the broadcast to {@link Activity#RESULT_CANCELED}. + */ + public static String ACTION_ENTER_DESK_MODE = "android.app.action.ENTER_DESK_MODE"; + + /** + * Broadcast sent when the device's UI has switch away from car mode back + * to normal mode. Typically used by a car mode app, to dismiss itself + * when the user exits car mode. + */ + public static String ACTION_EXIT_DESK_MODE = "android.app.action.EXIT_DESK_MODE"; + + /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}: + * automatically switch night mode on and off based on the time. + */ + public static final int MODE_NIGHT_AUTO = Configuration.UI_MODE_NIGHT_UNDEFINED >> 4; + + /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}: + * never run in night mode. + */ + public static final int MODE_NIGHT_NO = Configuration.UI_MODE_NIGHT_NO >> 4; + + /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}: + * always run in night mode. + */ + public static final int MODE_NIGHT_YES = Configuration.UI_MODE_NIGHT_YES >> 4; private IUiModeManager mService; /*package*/ UiModeManager() { mService = IUiModeManager.Stub.asInterface( - ServiceManager.getService("uimode")); + ServiceManager.getService(Context.UI_MODE_SERVICE)); } /** - * Disables the car mode. + * Turn off special mode if currently in car mode. */ public void disableCarMode() { if (mService != null) { @@ -42,17 +113,35 @@ public class UiModeManager { } /** + * Return the current running mode type. May be one of + * {@link Configuration#UI_MODE_TYPE_NORMAL Configuration.UI_MODE_TYPE_NORMAL}, + * {@link Configuration#UI_MODE_TYPE_DESK Configuration.UI_MODE_TYPE_DESK}, or + * {@link Configuration#UI_MODE_TYPE_CAR Configuration.UI_MODE_TYPE_CAR}, + */ + public int getCurrentModeType() { + if (mService != null) { + try { + return mService.getCurrentModeType(); + } catch (RemoteException e) { + Log.e(TAG, "getCurrentModeType: RemoteException", e); + } + } + return Configuration.UI_MODE_TYPE_NORMAL; + } + + /** * Sets the night mode. Changes to the night mode are only effective when - * the car mode is enabled on a device. + * the car or desk mode is enabled on a device. * * <p>The mode can be one of: * <ul> - * <li><em>{@link #MODE_NOTNIGHT}<em> - sets the device into notnight + * <li><em>{@link #MODE_NIGHT_NO}<em> - sets the device into notnight * mode.</li> - * <li><em>{@link #MODE_NIGHT}</em> - sets the device into night mode. + * <li><em>{@link #MODE_NIGHT_YES}</em> - sets the device into night mode. * </li> - * <li><em>{@link #MODE_AUTO}</em> - automatic night/notnight switching + * <li><em>{@link #MODE_NIGHT_AUTO}</em> - automatic night/notnight switching * depending on the location and certain other sensors.</li> + * </ul> */ public void setNightMode(int mode) { if (mService != null) { @@ -67,8 +156,8 @@ public class UiModeManager { /** * Returns the currently configured night mode. * - * @return {@link #MODE_NOTNIGHT}, {@link #MODE_NIGHT} or {@link #MODE_AUTO} - * When an error occurred -1 is returned. + * @return {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES}, or + * {@link #MODE_NIGHT_AUTO}. When an error occurred -1 is returned. */ public int getNightMode() { if (mService != null) { diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 91b1c4e1d533..5fb2aaec83d7 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -29,6 +29,7 @@ import android.database.IContentObserver; import android.database.SQLException; import android.net.Uri; import android.os.Binder; +import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.Process; @@ -217,6 +218,13 @@ public abstract class ContentProvider implements ComponentCallbacks { return ContentProvider.this.openAssetFile(uri, mode); } + /** + * @hide + */ + public Bundle call(String method, String request, Bundle args) { + return ContentProvider.this.call(method, request, args); + } + private void enforceReadPermission(Uri uri) { final int uid = Binder.getCallingUid(); if (uid == mMyUid) { @@ -748,4 +756,18 @@ public abstract class ContentProvider implements ComponentCallbacks { } return results; } -}
\ No newline at end of file + + /** + * @hide -- until interface has proven itself + * + * Call an provider-defined method. This can be used to implement + * interfaces that are cheaper than using a Cursor. + * + * @param method Method name to call. Opaque to framework. + * @param request Nullable String argument passed to method. + * @param args Nullable Bundle argument passed to method. + */ + public Bundle call(String method, String request, Bundle args) { + return null; + } +} diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java index bacb6849e11f..81b805564921 100644 --- a/core/java/android/content/ContentProviderNative.java +++ b/core/java/android/content/ContentProviderNative.java @@ -26,6 +26,7 @@ import android.database.IBulkCursor; import android.database.IContentObserver; import android.net.Uri; import android.os.Binder; +import android.os.Bundle; import android.os.RemoteException; import android.os.IBinder; import android.os.Parcel; @@ -222,6 +223,21 @@ abstract public class ContentProviderNative extends Binder implements IContentPr } return true; } + + case CALL_TRANSACTION: + { + data.enforceInterface(IContentProvider.descriptor); + + String method = data.readString(); + String stringArg = data.readString(); + Bundle args = data.readBundle(); + + Bundle responseBundle = call(method, stringArg, args); + + reply.writeNoException(); + reply.writeBundle(responseBundle); + return true; + } } } catch (Exception e) { DatabaseUtils.writeExceptionToParcel(reply, e); @@ -485,6 +501,22 @@ final class ContentProviderProxy implements IContentProvider return fd; } + public Bundle call(String method, String request, Bundle args) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + + data.writeInterfaceToken(IContentProvider.descriptor); + + data.writeString(method); + data.writeString(request); + data.writeBundle(args); + + mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0); + + DatabaseUtils.readExceptionFromParcel(reply); + return reply.readBundle(); + } + private IBinder mRemote; } - diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 1b0ef340a1cc..bcef75edf17a 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -736,7 +736,7 @@ public abstract class ContentResolver { * @hide */ public final IContentProvider acquireProvider(String name) { - if(name == null) { + if (name == null) { return null; } return acquireProvider(mContext, name); diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java index 1b0ca5859540..67e7581e5ffd 100644 --- a/core/java/android/content/IContentProvider.java +++ b/core/java/android/content/IContentProvider.java @@ -22,10 +22,11 @@ import android.database.CursorWindow; import android.database.IBulkCursor; import android.database.IContentObserver; import android.net.Uri; -import android.os.RemoteException; +import android.os.Bundle; import android.os.IBinder; import android.os.IInterface; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import java.io.FileNotFoundException; import java.util.ArrayList; @@ -58,6 +59,17 @@ public interface IContentProvider extends IInterface { throws RemoteException, FileNotFoundException; public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws RemoteException, OperationApplicationException; + /** + * @hide -- until interface has proven itself + * + * Call an provider-defined method. This can be used to implement + * interfaces that are cheaper than using a Cursor. + * + * @param method Method name to call. Opaque to framework. + * @param request Nullable String argument passed to method. + * @param args Nullable Bundle argument passed to method. + */ + public Bundle call(String method, String request, Bundle args) throws RemoteException; /* IPC constants */ static final String descriptor = "android.content.IContentProvider"; @@ -71,4 +83,5 @@ public interface IContentProvider extends IInterface { static final int OPEN_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 13; static final int OPEN_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 14; static final int APPLY_BATCH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 19; + static final int CALL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 20; } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index e63851f0a603..fd5591d674be 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1838,21 +1838,17 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.REBOOT"; /** - * Broadcast Action: A sticky broadcast indicating the phone was docked - * or undocked. + * Broadcast Action: A sticky broadcast for changes in the physical + * docking state of the device. * * <p>The intent will have the following extra values: * <ul> * <li><em>{@link #EXTRA_DOCK_STATE}</em> - the current dock - * state, which depends on the state of the car mode.</li> - * <li><em>{@link #EXTRA_PHYSICAL_DOCK_STATE}</em> - the physical dock - * state.</li> - * <li><em>{@link #EXTRA_CAR_MODE_ENABLED}</em> - a boolean indicating the - * state of the car mode.</li> + * state, indicating which dock the device is physically in.</li> * </ul> - * <p>This is intended for monitoring the current dock state. - * To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK} - * or {@link #CATEGORY_DESK_DOCK} instead. + * <p>This is intended for monitoring the current physical dock state. + * See {@link android.app.UiModeManager} for the normal API dealing with + * dock mode changes. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_DOCK_EVENT = @@ -2014,15 +2010,15 @@ public class Intent implements Parcelable, Cloneable { "android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"; /** * An activity to run when device is inserted into a car dock. - * Used with {@link #ACTION_MAIN} to launch an activity. - * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead. + * Used with {@link #ACTION_MAIN} to launch an activity. For more + * information, see {@link android.app.UiModeManager}. */ @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK"; /** * An activity to run when device is inserted into a car dock. - * Used with {@link #ACTION_MAIN} to launch an activity. - * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead. + * Used with {@link #ACTION_MAIN} to launch an activity. For more + * information, see {@link android.app.UiModeManager}. */ @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK"; @@ -2191,22 +2187,6 @@ public class Intent implements Parcelable, Cloneable { public static final int EXTRA_DOCK_STATE_CAR = 2; /** - * Used as an int extra field in {@link android.content.Intent#ACTION_DOCK_EVENT} - * intents to request the physical dock state. Possible values are - * {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED}, - * {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or - * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}. - */ - public static final String EXTRA_PHYSICAL_DOCK_STATE = - "android.intent.extra.PHYSICAL_DOCK_STATE"; - - /** - * Used as an boolean extra field in {@link android.content.Intent#ACTION_DOCK_EVENT} - * intents to indicate that the car mode is enabled or not. - */ - public static final String EXTRA_CAR_MODE_ENABLED = "android.intent.extra.CAR_MODE_ENABLED"; - - /** * Boolean that can be supplied as meta-data with a dock activity, to * indicate that the dock should take over the home key when it is active. */ diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index a737283cf4ec..61e3004c327e 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -165,7 +165,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration public static final int UI_MODE_TYPE_MASK = 0x0f; public static final int UI_MODE_TYPE_UNDEFINED = 0x00; public static final int UI_MODE_TYPE_NORMAL = 0x01; - public static final int UI_MODE_TYPE_CAR = 0x02; + public static final int UI_MODE_TYPE_DESK = 0x02; + public static final int UI_MODE_TYPE_CAR = 0x03; public static final int UI_MODE_NIGHT_MASK = 0x30; public static final int UI_MODE_NIGHT_UNDEFINED = 0x00; @@ -175,11 +176,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration /** * Bit mask of the ui mode. Currently there are two fields: * <p>The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the - * device. They may be one of - * {@link #UI_MODE_TYPE_NORMAL} or {@link #UI_MODE_TYPE_CAR}. + * device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED}, + * {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK}, + * or {@link #UI_MODE_TYPE_CAR}. * * <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen - * is in a special mode. They may be one of + * is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED}, * {@link #UI_MODE_NIGHT_NO} or {@link #UI_MODE_NIGHT_YES}. */ public int uiMode; @@ -272,7 +274,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration navigationHidden = NAVIGATIONHIDDEN_UNDEFINED; orientation = ORIENTATION_UNDEFINED; screenLayout = SCREENLAYOUT_SIZE_UNDEFINED; - uiMode = UI_MODE_TYPE_NORMAL; + uiMode = UI_MODE_TYPE_UNDEFINED; seq = 0; } @@ -354,10 +356,17 @@ public final class Configuration implements Parcelable, Comparable<Configuration changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; screenLayout = delta.screenLayout; } - if (delta.uiMode != UI_MODE_TYPE_NORMAL + if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED) && uiMode != delta.uiMode) { changed |= ActivityInfo.CONFIG_UI_MODE; - uiMode = delta.uiMode; + if ((delta.uiMode&UI_MODE_TYPE_MASK) != UI_MODE_TYPE_UNDEFINED) { + uiMode = (uiMode&~UI_MODE_TYPE_MASK) + | (delta.uiMode&UI_MODE_TYPE_MASK); + } + if ((delta.uiMode&UI_MODE_NIGHT_MASK) != UI_MODE_NIGHT_UNDEFINED) { + uiMode = (uiMode&~UI_MODE_NIGHT_MASK) + | (delta.uiMode&UI_MODE_NIGHT_MASK); + } } if (delta.seq != 0) { @@ -439,7 +448,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration && screenLayout != delta.screenLayout) { changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; } - if (delta.uiMode != UI_MODE_TYPE_NORMAL + if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED) && uiMode != delta.uiMode) { changed |= ActivityInfo.CONFIG_UI_MODE; } diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 0efcad9b5ec2..85d52ec83de3 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -137,8 +137,6 @@ public class Camera { * can be connected to another process. * * @throws IOException if the method fails. - * - * @hide */ public native final void reconnect() throws IOException; diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index d6fe107b10b2..0ec1c7413552 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -132,6 +132,45 @@ public final class Bundle implements Parcelable, Cloneable { } /** + * Make a Bundle for a single key/value pair. + * + * @hide + */ + public static Bundle forPair(String key, String value) { + // TODO: optimize this case. + Bundle b = new Bundle(1); + b.putString(key, value); + return b; + } + + /** + * TODO: optimize this later (getting just the value part of a Bundle + * with a single pair) once Bundle.forPair() above is implemented + * with a special single-value Map implementation/serialization. + * + * Note: value in single-pair Bundle may be null. + * + * @hide + */ + public String getPairValue() { + unparcel(); + int size = mMap.size(); + if (size > 1) { + Log.w(LOG_TAG, "getPairValue() used on Bundle with multiple pairs."); + } + if (size == 0) { + return null; + } + Object o = mMap.values().iterator().next(); + try { + return (String) o; + } catch (ClassCastException e) { + typeWarning("getPairValue()", o, "String", e); + return null; + } + } + + /** * Changes the ClassLoader this Bundle uses when instantiating objects. * * @param loader An explicit ClassLoader to use when instantiating objects diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 0b90f9135250..46c82e4f4fae 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -2935,6 +2935,13 @@ public final class ContactsContract { */ public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(AUTHORITY_URI, "phone_lookup"); + + /** + * The MIME type of {@link #CONTENT_FILTER_URI} providing a directory of phone lookup rows. + * + * @hide + */ + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/phone_lookup"; } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 8f410a908c1d..726f98af600c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -27,6 +27,7 @@ import android.content.ContentQueryMap; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; +import android.content.IContentProvider; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -492,6 +493,16 @@ public final class Settings { // End of Intent actions for Settings /** + * @hide - Private call() method on SettingsProvider to read from 'system' table. + */ + public static final String CALL_METHOD_GET_SYSTEM = "GET_system"; + + /** + * @hide - Private call() method on SettingsProvider to read from 'secure' table. + */ + public static final String CALL_METHOD_GET_SECURE = "GET_secure"; + + /** * Activity Extra: Limit available options in launched activity based on the given authority. * <p> * This can be passed as an extra field in an Activity Intent with one or more syncable content @@ -544,23 +555,36 @@ public final class Settings { } } + // Thread-safe. private static class NameValueCache { private final String mVersionSystemProperty; private final Uri mUri; - // Must synchronize(mValues) to access mValues and mValuesVersion. + private static final String[] SELECT_VALUE = + new String[] { Settings.NameValueTable.VALUE }; + private static final String NAME_EQ_PLACEHOLDER = "name=?"; + + // Must synchronize on 'this' to access mValues and mValuesVersion. private final HashMap<String, String> mValues = new HashMap<String, String>(); private long mValuesVersion = 0; - public NameValueCache(String versionSystemProperty, Uri uri) { + // Initially null; set lazily and held forever. Synchronized on 'this'. + private IContentProvider mContentProvider = null; + + // The method we'll call (or null, to not use) on the provider + // for the fast path of retrieving settings. + private final String mCallCommand; + + public NameValueCache(String versionSystemProperty, Uri uri, String callCommand) { mVersionSystemProperty = versionSystemProperty; mUri = uri; + mCallCommand = callCommand; } public String getString(ContentResolver cr, String name) { long newValuesVersion = SystemProperties.getLong(mVersionSystemProperty, 0); - synchronized (mValues) { + synchronized (this) { if (mValuesVersion != newValuesVersion) { if (LOCAL_LOGV) { Log.v(TAG, "invalidate [" + mUri.getLastPathSegment() + "]: current " + @@ -576,17 +600,47 @@ public final class Settings { } } + IContentProvider cp = null; + synchronized (this) { + cp = mContentProvider; + if (cp == null) { + cp = mContentProvider = cr.acquireProvider(mUri.getAuthority()); + } + } + + // Try the fast path first, not using query(). If this + // fails (alternate Settings provider that doesn't support + // this interface?) then we fall back to the query/table + // interface. + if (mCallCommand != null) { + try { + Bundle b = cp.call(mCallCommand, name, null); + if (b != null) { + String value = b.getPairValue(); + synchronized (this) { + mValues.put(name, value); + } + return value; + } + // If the response Bundle is null, we fall through + // to the query interface below. + } catch (RemoteException e) { + // Not supported by the remote side? Fall through + // to query(). + } + } + Cursor c = null; try { - c = cr.query(mUri, new String[] { Settings.NameValueTable.VALUE }, - Settings.NameValueTable.NAME + "=?", new String[]{name}, null); + c = cp.query(mUri, SELECT_VALUE, NAME_EQ_PLACEHOLDER, + new String[]{name}, null); if (c == null) { Log.w(TAG, "Can't get key " + name + " from " + mUri); return null; } String value = c.moveToNext() ? c.getString(0) : null; - synchronized (mValues) { + synchronized (this) { mValues.put(name, value); } if (LOCAL_LOGV) { @@ -594,7 +648,7 @@ public final class Settings { name + " = " + (value == null ? "(null)" : value)); } return value; - } catch (SQLException e) { + } catch (RemoteException e) { Log.w(TAG, "Can't get key " + name + " from " + mUri, e); return null; // Return null, but don't cache it. } finally { @@ -611,7 +665,8 @@ public final class Settings { public static final class System extends NameValueTable { public static final String SYS_PROP_SETTING_VERSION = "sys.settings_system_version"; - private static volatile NameValueCache mNameValueCache = null; + // Populated lazily, guarded by class object: + private static NameValueCache sNameValueCache = null; private static final HashSet<String> MOVED_TO_SECURE; static { @@ -660,10 +715,11 @@ public final class Settings { + " to android.provider.Settings.Secure, returning read-only value."); return Secure.getString(resolver, name); } - if (mNameValueCache == null) { - mNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI); + if (sNameValueCache == null) { + sNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI, + CALL_METHOD_GET_SYSTEM); } - return mNameValueCache.getString(resolver, name); + return sNameValueCache.getString(resolver, name); } /** @@ -1905,7 +1961,8 @@ public final class Settings { public static final class Secure extends NameValueTable { public static final String SYS_PROP_SETTING_VERSION = "sys.settings_secure_version"; - private static volatile NameValueCache mNameValueCache = null; + // Populated lazily, guarded by class object: + private static NameValueCache sNameValueCache = null; /** * Look up a name in the database. @@ -1914,10 +1971,11 @@ public final class Settings { * @return the corresponding value, or null if not present */ public synchronized static String getString(ContentResolver resolver, String name) { - if (mNameValueCache == null) { - mNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI); + if (sNameValueCache == null) { + sNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI, + CALL_METHOD_GET_SECURE); } - return mNameValueCache.getString(resolver, name); + return sNameValueCache.getString(resolver, name); } /** @@ -3085,13 +3143,6 @@ public final class Settings { public static final String MOUNT_UMS_NOTIFY_ENABLED = "mount_ums_notify_enabled"; /** - * Whether or not a notification is displayed when a Tetherable interface is detected. - * (0 = false, 1 = true) - * @hide - */ - public static final String TETHER_NOTIFY = "tether_notify"; - - /** * If nonzero, ANRs in invisible background processes bring up a dialog. * Otherwise, the process will be silently killed. * @hide diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index abbab0ea3498..7a0c4456d11d 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1516,19 +1516,28 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility /** * Always allow a user to overscroll this view, provided it is a * view that can scroll. + * + * @see #getOverscrollMode() + * @see #setOverscrollMode(int) */ - private static final int OVERSCROLL_ALWAYS = 0; + public static final int OVERSCROLL_ALWAYS = 0; /** * Allow a user to overscroll this view only if the content is large * enough to meaningfully scroll, provided it is a view that can scroll. + * + * @see #getOverscrollMode() + * @see #setOverscrollMode(int) */ - private static final int OVERSCROLL_IF_CONTENT_SCROLLS = 1; + public static final int OVERSCROLL_IF_CONTENT_SCROLLS = 1; /** * Never allow a user to overscroll this view. + * + * @see #getOverscrollMode() + * @see #setOverscrollMode(int) */ - private static final int OVERSCROLL_NEVER = 2; + public static final int OVERSCROLL_NEVER = 2; /** * Controls the overscroll mode for this view. @@ -8770,6 +8779,38 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility boolean clampedX, boolean clampedY) { // Intentionally empty. } + + /** + * Returns the overscroll mode for this view. The result will be + * one of {@link #OVERSCROLL_ALWAYS} (default), {@link #OVERSCROLL_IF_CONTENT_SCROLLS} + * (allow overscrolling only if the view content is larger than the container), + * or {@link #OVERSCROLL_NEVER}. + * + * @return This view's overscroll mode. + */ + public int getOverscrollMode() { + return mOverscrollMode; + } + + /** + * Set the overscroll mode for this view. Valid overscroll modes are + * {@link #OVERSCROLL_ALWAYS} (default), {@link #OVERSCROLL_IF_CONTENT_SCROLLS} + * (allow overscrolling only if the view content is larger than the container), + * or {@link #OVERSCROLL_NEVER}. + * + * Setting the overscroll mode of a view will have an effect only if the + * view is capable of scrolling. + * + * @param overscrollMode The new overscroll mode for this view. + */ + public void setOverscrollMode(int overscrollMode) { + if (overscrollMode != OVERSCROLL_ALWAYS && + overscrollMode != OVERSCROLL_IF_CONTENT_SCROLLS && + overscrollMode != OVERSCROLL_NEVER) { + throw new IllegalArgumentException("Invalid overscroll mode " + overscrollMode); + } + mOverscrollMode = overscrollMode; + } /** * A MeasureSpec encapsulates the layout requirements passed from parent to child. diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 4db5871ef50d..b8d71b96cb68 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -24,12 +24,17 @@ import android.content.DialogInterface.OnCancelListener; import android.content.pm.PackageManager; import android.database.DataSetObserver; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Interpolator; +import android.graphics.Paint; import android.graphics.Picture; import android.graphics.Point; import android.graphics.Rect; +import android.graphics.Region; +import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.net.http.SslCertificate; import android.net.Uri; @@ -70,7 +75,7 @@ import android.widget.CheckedTextView; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.ListView; -import android.widget.Scroller; +import android.widget.OverScroller; import android.widget.Toast; import android.widget.ZoomButtonsController; import android.widget.ZoomControls; @@ -455,7 +460,9 @@ public class WebView extends AbsoluteLayout // time for the longest scroll animation private static final int MAX_DURATION = 750; // milliseconds private static final int SLIDE_TITLE_DURATION = 500; // milliseconds - private Scroller mScroller; + private OverScroller mScroller; + private boolean mInOverScrollMode = false; + private static Paint mOverScrollBackground; private boolean mWrapContent; private static final int MOTIONLESS_FALSE = 0; @@ -810,7 +817,7 @@ public class WebView extends AbsoluteLayout mViewManager = new ViewManager(this); mWebViewCore = new WebViewCore(context, this, mCallbackProxy, javascriptInterfaces); mDatabase = WebViewDatabase.getInstance(context); - mScroller = new Scroller(context); + mScroller = new OverScroller(context); mZoomButtonsController = new ZoomButtonsController(this); mZoomButtonsController.setOnZoomListener(mZoomListener); @@ -1024,7 +1031,8 @@ public class WebView extends AbsoluteLayout * Return the amount of the titlebarview (if any) that is visible */ private int getVisibleTitleHeight() { - return Math.max(getTitleHeight() - mScrollY, 0); + // need to restrict mScrollY due to over scroll + return Math.max(getTitleHeight() - Math.max(0, mScrollY), 0); } /* @@ -1254,20 +1262,19 @@ public class WebView extends AbsoluteLayout final FileOutputStream out = new FileOutputStream(dest); p.writeToStream(out); out.close(); - } catch (FileNotFoundException e){ - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (RuntimeException e) { - e.printStackTrace(); - } - if (dest.length() > 0) { + // now update the bundle b.putInt("scrollX", mScrollX); b.putInt("scrollY", mScrollY); b.putFloat("scale", mActualScale); b.putFloat("textwrapScale", mTextWrapScale); b.putBoolean("overview", mInZoomOverview); return true; + } catch (FileNotFoundException e){ + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (RuntimeException e) { + e.printStackTrace(); } return false; } @@ -1868,11 +1875,13 @@ public class WebView extends AbsoluteLayout // Expects x in view coordinates private int pinLocX(int x) { + if (mInOverScrollMode) return x; return pinLoc(x, getViewWidth(), computeHorizontalScrollRange()); } // Expects y in view coordinates private int pinLocY(int y) { + if (mInOverScrollMode) return y; int titleH = getTitleHeight(); // if the titlebar is still visible, just pin against 0 if (y <= titleH) { @@ -2270,6 +2279,24 @@ public class WebView extends AbsoluteLayout scrollBar.draw(canvas); } + @Override + protected void onOverscrolled(int scrollX, int scrollY, boolean clampedX, + boolean clampedY) { + mInOverScrollMode = false; + int maxX = computeMaxScrollX(); + if (Math.abs(mMinZoomScale - mMaxZoomScale) < 0.01f && maxX == 0) { + // do not over scroll x if the page can't be zoomed and it just fits + // the screen + scrollX = pinLocX(scrollX); + } else if (scrollX < 0 || scrollX > maxX) { + mInOverScrollMode = true; + } + if (scrollY < 0 || scrollY > computeMaxScrollY()) { + mInOverScrollMode = true; + } + super.scrollTo(scrollX, scrollY); + } + /** * Get the url for the current page. This is not always the same as the url * passed to WebViewClient.onPageStarted because although the load for @@ -2612,13 +2639,14 @@ public class WebView extends AbsoluteLayout if (mScroller.computeScrollOffset()) { int oldX = mScrollX; int oldY = mScrollY; - mScrollX = mScroller.getCurrX(); - mScrollY = mScroller.getCurrY(); + int x = mScroller.getCurrX(); + int y = mScroller.getCurrY(); postInvalidate(); // So we draw again - if (oldX != mScrollX || oldY != mScrollY) { - // as onScrollChanged() is not called, sendOurVisibleRect() - // needs to be call explicitly - sendOurVisibleRect(); + if (oldX != x || oldY != y) { + overscrollBy(x - oldX, y - oldY, oldX, oldY, + computeMaxScrollX(), computeMaxScrollY(), + getViewWidth() / 3, getViewHeight() / 3); + onScrollChanged(mScrollX, mScrollY, oldX, oldY); } } else { super.computeScroll(); @@ -3029,8 +3057,13 @@ public class WebView extends AbsoluteLayout protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (child == mTitleBar) { // When drawing the title bar, move it horizontally to always show - // at the top of the WebView. + // at the top of the WebView. While overscroll, stick the title bar + // on the top otherwise we may have two during loading, one is drawn + // here, another is drawn by the Browser. mTitleBar.offsetLeftAndRight(mScrollX - mTitleBar.getLeft()); + if (mScrollY <= 0) { + mTitleBar.offsetTopAndBottom(mScrollY - mTitleBar.getTop()); + } } return super.drawChild(canvas, child, drawingTime); } @@ -3058,6 +3091,29 @@ public class WebView extends AbsoluteLayout } int saveCount = canvas.save(); + if (mInOverScrollMode) { + if (mOverScrollBackground == null) { + mOverScrollBackground = new Paint(); + Bitmap bm = BitmapFactory.decodeResource( + mContext.getResources(), + com.android.internal.R.drawable.pattern_underwear); + mOverScrollBackground.setShader(new BitmapShader(bm, + Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)); + } + int top = getTitleHeight(); + // first draw the background and anchor to the top of the view + canvas.save(); + canvas.translate(mScrollX, mScrollY); + canvas.clipRect(-mScrollX, top - mScrollY, + computeHorizontalScrollRange() - mScrollX, top + + computeVerticalScrollRange() - mScrollY, + Region.Op.DIFFERENCE); + canvas.drawPaint(mOverScrollBackground); + canvas.restore(); + // next clip the region for the content + canvas.clipRect(0, top, computeHorizontalScrollRange(), top + + computeVerticalScrollRange()); + } if (mTitleBar != null) { canvas.translate(0, (int) mTitleBar.getHeight()); } @@ -3075,12 +3131,12 @@ public class WebView extends AbsoluteLayout canvas.restoreToCount(saveCount); // Now draw the shadow. - if (mTitleBar != null) { - int y = mScrollY + getVisibleTitleHeight(); + int titleH = getVisibleTitleHeight(); + if (mTitleBar != null && titleH == 0) { int height = (int) (5f * getContext().getResources() .getDisplayMetrics().density); - mTitleShadow.setBounds(mScrollX, y, mScrollX + getWidth(), - y + height); + mTitleShadow.setBounds(mScrollX, mScrollY, mScrollX + getWidth(), + mScrollY + height); mTitleShadow.draw(canvas); } if (AUTO_REDRAW_HACK && mAutoRedraw) { @@ -4681,18 +4737,6 @@ public class WebView extends AbsoluteLayout } // do pan - int newScrollX = pinLocX(mScrollX + deltaX); - int newDeltaX = newScrollX - mScrollX; - if (deltaX != newDeltaX) { - deltaX = newDeltaX; - fDeltaX = (float) newDeltaX; - } - int newScrollY = pinLocY(mScrollY + deltaY); - int newDeltaY = newScrollY - mScrollY; - if (deltaY != newDeltaY) { - deltaY = newDeltaY; - fDeltaY = (float) newDeltaY; - } boolean done = false; boolean keepScrollBarsVisible = false; if (Math.abs(fDeltaX) < 1.0f && Math.abs(fDeltaY) < 1.0f) { @@ -4737,7 +4781,9 @@ public class WebView extends AbsoluteLayout } } if ((deltaX | deltaY) != 0) { - scrollBy(deltaX, deltaY); + overscrollBy(deltaX, deltaY, mScrollX, mScrollY, + computeMaxScrollX(), computeMaxScrollY(), + getViewWidth() / 3, getViewHeight() / 3); if (deltaX != 0) { mLastTouchX = x; } @@ -4820,8 +4866,8 @@ public class WebView extends AbsoluteLayout Log.w(LOGTAG, "Miss a drag as we are waiting for" + " WebCore's response for touch down."); if (mFullScreenHolder == null - && (computeHorizontalScrollExtent() < computeHorizontalScrollRange() - || computeVerticalScrollExtent() < computeVerticalScrollRange())) { + && (computeMaxScrollX() > 0 + || computeMaxScrollY() > 0)) { // remove the pending TOUCH_EVENT and send a // cancel mWebViewCore @@ -4867,6 +4913,12 @@ public class WebView extends AbsoluteLayout mVelocityTracker.addMovement(ev); doFling(); break; + } else { + if (mScroller.springback(mScrollX, mScrollY, 0, + computeMaxScrollX(), 0, + computeMaxScrollY())) { + invalidate(); + } } mLastVelocity = 0; WebViewCore.resumePriority(); @@ -4887,6 +4939,12 @@ public class WebView extends AbsoluteLayout } case MotionEvent.ACTION_CANCEL: { cancelTouch(); + if (mTouchMode == TOUCH_DRAG_MODE) { + if (mScroller.springback(mScrollX, mScrollY, 0, + computeMaxScrollX(), 0, computeMaxScrollY())) { + invalidate(); + } + } break; } } @@ -5205,16 +5263,18 @@ public class WebView extends AbsoluteLayout } } + private int computeMaxScrollX() { + return Math.max(computeHorizontalScrollRange() - getViewWidth(), 0); + } + private int computeMaxScrollY() { - int maxContentH = computeVerticalScrollRange() + getTitleHeight(); - return Math.max(maxContentH - getViewHeightWithTitle(), getTitleHeight()); + return Math.max(computeVerticalScrollRange() + getTitleHeight() + - getViewHeightWithTitle(), getTitleHeight()); } public void flingScroll(int vx, int vy) { - int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0); - int maxY = computeMaxScrollY(); - - mScroller.fling(mScrollX, mScrollY, vx, vy, 0, maxX, 0, maxY); + mScroller.fling(mScrollX, mScrollY, vx, vy, 0, computeMaxScrollX(), 0, + computeMaxScrollY(), getViewWidth() / 3, getViewHeight() / 3); invalidate(); } @@ -5222,7 +5282,7 @@ public class WebView extends AbsoluteLayout if (mVelocityTracker == null) { return; } - int maxX = Math.max(computeHorizontalScrollRange() - getViewWidth(), 0); + int maxX = computeMaxScrollX(); int maxY = computeMaxScrollY(); mVelocityTracker.computeCurrentVelocity(1000, mMaximumFling); @@ -5244,6 +5304,10 @@ public class WebView extends AbsoluteLayout } if ((maxX == 0 && vy == 0) || (maxY == 0 && vx == 0)) { WebViewCore.resumePriority(); + if (mScroller.springback(mScrollX, mScrollY, 0, computeMaxScrollX(), + 0, computeMaxScrollY())) { + invalidate(); + } return; } float currentVelocity = mScroller.getCurrVelocity(); @@ -5271,7 +5335,8 @@ public class WebView extends AbsoluteLayout mLastVelY = vy; mLastVelocity = (float) Math.hypot(vx, vy); - mScroller.fling(mScrollX, mScrollY, -vx, -vy, 0, maxX, 0, maxY); + mScroller.fling(mScrollX, mScrollY, -vx, -vy, 0, maxX, 0, maxY, + getViewWidth() / 3, getViewHeight() / 3); // TODO: duration is calculated based on velocity, if the range is // small, the animation will stop before duration is up. We may // want to calculate how long the animation is going to run to precisely @@ -5928,40 +5993,43 @@ public class WebView extends AbsoluteLayout WebViewCore.RestoreState restoreState = draw.mRestoreState; boolean hasRestoreState = restoreState != null; if (hasRestoreState) { - mInZoomOverview = false; updateZoomRange(restoreState, viewSize.x, draw.mMinPrefWidth, true); - if (mInitialScaleInPercent > 0) { - setNewZoomScale(mInitialScaleInPercent / 100.0f, + if (!mDrawHistory) { + mInZoomOverview = false; + + if (mInitialScaleInPercent > 0) { + setNewZoomScale(mInitialScaleInPercent / 100.0f, mInitialScaleInPercent != mTextWrapScale * 100, false); - } else if (restoreState.mViewScale > 0) { - mTextWrapScale = restoreState.mTextWrapScale; - setNewZoomScale(restoreState.mViewScale, false, + } else if (restoreState.mViewScale > 0) { + mTextWrapScale = restoreState.mTextWrapScale; + setNewZoomScale(restoreState.mViewScale, false, false); - } else { - mInZoomOverview = useWideViewport + } else { + mInZoomOverview = useWideViewport && settings.getLoadWithOverviewMode(); - float scale; - if (mInZoomOverview) { - scale = (float) viewWidth + float scale; + if (mInZoomOverview) { + scale = (float) viewWidth / DEFAULT_VIEWPORT_WIDTH; - } else { - scale = restoreState.mTextWrapScale; - } - setNewZoomScale(scale, Math.abs(scale + } else { + scale = restoreState.mTextWrapScale; + } + setNewZoomScale(scale, Math.abs(scale - mTextWrapScale) >= 0.01f, false); - } - setContentScrollTo(restoreState.mScrollX, + } + setContentScrollTo(restoreState.mScrollX, restoreState.mScrollY); - // As we are on a new page, remove the WebTextView. This - // is necessary for page loads driven by webkit, and in - // particular when the user was on a password field, so - // the WebTextView was visible. - clearTextEntry(false); - // update the zoom buttons as the scale can be changed - if (getSettings().getBuiltInZoomControls()) { - updateZoomButtonsEnabled(); + // As we are on a new page, remove the WebTextView. This + // is necessary for page loads driven by webkit, and in + // particular when the user was on a password field, so + // the WebTextView was visible. + clearTextEntry(false); + // update the zoom buttons as the scale can be changed + if (getSettings().getBuiltInZoomControls()) { + updateZoomButtonsEnabled(); + } } } // We update the layout (i.e. request a layout from the diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 71f69feeb19d..b339015e2646 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -2191,7 +2191,14 @@ final class WebViewCore { ); } data.mWidth = Math.round(webViewWidth / data.mScale); - data.mHeight = mCurrentViewHeight * data.mWidth / viewportWidth; + // We may get a call here when mCurrentViewHeight == 0 if webcore completes the + // first layout before we sync our webview dimensions to it. In that case, we + // request the real height of the webview. This is not a perfect solution as we + // are calling a WebView method from the WebCore thread. But this is preferable + // to syncing an incorrect height. + data.mHeight = mCurrentViewHeight == 0 ? + Math.round(mWebView.getViewHeight() / data.mScale) + : mCurrentViewHeight * data.mWidth / viewportWidth; data.mTextWrapWidth = Math.round(webViewWidth / mRestoreState.mTextWrapScale); data.mIgnoreHeight = false; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index b78373d4ccdf..06880a17df4b 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2067,10 +2067,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te // Remember where the motion event started v = getChildAt(motionPosition - mFirstPosition); mMotionViewOriginalTop = v.getTop(); - mMotionX = x; - mMotionY = y; - mMotionPosition = motionPosition; } + mMotionX = x; + mMotionY = y; + mMotionPosition = motionPosition; mLastY = Integer.MIN_VALUE; break; } diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java index c2517a849604..fb8b5aa938da 100644 --- a/core/java/android/widget/VideoView.java +++ b/core/java/android/widget/VideoView.java @@ -484,6 +484,9 @@ public class VideoView extends SurfaceView implements MediaPlayerControl { // after we return from this we can't use the surface any more mSurfaceHolder = null; if (mMediaController != null) mMediaController.hide(); + if (mCurrentState != STATE_SUSPEND) { + release(true); + } } }; diff --git a/core/java/com/android/internal/app/TetherActivity.java b/core/java/com/android/internal/app/TetherActivity.java deleted file mode 100644 index 7f83b2b81a41..000000000000 --- a/core/java/com/android/internal/app/TetherActivity.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (C) 2007 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.app; - -import android.app.AlertDialog; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.ConnectivityManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.widget.Toast; -import android.util.Log; - -/** - * This activity is shown to the user in two cases: when a connection is possible via - * a usb tether and when any type of tether is connected. In the connecting case - * It allows them to start a USB tether. In the Tethered/disconnecting case it - * will disconnect all tethers. - */ -public class TetherActivity extends AlertActivity implements - DialogInterface.OnClickListener { - - private static final int POSITIVE_BUTTON = AlertDialog.BUTTON1; - - // count of the number of tethered connections at activity create time. - private int mTethered; - - /* Used to detect when the USB cable is unplugged, so we can call finish() */ - private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction() == ConnectivityManager.ACTION_TETHER_STATE_CHANGED) { - handleTetherStateChanged(intent); - } - } - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // determine if we advertise tethering or untethering - ConnectivityManager cm = - (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); - - mTethered = cm.getTetheredIfaces().length; - int tetherable = cm.getTetherableIfaces().length; - if ((mTethered == 0) && (tetherable == 0)) { - finish(); - return; - } - - // Set up the dialog - // if we have a tethered connection we put up a "Do you want to Disconect" dialog - // otherwise we must have a tetherable interface (else we'd return above) - // and so we want to put up the "do you want to connect" dialog - if (mTethered == 0) { - mAlertParams.mIconId = com.android.internal.R.drawable.ic_dialog_usb; - mAlertParams.mTitle = getString(com.android.internal.R.string.tether_title); - mAlertParams.mMessage = getString(com.android.internal.R.string.tether_message); - mAlertParams.mPositiveButtonText = - getString(com.android.internal.R.string.tether_button); - mAlertParams.mPositiveButtonListener = this; - mAlertParams.mNegativeButtonText = - getString(com.android.internal.R.string.tether_button_cancel); - mAlertParams.mNegativeButtonListener = this; - } else { - mAlertParams.mIconId = com.android.internal.R.drawable.ic_dialog_usb; - mAlertParams.mTitle = getString(com.android.internal.R.string.tether_stop_title); - mAlertParams.mMessage = getString(com.android.internal.R.string.tether_stop_message); - mAlertParams.mPositiveButtonText = - getString(com.android.internal.R.string.tether_stop_button); - mAlertParams.mPositiveButtonListener = this; - mAlertParams.mNegativeButtonText = - getString(com.android.internal.R.string.tether_stop_button_cancel); - mAlertParams.mNegativeButtonListener = this; - } - setupAlert(); - } - - @Override - protected void onResume() { - super.onResume(); - - registerReceiver(mTetherReceiver, new IntentFilter( - ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); - } - - @Override - protected void onPause() { - super.onPause(); - - unregisterReceiver(mTetherReceiver); - } - - /** - * {@inheritDoc} - */ - public void onClick(DialogInterface dialog, int which) { - int error = ConnectivityManager.TETHER_ERROR_NO_ERROR; - - if (which == POSITIVE_BUTTON) { - ConnectivityManager cm = - (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); - // start/stop tethering - String[] tethered = cm.getTetheredIfaces(); - - if (tethered.length == 0) { - String[] tetherable = cm.getTetherableIfaces(); - String[] usbRegexs = cm.getTetherableUsbRegexs(); - for (String t : tetherable) { - for (String r : usbRegexs) { - if (t.matches(r)) { - error = cm.tether(t); - break; - } - } - } - showTetheringError(error); - } else { - for (String t : tethered) { - error = cm.untether(t); - } - showUnTetheringError(error); - } - } - // No matter what, finish the activity - finish(); - } - - private void handleTetherStateChanged(Intent intent) { - // determine if we advertise tethering or untethering - ConnectivityManager cm = - (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); - if (mTethered != cm.getTetheredIfaces().length) { - finish(); - } - } - - private void showTetheringError(int error) { - switch(error) { - case ConnectivityManager.TETHER_ERROR_NO_ERROR: - return; - default: - Toast.makeText(this, com.android.internal.R.string.tether_error_message, - Toast.LENGTH_LONG).show(); - } - } - - private void showUnTetheringError(int error) { - switch(error) { - case ConnectivityManager.TETHER_ERROR_NO_ERROR: - return; - default: - Toast.makeText(this, com.android.internal.R.string.tether_stop_error_message, - Toast.LENGTH_LONG).show(); - } - } -} diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp index b93311b22776..bd55e83ea82c 100644 --- a/core/jni/android_database_SQLiteDatabase.cpp +++ b/core/jni/android_database_SQLiteDatabase.cpp @@ -63,19 +63,28 @@ enum { static jfieldID offset_db_handle; +static char *createStr(const char *path) { + int len = strlen(path); + char *str = (char *)malloc(len + 1); + strncpy(str, path, len); + str[len] = NULL; + return str; +} + static void sqlLogger(void *databaseName, int iErrCode, const char *zMsg) { - LOGI("sqlite returned: error code = %d, msg = %s\n", iErrCode, zMsg); + LOGI("sqlite returned: database = %s, error code = %d, msg = %s\n", + (char *)databaseName, iErrCode, zMsg); } // register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called. -static void registerLoggingFunc() { +static void registerLoggingFunc(const char *path) { static bool loggingFuncSet = false; if (loggingFuncSet) { return; } LOGV("Registering sqlite logging func \n"); - int err = sqlite3_config(SQLITE_CONFIG_LOG, &sqlLogger, 0); + int err = sqlite3_config(SQLITE_CONFIG_LOG, &sqlLogger, (void *)createStr(path)); if (err != SQLITE_OK) { LOGE("sqlite_config failed error_code = %d. THIS SHOULD NEVER occur.\n", err); return; @@ -93,7 +102,7 @@ static void dbopen(JNIEnv* env, jobject object, jstring pathString, jint flags) int sqliteFlags; // register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called. - registerLoggingFunc(); + registerLoggingFunc(path8); // convert our flags into the sqlite flags if (flags & CREATE_IF_NECESSARY) { @@ -172,10 +181,7 @@ static char *getDatabaseName(JNIEnv* env, sqlite3 * handle, jstring databaseName LOGE("Failure in getDatabaseName(). VM ran out of memory?\n"); return NULL; // VM would have thrown OutOfMemoryError } - int len = strlen(path); - char *dbNameStr = (char *)malloc(len + 1); - strncpy(dbNameStr, path, len); - dbNameStr[len-1] = NULL; + char *dbNameStr = createStr(path); env->ReleaseStringUTFChars(databaseName, path); return dbNameStr; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 63584eda79d8..f1e614b8dfb1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -52,7 +52,13 @@ <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_OK" /> <protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" /> <protected-broadcast android:name="android.intent.action.REBOOT" /> + <protected-broadcast android:name="android.intent.action.DOCK_EVENT" /> + <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" /> + <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" /> + <protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" /> + <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" /> + <protected-broadcast android:name="android.backup.intent.RUN" /> <protected-broadcast android:name="android.backup.intent.CLEAR" /> <protected-broadcast android:name="android.backup.intent.INIT" /> @@ -1271,10 +1277,6 @@ <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> - <activity android:name="com.android.internal.app.TetherActivity" - android:theme="@style/Theme.Dialog.Alert" - android:excludeFromRecents="true"> - </activity> <activity android:name="com.android.server.status.UsbStorageActivity" android:excludeFromRecents="true"> </activity> diff --git a/core/res/res/drawable-hdpi/ic_lock_silent_mode.png b/core/res/res/drawable-hdpi/ic_lock_silent_mode.png Binary files differindex 00e196063310..0d4c590f4e3f 100644 --- a/core/res/res/drawable-hdpi/ic_lock_silent_mode.png +++ b/core/res/res/drawable-hdpi/ic_lock_silent_mode.png diff --git a/core/res/res/drawable-hdpi/ic_lock_silent_mode_off.png b/core/res/res/drawable-hdpi/ic_lock_silent_mode_off.png Binary files differindex 6b4ce893bcf5..17d705c62b17 100644 --- a/core/res/res/drawable-hdpi/ic_lock_silent_mode_off.png +++ b/core/res/res/drawable-hdpi/ic_lock_silent_mode_off.png diff --git a/core/res/res/drawable-hdpi/ic_lock_silent_mode_vibrate.png b/core/res/res/drawable-hdpi/ic_lock_silent_mode_vibrate.png Binary files differnew file mode 100644 index 000000000000..4503aceb7dde --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_lock_silent_mode_vibrate.png diff --git a/core/res/res/drawable-hdpi/ic_vibrate.png b/core/res/res/drawable-hdpi/ic_vibrate.png Binary files differindex aa83534a36be..ca23372eb2f0 100644 --- a/core/res/res/drawable-hdpi/ic_vibrate.png +++ b/core/res/res/drawable-hdpi/ic_vibrate.png diff --git a/core/res/res/drawable-hdpi/ic_vibrate_small.png b/core/res/res/drawable-hdpi/ic_vibrate_small.png Binary files differnew file mode 100644 index 000000000000..61b8bd908901 --- /dev/null +++ b/core/res/res/drawable-hdpi/ic_vibrate_small.png diff --git a/core/res/res/drawable-hdpi/ic_volume.png b/core/res/res/drawable-hdpi/ic_volume.png Binary files differindex 7714f6aefff1..bf538ee2e2e9 100644 --- a/core/res/res/drawable-hdpi/ic_volume.png +++ b/core/res/res/drawable-hdpi/ic_volume.png diff --git a/core/res/res/drawable-hdpi/ic_volume_off.png b/core/res/res/drawable-hdpi/ic_volume_off.png Binary files differindex 313dd5bcec2d..aa344083346b 100644 --- a/core/res/res/drawable-hdpi/ic_volume_off.png +++ b/core/res/res/drawable-hdpi/ic_volume_off.png diff --git a/core/res/res/drawable-hdpi/ic_volume_off_small.png b/core/res/res/drawable-hdpi/ic_volume_off_small.png Binary files differindex 62322ec2e60d..1329414eec1f 100644 --- a/core/res/res/drawable-hdpi/ic_volume_off_small.png +++ b/core/res/res/drawable-hdpi/ic_volume_off_small.png diff --git a/core/res/res/drawable-hdpi/ic_volume_small.png b/core/res/res/drawable-hdpi/ic_volume_small.png Binary files differindex 96c7948d9465..4e9a7eae10a8 100644 --- a/core/res/res/drawable-hdpi/ic_volume_small.png +++ b/core/res/res/drawable-hdpi/ic_volume_small.png diff --git a/core/res/res/drawable-mdpi/ic_lock_silent_mode.png b/core/res/res/drawable-mdpi/ic_lock_silent_mode.png Binary files differindex 439a6f59ec5a..5c3a226e48bb 100644 --- a/core/res/res/drawable-mdpi/ic_lock_silent_mode.png +++ b/core/res/res/drawable-mdpi/ic_lock_silent_mode.png diff --git a/core/res/res/drawable-mdpi/ic_lock_silent_mode_off.png b/core/res/res/drawable-mdpi/ic_lock_silent_mode_off.png Binary files differindex fc7e960aa588..95257a36ab82 100644 --- a/core/res/res/drawable-mdpi/ic_lock_silent_mode_off.png +++ b/core/res/res/drawable-mdpi/ic_lock_silent_mode_off.png diff --git a/core/res/res/drawable-mdpi/ic_lock_silent_mode_vibrate.png b/core/res/res/drawable-mdpi/ic_lock_silent_mode_vibrate.png Binary files differnew file mode 100644 index 000000000000..7da79aa20cb2 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_lock_silent_mode_vibrate.png diff --git a/core/res/res/drawable-mdpi/ic_vibrate.png b/core/res/res/drawable-mdpi/ic_vibrate.png Binary files differindex eb24e5064635..4fecce14fb21 100755..100644 --- a/core/res/res/drawable-mdpi/ic_vibrate.png +++ b/core/res/res/drawable-mdpi/ic_vibrate.png diff --git a/core/res/res/drawable-mdpi/ic_vibrate_small.png b/core/res/res/drawable-mdpi/ic_vibrate_small.png Binary files differnew file mode 100644 index 000000000000..f04804e2db89 --- /dev/null +++ b/core/res/res/drawable-mdpi/ic_vibrate_small.png diff --git a/core/res/res/drawable-mdpi/ic_volume.png b/core/res/res/drawable-mdpi/ic_volume.png Binary files differindex cee70f0e7338..20aa0304553f 100755..100644 --- a/core/res/res/drawable-mdpi/ic_volume.png +++ b/core/res/res/drawable-mdpi/ic_volume.png diff --git a/core/res/res/drawable-mdpi/ic_volume_off.png b/core/res/res/drawable-mdpi/ic_volume_off.png Binary files differindex f3850fc04762..fefb9c40134e 100644 --- a/core/res/res/drawable-mdpi/ic_volume_off.png +++ b/core/res/res/drawable-mdpi/ic_volume_off.png diff --git a/core/res/res/drawable-mdpi/ic_volume_off_small.png b/core/res/res/drawable-mdpi/ic_volume_off_small.png Binary files differindex ae55bd664581..529298cc2692 100755..100644 --- a/core/res/res/drawable-mdpi/ic_volume_off_small.png +++ b/core/res/res/drawable-mdpi/ic_volume_off_small.png diff --git a/core/res/res/drawable-mdpi/ic_volume_small.png b/core/res/res/drawable-mdpi/ic_volume_small.png Binary files differindex 00a4f89fffbb..2a7ec03456b7 100755..100644 --- a/core/res/res/drawable-mdpi/ic_volume_small.png +++ b/core/res/res/drawable-mdpi/ic_volume_small.png diff --git a/core/res/res/drawable/pattern_underwear.png b/core/res/res/drawable/pattern_underwear.png Binary files differnew file mode 100644 index 000000000000..651212fb0855 --- /dev/null +++ b/core/res/res/drawable/pattern_underwear.png diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 8308801646ae..e68f21434b48 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1101,7 +1101,7 @@ the state of network connectivity.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_changeTetherState">change tethered connectivity</string> + <string name="permlab_changeTetherState">Change tethered connectivity</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the applicaiton to do this. --> <string name="permdesc_changeTetherState">Allows an application to change the state of tethered network connectivity.</string> @@ -2246,44 +2246,6 @@ --> <string name="description_star">favorite</string> - - <!-- Strings for Tethering dialogs --> - <!-- This is the label for the activity, and should never be visible to the user. --> - <!-- See TETHERING. TETHERING_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to Tether. This is the title. --> - <string name="tether_title">USB tethering available</string> - <!-- See TETHER. This is the message. --> - <string name="tether_message">Select \"Tether\" if you want to share your phone\'s data connection with your computer.</string> - <!-- See TETHER. This is the button text to Tether the computer with the phone. --> - <string name="tether_button">Tether</string> - <!-- See TETHER. This is the button text to ignore the plugging in of the phone.. --> - <string name="tether_button_cancel">Cancel</string> - - <!-- See TETHER. If there was a recoverable error, this is the text. --> - <string name="tether_error_message">We\'ve encountered a problem turning on Tethering. Please try again.</string> - - <!-- TETHER: When the user connects the phone to a computer, we show a notification asking if he wants to share his cellular network connection. This is the title --> - <string name="tether_available_notification_title">USB tethering available</string> - <!-- See USB_STORAGE. This is the message. --> - <string name="tether_available_notification_message">Select to tether your computer to your phone.</string> - <!-- TETHER_STOP: While TETHER is enabled, we show a notification dialog asking if he wants to stop. This is the title --> - <string name="tether_stop_notification_title">Untether</string> - <!-- See TETHER. This is the message. --> - <string name="tether_stop_notification_message">Select to untether your computer.</string> - - <!-- TETHER stop dialog strings --> - <!-- This is the label for the activity, and should never be visible to the user. --> - <!-- See TETHER_STOP. TETHER_STOP_DIALOG: After the user selects the notification, a dialog is shown asking if he wants to stop tethering. This is the title. --> - <string name="tether_stop_title">Disconnect tethering</string> - <!-- See TETHER_STOP. This is the message. --> - <string name="tether_stop_message">You have been sharing your phone\'s cellular data connection with your computer. Select \"Disconnect\" to disconnect USB tethering.</string> - <!-- See TETHER_STOP. This is the button text to disconnect tethering. --> - <string name="tether_stop_button">Disconnect</string> - <!-- See TETHER_STOP. This is the button text to cancel disconnecting the tether. --> - <string name="tether_stop_button_cancel">Cancel</string> - - <!-- See TETHER_STOP. If there was an error disconnect, this is the text. --> - <string name="tether_stop_error_message">We\'ve encountered a problem turning off Tethering. Please try again.</string> - <!-- Strings for car mode notification --> <!-- Shown when car mode is enabled --> <string name="car_mode_disable_notification_title">Car mode enabled</string> diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index cbcef4e1af77..0e796dc561f1 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -946,7 +946,8 @@ struct ResTable_config MASK_UI_MODE_TYPE = 0x0f, UI_MODE_TYPE_ANY = 0x00, UI_MODE_TYPE_NORMAL = 0x01, - UI_MODE_TYPE_CAR = 0x02, + UI_MODE_TYPE_DESK = 0x02, + UI_MODE_TYPE_CAR = 0x03, // uiMode bits for the night switch. MASK_UI_MODE_NIGHT = 0x30, diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index 2269352e5a32..8089389ffcd6 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -3247,7 +3247,10 @@ bool AudioFlinger::RecordThread::threadLoop() if (mBytesRead < 0) { LOGE("Error reading audio input"); if (mActiveTrack->mState == TrackBase::ACTIVE) { - sleep(1); + // Force input into standby so that it tries to + // recover at next read attempt + mInput->standby(); + usleep(5000); } mRsmpInIndex = mFrameCount; framesOut = 0; @@ -3429,7 +3432,10 @@ status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* if (mBytesRead < 0) { LOGE("RecordThread::getNextBuffer() Error reading audio input"); if (mActiveTrack->mState == TrackBase::ACTIVE) { - sleep(1); + // Force input into standby so that it tries to + // recover at next read attempt + mInput->standby(); + usleep(5000); } buffer->raw = 0; buffer->frameCount = 0; diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index 34cd9d17c2cb..d45eaf0b262e 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -176,7 +176,7 @@ int EventHub::getSwitchState(int32_t deviceId, int sw) const if (device == NULL) return -1; if (sw >= 0 && sw <= SW_MAX) { - uint8_t sw_bitmask[(SW_MAX+1)/8]; + uint8_t sw_bitmask[(SW_MAX+7)/8]; memset(sw_bitmask, 0, sizeof(sw_bitmask)); if (ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) { @@ -200,7 +200,7 @@ int EventHub::getScancodeState(int32_t deviceId, int code) const if (device == NULL) return -1; if (code >= 0 && code <= KEY_MAX) { - uint8_t key_bitmask[(KEY_MAX+1)/8]; + uint8_t key_bitmask[(KEY_MAX+7)/8]; memset(key_bitmask, 0, sizeof(key_bitmask)); if (ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) { @@ -225,7 +225,7 @@ int EventHub::getKeycodeState(int32_t deviceId, int code) const Vector<int32_t> scanCodes; device->layoutMap->findScancodes(code, &scanCodes); - uint8_t key_bitmask[(KEY_MAX+1)/8]; + uint8_t key_bitmask[(KEY_MAX+7)/8]; memset(key_bitmask, 0, sizeof(key_bitmask)); if (ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) { @@ -608,12 +608,12 @@ int EventHub::open_device(const char *deviceName) // consider up through the function keys; we don't want to include // ones after that (play cd etc) so we don't mistakenly consider a // controller to be a keyboard. - uint8_t key_bitmask[(KEY_MAX+1)/8]; + uint8_t key_bitmask[(KEY_MAX+7)/8]; memset(key_bitmask, 0, sizeof(key_bitmask)); LOGV("Getting keys..."); if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) { //LOGI("MAP\n"); - //for (int i=0; i<((KEY_MAX+1)/8); i++) { + //for (int i=0; i<((KEY_MAX+7)/8); i++) { // LOGI("%d: 0x%02x\n", i, key_bitmask[i]); //} for (int i=0; i<((BTN_MISC+7)/8); i++) { @@ -636,7 +636,7 @@ int EventHub::open_device(const char *deviceName) // See if this is a trackball. if (test_bit(BTN_MOUSE, key_bitmask)) { - uint8_t rel_bitmask[(REL_MAX+1)/8]; + uint8_t rel_bitmask[(REL_MAX+7)/8]; memset(rel_bitmask, 0, sizeof(rel_bitmask)); LOGV("Getting relative controllers..."); if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) @@ -647,7 +647,7 @@ int EventHub::open_device(const char *deviceName) } } - uint8_t abs_bitmask[(ABS_MAX+1)/8]; + uint8_t abs_bitmask[(ABS_MAX+7)/8]; memset(abs_bitmask, 0, sizeof(abs_bitmask)); LOGV("Getting absolute controllers..."); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask); @@ -666,7 +666,7 @@ int EventHub::open_device(const char *deviceName) #ifdef EV_SW // figure out the switches this device reports - uint8_t sw_bitmask[(SW_MAX+1)/8]; + uint8_t sw_bitmask[(SW_MAX+7)/8]; memset(sw_bitmask, 0, sizeof(sw_bitmask)); if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) { for (int i=0; i<EV_SW; i++) { diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java index eade680d16f6..09ac0ac0a0ea 100644 --- a/media/java/android/media/CamcorderProfile.java +++ b/media/java/android/media/CamcorderProfile.java @@ -34,7 +34,6 @@ package android.media; * <li> Audio sample rate * <li> Number of audio channels for recording. * </ul> - * {@hide} */ public class CamcorderProfile { diff --git a/media/java/android/media/CameraProfile.java b/media/java/android/media/CameraProfile.java index 9685e7ee1a61..f1616ccdfc1e 100644 --- a/media/java/android/media/CameraProfile.java +++ b/media/java/android/media/CameraProfile.java @@ -21,7 +21,6 @@ package android.media; * capture (jpeg) quality levels (0-100) used for low, medium, and high * quality settings in the Camera application. * - * {@hide} */ public class CameraProfile { diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index bce33713f6ec..ad037d6e42b4 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -552,13 +552,17 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize) audioBuffer.frameCount = userSize/frameSize(); - // Calling obtainBuffer() with a negative wait count causes - // an (almost) infinite wait time. - status_t err = obtainBuffer(&audioBuffer, -1); + // By using a wait count corresponding to twice the timeout period in + // obtainBuffer() we give a chance to recover once for a read timeout + // (if media_server crashed for instance) before returning a length of + // 0 bytes read to the client + status_t err = obtainBuffer(&audioBuffer, ((2 * MAX_RUN_TIMEOUT_MS) / WAIT_PERIOD_MS)); if (err < 0) { // out of buffers, return #bytes written if (err == status_t(NO_MORE_BUFFERS)) break; + if (err == status_t(TIMED_OUT)) + err = 0; return ssize_t(err); } diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index ab65b4414e2c..5090c3939cb0 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -297,13 +297,11 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { CHECK(meta->findCString(kKeyMIMEType, &mime)); if (!haveVideo && !strncasecmp(mime, "video/", 6)) { - if (setVideoSource(extractor->getTrack(i)) == OK) { - haveVideo = true; - } + setVideoSource(extractor->getTrack(i)); + haveVideo = true; } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { - if (setAudioSource(extractor->getTrack(i)) == OK) { - haveAudio = true; - } + setAudioSource(extractor->getTrack(i)); + haveAudio = true; } if (haveAudio && haveVideo) { @@ -331,6 +329,9 @@ void AwesomePlayer::reset_l() { } mPrefetcher.clear(); + mAudioTrack.clear(); + mVideoTrack.clear(); + // Shutdown audio first, so that the respone to the reset request // appears to happen instantaneously as far as the user is concerned // If we did this later, audio would continue playing while we @@ -699,32 +700,34 @@ status_t AwesomePlayer::getVideoDimensions( return OK; } -status_t AwesomePlayer::setAudioSource(sp<MediaSource> source) { - if (source == NULL) { - return UNKNOWN_ERROR; - } +void AwesomePlayer::setAudioSource(sp<MediaSource> source) { + CHECK(source != NULL); if (mPrefetcher != NULL) { source = mPrefetcher->addSource(source); } - sp<MetaData> meta = source->getFormat(); + mAudioTrack = source; +} + +status_t AwesomePlayer::initAudioDecoder() { + sp<MetaData> meta = mAudioTrack->getFormat(); const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { - mAudioSource = source; + mAudioSource = mAudioTrack; } else { mAudioSource = OMXCodec::Create( - mClient.interface(), source->getFormat(), + mClient.interface(), mAudioTrack->getFormat(), false, // createEncoder - source); + mAudioTrack); } if (mAudioSource != NULL) { int64_t durationUs; - if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) { + if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { if (mDurationUs < 0 || durationUs > mDurationUs) { mDurationUs = durationUs; } @@ -734,30 +737,32 @@ status_t AwesomePlayer::setAudioSource(sp<MediaSource> source) { return mAudioSource != NULL ? OK : UNKNOWN_ERROR; } -status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) { - if (source == NULL) { - return UNKNOWN_ERROR; - } +void AwesomePlayer::setVideoSource(sp<MediaSource> source) { + CHECK(source != NULL); if (mPrefetcher != NULL) { source = mPrefetcher->addSource(source); } + mVideoTrack = source; +} + +status_t AwesomePlayer::initVideoDecoder() { mVideoSource = OMXCodec::Create( - mClient.interface(), source->getFormat(), + mClient.interface(), mVideoTrack->getFormat(), false, // createEncoder - source); + mVideoTrack); if (mVideoSource != NULL) { int64_t durationUs; - if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) { + if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { if (mDurationUs < 0 || durationUs > mDurationUs) { mDurationUs = durationUs; } } - CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth)); - CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight)); + CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth)); + CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight)); mVideoSource->start(); } @@ -1045,6 +1050,19 @@ status_t AwesomePlayer::finishSetDataSource_l() { return setDataSource_l(extractor); } +void AwesomePlayer::abortPrepare(status_t err) { + CHECK(err != OK); + + if (mIsAsyncPrepare) { + notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); + } + + mPrepareResult = err; + mFlags &= ~PREPARING; + mAsyncPrepareEvent = NULL; + mPreparedCondition.broadcast(); +} + void AwesomePlayer::onPrepareAsyncEvent() { { Mutex::Autolock autoLock(mLock); @@ -1053,15 +1071,7 @@ void AwesomePlayer::onPrepareAsyncEvent() { status_t err = finishSetDataSource_l(); if (err != OK) { - if (mIsAsyncPrepare) { - notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); - } - - mPrepareResult = err; - mFlags &= ~PREPARING; - mAsyncPrepareEvent = NULL; - mPreparedCondition.broadcast(); - + abortPrepare(err); return; } } @@ -1081,6 +1091,24 @@ void AwesomePlayer::onPrepareAsyncEvent() { Mutex::Autolock autoLock(mLock); + if (mVideoTrack != NULL && mVideoSource == NULL) { + status_t err = initVideoDecoder(); + + if (err != OK) { + abortPrepare(err); + return; + } + } + + if (mAudioTrack != NULL && mAudioSource == NULL) { + status_t err = initAudioDecoder(); + + if (err != OK) { + abortPrepare(err); + return; + } + } + if (mIsAsyncPrepare) { if (mVideoWidth < 0 || mVideoHeight < 0) { notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp index ab38bca985d7..c168771b6592 100644 --- a/media/libstagefright/MP3Extractor.cpp +++ b/media/libstagefright/MP3Extractor.cpp @@ -36,8 +36,10 @@ namespace android { // Everything must match except for -// protection, bitrate, padding, private bits and mode extension. -static const uint32_t kMask = 0xfffe0ccf; +// protection, bitrate, padding, private bits, mode extension, +// copyright bit, original bit and emphasis. +// Yes ... there are things that must indeed match... +static const uint32_t kMask = 0xfffe0cc0; static bool get_mp3_frame_size( uint32_t header, size_t *frame_size, @@ -669,7 +671,7 @@ status_t MP3Source::read( } // Lost sync. - LOGV("lost sync!\n"); + LOGV("lost sync! header = 0x%08x, old header = 0x%08x\n", header, mFixedHeader); off_t pos = mCurrentPos; if (!Resync(mDataSource, mFixedHeader, &pos, NULL)) { diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 3590987d0a13..7106524afbb5 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -112,10 +112,12 @@ private: sp<DataSource> mFileSource; + sp<MediaSource> mVideoTrack; sp<MediaSource> mVideoSource; sp<AwesomeRenderer> mVideoRenderer; bool mVideoRendererIsPreview; + sp<MediaSource> mAudioTrack; sp<MediaSource> mAudioSource; AudioPlayer *mAudioPlayer; int64_t mDurationUs; @@ -199,8 +201,11 @@ private: void cancelPlayerEvents(bool keepBufferingGoing = false); - status_t setAudioSource(sp<MediaSource> source); - status_t setVideoSource(sp<MediaSource> source); + void setAudioSource(sp<MediaSource> source); + status_t initAudioDecoder(); + + void setVideoSource(sp<MediaSource> source); + status_t initVideoDecoder(); void onStreamDone(); @@ -210,6 +215,8 @@ private: void onBufferingUpdate(); void onCheckAudioStatus(); void onPrepareAsyncEvent(); + void abortPrepare(status_t err); + status_t finishSetDataSource_l(); AwesomePlayer(const AwesomePlayer &); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index db802d33cf1d..4f1146b7ca7f 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -30,9 +30,11 @@ import android.content.pm.PackageManager; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteQueryBuilder; import android.media.RingtoneManager; import android.net.Uri; +import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.SystemProperties; import android.provider.DrmStore; @@ -48,6 +50,8 @@ public class SettingsProvider extends ContentProvider { private static final String TABLE_FAVORITES = "favorites"; private static final String TABLE_OLD_FAVORITES = "old_favorites"; + private static final String[] COLUMN_VALUE = new String[] { "value" }; + protected DatabaseHelper mOpenHelper; private BackupManager mBackupManager; @@ -220,6 +224,44 @@ public class SettingsProvider extends ContentProvider { } } + /** + * Fast path that avoids the use of chatty remoted Cursors. + */ + @Override + public Bundle call(String method, String request, Bundle args) { + if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) { + return lookupValue("system", request); + } + + if (Settings.CALL_METHOD_GET_SECURE.equals(method)) { + return lookupValue("secure", request); + } + return null; + } + + // Looks up value 'key' in 'table' and returns either a single-pair Bundle, + // possibly with a null value, or null on failure. + private Bundle lookupValue(String table, String key) { + // TODO: avoid database lookup and serve from in-process cache. + SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + Cursor cursor = null; + try { + cursor = db.query(table, COLUMN_VALUE, "name=?", new String[]{key}, + null, null, null, null); + if (cursor != null && cursor.getCount() == 1) { + cursor.moveToFirst(); + String value = cursor.getString(0); + return Bundle.forPair("value", value); + } + } catch (SQLiteException e) { + Log.w(TAG, "settings lookup error", e); + return null; + } finally { + if (cursor != null) cursor.close(); + } + return Bundle.forPair("value", null); + } + @Override public Cursor query(Uri url, String[] select, String where, String[] whereArgs, String sort) { SqlArguments args = new SqlArguments(url, where, whereArgs); diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java index 73e760e59b98..bee8872ede0a 100644 --- a/services/java/com/android/server/DockObserver.java +++ b/services/java/com/android/server/DockObserver.java @@ -16,53 +16,24 @@ package com.android.server; -import android.app.Activity; -import android.app.ActivityManagerNative; -import android.app.AlarmManager; -import android.app.IActivityManager; -import android.app.IUiModeManager; -import android.app.KeyguardManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.StatusBarManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Configuration; -import android.location.Criteria; -import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; -import android.location.LocationProvider; -import android.os.Binder; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; -import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.UEventObserver; import android.provider.Settings; import android.server.BluetoothService; -import android.text.format.DateUtils; -import android.text.format.Time; import android.util.Log; import android.util.Slog; -import com.android.internal.R; -import com.android.internal.app.DisableCarModeActivity; -import com.android.internal.widget.LockPatternUtils; - import java.io.FileNotFoundException; import java.io.FileReader; @@ -76,178 +47,22 @@ class DockObserver extends UEventObserver { private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock"; private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state"; - private static final String KEY_LAST_UPDATE_INTERVAL = "LAST_UPDATE_INTERVAL"; - private static final int MSG_DOCK_STATE = 0; - private static final int MSG_UPDATE_TWILIGHT = 1; - private static final int MSG_ENABLE_LOCATION_UPDATES = 2; - - public static final int MODE_NIGHT_AUTO = Configuration.UI_MODE_NIGHT_MASK >> 4; - public static final int MODE_NIGHT_NO = Configuration.UI_MODE_NIGHT_NO >> 4; - public static final int MODE_NIGHT_YES = Configuration.UI_MODE_NIGHT_YES >> 4; - - private static final long LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS; - private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20; - private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000; - private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 5 * DateUtils.MINUTE_IN_MILLIS; - private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS; - - private static final String ACTION_UPDATE_NIGHT_MODE = "com.android.server.action.UPDATE_NIGHT_MODE"; private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; - private int mNightMode = MODE_NIGHT_NO; - private boolean mCarModeEnabled = false; - private boolean mSystemReady; private final Context mContext; private PowerManagerService mPowerManager; - private NotificationManager mNotificationManager; - - private KeyguardManager.KeyguardLock mKeyguardLock; - private boolean mKeyguardDisabled; - private LockPatternUtils mLockPatternUtils; - - private AlarmManager mAlarmManager; - - private LocationManager mLocationManager; - private Location mLocation; - private StatusBarManager mStatusBarManager; - - // The broadcast receiver which receives the result of the ordered broadcast sent when - // the dock state changes. The original ordered broadcast is sent with an initial result - // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g., - // to RESULT_CANCELED, then the intent to start a dock app will not be sent. - private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (getResultCode() != Activity.RESULT_OK) { - return; - } - - // Launch a dock activity - String category; - if (mCarModeEnabled) { - // Only launch car home when car mode is enabled. - category = Intent.CATEGORY_CAR_DOCK; - } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { - category = Intent.CATEGORY_DESK_DOCK; - } else { - category = null; - } - if (category != null) { - intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(category); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - try { - mContext.startActivity(intent); - } catch (ActivityNotFoundException e) { - Slog.w(TAG, e.getCause()); - } - } - } - }; - - private final BroadcastReceiver mTwilightUpdateReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) { - mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT); - } - } - }; - - // A LocationListener to initialize the network location provider. The location updates - // are handled through the passive location provider. - private final LocationListener mEmptyLocationListener = new LocationListener() { - public void onLocationChanged(Location location) { - } - - public void onProviderDisabled(String provider) { - } - - public void onProviderEnabled(String provider) { - } - - public void onStatusChanged(String provider, int status, Bundle extras) { - } - }; - - private final LocationListener mLocationListener = new LocationListener() { - - public void onLocationChanged(Location location) { - final boolean hasMoved = hasMoved(location); - final boolean hasBetterAccuracy = location.getAccuracy() < mLocation.getAccuracy(); - if (hasMoved || hasBetterAccuracy) { - synchronized (this) { - mLocation = location; - } - if (hasMoved && mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) { - mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT); - } - } - } - - public void onProviderDisabled(String provider) { - } - - public void onProviderEnabled(String provider) { - } - - public void onStatusChanged(String provider, int status, Bundle extras) { - } - - /* - * The user has moved if the accuracy circles of the two locations - * don't overlap. - */ - private boolean hasMoved(Location location) { - if (location == null) { - return false; - } - if (mLocation == null) { - return true; - } - - /* if new location is older than the current one, the devices hasn't - * moved. - */ - if (location.getTime() < mLocation.getTime()) { - return false; - } - - /* Get the distance between the two points */ - float distance = mLocation.distanceTo(location); - - /* Get the total accuracy radius for both locations */ - float totalAccuracy = mLocation.getAccuracy() + location.getAccuracy(); - - /* If the distance is greater than the combined accuracy of the two - * points then they can't overlap and hence the user has moved. - */ - return distance >= totalAccuracy; - } - }; public DockObserver(Context context, PowerManagerService pm) { mContext = context; mPowerManager = pm; - mLockPatternUtils = new LockPatternUtils(context); init(); // set initial status - ServiceManager.addService("uimode", mBinder); - - mAlarmManager = - (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - mLocationManager = - (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE); - mContext.registerReceiver(mTwilightUpdateReceiver, - new IntentFilter(ACTION_UPDATE_NIGHT_MODE)); - startObserving(DOCK_UEVENT_MATCH); } @@ -263,14 +78,6 @@ class DockObserver extends UEventObserver { if (newState != mDockState) { mPreviousDockState = mDockState; mDockState = newState; - boolean carModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; - if (mCarModeEnabled != carModeEnabled) { - try { - setCarMode(carModeEnabled); - } catch (RemoteException e1) { - Slog.w(TAG, "Unable to change car mode.", e1); - } - } if (mSystemReady) { // Don't force screen on when undocking from the desk dock. // The change in power state will do this anyway. @@ -306,24 +113,11 @@ class DockObserver extends UEventObserver { void systemReady() { synchronized (this) { - KeyguardManager keyguardManager = - (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE); - mKeyguardLock = keyguardManager.newKeyguardLock(TAG); - - final boolean enableCarMode = mDockState == Intent.EXTRA_DOCK_STATE_CAR; - if (enableCarMode) { - try { - setCarMode(enableCarMode); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to change car mode.", e); - } - } // don't bother broadcasting undocked here if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) { update(); } mSystemReady = true; - mHandler.sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES); } } @@ -332,10 +126,6 @@ class DockObserver extends UEventObserver { } private final Handler mHandler = new Handler() { - - boolean mPassiveListenerEnabled; - boolean mNetworkListenerEnabled; - @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -353,17 +143,7 @@ class DockObserver extends UEventObserver { // Pack up the values and broadcast them to everyone Intent intent = new Intent(Intent.ACTION_DOCK_EVENT); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - if (mCarModeEnabled && mDockState != Intent.EXTRA_DOCK_STATE_CAR) { - // Pretend to be in DOCK_STATE_CAR. - intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_CAR); - } else if (!mCarModeEnabled && mDockState == Intent.EXTRA_DOCK_STATE_CAR) { - // Pretend to be in DOCK_STATE_UNDOCKED. - intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); - } else { - intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); - } - intent.putExtra(Intent.EXTRA_PHYSICAL_DOCK_STATE, mDockState); - intent.putExtra(Intent.EXTRA_CAR_MODE_ENABLED, mCarModeEnabled); + intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); // Check if this is Bluetooth Dock String address = BluetoothService.readDockBluetoothAddress(); @@ -406,296 +186,10 @@ class DockObserver extends UEventObserver { } } - // Send the ordered broadcast; the result receiver will receive after all - // broadcasts have been sent. If any broadcast receiver changes the result - // code from the initial value of RESULT_OK, then the result receiver will - // not launch the corresponding dock application. This gives apps a chance - // to override the behavior and stay in their app even when the device is - // placed into a dock. - mContext.sendStickyOrderedBroadcast( - intent, mResultReceiver, null, Activity.RESULT_OK, null, null); - - } - break; - case MSG_UPDATE_TWILIGHT: - synchronized (this) { - if (mCarModeEnabled && mLocation != null && mNightMode == MODE_NIGHT_AUTO) { - try { - DockObserver.this.updateTwilight(); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to change night mode.", e); - } - } - } - break; - case MSG_ENABLE_LOCATION_UPDATES: - // enable passive provider to receive updates from location fixes (gps - // and network). - boolean passiveLocationEnabled; - try { - passiveLocationEnabled = - mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER); - } catch (Exception e) { - // we may get IllegalArgumentException if passive location provider - // does not exist or is not yet installed. - passiveLocationEnabled = false; - } - if (!mPassiveListenerEnabled && passiveLocationEnabled) { - mPassiveListenerEnabled = true; - mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, - 0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener); - } - // enable network provider to receive at least location updates for a given - // distance. - boolean networkLocationEnabled; - try { - networkLocationEnabled = - mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); - } catch (Exception e) { - // we may get IllegalArgumentException if network location provider - // does not exist or is not yet installed. - networkLocationEnabled = false; - } - if (!mNetworkListenerEnabled && networkLocationEnabled) { - mNetworkListenerEnabled = true; - mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, - LOCATION_UPDATE_MS, 0, mEmptyLocationListener); - - retrieveLocation(); - if (mCarModeEnabled && mLocation != null && mNightMode == MODE_NIGHT_AUTO) { - try { - DockObserver.this.updateTwilight(); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to change night mode.", e); - } - } - } - if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) { - long interval = msg.getData().getLong(KEY_LAST_UPDATE_INTERVAL); - interval *= 1.5; - if (interval == 0) { - interval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN; - } else if (interval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) { - interval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX; - } - Bundle bundle = new Bundle(); - bundle.putLong(KEY_LAST_UPDATE_INTERVAL, interval); - Message newMsg = mHandler.obtainMessage(MSG_ENABLE_LOCATION_UPDATES); - newMsg.setData(bundle); - mHandler.sendMessageDelayed(newMsg, interval); + mContext.sendStickyBroadcast(intent); } break; } } - - private void retrieveLocation() { - final Location gpsLocation = - mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); - Location location; - Criteria criteria = new Criteria(); - criteria.setSpeedRequired(false); - criteria.setAltitudeRequired(false); - criteria.setBearingRequired(false); - criteria.setAccuracy(Criteria.ACCURACY_FINE); - final String bestProvider = mLocationManager.getBestProvider(criteria, true); - location = mLocationManager.getLastKnownLocation(bestProvider); - // In the case there is no location available (e.g. GPS fix or network location - // is not available yet), the longitude of the location is estimated using the timezone, - // latitude and accuracy are set to get a good average. - if (location == null) { - Time currentTime = new Time(); - currentTime.set(System.currentTimeMillis()); - double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE * - (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0)); - location = new Location("fake"); - location.setLongitude(lngOffset); - location.setLatitude(0); - location.setAccuracy(417000.0f); - location.setTime(System.currentTimeMillis()); - } - synchronized (this) { - mLocation = location; - } - } - }; - - private void adjustStatusBarCarMode() { - if (mStatusBarManager == null) { - mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); - } - - // Fear not: StatusBarService manages a list of requests to disable - // features of the status bar; these are ORed together to form the - // active disabled list. So if (for example) the device is locked and - // the status bar should be totally disabled, the calls below will - // have no effect until the device is unlocked. - if (mStatusBarManager != null) { - long ident = Binder.clearCallingIdentity(); - mStatusBarManager.disable(mCarModeEnabled - ? StatusBarManager.DISABLE_NOTIFICATION_TICKER - : StatusBarManager.DISABLE_NONE); - Binder.restoreCallingIdentity(ident); - } - - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); - } - - if (mNotificationManager != null) { - long ident = Binder.clearCallingIdentity(); - if (mCarModeEnabled) { - Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class); - - Notification n = new Notification(); - n.icon = R.drawable.stat_notify_car_mode; - n.defaults = Notification.DEFAULT_LIGHTS; - n.flags = Notification.FLAG_ONGOING_EVENT; - n.when = 0; - n.setLatestEventInfo( - mContext, - mContext.getString(R.string.car_mode_disable_notification_title), - mContext.getString(R.string.car_mode_disable_notification_message), - PendingIntent.getActivity(mContext, 0, carModeOffIntent, 0)); - mNotificationManager.notify(0, n); - } else { - mNotificationManager.cancel(0); - } - Binder.restoreCallingIdentity(ident); - } - } - - private void setCarMode(boolean enabled) throws RemoteException { - mCarModeEnabled = enabled; - if (enabled) { - if (mNightMode == MODE_NIGHT_AUTO) { - updateTwilight(); - } else { - setMode(Configuration.UI_MODE_TYPE_CAR, mNightMode << 4); - } - } else { - // Disabling the car mode clears the night mode. - setMode(Configuration.UI_MODE_TYPE_NORMAL, - Configuration.UI_MODE_NIGHT_UNDEFINED); - } - adjustStatusBarCarMode(); - } - - private void setMode(int modeType, int modeNight) throws RemoteException { - long ident = Binder.clearCallingIdentity(); - final IActivityManager am = ActivityManagerNative.getDefault(); - Configuration config = am.getConfiguration(); - if (config.uiMode != (modeType | modeNight)) { - config.uiMode = modeType | modeNight; - am.updateConfiguration(config); - } - Binder.restoreCallingIdentity(ident); - } - - private void setNightMode(int mode) throws RemoteException { - if (mNightMode != mode) { - mNightMode = mode; - switch (mode) { - case MODE_NIGHT_NO: - case MODE_NIGHT_YES: - setMode(Configuration.UI_MODE_TYPE_CAR, mode << 4); - break; - case MODE_NIGHT_AUTO: - long ident = Binder.clearCallingIdentity(); - updateTwilight(); - Binder.restoreCallingIdentity(ident); - break; - default: - setMode(Configuration.UI_MODE_TYPE_CAR, MODE_NIGHT_NO << 4); - break; - } - } - } - - private void updateTwilight() throws RemoteException { - synchronized (this) { - if (mLocation == null) { - return; - } - final long currentTime = System.currentTimeMillis(); - int nightMode; - // calculate current twilight - TwilightCalculator tw = new TwilightCalculator(); - tw.calculateTwilight(currentTime, - mLocation.getLatitude(), mLocation.getLongitude()); - if (tw.mState == TwilightCalculator.DAY) { - nightMode = MODE_NIGHT_NO; - } else { - nightMode = MODE_NIGHT_YES; - } - - // schedule next update - long nextUpdate = 0; - if (tw.mSunrise == -1 || tw.mSunset == -1) { - // In the case the day or night never ends the update is scheduled 12 hours later. - nextUpdate = currentTime + 12 * DateUtils.HOUR_IN_MILLIS; - } else { - final int mLastTwilightState = tw.mState; - // add some extra time to be on the save side. - nextUpdate += DateUtils.MINUTE_IN_MILLIS; - if (currentTime > tw.mSunset) { - // next update should be on the following day - tw.calculateTwilight(currentTime - + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(), - mLocation.getLongitude()); - } - - if (mLastTwilightState == TwilightCalculator.NIGHT) { - nextUpdate += tw.mSunrise; - } else { - nextUpdate += tw.mSunset; - } - } - - Intent updateIntent = new Intent(ACTION_UPDATE_NIGHT_MODE); - PendingIntent pendingIntent = - PendingIntent.getBroadcast(mContext, 0, updateIntent, 0); - mAlarmManager.cancel(pendingIntent); - mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent); - - // Make sure that we really set the new mode only if we're in car mode and - // automatic switching is enables. - if (mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) { - setMode(Configuration.UI_MODE_TYPE_CAR, nightMode << 4); - } - } - } - - /** - * Wrapper class implementing the IUiModeManager interface. - */ - private final IUiModeManager.Stub mBinder = new IUiModeManager.Stub() { - - public void disableCarMode() throws RemoteException { - if (mCarModeEnabled) { - setCarMode(false); - update(); - } - } - - public void enableCarMode() throws RemoteException { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.ENABLE_CAR_MODE, - "Need ENABLE_CAR_MODE permission"); - if (!mCarModeEnabled) { - setCarMode(true); - update(); - } - } - - public void setNightMode(int mode) throws RemoteException { - if (mCarModeEnabled) { - DockObserver.this.setNightMode(mode); - } - } - - public int getNightMode() throws RemoteException { - return mNightMode; - } }; } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index eaf4802983de..8d00debaf2f4 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -1205,8 +1205,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // Remove expired alerts if (intentsToRemove != null) { for (PendingIntent i : intentsToRemove) { - ProximityAlert alert = mProximityAlerts.remove(i); + ProximityAlert alert = mProximityAlerts.get(i); mProximitiesEntered.remove(alert); + removeProximityAlertLocked(i); } } } diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 664f02889229..6ce25824b847 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -540,6 +540,7 @@ class PackageManagerService extends IPackageManager.Stub { if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1); PostInstallData data = mRunningInstalls.get(msg.arg1); mRunningInstalls.delete(msg.arg1); + boolean deleteOld = false; if (data != null) { InstallArgs args = data.args; @@ -563,13 +564,17 @@ class PackageManagerService extends IPackageManager.Stub { } if (res.removedInfo.args != null) { // Remove the replaced package's older resources safely now - synchronized (mInstallLock) { - res.removedInfo.args.doPostDeleteLI(true); - } + deleteOld = true; } } + // Force a gc to clear up things Runtime.getRuntime().gc(); - + // We delete after a gc for applications on sdcard. + if (deleteOld) { + synchronized (mInstallLock) { + res.removedInfo.args.doPostDeleteLI(true); + } + } if (args.observer != null) { try { args.observer.packageInstalled(res.name, res.returnCode); @@ -1350,6 +1355,10 @@ class PackageManagerService extends IPackageManager.Stub { if(ps.pkg == null) { ps.pkg = new PackageParser.Package(packageName); ps.pkg.applicationInfo.packageName = packageName; + ps.pkg.applicationInfo.flags = ps.pkgFlags; + ps.pkg.applicationInfo.publicSourceDir = ps.resourcePathString; + ps.pkg.applicationInfo.sourceDir = ps.codePathString; + ps.pkg.applicationInfo.dataDir = getDataPathForPackage(ps.pkg).getPath(); } return generatePackageInfo(ps.pkg, flags); } @@ -2567,6 +2576,17 @@ class PackageManagerService extends IPackageManager.Stub { } return true; } + + private File getDataPathForPackage(PackageParser.Package pkg) { + boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg); + File dataPath; + if (useEncryptedFSDir) { + dataPath = new File(mSecureAppDataDir, pkg.packageName); + } else { + dataPath = new File(mAppDataDir, pkg.packageName); + } + return dataPath; + } private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanMode) { @@ -2864,17 +2884,19 @@ class PackageManagerService extends IPackageManager.Stub { int i; for (i=0; i<N; i++) { PackageParser.Provider p = pkg.providers.get(i); - String names[] = p.info.authority.split(";"); - for (int j = 0; j < names.length; j++) { - if (mProviders.containsKey(names[j])) { - PackageParser.Provider other = mProviders.get(names[j]); - Log.w(TAG, "Can't install because provider name " + names[j] + - " (in package " + pkg.applicationInfo.packageName + - ") is already used by " - + ((other != null && other.getComponentName() != null) - ? other.getComponentName().getPackageName() : "?")); - mLastScanError = PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER; - return null; + if (p.info.authority != null) { + String names[] = p.info.authority.split(";"); + for (int j = 0; j < names.length; j++) { + if (mProviders.containsKey(names[j])) { + PackageParser.Provider other = mProviders.get(names[j]); + Log.w(TAG, "Can't install because provider name " + names[j] + + " (in package " + pkg.applicationInfo.packageName + + ") is already used by " + + ((other != null && other.getComponentName() != null) + ? other.getComponentName().getPackageName() : "?")); + mLastScanError = PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER; + return null; + } } } } @@ -2932,11 +2954,7 @@ class PackageManagerService extends IPackageManager.Stub { } else { // This is a normal package, need to make its data directory. boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg); - if (useEncryptedFSDir) { - dataPath = new File(mSecureAppDataDir, pkgName); - } else { - dataPath = new File(mAppDataDir, pkgName); - } + dataPath = getDataPathForPackage(pkg); boolean uidError = false; @@ -3087,38 +3105,40 @@ class PackageManagerService extends IPackageManager.Stub { mProvidersByComponent.put(new ComponentName(p.info.packageName, p.info.name), p); p.syncable = p.info.isSyncable; - String names[] = p.info.authority.split(";"); - p.info.authority = null; - for (int j = 0; j < names.length; j++) { - if (j == 1 && p.syncable) { - // We only want the first authority for a provider to possibly be - // syncable, so if we already added this provider using a different - // authority clear the syncable flag. We copy the provider before - // changing it because the mProviders object contains a reference - // to a provider that we don't want to change. - // Only do this for the second authority since the resulting provider - // object can be the same for all future authorities for this provider. - p = new PackageParser.Provider(p); - p.syncable = false; - } - if (!mProviders.containsKey(names[j])) { - mProviders.put(names[j], p); - if (p.info.authority == null) { - p.info.authority = names[j]; + if (p.info.authority != null) { + String names[] = p.info.authority.split(";"); + p.info.authority = null; + for (int j = 0; j < names.length; j++) { + if (j == 1 && p.syncable) { + // We only want the first authority for a provider to possibly be + // syncable, so if we already added this provider using a different + // authority clear the syncable flag. We copy the provider before + // changing it because the mProviders object contains a reference + // to a provider that we don't want to change. + // Only do this for the second authority since the resulting provider + // object can be the same for all future authorities for this provider. + p = new PackageParser.Provider(p); + p.syncable = false; + } + if (!mProviders.containsKey(names[j])) { + mProviders.put(names[j], p); + if (p.info.authority == null) { + p.info.authority = names[j]; + } else { + p.info.authority = p.info.authority + ";" + names[j]; + } + if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) + Log.d(TAG, "Registered content provider: " + names[j] + + ", className = " + p.info.name + + ", isSyncable = " + p.info.isSyncable); } else { - p.info.authority = p.info.authority + ";" + names[j]; + PackageParser.Provider other = mProviders.get(names[j]); + Log.w(TAG, "Skipping provider name " + names[j] + + " (in package " + pkg.applicationInfo.packageName + + "): name already used by " + + ((other != null && other.getComponentName() != null) + ? other.getComponentName().getPackageName() : "?")); } - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) - Log.d(TAG, "Registered content provider: " + names[j] + - ", className = " + p.info.name + - ", isSyncable = " + p.info.isSyncable); - } else { - PackageParser.Provider other = mProviders.get(names[j]); - Log.w(TAG, "Skipping provider name " + names[j] + - " (in package " + pkg.applicationInfo.packageName + - "): name already used by " - + ((other != null && other.getComponentName() != null) - ? other.getComponentName().getPackageName() : "?")); } } if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { @@ -5159,14 +5179,9 @@ class PackageManagerService extends IPackageManager.Stub { int scanMode, String installerPackageName, PackageInstalledInfo res) { // Remember this for later, in case we need to rollback this install - boolean dataDirExists; String pkgName = pkg.packageName; - if (useEncryptedFilesystemForPackage(pkg)) { - dataDirExists = (new File(mSecureAppDataDir, pkgName)).exists(); - } else { - dataDirExists = (new File(mAppDataDir, pkgName)).exists(); - } + boolean dataDirExists = getDataPathForPackage(pkg).exists(); res.name = pkgName; synchronized(mPackages) { if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) { @@ -5741,6 +5756,8 @@ class PackageManagerService extends IPackageManager.Stub { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras); } } + // Force a gc here. + Runtime.getRuntime().gc(); // Delete the resources here after sending the broadcast to let // other processes clean up before deleting resources. if (info.args != null) { @@ -7136,7 +7153,8 @@ class PackageManagerService extends IPackageManager.Stub { void setFlags(int pkgFlags) { this.pkgFlags = (pkgFlags & ApplicationInfo.FLAG_SYSTEM) | (pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) | - (pkgFlags & ApplicationInfo.FLAG_ON_SDCARD); + (pkgFlags & ApplicationInfo.FLAG_ON_SDCARD) | + (pkgFlags & ApplicationInfo.FLAG_NEVER_ENCRYPT); } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index deee7f376221..b023958101da 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -97,6 +97,7 @@ class ServerThread extends Thread { BluetoothA2dpService bluetoothA2dp = null; HeadsetObserver headset = null; DockObserver dock = null; + UiModeManagerService uiMode = null; RecognitionManagerService recognition = null; // Critical services... @@ -363,6 +364,14 @@ class ServerThread extends Thread { } try { + Slog.i(TAG, "UI Mode Manager Service"); + // Listen for dock station changes + uiMode = new UiModeManagerService(context); + } catch (Throwable e) { + Slog.e(TAG, "Failure starting UiModeManagerService", e); + } + + try { Slog.i(TAG, "Backup Service"); ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context)); @@ -441,6 +450,7 @@ class ServerThread extends Thread { final BatteryService batteryF = battery; final ConnectivityService connectivityF = connectivity; final DockObserver dockF = dock; + final UiModeManagerService uiModeF = uiMode; final AppWidgetService appWidgetF = appWidget; final WallpaperManagerService wallpaperF = wallpaper; final InputMethodManagerService immF = imm; @@ -460,6 +470,7 @@ class ServerThread extends Thread { if (batteryF != null) batteryF.systemReady(); if (connectivityF != null) connectivityF.systemReady(); if (dockF != null) dockF.systemReady(); + if (uiModeF != null) uiModeF.systemReady(); if (recognitionF != null) recognitionF.systemReady(); Watchdog.getInstance().start(); diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java new file mode 100644 index 000000000000..71826ffddc7d --- /dev/null +++ b/services/java/com/android/server/UiModeManagerService.java @@ -0,0 +1,692 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.app.Activity; +import android.app.ActivityManagerNative; +import android.app.AlarmManager; +import android.app.IActivityManager; +import android.app.KeyguardManager; +import android.app.IUiModeManager; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.StatusBarManager; +import android.app.UiModeManager; +import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.location.Criteria; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.BatteryManager; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.text.format.DateUtils; +import android.text.format.Time; +import android.util.Slog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +import com.android.internal.R; +import com.android.internal.app.DisableCarModeActivity; + +class UiModeManagerService extends IUiModeManager.Stub { + private static final String TAG = UiModeManager.class.getSimpleName(); + private static final boolean LOG = false; + + private static final String KEY_LAST_UPDATE_INTERVAL = "LAST_UPDATE_INTERVAL"; + + private static final int MSG_UPDATE_TWILIGHT = 0; + private static final int MSG_ENABLE_LOCATION_UPDATES = 1; + + private static final long LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS; + private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20; + private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000; + private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 5 * DateUtils.MINUTE_IN_MILLIS; + private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS; + + private static final String ACTION_UPDATE_NIGHT_MODE = "com.android.server.action.UPDATE_NIGHT_MODE"; + + private final Context mContext; + + final Object mLock = new Object(); + + private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + + private int mNightMode = UiModeManager.MODE_NIGHT_NO; + private boolean mCarModeEnabled = false; + private boolean mCharging = false; + private final boolean mCarModeKeepsScreenOn; + private final boolean mDeskModeKeepsScreenOn; + + private boolean mComputedNightMode; + private int mCurUiMode = 0; + + private Configuration mConfiguration = new Configuration(); + + private boolean mSystemReady; + + private NotificationManager mNotificationManager; + + private AlarmManager mAlarmManager; + + private LocationManager mLocationManager; + private Location mLocation; + private StatusBarManager mStatusBarManager; + private KeyguardManager.KeyguardLock mKeyguardLock; + private final PowerManager.WakeLock mWakeLock; + + // The broadcast receiver which receives the result of the ordered broadcast sent when + // the dock state changes. The original ordered broadcast is sent with an initial result + // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g., + // to RESULT_CANCELED, then the intent to start a dock app will not be sent. + private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (getResultCode() != Activity.RESULT_OK) { + return; + } + + // Launch a dock activity + String category; + if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) { + // Only launch car home when car mode is enabled. + category = Intent.CATEGORY_CAR_DOCK; + } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(intent.getAction())) { + category = Intent.CATEGORY_DESK_DOCK; + } else { + category = null; + } + if (category != null) { + intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(category); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + try { + mContext.startActivity(intent); + } catch (ActivityNotFoundException e) { + Slog.w(TAG, e.getCause()); + } + } + } + }; + + private final BroadcastReceiver mTwilightUpdateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (isDoingNightMode() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT); + } + } + }; + + private final BroadcastReceiver mDockModeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, + Intent.EXTRA_DOCK_STATE_UNDOCKED); + updateDockState(state); + } + }; + + private final BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mCharging = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0); + synchronized (mLock) { + if (mSystemReady) { + updateLocked(); + } + } + } + }; + + // A LocationListener to initialize the network location provider. The location updates + // are handled through the passive location provider. + private final LocationListener mEmptyLocationListener = new LocationListener() { + public void onLocationChanged(Location location) { + } + + public void onProviderDisabled(String provider) { + } + + public void onProviderEnabled(String provider) { + } + + public void onStatusChanged(String provider, int status, Bundle extras) { + } + }; + + private final LocationListener mLocationListener = new LocationListener() { + + public void onLocationChanged(Location location) { + final boolean hasMoved = hasMoved(location); + final boolean hasBetterAccuracy = mLocation == null + || location.getAccuracy() < mLocation.getAccuracy(); + if (hasMoved || hasBetterAccuracy) { + synchronized (mLock) { + mLocation = location; + if (hasMoved && isDoingNightMode() + && mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT); + } + } + } + } + + public void onProviderDisabled(String provider) { + } + + public void onProviderEnabled(String provider) { + } + + public void onStatusChanged(String provider, int status, Bundle extras) { + } + + /* + * The user has moved if the accuracy circles of the two locations + * don't overlap. + */ + private boolean hasMoved(Location location) { + if (location == null) { + return false; + } + if (mLocation == null) { + return true; + } + + /* if new location is older than the current one, the devices hasn't + * moved. + */ + if (location.getTime() < mLocation.getTime()) { + return false; + } + + /* Get the distance between the two points */ + float distance = mLocation.distanceTo(location); + + /* Get the total accuracy radius for both locations */ + float totalAccuracy = mLocation.getAccuracy() + location.getAccuracy(); + + /* If the distance is greater than the combined accuracy of the two + * points then they can't overlap and hence the user has moved. + */ + return distance >= totalAccuracy; + } + }; + + public UiModeManagerService(Context context) { + mContext = context; + + ServiceManager.addService(Context.UI_MODE_SERVICE, this); + + mAlarmManager = + (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); + mLocationManager = + (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE); + mContext.registerReceiver(mTwilightUpdateReceiver, + new IntentFilter(ACTION_UPDATE_NIGHT_MODE)); + mContext.registerReceiver(mDockModeReceiver, + new IntentFilter(Intent.ACTION_DOCK_EVENT)); + mContext.registerReceiver(mBatteryReceiver, + new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + + PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); + + mConfiguration.setToDefaults(); + + mCarModeKeepsScreenOn = (context.getResources().getInteger( + com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1); + mDeskModeKeepsScreenOn = (context.getResources().getInteger( + com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1); + } + + public void disableCarMode() { + synchronized (mLock) { + setCarModeLocked(false); + if (mSystemReady) { + updateLocked(); + } + } + } + + public void enableCarMode() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.ENABLE_CAR_MODE, + "Need ENABLE_CAR_MODE permission"); + synchronized (mLock) { + setCarModeLocked(true); + if (mSystemReady) { + updateLocked(); + } + } + } + + public int getCurrentModeType() { + synchronized (mLock) { + return mCurUiMode & Configuration.UI_MODE_TYPE_MASK; + } + } + + public void setNightMode(int mode) throws RemoteException { + synchronized (mLock) { + switch (mode) { + case UiModeManager.MODE_NIGHT_NO: + case UiModeManager.MODE_NIGHT_YES: + case UiModeManager.MODE_NIGHT_AUTO: + break; + default: + throw new IllegalArgumentException("Unknown mode: " + mode); + } + if (!isDoingNightMode()) { + return; + } + + if (mNightMode != mode) { + mNightMode = mode; + updateLocked(); + } + } + } + + public int getNightMode() throws RemoteException { + return mNightMode; + } + + void systemReady() { + synchronized (mLock) { + mSystemReady = true; + mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; + updateLocked(); + mHandler.sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES); + } + } + + boolean isDoingNightMode() { + return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED; + } + + void setCarModeLocked(boolean enabled) { + if (mCarModeEnabled != enabled) { + mCarModeEnabled = enabled; + + // Disable keyguard when in car mode + if (mKeyguardLock == null) { + KeyguardManager km = + (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE); + if (km != null) { + mKeyguardLock = km.newKeyguardLock(TAG); + } + } + if (mKeyguardLock != null) { + if (enabled) { + mKeyguardLock.disableKeyguard(); + } else { + mKeyguardLock.reenableKeyguard(); + } + } + } + } + + void updateDockState(int newState) { + synchronized (mLock) { + if (newState != mDockState) { + mDockState = newState; + setCarModeLocked(mDockState == Intent.EXTRA_DOCK_STATE_CAR); + if (mSystemReady) { + updateLocked(); + } + } + } + } + + final void updateLocked() { + long ident = Binder.clearCallingIdentity(); + + try { + int uiMode = 0; + if (mCarModeEnabled) { + uiMode = Configuration.UI_MODE_TYPE_CAR; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { + uiMode = Configuration.UI_MODE_TYPE_DESK; + } + if (uiMode != 0) { + if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + updateTwilightLocked(); + uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES + : Configuration.UI_MODE_NIGHT_NO; + } else { + uiMode |= mNightMode << 4; + } + } else { + // Disabling the car mode clears the night mode. + uiMode = Configuration.UI_MODE_TYPE_NORMAL | + Configuration.UI_MODE_NIGHT_NO; + } + + if (uiMode != mCurUiMode) { + mCurUiMode = uiMode; + + try { + final IActivityManager am = ActivityManagerNative.getDefault(); + mConfiguration.uiMode = uiMode; + am.updateConfiguration(mConfiguration); + } catch (RemoteException e) { + Slog.w(TAG, "Failure communicating with activity manager", e); + } + } + + String action = null; + String oldAction = null; + if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) { + oldAction = UiModeManager.ACTION_EXIT_CAR_MODE; + } else if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_DESK) { + oldAction = UiModeManager.ACTION_EXIT_DESK_MODE; + } + + if (mCarModeEnabled) { + if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_CAR) { + adjustStatusBarCarModeLocked(); + + if (oldAction != null) { + mContext.sendBroadcast(new Intent(oldAction)); + } + mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR; + action = UiModeManager.ACTION_ENTER_CAR_MODE; + } + } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { + if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_DESK) { + if (oldAction != null) { + mContext.sendBroadcast(new Intent(oldAction)); + } + mLastBroadcastState = Intent.EXTRA_DOCK_STATE_DESK; + action = UiModeManager.ACTION_ENTER_DESK_MODE; + } + } else { + if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) { + adjustStatusBarCarModeLocked(); + } + + mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + action = oldAction; + } + + if (action != null) { + // Send the ordered broadcast; the result receiver will receive after all + // broadcasts have been sent. If any broadcast receiver changes the result + // code from the initial value of RESULT_OK, then the result receiver will + // not launch the corresponding dock application. This gives apps a chance + // to override the behavior and stay in their app even when the device is + // placed into a dock. + mContext.sendOrderedBroadcast(new Intent(action), null, + mResultReceiver, null, Activity.RESULT_OK, null, null); + } + + // keep screen on when charging and in car mode + boolean keepScreenOn = mCharging && + ((mCarModeEnabled && mCarModeKeepsScreenOn) || + (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn)); + if (keepScreenOn != mWakeLock.isHeld()) { + if (keepScreenOn) { + mWakeLock.acquire(); + } else { + mWakeLock.release(); + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private void adjustStatusBarCarModeLocked() { + if (mStatusBarManager == null) { + mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); + } + + // Fear not: StatusBarService manages a list of requests to disable + // features of the status bar; these are ORed together to form the + // active disabled list. So if (for example) the device is locked and + // the status bar should be totally disabled, the calls below will + // have no effect until the device is unlocked. + if (mStatusBarManager != null) { + mStatusBarManager.disable(mCarModeEnabled + ? StatusBarManager.DISABLE_NOTIFICATION_TICKER + : StatusBarManager.DISABLE_NONE); + } + + if (mNotificationManager == null) { + mNotificationManager = (NotificationManager) + mContext.getSystemService(Context.NOTIFICATION_SERVICE); + } + + if (mNotificationManager != null) { + if (mCarModeEnabled) { + Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class); + + Notification n = new Notification(); + n.icon = R.drawable.stat_notify_car_mode; + n.defaults = Notification.DEFAULT_LIGHTS; + n.flags = Notification.FLAG_ONGOING_EVENT; + n.when = 0; + n.setLatestEventInfo( + mContext, + mContext.getString(R.string.car_mode_disable_notification_title), + mContext.getString(R.string.car_mode_disable_notification_message), + PendingIntent.getActivity(mContext, 0, carModeOffIntent, 0)); + mNotificationManager.notify(0, n); + } else { + mNotificationManager.cancel(0); + } + } + } + + private final Handler mHandler = new Handler() { + + boolean mPassiveListenerEnabled; + boolean mNetworkListenerEnabled; + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UPDATE_TWILIGHT: + synchronized (mLock) { + if (isDoingNightMode() && mLocation != null + && mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + updateTwilightLocked(); + updateLocked(); + } + } + break; + case MSG_ENABLE_LOCATION_UPDATES: + // enable network provider to receive at least location updates for a given + // distance. + boolean networkLocationEnabled; + try { + networkLocationEnabled = + mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); + } catch (Exception e) { + // we may get IllegalArgumentException if network location provider + // does not exist or is not yet installed. + networkLocationEnabled = false; + } + if (!mNetworkListenerEnabled && networkLocationEnabled) { + mNetworkListenerEnabled = true; + mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, + LOCATION_UPDATE_MS, 0, mEmptyLocationListener); + + if (mLocation == null) { + retrieveLocation(); + } + synchronized (mLock) { + if (isDoingNightMode() && mLocation != null + && mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + updateTwilightLocked(); + updateLocked(); + } + } + } + // enable passive provider to receive updates from location fixes (gps + // and network). + boolean passiveLocationEnabled; + try { + passiveLocationEnabled = + mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER); + } catch (Exception e) { + // we may get IllegalArgumentException if passive location provider + // does not exist or is not yet installed. + passiveLocationEnabled = false; + } + if (!mPassiveListenerEnabled && passiveLocationEnabled) { + mPassiveListenerEnabled = true; + mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, + 0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener); + } + if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) { + long interval = msg.getData().getLong(KEY_LAST_UPDATE_INTERVAL); + interval *= 1.5; + if (interval == 0) { + interval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN; + } else if (interval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) { + interval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX; + } + Bundle bundle = new Bundle(); + bundle.putLong(KEY_LAST_UPDATE_INTERVAL, interval); + Message newMsg = mHandler.obtainMessage(MSG_ENABLE_LOCATION_UPDATES); + newMsg.setData(bundle); + mHandler.sendMessageDelayed(newMsg, interval); + } + break; + } + } + + private void retrieveLocation() { + Location location; + Criteria criteria = new Criteria(); + criteria.setSpeedRequired(false); + criteria.setAltitudeRequired(false); + criteria.setBearingRequired(false); + criteria.setAccuracy(Criteria.ACCURACY_FINE); + final String bestProvider = mLocationManager.getBestProvider(criteria, true); + location = mLocationManager.getLastKnownLocation(bestProvider); + // In the case there is no location available (e.g. GPS fix or network location + // is not available yet), the longitude of the location is estimated using the timezone, + // latitude and accuracy are set to get a good average. + if (location == null) { + Time currentTime = new Time(); + currentTime.set(System.currentTimeMillis()); + double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE * + (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0)); + location = new Location("fake"); + location.setLongitude(lngOffset); + location.setLatitude(0); + location.setAccuracy(417000.0f); + location.setTime(System.currentTimeMillis()); + } + synchronized (mLock) { + mLocation = location; + } + } + }; + + void updateTwilightLocked() { + if (mLocation == null) { + return; + } + final long currentTime = System.currentTimeMillis(); + boolean nightMode; + // calculate current twilight + TwilightCalculator tw = new TwilightCalculator(); + tw.calculateTwilight(currentTime, + mLocation.getLatitude(), mLocation.getLongitude()); + if (tw.mState == TwilightCalculator.DAY) { + nightMode = false; + } else { + nightMode = true; + } + + // schedule next update + long nextUpdate = 0; + if (tw.mSunrise == -1 || tw.mSunset == -1) { + // In the case the day or night never ends the update is scheduled 12 hours later. + nextUpdate = currentTime + 12 * DateUtils.HOUR_IN_MILLIS; + } else { + final int mLastTwilightState = tw.mState; + // add some extra time to be on the save side. + nextUpdate += DateUtils.MINUTE_IN_MILLIS; + if (currentTime > tw.mSunset) { + // next update should be on the following day + tw.calculateTwilight(currentTime + + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(), + mLocation.getLongitude()); + } + + if (mLastTwilightState == TwilightCalculator.NIGHT) { + nextUpdate += tw.mSunrise; + } else { + nextUpdate += tw.mSunset; + } + } + + Intent updateIntent = new Intent(ACTION_UPDATE_NIGHT_MODE); + PendingIntent pendingIntent = + PendingIntent.getBroadcast(mContext, 0, updateIntent, 0); + mAlarmManager.cancel(pendingIntent); + mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent); + + mComputedNightMode = nightMode; + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + + pw.println("Permission Denial: can't dump uimode service from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + synchronized (mLock) { + pw.println("Current UI Mode Service state:"); + pw.print(" mDockState="); pw.print(mDockState); + pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); + pw.print(" mNightMode="); pw.print(mNightMode); + pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); + pw.print(" mComputedNightMode="); pw.println(mComputedNightMode); + pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode)); + pw.print(" mSystemReady="); pw.println(mSystemReady); + if (mLocation != null) { + pw.print(" mLocation="); pw.println(mLocation); + } + } + } +} diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java index ee69715391b9..f97f50a45a12 100644 --- a/services/java/com/android/server/Watchdog.java +++ b/services/java/com/android/server/Watchdog.java @@ -34,8 +34,10 @@ import android.os.SystemProperties; import android.provider.Settings; import android.util.Config; import android.util.EventLog; +import android.util.Log; import android.util.Slog; +import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Calendar; @@ -804,19 +806,14 @@ public class Watchdog extends Thread { // to timeout on is asleep as well and won't have a chance to run. Causing a false // positive on when to kill things. long start = SystemClock.uptimeMillis(); - do { + while (timeout > 0 && !mForceKillSystem) { try { - wait(timeout); + wait(timeout); // notifyAll() is called when mForceKillSystem is set } catch (InterruptedException e) { - if (SystemProperties.getBoolean("ro.secure", false)) { - // If this is a secure build, just log the error. - Slog.e("WatchDog", "Woof! Woof! Interrupter!"); - } else { - throw new AssertionError("Someone interrupted the watchdog"); - } + Log.wtf(TAG, e); } timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start); - } while (timeout > 0 && !mForceKillSystem); + } if (mCompleted && !mForceKillSystem) { // The monitors have returned. @@ -825,22 +822,24 @@ public class Watchdog extends Thread { } // If we got here, that means that the system is most likely hung. - // First send a SIGQUIT so that we can see where it was hung. Then - // kill this process so that the system will restart. + // First collect stack traces from all threads of the system process. + // Then kill this process so that the system will restart. + String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null"; EventLog.writeEvent(EventLogTags.WATCHDOG, name); - Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT); - // Wait a bit longer before killing so we can make sure that the stacks are captured. - try { - Thread.sleep(10*1000); - } catch (InterruptedException e) { - } + ArrayList pids = new ArrayList(); + pids.add(Process.myPid()); + File stack = ActivityManagerService.dumpStackTraces(pids); + mActivity.addErrorToDropBox("watchdog", null, null, null, name, null, stack, null); // Only kill the process if the debugger is not attached. if (!Debug.isDebuggerConnected()) { - Slog.i(TAG, "Watchdog is killing the system process"); + Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name); Process.killProcess(Process.myPid()); + System.exit(10); + } else { + Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process"); } } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index a263b23f3233..9018872eba10 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -4662,7 +4662,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen * @param pids of dalvik VM processes to dump stack traces for * @return file containing stack traces, or null if no dump file is configured */ - private static File dumpStackTraces(ArrayList<Integer> pids) { + public static File dumpStackTraces(ArrayList<Integer> pids) { String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null); if (tracesPath == null || tracesPath.length() == 0) { return null; @@ -8958,10 +8958,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen * @param logFile to include in the report, null if none * @param crashInfo giving an application stack trace, null if absent */ - private void addErrorToDropBox(String eventType, + public void addErrorToDropBox(String eventType, ProcessRecord process, HistoryRecord activity, HistoryRecord parent, String subject, String report, File logFile, ApplicationErrorReport.CrashInfo crashInfo) { + // NOTE -- this must never acquire the ActivityManagerService lock, + // otherwise the watchdog may be prevented from resetting the system. + String dropboxTag; if (process == null || process.pid == MY_PID) { dropboxTag = "system_server_" + eventType; diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index ee54f7308aa5..78329dbf00c0 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -40,7 +40,6 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; import android.util.Log; -import android.widget.Toast; import com.android.internal.telephony.Phone; import com.android.internal.util.HierarchicalState; @@ -66,7 +65,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private Context mContext; private final String TAG = "Tethering"; - private boolean mPlaySounds = false; private boolean mBooted = false; //used to remember if we got connected before boot finished private boolean mDeferedUsbConnection = false; @@ -78,8 +76,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private HashMap<String, TetherInterfaceSM> mIfaces; - private ArrayList<String> mActiveTtys; - private BroadcastReceiver mStateReceiver; private static final String USB_NEAR_IFACE_ADDR = "169.254.2.1"; @@ -112,7 +108,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } mIfaces = new HashMap<String, TetherInterfaceSM>(); - mActiveTtys = new ArrayList<String>(); mTetherMasterSM = new TetherMasterSM("TetherMaster"); mTetherMasterSM.start(); @@ -323,142 +318,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { mContext.sendStickyBroadcast(broadcast); Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " + activeList.size() + ", " + erroredList.size()); - // check if we need to send a USB notification - // Check if the user wants to be bothered - boolean tellUser = (Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.TETHER_NOTIFY, 0) == 1); - for (Object o : activeList) { - String s = (String)o; - for (Object regexObject : mTetherableUsbRegexs) { - if (s.matches((String)regexObject)) { - showTetheredNotification(); - return; - } - } - } - if (tellUser) { - for (Object o : availableList) { - String s = (String)o; - for (String match : mTetherableUsbRegexs) { - if (s.matches(match)) { - showTetherAvailableNotification(); - return; - } - } - } - } - clearNotification(); - } - - private void showTetherAvailableNotification() { - NotificationManager notificationManager = (NotificationManager)mContext. - getSystemService(Context.NOTIFICATION_SERVICE); - if (notificationManager == null) { - return; - } - Intent intent = new Intent(); - intent.setClass(mContext, com.android.internal.app.TetherActivity.class); - - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); - - Resources r = Resources.getSystem(); - CharSequence title = r.getText(com.android.internal.R.string. - tether_available_notification_title); - CharSequence message = r.getText(com.android.internal.R.string. - tether_available_notification_message); - - if(mTetheringNotification == null) { - mTetheringNotification = new Notification(); - mTetheringNotification.when = 0; - } - mTetheringNotification.icon = com.android.internal.R.drawable.stat_sys_tether_usb; - - boolean playSounds = false; - //playSounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1"); - if (playSounds) { - mTetheringNotification.defaults |= Notification.DEFAULT_SOUND; - } else { - mTetheringNotification.defaults &= ~Notification.DEFAULT_SOUND; - } - - mTetheringNotification.flags = Notification.FLAG_ONGOING_EVENT; - mTetheringNotification.tickerText = title; - mTetheringNotification.setLatestEventInfo(mContext, title, message, pi); - - notificationManager.notify(mTetheringNotification.icon, mTetheringNotification); - - } - - private void showTetheredNotification() { - NotificationManager notificationManager = (NotificationManager)mContext. - getSystemService(Context.NOTIFICATION_SERVICE); - if (notificationManager == null) { - return; - } - - Intent intent = new Intent(); - intent.setClass(mContext, com.android.internal.app.TetherActivity.class); - - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); - - Resources r = Resources.getSystem(); - CharSequence title = r.getText(com.android.internal.R.string. - tether_stop_notification_title); - CharSequence message = r.getText(com.android.internal.R.string. - tether_stop_notification_message); - - if(mTetheringNotification == null) { - mTetheringNotification = new Notification(); - mTetheringNotification.when = 0; - } - mTetheringNotification.icon = com.android.internal.R.drawable.stat_sys_tether_usb; - - boolean playSounds = false; - //playSounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1"); - if (playSounds) { - mTetheringNotification.defaults |= Notification.DEFAULT_SOUND; - } else { - mTetheringNotification.defaults &= ~Notification.DEFAULT_SOUND; - } - - mTetheringNotification.flags = Notification.FLAG_ONGOING_EVENT; - mTetheringNotification.tickerText = title; - mTetheringNotification.setLatestEventInfo(mContext, title, message, pi); - - notificationManager.notify(mTetheringNotification.icon, mTetheringNotification); - } - - private void clearNotification() { - NotificationManager notificationManager = (NotificationManager)mContext. - getSystemService(Context.NOTIFICATION_SERVICE); - if (notificationManager != null && mTetheringNotification != null) { - notificationManager.cancel(mTetheringNotification.icon); - mTetheringNotification = null; - } - } - - private void showErrorToast(int error) { - int num; - switch(error) { - case ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR: - case ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR: - case ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR: - case ConnectivityManager.TETHER_ERROR_MASTER_ERROR: - num = com.android.internal.R.string.tether_error_message; - break; - case ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR: - case ConnectivityManager.TETHER_ERROR_DISABLE_NAT_ERROR: - num = com.android.internal.R.string.tether_stop_error_message; - break; - default: - // do nothing - return; - } - String text = mContext.getResources().getString(num) + " - EC" + error; - Log.e(TAG, text); - Toast.makeText(mContext, text, Toast.LENGTH_LONG).show(); } private class StateReceiver extends BroadcastReceiver { @@ -748,7 +607,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { // further error.. Tethering.this.configureUsbIface(false); } - Tethering.this.showErrorToast(error); } } diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java index 4078622333a3..3fd71c8426d0 100644 --- a/test-runner/src/android/test/mock/MockContentProvider.java +++ b/test-runner/src/android/test/mock/MockContentProvider.java @@ -32,6 +32,7 @@ import android.database.CursorWindow; import android.database.IBulkCursor; import android.database.IContentObserver; import android.net.Uri; +import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -113,6 +114,15 @@ public class MockContentProvider extends ContentProvider { return MockContentProvider.this.update(url, values, selection, selectionArgs); } + /** + * @hide + */ + @SuppressWarnings("unused") + public Bundle call(String method, String request, Bundle args) + throws RemoteException { + return MockContentProvider.this.call(method, request, args); + } + public IBinder asBinder() { throw new UnsupportedOperationException(); } @@ -205,6 +215,14 @@ public class MockContentProvider extends ContentProvider { } /** + * @hide + */ + @Override + public Bundle call(String method, String request, Bundle args) { + throw new UnsupportedOperationException("unimplemented mock method call"); + } + + /** * Returns IContentProvider which calls back same methods in this class. * By overriding this class, we avoid the mechanism hidden behind ContentProvider * (IPC, etc.) diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java index 7c0a1e21ae70..0be5bea276f3 100644 --- a/test-runner/src/android/test/mock/MockIContentProvider.java +++ b/test-runner/src/android/test/mock/MockIContentProvider.java @@ -27,6 +27,7 @@ import android.database.CursorWindow; import android.database.IBulkCursor; import android.database.IContentObserver; import android.net.Uri; +import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -38,7 +39,7 @@ import java.util.ArrayList; * {@link java.lang.UnsupportedOperationException}. Tests can extend this class to * implement behavior needed for tests. * - * @hide - @hide because this exposes bulkQuery(), which must also be hidden. + * @hide - @hide because this exposes bulkQuery() and call(), which must also be hidden. */ public class MockIContentProvider implements IContentProvider { public int bulkInsert(Uri url, ContentValues[] initialValues) { @@ -93,6 +94,11 @@ public class MockIContentProvider implements IContentProvider { throw new UnsupportedOperationException("unimplemented mock method"); } + public Bundle call(String method, String request, Bundle args) + throws RemoteException { + throw new UnsupportedOperationException("unimplemented mock method"); + } + public IBinder asBinder() { throw new UnsupportedOperationException("unimplemented mock method"); } diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp index 6e7a66da75ba..fc655a7abbb7 100644 --- a/tools/aapt/AaptAssets.cpp +++ b/tools/aapt/AaptAssets.cpp @@ -820,7 +820,12 @@ bool AaptGroupEntry::getUiModeTypeName(const char* name, if (strcmp(name, kWildcardName) == 0) { if (out) out->uiMode = (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) - | ResTable_config::UI_MODE_TYPE_NORMAL; + | ResTable_config::UI_MODE_TYPE_ANY; + return true; + } else if (strcmp(name, "desk") == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) + | ResTable_config::UI_MODE_TYPE_DESK; return true; } else if (strcmp(name, "car") == 0) { if (out) out->uiMode = diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index ea021d82e4da..b7580b33c723 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -447,7 +447,7 @@ static void checkForIds(const String8& path, ResXMLParser& parser) static bool applyFileOverlay(Bundle *bundle, const sp<AaptAssets>& assets, - const sp<ResourceTypeSet>& baseSet, + sp<ResourceTypeSet> *baseSet, const char *resType) { if (bundle->getVerbose()) { @@ -475,13 +475,16 @@ static bool applyFileOverlay(Bundle *bundle, if (bundle->getVerbose()) { printf("trying overlaySet Key=%s\n",overlaySet->keyAt(overlayIndex).string()); } - size_t baseIndex = baseSet->indexOfKey(overlaySet->keyAt(overlayIndex)); + size_t baseIndex = UNKNOWN_ERROR; + if (baseSet->get() != NULL) { + baseIndex = (*baseSet)->indexOfKey(overlaySet->keyAt(overlayIndex)); + } if (baseIndex < UNKNOWN_ERROR) { // look for same flavor. For a given file (strings.xml, for example) // there may be a locale specific or other flavors - we want to match // the same flavor. sp<AaptGroup> overlayGroup = overlaySet->valueAt(overlayIndex); - sp<AaptGroup> baseGroup = baseSet->valueAt(baseIndex); + sp<AaptGroup> baseGroup = (*baseSet)->valueAt(baseIndex); DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > overlayFiles = overlayGroup->getFiles(); @@ -520,8 +523,12 @@ static bool applyFileOverlay(Bundle *bundle, assets->addGroupEntry(overlayFiles.keyAt(overlayGroupIndex)); } } else { + if (baseSet->get() == NULL) { + *baseSet = new ResourceTypeSet(); + assets->getResources()->add(String8(resType), *baseSet); + } // this group doesn't exist (a file that's only in the overlay) - baseSet->add(overlaySet->keyAt(overlayIndex), + (*baseSet)->add(overlaySet->keyAt(overlayIndex), overlaySet->valueAt(overlayIndex)); // make sure all flavors are defined in the resources. sp<AaptGroup> overlayGroup = overlaySet->valueAt(overlayIndex); @@ -751,13 +758,13 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets) current = current->getOverlay(); } // apply the overlay files to the base set - if (!applyFileOverlay(bundle, assets, drawables, "drawable") || - !applyFileOverlay(bundle, assets, layouts, "layout") || - !applyFileOverlay(bundle, assets, anims, "anim") || - !applyFileOverlay(bundle, assets, xmls, "xml") || - !applyFileOverlay(bundle, assets, raws, "raw") || - !applyFileOverlay(bundle, assets, colors, "color") || - !applyFileOverlay(bundle, assets, menus, "menu")) { + if (!applyFileOverlay(bundle, assets, &drawables, "drawable") || + !applyFileOverlay(bundle, assets, &layouts, "layout") || + !applyFileOverlay(bundle, assets, &anims, "anim") || + !applyFileOverlay(bundle, assets, &xmls, "xml") || + !applyFileOverlay(bundle, assets, &raws, "raw") || + !applyFileOverlay(bundle, assets, &colors, "color") || + !applyFileOverlay(bundle, assets, &menus, "menu")) { return UNKNOWN_ERROR; } diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 0b531c228ad3..1f9d15285785 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -2369,7 +2369,7 @@ ResourceTable::validateLocalizations(void) if (configSet.find(region) == configSet.end()) { if (configSet.count(defaultLocale) == 0) { fprintf(stdout, "aapt: warning: " - "*** string '%s' has no default or required localization " + "**** string '%s' has no default or required localization " "for '%s' in %s\n", String8(nameIter->first).string(), config.string(), |