diff options
34 files changed, 655 insertions, 296 deletions
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java index 5cde65c..03e0c0f 100644 --- a/core/java/android/accounts/AccountManagerService.java +++ b/core/java/android/accounts/AccountManagerService.java @@ -247,7 +247,6 @@ public class AccountManagerService } public void systemReady() { - initUser(UserHandle.USER_OWNER); } private UserManager getUserManager() { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 7492629..67d3930 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2809,6 +2809,15 @@ class ActivityManagerProxy implements IActivityManager return success; } + public void clearPendingBackup() throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(CLEAR_PENDING_BACKUP_TRANSACTION, data, reply, 0); + reply.recycle(); + data.recycle(); + } + public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 5f65f08..456d757 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -29,6 +29,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ProviderInfo; @@ -2396,12 +2397,31 @@ public final class ActivityThread { private void handleCreateBackupAgent(CreateBackupAgentData data) { if (DEBUG_BACKUP) Slog.v(TAG, "handleCreateBackupAgent: " + data); + // Sanity check the requested target package's uid against ours + try { + PackageInfo requestedPackage = getPackageManager().getPackageInfo( + data.appInfo.packageName, 0, UserHandle.myUserId()); + if (requestedPackage.applicationInfo.uid != Process.myUid()) { + Slog.w(TAG, "Asked to instantiate non-matching package " + + data.appInfo.packageName); + return; + } + } catch (RemoteException e) { + Slog.e(TAG, "Can't reach package manager", e); + return; + } + // no longer idle; we have backup work to do unscheduleGcIdler(); // instantiate the BackupAgent class named in the manifest LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo); String packageName = packageInfo.mPackageName; + if (packageName == null) { + Slog.d(TAG, "Asked to create backup agent for nonexistent package"); + return; + } + if (mBackupAgents.get(packageName) != null) { Slog.d(TAG, "BackupAgent " + " for " + packageName + " already exists"); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 97250e9..8fc1c86 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -152,6 +152,7 @@ public interface IActivityManager extends IInterface { public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode) throws RemoteException; + public void clearPendingBackup() throws RemoteException; public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException; public void unbindBackupAgent(ApplicationInfo appInfo) throws RemoteException; public void killApplicationProcess(String processName, int uid) throws RemoteException; @@ -619,4 +620,5 @@ public interface IActivityManager extends IInterface { int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156; int REQUEST_BUG_REPORT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+157; int INPUT_DISPATCHING_TIMED_OUT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+158; + int CLEAR_PENDING_BACKUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+159; } diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index 58df167..bb0c686 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -55,6 +55,7 @@ import android.text.format.Time; import android.util.EventLog; import android.util.Log; import android.util.Pair; +import android.util.Slog; import com.android.internal.R; import com.android.internal.util.IndentingPrintWriter; @@ -311,13 +312,10 @@ public class SyncManager { if (userId == UserHandle.USER_NULL) return; if (Intent.ACTION_USER_REMOVED.equals(action)) { - Log.i(TAG, "User removed: u" + userId); onUserRemoved(userId); } else if (Intent.ACTION_USER_STARTING.equals(action)) { - Log.i(TAG, "User starting: u" + userId); onUserStarting(userId); } else if (Intent.ACTION_USER_STOPPING.equals(action)) { - Log.i(TAG, "User stopping: u" + userId); onUserStopping(userId); } } @@ -338,6 +336,10 @@ public class SyncManager { } } + /** + * Should only be created after {@link ContentService#systemReady()} so that + * {@link PackageManager} is ready to query. + */ public SyncManager(Context context, boolean factoryTest) { // Initialize the SyncStorageEngine first, before registering observers // and creating threads and so on; it may fail if the disk is full. @@ -441,9 +443,6 @@ public class SyncManager { UserHandle.ALL, new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION), null, null); - - // do this synchronously to ensure we have the accounts before this call returns - onUserStarting(UserHandle.USER_OWNER); } // Pick a random second in a day to seed all periodic syncs diff --git a/core/java/android/content/SyncQueue.java b/core/java/android/content/SyncQueue.java index 14bfc5b..c9a325e 100644 --- a/core/java/android/content/SyncQueue.java +++ b/core/java/android/content/SyncQueue.java @@ -51,8 +51,6 @@ public class SyncQueue { public SyncQueue(SyncStorageEngine syncStorageEngine, final SyncAdaptersCache syncAdapters) { mSyncStorageEngine = syncStorageEngine; mSyncAdapters = syncAdapters; - - addPendingOperations(UserHandle.USER_OWNER); } public void addPendingOperations(int userId) { diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 4820c5e..6c9290b 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -51,12 +51,17 @@ import com.android.internal.policy.PolicyManager; * an exhibition/lean-back experience.</p> * * <p>The Dream lifecycle is as follows:</p> - * <ul> - * <li>onAttachedToWindow</li> - * <li>onDreamingStarted</li> - * <li>onDreamingStopped</li> - * <li>onDetachedFromWindow</li> - * </ul> + * <ol> + * <li>{@link #onAttachedToWindow} + * <p>Use this for initial setup, such as calling {@link #setContentView setContentView()}.</li> + * <li>{@link #onDreamingStarted} + * <p>Your dream has started, so you should begin animations or other behaviors here.</li> + * <li>{@link #onDreamingStopped} + * <p>Use this to stop the things you started in {@link #onDreamingStarted}.</li> + * <li>{@link #onDetachedFromWindow} + * <p>Use this to dismantle resources your dream set up. For example, detach from handlers + * and listeners.</li> + * </ol> * * <p>In addition, onCreate and onDestroy (from the Service interface) will also be called, but * initialization and teardown should be done by overriding the hooks above.</p> @@ -80,14 +85,40 @@ import com.android.internal.policy.PolicyManager; * android:resource="@xml/my_dream" /> * </service> * </pre> - * <p>If specified, additional information for the dream is defined using the - * <code><{@link android.R.styleable#Dream dream}></code> element. For example:</p> - * <pre> - * (in res/xml/my_dream.xml) * + * <p>If specified with the {@code <meta-data>} element, + * additional information for the dream is defined using the + * {@link android.R.styleable#Dream <dream>} element in a separate XML file. + * Currently, the only addtional + * information you can provide is for a settings activity that allows the user to configure + * the dream behavior. For example:</p> + * <p class="code-caption">res/xml/my_dream.xml</p> + * <pre> * <dream xmlns:android="http://schemas.android.com/apk/res/android" * android:settingsActivity="com.example.app/.MyDreamSettingsActivity" /> * </pre> + * <p>This makes a Settings button available alongside your dream's listing in the + * system settings, which when pressed opens the specified activity.</p> + * + * + * <p>To specify your dream layout, call {@link #setContentView}, typically during the + * {@link #onAttachedToWindow} callback. For example:</p> + * <pre> + * public class MyDream extends DreamService { + * + * @Override + * public void onAttachedToWindow() { + * super.onAttachedToWindow(); + * + * // Exit dream upon user touch + * setInteractive(false); + * // Hide system UI + * setFullscreen(true); + * // Set the dream layout + * setContentView(R.layout.dream); + * } + * } + * </pre> */ public class DreamService extends Service implements Window.Callback { private final String TAG = DreamService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; @@ -323,11 +354,12 @@ public class DreamService extends Service implements Window.Callback { /** * Sets a view to be the content view for this Dream. - * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)}, + * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)} in an activity, * including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view. * - * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> - * @param view The desired content to display. + * <p>Note: This requires a window, so you should usually call it during + * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it + * during {@link #onCreate}).</p> * * @see #setContentView(int) * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) @@ -339,9 +371,12 @@ public class DreamService extends Service implements Window.Callback { /** * Sets a view to be the content view for this Dream. * Behaves similarly to - * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}. + * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)} + * in an activity. * - * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> + * <p>Note: This requires a window, so you should usually call it during + * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it + * during {@link #onCreate}).</p> * * @param view The desired content to display. * @param params Layout parameters for the view. diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 1b71b43..5d306d2 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -829,7 +829,6 @@ static void android_view_GLES20Canvas_clearLayerTexture(JNIEnv* env, jobject cla static void android_view_GLES20Canvas_setTextureLayerTransform(JNIEnv* env, jobject clazz, Layer* layer, SkMatrix* matrix) { - layer->getTransform().load(*matrix); } diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index c93008d..3e8892b 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -1418,7 +1418,7 @@ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur middel van \'n e-posrekening."\n\n" Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening."\n\n" Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string> <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Moet volume bo veilige vlak verhoog word?"\n"Deur vir lang tydperke op hoĆ« volume te luister, kan jou gehoor beskadig."</string> - <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hou twee vingers in om toeganklikheid te aktiveer."</string> + <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hou aan met twee vingers inhou om toeganklikheid te aktiveer."</string> <string name="accessibility_enabled" msgid="1381972048564547685">"Toeganklikheid geaktiveer."</string> <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Toeganklikheid gekanselleer."</string> <string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g> ."</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 4698002..afd847f 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -636,19 +636,12 @@ of new location providers at run-time. The new package does not have to be explicitly listed here, however it must have a signature that matches the signature of at least one package on this list. - Platforms should overlay additional packages in - config_overlay_locationProviderPackageNames, instead of overlaying - this config, if they only want to append packages and not replace - the entire array. --> <string-array name="config_locationProviderPackageNames" translatable="false"> + <!-- The standard AOSP fused location provider --> <item>com.android.location.fused</item> </string-array> - <!-- Pacakge name(s) supplied by overlay, and appended to - config_locationProviderPackageNames. --> - <string-array name="config_overlay_locationProviderPackageNames" translatable="false" /> - <!-- Boolean indicating if current platform supports bluetooth SCO for off call use cases --> <bool name="config_bluetooth_sco_off_call">true</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b3af161..7c0547e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1475,7 +1475,6 @@ <java-symbol type="array" name="radioAttributes" /> <java-symbol type="array" name="config_oemUsbModeOverride" /> <java-symbol type="array" name="config_locationProviderPackageNames" /> - <java-symbol type="array" name="config_overlay_locationProviderPackageNames" /> <java-symbol type="bool" name="config_animateScreenLights" /> <java-symbol type="bool" name="config_automatic_brightness_available" /> <java-symbol type="bool" name="config_sf_limitedAlpha" /> diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd index 62c054a..3cfed13 100644 --- a/docs/html/guide/topics/ui/dialogs.jd +++ b/docs/html/guide/topics/ui/dialogs.jd @@ -119,7 +119,7 @@ onCreateDialog()} callback method.</p> a {@link android.support.v4.app.DialogFragment}:</p> <pre> -public class FireMissilesDialog extends DialogFragment { +public class FireMissilesDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // Use the Builder class for convenient dialog construction @@ -469,7 +469,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - NoticeDialog.this.getDialog().cancel(); + LoginDialogFragment.this.getDialog().cancel(); } }); return builder.create(); @@ -497,15 +497,15 @@ in the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <p>When the user touches one of the dialog's action buttons or selects an item from its list, your {@link android.support.v4.app.DialogFragment} might perform the necessary action itself, but often you'll want to deliver the event to the activity or fragment that -opened the dialog. To do this, define an interface with a method for each type of click event, -then implement that interface in the host component that will +opened the dialog. To do this, define an interface with a method for each type of click event. +Then implement that interface in the host component that will receive the action events from the dialog.</p> <p>For example, here's a {@link android.support.v4.app.DialogFragment} that defines an interface through which it delivers the events back to the host activity:</p> <pre> -public class NoticeDialog extends DialogFragment { +public class NoticeDialogFragment extends DialogFragment { /* The activity that creates an instance of this dialog fragment must * implement this interface in order to receive event callbacks. @@ -516,48 +516,44 @@ public class NoticeDialog extends DialogFragment { } // Use this instance of the interface to deliver action events - static NoticeDialogListener mListener; - - /* Call this to instantiate a new NoticeDialog. - * @param activity The activity hosting the dialog, which must implement the - * NoticeDialogListener to receive event callbacks. - * @returns A new instance of NoticeDialog. - * @throws ClassCastException if the host activity does not - * implement NoticeDialogListener - */ - public static NoticeDialog newInstance(Activity activity) { + NoticeDialogListener mListener; + + // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); // Verify that the host activity implements the callback interface try { - // Instantiate the NoticeDialogListener so we can send events with it + // Instantiate the NoticeDialogListener so we can send events to the host mListener = (NoticeDialogListener) activity; } catch (ClassCastException e) { // The activity doesn't implement the interface, throw exception throw new ClassCastException(activity.toString() + " must implement NoticeDialogListener"); } - NoticeDialog frag = new NoticeDialog(); - return frag; } - ... } </pre> -<p>The activity hosting the dialog creates and shows an instance of the dialog -by calling {@code NoticeDialog.newInstance()} and receives the dialog's +<p>The activity hosting the dialog creates an instance of the dialog +with the dialog fragment's constructor and receives the dialog's events through an implementation of the {@code NoticeDialogListener} interface:</p> <pre> public class MainActivity extends FragmentActivity - implements NoticeDialog.NoticeDialogListener{ + implements NoticeDialogFragment.NoticeDialogListener{ ... public void showNoticeDialog() { // Create an instance of the dialog fragment and show it - DialogFragment dialog = NoticeDialog.newInstance(this); - dialog.show(getSupportFragmentManager(), "NoticeDialog"); + DialogFragment dialog = new NoticeDialogFragment(); + dialog.show(getSupportFragmentManager(), "NoticeDialogFragment"); } + // The dialog fragment receives a reference to this Activity through the + // Fragment.onAttach() callback, which it uses to call the following methods + // defined by the NoticeDialogFragment.NoticeDialogListener interface @Override public void onDialogPositiveClick(DialogFragment dialog) { // User touched the dialog's positive button @@ -573,11 +569,12 @@ public class MainActivity extends FragmentActivity </pre> <p>Because the host activity implements the {@code NoticeDialogListener}—which is -enforced by the {@code newInstance()} method shown above—the dialog fragment can use the +enforced by the {@link android.support.v4.app.Fragment#onAttach onAttach()} +callback method shown above—the dialog fragment can use the interface callback methods to deliver click events to the activity:</p> <pre> -public class NoticeDialog extends DialogFragment { +public class NoticeDialogFragment extends DialogFragment { ... @Override @@ -588,13 +585,13 @@ public class NoticeDialog extends DialogFragment { .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // Send the positive button event back to the host activity - mListener.onDialogPositiveClick(NoticeDialog.this); + mListener.onDialogPositiveClick(NoticeDialogFragment.this); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // Send the negative button event back to the host activity - mListener.onDialogPositiveClick(NoticeDialog.this); + mListener.onDialogPositiveClick(NoticeDialogFragment.this); } }); return builder.create(); @@ -604,8 +601,6 @@ public class NoticeDialog extends DialogFragment { - - <h2 id="ShowingADialog">Showing a Dialog</h2> <p>When you want to show your dialog, create an instance of your {@link @@ -621,7 +616,7 @@ android.support.v4.app.Fragment}. For example:</p> <pre> public void confirmFireMissiles() { - DialogFragment newFragment = FireMissilesDialog.newInstance(this); + DialogFragment newFragment = new FireMissilesDialogFragment(); newFragment.show(getSupportFragmentManager(), "missiles"); } </pre> @@ -653,7 +648,7 @@ onCreateView()} callback.</p> dialog or an embeddable fragment (using a layout named <code>purchase_items.xml</code>):</p> <pre> -public class CustomLayoutDialog extends DialogFragment { +public class CustomDialogFragment extends DialogFragment { /** The system calls this to get the DialogFragment's layout, regardless of whether it's being displayed as a dialog or an embedded fragment. */ @Override @@ -683,7 +678,7 @@ or a fullscreen UI, based on the screen size:</p> <pre> public void showDialog() { FragmentManager fragmentManager = getSupportFragmentManager(); - CustomLayoutDialog newFragment = new CustomLayoutDialog(); + CustomDialogFragment newFragment = new CustomDialogFragment(); if (mIsLargeLayout) { // The device is using a large layout, so show the fragment as a dialog diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 69be317..448e3da 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -209,6 +209,9 @@ struct Layer { } inline void allocateTexture(GLenum format, GLenum storage) { +#if DEBUG_LAYERS + ALOGD(" Allocate layer: %dx%d", getWidth(), getHeight()); +#endif glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0, format, storage, NULL); } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 406d5e9..b6be5b3 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -895,12 +895,6 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { float alpha = layer->getAlpha() / 255.0f; - mat4& transform = layer->getTransform(); - if (!transform.isIdentity()) { - save(0); - mSnapshot->transform->multiply(transform); - } - setupDraw(); if (layer->getRenderTarget() == GL_TEXTURE_2D) { setupDrawWithTexture(); @@ -937,10 +931,6 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); finishDrawTexture(); - - if (!transform.isIdentity()) { - restore(); - } } void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) { @@ -2792,12 +2782,24 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain return DrawGlInfo::kStatusDone; } + mat4* transform = NULL; + if (layer->isTextureLayer()) { + transform = &layer->getTransform(); + if (!transform->isIdentity()) { + save(0); + mSnapshot->transform->multiply(*transform); + } + } + Rect transformed; Rect clip; const bool rejected = quickRejectNoScissor(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip); if (rejected) { + if (transform && !transform->isIdentity()) { + restore(); + } return DrawGlInfo::kStatusDone; } @@ -2858,6 +2860,10 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain } } + if (transform && !transform->isIdentity()) { + restore(); + } + return DrawGlInfo::kStatusDrew; } diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java index cb291ea..6871ee2 100644 --- a/location/java/android/location/LocationRequest.java +++ b/location/java/android/location/LocationRequest.java @@ -221,6 +221,18 @@ public final class LocationRequest implements Parcelable { /** @hide */ public LocationRequest() { } + /** @hide */ + public LocationRequest(LocationRequest src) { + mQuality = src.mQuality; + mInterval = src.mInterval; + mFastestInterval = src.mFastestInterval; + mExplicitFastestInterval = src.mExplicitFastestInterval; + mExpireAt = src.mExpireAt; + mNumUpdates = src.mNumUpdates; + mSmallestDisplacement = src.mSmallestDisplacement; + mProvider = src.mProvider; + } + /** * Set the quality of the request. * diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml index 4c57401..10b9064 100644 --- a/packages/FusedLocation/AndroidManifest.xml +++ b/packages/FusedLocation/AndroidManifest.xml @@ -18,7 +18,8 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.location.fused" - coreApp="true"> + coreApp="true" + android:sharedUserId="android.uid.system"> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> @@ -39,7 +40,7 @@ <intent-filter> <action android:name="com.android.location.service.FusedLocationProvider" /> </intent-filter> - <meta-data android:name="version" android:value="1" /> + <meta-data android:name="serviceVersion" android:value="0" /> </service> </application> </manifest> diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml index 5a5769b..f7b1d78 100644 --- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml +++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml @@ -21,6 +21,8 @@ <ImageView android:id="@+id/brightness_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:paddingRight="10dp" android:src="@drawable/ic_qs_brightness_auto_off" diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index 0958f70..0a7dd7c 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -109,7 +109,7 @@ public class ImageWallpaper extends WallpaperService { private WallpaperObserver mReceiver; Bitmap mBackground; - int mBackgroundWidth = -1, mBackgroundHeight = -1; + int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1; int mLastRotation = -1; float mXOffset; float mYOffset; @@ -156,7 +156,7 @@ public class ImageWallpaper extends WallpaperService { } synchronized (mLock) { - mBackgroundWidth = mBackgroundHeight = -1; + mLastSurfaceWidth = mLastSurfaceHeight = -1; mBackground = null; mRedrawNeeded = true; drawFrameLocked(); @@ -172,6 +172,9 @@ public class ImageWallpaper extends WallpaperService { public void trimMemory(int level) { if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW && mBackground != null && mIsHwAccelerated) { + if (DEBUG) { + Log.d(TAG, "trimMemory"); + } mBackground.recycle(); mBackground = null; mWallpaperManager.forgetLoadedWallpaper(); @@ -286,13 +289,13 @@ public class ImageWallpaper extends WallpaperService { @Override public void onSurfaceDestroyed(SurfaceHolder holder) { super.onSurfaceDestroyed(holder); - mBackgroundWidth = mBackgroundHeight = -1; + mLastSurfaceWidth = mLastSurfaceHeight = -1; } @Override public void onSurfaceCreated(SurfaceHolder holder) { super.onSurfaceCreated(holder); - mBackgroundWidth = mBackgroundHeight = -1; + mLastSurfaceWidth = mLastSurfaceHeight = -1; } @Override @@ -314,9 +317,9 @@ public class ImageWallpaper extends WallpaperService { final int dh = frame.height(); int newRotation = ((WindowManager) getSystemService(WINDOW_SERVICE)). getDefaultDisplay().getRotation(); + boolean surfaceDimensionsChanged = dw != mLastSurfaceWidth || dh != mLastSurfaceHeight; - boolean redrawNeeded = dw != mBackgroundWidth || dh != mBackgroundHeight || - newRotation != mLastRotation; + boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation; if (!redrawNeeded && !mOffsetsChanged) { if (DEBUG) { Log.d(TAG, "Suppressed drawFrame since redraw is not needed " @@ -327,21 +330,41 @@ public class ImageWallpaper extends WallpaperService { mLastRotation = newRotation; // Load bitmap if it is not yet loaded or if it was loaded at a different size - if (mBackground == null || dw != mBackgroundWidth || dw != mBackgroundHeight) { + if (mBackground == null || surfaceDimensionsChanged) { if (DEBUG) { - Log.d(TAG, "Reloading bitmap"); + Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = " + + mBackground + ", " + + ((mBackground == null) ? 0 : mBackground.getWidth()) + ", " + + ((mBackground == null) ? 0 : mBackground.getHeight()) + ", " + + dw + ", " + dh); } - mWallpaperManager.forgetLoadedWallpaper(); updateWallpaperLocked(); + if (mBackground == null) { + if (DEBUG) { + Log.d(TAG, "Unable to load bitmap"); + } + return; + } + if (DEBUG) { + if (dw != mBackground.getWidth() || dh != mBackground.getHeight()) { + Log.d(TAG, "Surface != bitmap dimensions: surface w/h, bitmap w/h: " + + dw + ", " + dh + ", " + mBackground.getWidth() + ", " + + mBackground.getHeight()); + } + } } - final int availw = dw - mBackgroundWidth; - final int availh = dh - mBackgroundHeight; + final int availw = dw - mBackground.getWidth(); + final int availh = dh - mBackground.getHeight(); int xPixels = availw < 0 ? (int)(availw * mXOffset + .5f) : (availw / 2); int yPixels = availh < 0 ? (int)(availh * mYOffset + .5f) : (availh / 2); mOffsetsChanged = false; mRedrawNeeded = false; + if (surfaceDimensionsChanged) { + mLastSurfaceWidth = dw; + mLastSurfaceHeight = dh; + } mLastXTranslation = xPixels; mLastYTranslation = yPixels; if (!redrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) { @@ -374,9 +397,10 @@ public class ImageWallpaper extends WallpaperService { } - void updateWallpaperLocked() { + private void updateWallpaperLocked() { Throwable exception = null; try { + mWallpaperManager.forgetLoadedWallpaper(); // force reload mBackground = mWallpaperManager.getBitmap(); } catch (RuntimeException e) { exception = e; @@ -397,9 +421,6 @@ public class ImageWallpaper extends WallpaperService { Log.w(TAG, "Unable reset to default wallpaper!", ex); } } - - mBackgroundWidth = mBackground != null ? mBackground.getWidth() : 0; - mBackgroundHeight = mBackground != null ? mBackground.getHeight() : 0; } private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int x, int y) { @@ -413,7 +434,8 @@ public class ImageWallpaper extends WallpaperService { c.translate(x, y); if (w < 0 || h < 0) { c.save(Canvas.CLIP_SAVE_FLAG); - c.clipRect(0, 0, mBackgroundWidth, mBackgroundHeight, Op.DIFFERENCE); + c.clipRect(0, 0, mBackground.getWidth(), mBackground.getHeight(), + Op.DIFFERENCE); c.drawColor(0xff000000); c.restore(); } @@ -429,8 +451,8 @@ public class ImageWallpaper extends WallpaperService { private boolean drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) { if (!initGL(sh)) return false; - final float right = left + mBackgroundWidth; - final float bottom = top + mBackgroundHeight; + final float right = left + mBackground.getWidth(); + final float bottom = top + mBackground.getHeight(); final Rect frame = sh.getSurfaceFrame(); final Matrix4f ortho = new Matrix4f(); diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java index 57d2ed3..9f0bcf5 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java @@ -185,6 +185,16 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener final Activity activity = (Activity) RecentsPanelView.this.getContext(); final SystemUIApplication app = (SystemUIApplication) activity.getApplication(); if (app.isWaitingForWindowAnimationStart()) { + if (mItemToAnimateInWhenWindowAnimationIsFinished != null) { + for (View v : + new View[] { holder.iconView, holder.labelView, holder.calloutLine }) { + if (v != null) { + v.setAlpha(1f); + v.setTranslationX(0f); + v.setTranslationY(0f); + } + } + } mItemToAnimateInWhenWindowAnimationIsFinished = holder; final int translation = -getResources().getDimensionPixelSize( R.dimen.status_bar_recents_app_icon_translate_distance); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index a857eba..248a516 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -35,7 +35,7 @@ public class NotificationPanelView extends PanelView { View mHandleView; int mFingers; PhoneStatusBar mStatusBar; - private boolean mFlipped; + boolean mOkToFlip; public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -94,10 +94,10 @@ public class NotificationPanelView extends PanelView { if (PhoneStatusBar.SETTINGS_DRAG_SHORTCUT && mStatusBar.mHasFlipSettings) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: - mFlipped = false; + mOkToFlip = getExpandedHeight() == 0; break; case MotionEvent.ACTION_POINTER_DOWN: - if (!mFlipped) { + if (mOkToFlip) { float miny = event.getY(0); float maxy = miny; for (int i=1; i<event.getPointerCount(); i++) { @@ -111,7 +111,7 @@ public class NotificationPanelView extends PanelView { } else { mStatusBar.flipToSettings(); } - mFlipped = true; + mOkToFlip = false; } } break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 27a4db5..1c4dff8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1487,6 +1487,7 @@ public class PhoneStatusBar extends BaseStatusBar { mFlipSettingsView.setVisibility(View.VISIBLE); mSettingsButton.setVisibility(View.GONE); mScrollView.setVisibility(View.GONE); + mScrollView.setScaleX(0f); mNotificationButton.setVisibility(View.VISIBLE); mNotificationButton.setAlpha(1f); mClearButton.setVisibility(View.GONE); diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 91d5eaa..24ce9bc 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -299,6 +299,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mCarDockRotation; int mDeskDockRotation; int mHdmiRotation; + boolean mHdmiRotationLock; int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE; int mUserRotation = Surface.ROTATION_0; @@ -1035,11 +1036,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { mCanHideNavigationBar = false; } + // For demo purposes, allow the rotation of the HDMI display to be controlled. + // By default, HDMI locks rotation to landscape. if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) { mHdmiRotation = mPortraitRotation; } else { mHdmiRotation = mLandscapeRotation; } + mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", true); } public void updateSettings() { @@ -3873,7 +3877,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // enable 180 degree rotation while docked. preferredRotation = mDeskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation; - } else if (mHdmiPlugged) { + } else if (mHdmiPlugged && mHdmiRotationLock) { // Ignore sensor when plugged into HDMI. // Note that the dock orientation overrides the HDMI orientation. preferredRotation = mHdmiRotation; @@ -4538,5 +4542,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation); pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation); pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation); + pw.print(prefix); pw.print("mHdmiRotation="); pw.print(mHdmiRotation); + pw.print(" mHdmiRotationLock="); pw.println(mHdmiRotationLock); } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java index 0ad2404..b66c883 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java @@ -43,7 +43,7 @@ import com.android.internal.widget.LockPatternUtils; /** * Manages creating, showing, hiding and resetting the keyguard. Calls back - * via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke + * via {@link KeyguardViewMediator.ViewMediatorCallback} to poke * the wake lock and report that the keyguard is done, which is in turn, * reported to this class by the current {@link KeyguardViewBase}. */ @@ -233,6 +233,7 @@ public class KeyguardViewManager { if (mScreenOn) { mKeyguardView.show(); + mKeyguardView.requestFocus(); } } @@ -314,22 +315,25 @@ public class KeyguardViewManager { // Caller should wait for this window to be shown before turning // on the screen. - if (mKeyguardHost.getVisibility() == View.VISIBLE) { - // Keyguard may be in the process of being shown, but not yet - // updated with the window manager... give it a chance to do so. - mKeyguardHost.post(new Runnable() { - public void run() { - if (mKeyguardHost.getVisibility() == View.VISIBLE) { - showListener.onShown(mKeyguardHost.getWindowToken()); - } else { - showListener.onShown(null); + if (showListener != null) { + if (mKeyguardHost.getVisibility() == View.VISIBLE) { + // Keyguard may be in the process of being shown, but not yet + // updated with the window manager... give it a chance to do so. + mKeyguardHost.post(new Runnable() { + @Override + public void run() { + if (mKeyguardHost.getVisibility() == View.VISIBLE) { + showListener.onShown(mKeyguardHost.getWindowToken()); + } else { + showListener.onShown(null); + } } - } - }); - } else { - showListener.onShown(null); + }); + } else { + showListener.onShown(null); + } } - } else { + } else if (showListener != null) { showListener.onShown(null); } } @@ -356,10 +360,9 @@ public class KeyguardViewManager { if (mKeyguardView != null) { mKeyguardView.wakeWhenReadyTq(keyCode); return true; - } else { - Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq"); - return false; } + Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq"); + return false; } /** @@ -382,6 +385,7 @@ public class KeyguardViewManager { final KeyguardViewBase lastView = mKeyguardView; mKeyguardView = null; mKeyguardHost.postDelayed(new Runnable() { + @Override public void run() { synchronized (KeyguardViewManager.this) { lastView.cleanUp(); diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java index 92f9dfd..ceb0325 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java @@ -629,9 +629,7 @@ public class KeyguardViewMediator { mScreenOn = true; cancelDoKeyguardLaterLocked(); if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence); - if (showListener != null) { - notifyScreenOnLocked(showListener); - } + notifyScreenOnLocked(showListener); } maybeSendUserPresentBroadcast(); } @@ -1365,7 +1363,7 @@ public class KeyguardViewMediator { /** * Handle message sent by {@link #verifyUnlock} - * @see #RESET + * @see #VERIFY_UNLOCK */ private void handleVerifyUnlock() { synchronized (KeyguardViewMediator.this) { diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 9f01eca..f241c80 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -1474,6 +1474,7 @@ class BackupManagerService extends IBackupManager.Stub { if (MORE_DEBUG) Slog.v(TAG, " removing participant " + packageName); removeEverBackedUp(packageName); set.remove(packageName); + mPendingBackups.remove(packageName); } } @@ -1625,6 +1626,7 @@ class BackupManagerService extends IBackupManager.Stub { } catch (InterruptedException e) { // just bail if (DEBUG) Slog.w(TAG, "Interrupted: " + e); + mActivityManager.clearPendingBackup(); return null; } } @@ -1632,6 +1634,7 @@ class BackupManagerService extends IBackupManager.Stub { // if we timed out with no connect, abort and move on if (mConnecting == true) { Slog.w(TAG, "Timeout waiting for agent " + app); + mActivityManager.clearPendingBackup(); return null; } if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent); diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 63eeeb3..37dee19 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -23,8 +23,11 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.content.pm.Signature; import android.content.res.Resources; import android.database.ContentObserver; import android.location.Address; @@ -90,10 +93,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run private static final String WAKELOCK_KEY = TAG; private static final String THREAD_NAME = TAG; - private static final String ACCESS_FINE_LOCATION = - android.Manifest.permission.ACCESS_FINE_LOCATION; - private static final String ACCESS_COARSE_LOCATION = - android.Manifest.permission.ACCESS_COARSE_LOCATION; + // Location resolution level: no location data whatsoever + private static final int RESOLUTION_LEVEL_NONE = 0; + // Location resolution level: coarse location data only + private static final int RESOLUTION_LEVEL_COARSE = 1; + // Location resolution level: fine location data + private static final int RESOLUTION_LEVEL_FINE = 2; + private static final String ACCESS_MOCK_LOCATION = android.Manifest.permission.ACCESS_MOCK_LOCATION; private static final String ACCESS_LOCATION_EXTRA_COMMANDS = @@ -246,6 +252,74 @@ public class LocationManagerService extends ILocationManager.Stub implements Run updateProvidersLocked(); } + private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) { + PackageManager pm = mContext.getPackageManager(); + String systemPackageName = mContext.getPackageName(); + ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs); + + List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser( + new Intent(FUSED_LOCATION_SERVICE_ACTION), + PackageManager.GET_META_DATA, mCurrentUserId); + for (ResolveInfo rInfo : rInfos) { + String packageName = rInfo.serviceInfo.packageName; + + // Check that the signature is in the list of supported sigs. If it's not in + // this list the standard provider binding logic won't bind to it. + try { + PackageInfo pInfo; + pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) { + Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION + + ", but has wrong signature, ignoring"); + continue; + } + } catch (NameNotFoundException e) { + Log.e(TAG, "missing package: " + packageName); + continue; + } + + // Get the version info + if (rInfo.serviceInfo.metaData == null) { + Log.w(TAG, "Found fused provider without metadata: " + packageName); + continue; + } + + int version = rInfo.serviceInfo.metaData.getInt( + ServiceWatcher.EXTRA_SERVICE_VERSION, -1); + if (version == 0) { + // This should be the fallback fused location provider. + + // Make sure it's in the system partition. + if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName); + continue; + } + + // Check that the fallback is signed the same as the OS + // as a proxy for coreApp="true" + if (pm.checkSignatures(systemPackageName, packageName) + != PackageManager.SIGNATURE_MATCH) { + if (D) Log.d(TAG, "Fallback candidate not signed the same as system: " + + packageName); + continue; + } + + // Found a valid fallback. + if (D) Log.d(TAG, "Found fallback provider: " + packageName); + return; + } else { + if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName); + } + } + + throw new IllegalStateException("Unable to find a fused location provider that is in the " + + "system partition with version 0 and signed with the platform certificate. " + + "Such a package is needed to provide a default fused location provider in the " + + "event that no other fused location provider has been installed or is currently " + + "available. For example, coreOnly boot mode when decrypting the data " + + "partition. The fallback must also be marked coreApp=\"true\" in the manifest"); + } + private void loadProvidersLocked() { // create a passive location provider, which is always enabled PassiveProvider passiveProvider = new PassiveProvider(this); @@ -275,14 +349,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run */ Resources resources = mContext.getResources(); ArrayList<String> providerPackageNames = new ArrayList<String>(); - String[] pkgs1 = resources.getStringArray( + String[] pkgs = resources.getStringArray( com.android.internal.R.array.config_locationProviderPackageNames); - String[] pkgs2 = resources.getStringArray( - com.android.internal.R.array.config_overlay_locationProviderPackageNames); - if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1)); - if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2)); - if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1)); - if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2)); + if (D) Log.d(TAG, "certificates for location providers pulled from: " + + Arrays.toString(pkgs)); + if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs)); + + ensureFallbackFusedProviderPresentLocked(providerPackageNames); // bind to network provider LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind( @@ -347,7 +420,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run final int mUid; // uid of receiver final int mPid; // pid of receiver final String mPackageName; // package name of receiver - final String mPermission; // best permission that receiver has + final int mAllowedResolutionLevel; // resolution level allowed to receiver final ILocationListener mListener; final PendingIntent mPendingIntent; @@ -366,7 +439,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } else { mKey = intent; } - mPermission = checkPermission(); + mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid); mUid = uid; mPid = pid; mPackageName = packageName; @@ -440,7 +513,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // synchronize to ensure incrementPendingBroadcastsLocked() // is called before decrementPendingBroadcasts() mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler, - mPermission); + getResolutionPermission(mAllowedResolutionLevel)); // call this after broadcasting so we do not increment // if we throw an exeption. incrementPendingBroadcastsLocked(); @@ -474,7 +547,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // synchronize to ensure incrementPendingBroadcastsLocked() // is called before decrementPendingBroadcasts() mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler, - mPermission); + getResolutionPermission(mAllowedResolutionLevel)); // call this after broadcasting so we do not increment // if we throw an exeption. incrementPendingBroadcastsLocked(); @@ -512,7 +585,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // synchronize to ensure incrementPendingBroadcastsLocked() // is called before decrementPendingBroadcasts() mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler, - mPermission); + getResolutionPermission(mAllowedResolutionLevel)); // call this after broadcasting so we do not increment // if we throw an exeption. incrementPendingBroadcastsLocked(); @@ -609,51 +682,76 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } /** - * Returns the best permission available to the caller. + * Returns the permission string associated with the specified resolution level. + * + * @param resolutionLevel the resolution level + * @return the permission string */ - private String getBestCallingPermission() { - if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) == - PackageManager.PERMISSION_GRANTED) { - return ACCESS_FINE_LOCATION; - } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) == - PackageManager.PERMISSION_GRANTED) { - return ACCESS_COARSE_LOCATION; + private String getResolutionPermission(int resolutionLevel) { + switch (resolutionLevel) { + case RESOLUTION_LEVEL_FINE: + return android.Manifest.permission.ACCESS_FINE_LOCATION; + case RESOLUTION_LEVEL_COARSE: + return android.Manifest.permission.ACCESS_COARSE_LOCATION; + default: + return null; } - return null; } /** - * Throw SecurityException if caller has neither COARSE or FINE. - * Otherwise, return the best permission. + * Returns the resolution level allowed to the given PID/UID pair. + * + * @param pid the PID + * @param uid the UID + * @return resolution level allowed to the pid/uid pair */ - private String checkPermission() { - String perm = getBestCallingPermission(); - if (perm == null) { - throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" + - " ACCESS_FINE_LOCATION permission"); + private int getAllowedResolutionLevel(int pid, int uid) { + if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION, + pid, uid) == PackageManager.PERMISSION_GRANTED) { + return RESOLUTION_LEVEL_FINE; + } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, + pid, uid) == PackageManager.PERMISSION_GRANTED) { + return RESOLUTION_LEVEL_COARSE; + } else { + return RESOLUTION_LEVEL_NONE; } - return perm; } /** - * Throw SecurityException if caller lacks permission to use Geofences. + * Returns the resolution level allowed to the caller + * + * @return resolution level allowed to caller + */ + private int getCallerAllowedResolutionLevel() { + return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid()); + } + + /** + * Throw SecurityException if specified resolution level is insufficient to use geofences. + * + * @param allowedResolutionLevel resolution level allowed to caller */ - private void checkGeofencePermission() { - if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != - PackageManager.PERMISSION_GRANTED) { + private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) { + if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) { throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission"); } } - private String getMinimumPermissionForProvider(String provider) { + /** + * Return the minimum resolution level required to use the specified location provider. + * + * @param provider the name of the location provider + * @return minimum resolution level required for provider + */ + private int getMinimumResolutionLevelForProviderUse(String provider) { if (LocationManager.GPS_PROVIDER.equals(provider) || LocationManager.PASSIVE_PROVIDER.equals(provider)) { // gps and passive providers require FINE permission - return ACCESS_FINE_LOCATION; + return RESOLUTION_LEVEL_FINE; } else if (LocationManager.NETWORK_PROVIDER.equals(provider) || LocationManager.FUSED_PROVIDER.equals(provider)) { // network and fused providers are ok with COARSE or FINE - return ACCESS_COARSE_LOCATION; + return RESOLUTION_LEVEL_COARSE; } else { // mock providers LocationProviderInterface lp = mMockProviders.get(provider); @@ -662,41 +760,38 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (properties != null) { if (properties.mRequiresSatellite) { // provider requiring satellites require FINE permission - return ACCESS_FINE_LOCATION; + return RESOLUTION_LEVEL_FINE; } else if (properties.mRequiresNetwork || properties.mRequiresCell) { // provider requiring network and or cell require COARSE or FINE - return ACCESS_COARSE_LOCATION; + return RESOLUTION_LEVEL_COARSE; } } } } - - return null; + return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE } - private boolean isPermissionSufficient(String perm, String minPerm) { - if (ACCESS_FINE_LOCATION.equals(minPerm)) { - return ACCESS_FINE_LOCATION.equals(perm); - } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) { - return ACCESS_FINE_LOCATION.equals(perm) || - ACCESS_COARSE_LOCATION.equals(perm); - } else { - return false; - } - } - - private void checkPermissionForProvider(String perm, String provider) { - String minPerm = getMinimumPermissionForProvider(provider); - if (!isPermissionSufficient(perm, minPerm)) { - if (ACCESS_FINE_LOCATION.equals(minPerm)) { - throw new SecurityException("Location provider \"" + provider + - "\" requires ACCESS_FINE_LOCATION permission."); - } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) { - throw new SecurityException("Location provider \"" + provider + - "\" requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission."); - } else { - throw new SecurityException("Insufficient permission for location provider \"" + - provider + "\"."); + /** + * Throw SecurityException if specified resolution level is insufficient to use the named + * location provider. + * + * @param allowedResolutionLevel resolution level allowed to caller + * @param providerName the name of the location provider + */ + private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel, + String providerName) { + int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName); + if (allowedResolutionLevel < requiredResolutionLevel) { + switch (requiredResolutionLevel) { + case RESOLUTION_LEVEL_FINE: + throw new SecurityException("\"" + providerName + "\" location provider " + + "requires ACCESS_FINE_LOCATION permission."); + case RESOLUTION_LEVEL_COARSE: + throw new SecurityException("\"" + providerName + "\" location provider " + + "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission."); + default: + throw new SecurityException("Insufficient permission for \"" + providerName + + "\" location provider."); } } } @@ -731,8 +826,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run */ @Override public List<String> getProviders(Criteria criteria, boolean enabledOnly) { + int allowedResolutionLevel = getCallerAllowedResolutionLevel(); ArrayList<String> out; - String perm = getBestCallingPermission(); int callingUserId = UserHandle.getCallingUserId(); long identity = Binder.clearCallingIdentity(); try { @@ -743,7 +838,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (LocationManager.FUSED_PROVIDER.equals(name)) { continue; } - if (isPermissionSufficient(perm, getMinimumPermissionForProvider(name))) { + if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) { if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) { continue; } @@ -803,8 +898,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run @Override public boolean providerMeetsCriteria(String provider, Criteria criteria) { - checkPermission(); - LocationProviderInterface p = mProvidersByName.get(provider); if (p == null) { throw new IllegalArgumentException("provider=" + provider); @@ -1010,33 +1103,41 @@ public class LocationManagerService extends ILocationManager.Stub implements Run return receiver; } - private String checkPermissionAndRequest(LocationRequest request) { - String perm = getBestCallingPermission(); - String provider = request.getProvider(); - checkPermissionForProvider(perm, provider); - - if (ACCESS_COARSE_LOCATION.equals(perm)) { - switch (request.getQuality()) { + /** + * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution + * and consistency requirements. + * + * @param request the LocationRequest from which to create a sanitized version + * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution + * constraints + * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution + * @return a version of request that meets the given resolution and consistency requirements + * @hide + */ + private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) { + LocationRequest sanitizedRequest = new LocationRequest(request); + if (resolutionLevel < RESOLUTION_LEVEL_FINE) { + switch (sanitizedRequest.getQuality()) { case LocationRequest.ACCURACY_FINE: - request.setQuality(LocationRequest.ACCURACY_BLOCK); + sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK); break; case LocationRequest.POWER_HIGH: - request.setQuality(LocationRequest.POWER_LOW); + sanitizedRequest.setQuality(LocationRequest.POWER_LOW); break; } // throttle - if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { - request.setInterval(LocationFudger.FASTEST_INTERVAL_MS); + if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { + sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS); } - if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { - request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); + if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { + sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); } } // make getFastestInterval() the minimum of interval and fastest interval - if (request.getFastestInterval() > request.getInterval()) { + if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) { request.setFastestInterval(request.getInterval()); } - return perm; + return sanitizedRequest; } private void checkPackageName(String packageName) { @@ -1079,7 +1180,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run PendingIntent intent, String packageName) { if (request == null) request = DEFAULT_LOCATION_REQUEST; checkPackageName(packageName); - checkPermissionAndRequest(request); + int allowedResolutionLevel = getCallerAllowedResolutionLevel(); + checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, + request.getProvider()); + LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel); final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); @@ -1089,7 +1193,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run long identity = Binder.clearCallingIdentity(); try { synchronized (mLock) { - requestLocationUpdatesLocked(request, recevier, pid, uid, packageName); + requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName); } } finally { Binder.restoreCallingIdentity(identity); @@ -1132,7 +1236,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run public void removeUpdates(ILocationListener listener, PendingIntent intent, String packageName) { checkPackageName(packageName); - checkPermission(); + final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName); @@ -1188,8 +1292,11 @@ public class LocationManagerService extends ILocationManager.Stub implements Run public Location getLastLocation(LocationRequest request, String packageName) { if (D) Log.d(TAG, "getLastLocation: " + request); if (request == null) request = DEFAULT_LOCATION_REQUEST; - String perm = checkPermissionAndRequest(request); + int allowedResolutionLevel = getCallerAllowedResolutionLevel(); checkPackageName(packageName); + checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, + request.getProvider()); + // no need to sanitize this request, as only the provider name is used long identity = Binder.clearCallingIdentity(); try { @@ -1213,13 +1320,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (location == null) { return null; } - if (ACCESS_FINE_LOCATION.equals(perm)) { - return location; - } else { + if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) { Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); if (noGPSLocation != null) { return mLocationFudger.getOrCreate(noGPSLocation); } + } else { + return location; } } return null; @@ -1232,18 +1339,21 @@ public class LocationManagerService extends ILocationManager.Stub implements Run public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent, String packageName) { if (request == null) request = DEFAULT_LOCATION_REQUEST; - checkGeofencePermission(); - checkPermissionAndRequest(request); + int allowedResolutionLevel = getCallerAllowedResolutionLevel(); + checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel); checkPendingIntent(intent); checkPackageName(packageName); + checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, + request.getProvider()); + LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel); - if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent); + if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent); // geo-fence manager uses the public location API, need to clear identity int uid = Binder.getCallingUid(); long identity = Binder.clearCallingIdentity(); try { - mGeofenceManager.addFence(request, geofence, intent, uid, packageName); + mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName); } finally { Binder.restoreCallingIdentity(identity); } @@ -1251,7 +1361,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run @Override public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) { - checkGeofencePermission(); + checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel()); checkPendingIntent(intent); checkPackageName(packageName); @@ -1272,10 +1382,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (mGpsStatusProvider == null) { return false; } - if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != - PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); - } + checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), + LocationManager.GPS_PROVIDER); try { mGpsStatusProvider.addGpsStatusListener(listener); @@ -1303,8 +1411,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // throw NullPointerException to remain compatible with previous implementation throw new NullPointerException(); } + checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), + provider); - checkPermission(); // and check for ACCESS_LOCATION_EXTRA_COMMANDS if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) != PackageManager.PERMISSION_GRANTED)) { @@ -1344,7 +1453,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run return null; } - checkPermissionForProvider(getBestCallingPermission(), provider); + checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), + provider); LocationProviderInterface p; synchronized (mLock) { @@ -1357,7 +1467,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run @Override public boolean isProviderEnabled(String provider) { - checkPermissionForProvider(getBestCallingPermission(), provider); + checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), + provider); if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; long identity = Binder.clearCallingIdentity(); @@ -1522,10 +1633,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } Location notifyLocation = null; - if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) { - notifyLocation = lastLocation; // use fine location + if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) { + notifyLocation = coarseLocation; // use coarse location } else { - notifyLocation = coarseLocation; // use coarse location if available + notifyLocation = lastLocation; // use fine location } if (notifyLocation != null) { Location lastLoc = r.mLastFixBroadcast; diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/java/com/android/server/ServiceWatcher.java index 5598b0a..2e7c6d1 100644 --- a/services/java/com/android/server/ServiceWatcher.java +++ b/services/java/com/android/server/ServiceWatcher.java @@ -43,7 +43,7 @@ import java.util.List; */ public class ServiceWatcher implements ServiceConnection { private static final boolean D = false; - private static final String EXTRA_VERSION = "version"; + public static final String EXTRA_SERVICE_VERSION = "serviceVersion"; private final String mTag; private final Context mContext; @@ -58,9 +58,27 @@ public class ServiceWatcher implements ServiceConnection { // all fields below synchronized on mLock private IBinder mBinder; // connected service private String mPackageName; // current best package - private int mVersion; // current best version + private int mVersion = Integer.MIN_VALUE; // current best version private int mCurrentUserId; + public static ArrayList<HashSet<Signature>> getSignatureSets(Context context, + List<String> initialPackageNames) { + PackageManager pm = context.getPackageManager(); + ArrayList<HashSet<Signature>> sigSets = new ArrayList<HashSet<Signature>>(); + for (int i = 0, size = initialPackageNames.size(); i < size; i++) { + String pkg = initialPackageNames.get(i); + try { + HashSet<Signature> set = new HashSet<Signature>(); + Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures; + set.addAll(Arrays.asList(sigs)); + sigSets.add(set); + } catch (NameNotFoundException e) { + Log.w("ServiceWatcher", pkg + " not found"); + } + } + return sigSets; + } + public ServiceWatcher(Context context, String logTag, String action, List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) { mContext = context; @@ -71,20 +89,7 @@ public class ServiceWatcher implements ServiceConnection { mHandler = handler; mCurrentUserId = userId; - mSignatureSets = new ArrayList<HashSet<Signature>>(); - for (int i=0; i < initialPackageNames.size(); i++) { - String pkg = initialPackageNames.get(i); - HashSet<Signature> set = new HashSet<Signature>(); - try { - Signature[] sigs = - mPm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures; - set.addAll(Arrays.asList(sigs)); - mSignatureSets.add(set); - } catch (NameNotFoundException e) { - Log.w(logTag, pkg + " not found"); - } - } - + mSignatureSets = getSignatureSets(context, initialPackageNames); } public boolean start() { @@ -132,15 +137,16 @@ public class ServiceWatcher implements ServiceConnection { // check version int version = 0; if (rInfo.serviceInfo.metaData != null) { - version = rInfo.serviceInfo.metaData.getInt(EXTRA_VERSION, 0); + version = rInfo.serviceInfo.metaData.getInt(EXTRA_SERVICE_VERSION, 0); } + if (version > mVersion) { bestVersion = version; bestPackage = packageName; } } - if (D) Log.d(mTag, String.format("bindBestPackage %s found %d, %s", + if (D) Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction, (justCheckThisPackage == null ? "" : "(" + justCheckThisPackage + ") "), rInfos.size(), (bestPackage == null ? "no new best package" : "new best packge: " + bestPackage))); @@ -174,7 +180,8 @@ public class ServiceWatcher implements ServiceConnection { | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE, mCurrentUserId); } - private boolean isSignatureMatch(Signature[] signatures) { + public static boolean isSignatureMatch(Signature[] signatures, + List<HashSet<Signature>> sigSets) { if (signatures == null) return false; // build hashset of input to test against @@ -184,7 +191,7 @@ public class ServiceWatcher implements ServiceConnection { } // test input against each of the signature sets - for (HashSet<Signature> referenceSet : mSignatureSets) { + for (HashSet<Signature> referenceSet : sigSets) { if (referenceSet.equals(inputSet)) { return true; } @@ -192,6 +199,10 @@ public class ServiceWatcher implements ServiceConnection { return false; } + private boolean isSignatureMatch(Signature[] signatures) { + return isSignatureMatch(signatures, mSignatureSets); + } + private final PackageMonitor mPackageMonitor = new PackageMonitor() { /** * Called when package has been reinstalled diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 7132e1e..1737876 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -11119,8 +11119,8 @@ public final class ActivityManagerService extends ActivityManagerNative // instantiated. The backup agent will invoke backupAgentCreated() on the // activity manager to announce its creation. public boolean bindBackupAgent(ApplicationInfo app, int backupMode) { - if (DEBUG_BACKUP) Slog.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode); - enforceCallingPermission("android.permission.BACKUP", "startBackupAgent"); + if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + app + " mode=" + backupMode); + enforceCallingPermission("android.permission.BACKUP", "bindBackupAgent"); synchronized(this) { // !!! TODO: currently no check here that we're already bound @@ -11181,6 +11181,17 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } + @Override + public void clearPendingBackup() { + if (DEBUG_BACKUP) Slog.v(TAG, "clearPendingBackup"); + enforceCallingPermission("android.permission.BACKUP", "clearPendingBackup"); + + synchronized (this) { + mBackupTarget = null; + mBackupAppName = null; + } + } + // A backup agent has just come up public void backupAgentCreated(String agentPackageName, IBinder agent) { if (DEBUG_BACKUP) Slog.v(TAG, "backupAgentCreated: " + agentPackageName @@ -11217,32 +11228,34 @@ public final class ActivityManagerService extends ActivityManagerNative } synchronized(this) { - if (mBackupAppName == null) { - Slog.w(TAG, "Unbinding backup agent with no active backup"); - return; - } - - if (!mBackupAppName.equals(appInfo.packageName)) { - Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target"); - return; - } + try { + if (mBackupAppName == null) { + Slog.w(TAG, "Unbinding backup agent with no active backup"); + return; + } - ProcessRecord proc = mBackupTarget.app; - mBackupTarget = null; - mBackupAppName = null; + if (!mBackupAppName.equals(appInfo.packageName)) { + Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target"); + return; + } - // Not backing this app up any more; reset its OOM adjustment - updateOomAdjLocked(proc); + // Not backing this app up any more; reset its OOM adjustment + final ProcessRecord proc = mBackupTarget.app; + updateOomAdjLocked(proc); - // If the app crashed during backup, 'thread' will be null here - if (proc.thread != null) { - try { - proc.thread.scheduleDestroyBackupAgent(appInfo, - compatibilityInfoForPackageLocked(appInfo)); - } catch (Exception e) { - Slog.e(TAG, "Exception when unbinding backup agent:"); - e.printStackTrace(); + // If the app crashed during backup, 'thread' will be null here + if (proc.thread != null) { + try { + proc.thread.scheduleDestroyBackupAgent(appInfo, + compatibilityInfoForPackageLocked(appInfo)); + } catch (Exception e) { + Slog.e(TAG, "Exception when unbinding backup agent:"); + e.printStackTrace(); + } } + } finally { + mBackupTarget = null; + mBackupAppName = null; } } } diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/java/com/android/server/display/DisplayDeviceInfo.java index b4dab86..e76bf44 100644 --- a/services/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/java/com/android/server/display/DisplayDeviceInfo.java @@ -17,6 +17,7 @@ package com.android.server.display; import android.util.DisplayMetrics; +import android.view.Surface; import libcore.util.Objects; @@ -31,11 +32,21 @@ final class DisplayDeviceInfo { public static final int FLAG_DEFAULT_DISPLAY = 1 << 0; /** - * Flag: Indicates that this display device can rotate to show contents in a - * different orientation. Otherwise the rotation is assumed to be fixed in the - * natural orientation and the display manager should transform the content to fit. + * Flag: Indicates that the orientation of this display device is coupled to the + * rotation of its associated logical display. + * <p> + * This flag should be applied to the default display to indicate that the user + * physically rotates the display when content is presented in a different orientation. + * The display manager will apply a coordinate transformation assuming that the + * physical orientation of the display matches the logical orientation of its content. + * </p><p> + * The flag should not be set when the display device is mounted in a fixed orientation + * such as on a desk. The display manager will apply a coordinate transformation + * such as a scale and translation to letterbox or pillarbox format under the + * assumption that the physical orientation of the display is invariant. + * </p> */ - public static final int FLAG_SUPPORTS_ROTATION = 1 << 1; + public static final int FLAG_ROTATES_WITH_CONTENT = 1 << 1; /** * Flag: Indicates that this display device has secure video output, such as HDCP. @@ -116,6 +127,17 @@ final class DisplayDeviceInfo { */ public int touch; + /** + * The additional rotation to apply to all content presented on the display device + * relative to its physical coordinate system. Default is {@link Surface#ROTATION_0}. + * <p> + * This field can be used to compensate for the fact that the display has been + * physically rotated relative to its natural orientation such as an HDMI monitor + * that has been mounted sideways to appear to be portrait rather than landscape. + * </p> + */ + public int rotation = Surface.ROTATION_0; + public void setAssumedDensityForExternalDisplay(int width, int height) { densityDpi = Math.min(width, height) * DisplayMetrics.DENSITY_XHIGH / 1080; // Technically, these values should be smaller than the apparent density @@ -139,7 +161,8 @@ final class DisplayDeviceInfo { && xDpi == other.xDpi && yDpi == other.yDpi && flags == other.flags - && touch == other.touch; + && touch == other.touch + && rotation == other.rotation; } @Override @@ -157,14 +180,18 @@ final class DisplayDeviceInfo { yDpi = other.yDpi; flags = other.flags; touch = other.touch; + rotation = other.rotation; } // For debugging purposes @Override public String toString() { - return "DisplayDeviceInfo{\"" + name + "\": " + width + " x " + height + ", " + refreshRate + " fps, " + return "DisplayDeviceInfo{\"" + name + "\": " + width + " x " + height + ", " + + refreshRate + " fps, " + "density " + densityDpi + ", " + xDpi + " x " + yDpi + " dpi" - + ", touch " + touchToString(touch) + flagsToString(flags) + "}"; + + ", touch " + touchToString(touch) + flagsToString(flags) + + ", rotation " + rotation + + "}"; } private static String touchToString(int touch) { @@ -185,8 +212,8 @@ final class DisplayDeviceInfo { if ((flags & FLAG_DEFAULT_DISPLAY) != 0) { msg.append(", FLAG_DEFAULT_DISPLAY"); } - if ((flags & FLAG_SUPPORTS_ROTATION) != 0) { - msg.append(", FLAG_SUPPORTS_ROTATION"); + if ((flags & FLAG_ROTATES_WITH_CONTENT) != 0) { + msg.append(", FLAG_ROTATES_WITH_CONTENT"); } if ((flags & FLAG_SECURE) != 0) { msg.append(", FLAG_SECURE"); diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java index 93896af..e58a0a5 100644 --- a/services/java/com/android/server/display/DisplayManagerService.java +++ b/services/java/com/android/server/display/DisplayManagerService.java @@ -127,6 +127,13 @@ public final class DisplayManagerService extends IDisplayManager.Stub { // services should be started. This option may disable certain display adapters. public boolean mOnlyCore; + // True if the display manager service should pretend there is only one display + // and only tell applications about the existence of the default logical display. + // The display manager can still mirror content to secondary displays but applications + // cannot present unique content on those displays. + // Used for demonstration purposes only. + private final boolean mSingleDisplayDemoMode; + // All callback records indexed by calling process id. public final SparseArray<CallbackRecord> mCallbacks = new SparseArray<CallbackRecord>(); @@ -182,6 +189,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { mHandler = new DisplayManagerHandler(mainHandler.getLooper()); mUiHandler = uiHandler; mDisplayAdapterListener = new DisplayAdapterListener(); + mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER); } @@ -631,6 +639,12 @@ public final class DisplayManagerService extends IDisplayManager.Stub { isDefault = false; } + if (!isDefault && mSingleDisplayDemoMode) { + Slog.i(TAG, "Not creating a logical display for a secondary display " + + " because single display demo mode is enabled: " + deviceInfo); + return; + } + final int displayId = assignDisplayIdLocked(isDefault); final int layerStack = assignLayerStackLocked(displayId); @@ -857,6 +871,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId); pw.println(" mDefaultViewport=" + mDefaultViewport); pw.println(" mExternalTouchViewport=" + mExternalTouchViewport); + pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode); IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); ipw.increaseIndent(); diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java index d780006..fe38d7f 100644 --- a/services/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/java/com/android/server/display/LocalDisplayAdapter.java @@ -20,6 +20,7 @@ import android.content.Context; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.SystemProperties; import android.util.SparseArray; import android.view.DisplayEventReceiver; import android.view.Surface; @@ -135,7 +136,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.name = getContext().getResources().getString( com.android.internal.R.string.display_manager_built_in_display_name); mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY - | DisplayDeviceInfo.FLAG_SUPPORTS_ROTATION; + | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f); mInfo.xDpi = mPhys.xDpi; mInfo.yDpi = mPhys.yDpi; @@ -145,6 +146,12 @@ final class LocalDisplayAdapter extends DisplayAdapter { com.android.internal.R.string.display_manager_hdmi_display_name); mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL; mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height); + + // For demonstration purposes, allow rotation of the external display. + // In the future we might allow the user to configure this directly. + if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) { + mInfo.rotation = Surface.ROTATION_270; + } } } return mInfo; diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java index 680662e..aa7ea82 100644 --- a/services/java/com/android/server/display/LogicalDisplay.java +++ b/services/java/com/android/server/display/LogicalDisplay.java @@ -241,10 +241,13 @@ final class LogicalDisplay { // is rotated when the contents of the logical display are rendered. int orientation = Surface.ROTATION_0; if (device == mPrimaryDisplayDevice - && (displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_SUPPORTS_ROTATION) != 0) { + && (displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) { orientation = displayInfo.rotation; } + // Apply the physical rotation of the display device itself. + orientation = (orientation + displayDeviceInfo.rotation) % 4; + // Set the frame. // The frame specifies the rotated physical coordinates into which the viewport // is mapped. We need to take care to preserve the aspect ratio of the viewport. diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java index 77e6c03..072dd33 100644 --- a/services/java/com/android/server/pm/UserManagerService.java +++ b/services/java/com/android/server/pm/UserManagerService.java @@ -62,6 +62,8 @@ public class UserManagerService extends IUserManager.Stub { private static final String LOG_TAG = "UserManagerService"; + private static final boolean DBG = false; + private static final String TAG_NAME = "name"; private static final String ATTR_FLAGS = "flags"; private static final String ATTR_ICON_PATH = "icon"; @@ -97,6 +99,9 @@ public class UserManagerService extends IUserManager.Stub { private int[] mUserIds; private boolean mGuestEnabled; private int mNextSerialNumber; + // This resets on a reboot. Otherwise it keeps incrementing so that user ids are + // not reused in quick succession + private int mNextUserId = MIN_USER_ID; private static UserManagerService sInstance; @@ -199,7 +204,8 @@ public class UserManagerService extends IUserManager.Stub { */ private UserInfo getUserInfoLocked(int userId) { UserInfo ui = mUsers.get(userId); - if (ui != null && ui.partial) { + // If it is partial and not in the process of being removed, return as unknown user. + if (ui != null && ui.partial && !mRemovingUserIds.contains(userId)) { Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId); return null; } @@ -668,6 +674,7 @@ public class UserManagerService extends IUserManager.Stub { long now = System.currentTimeMillis(); userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0; userInfo.partial = true; + Environment.getUserSystemDirectory(userInfo.id).mkdirs(); mUsers.put(userId, userInfo); writeUserListLocked(); writeUserLocked(userInfo); @@ -709,7 +716,7 @@ public class UserManagerService extends IUserManager.Stub { user.partial = true; writeUserLocked(user); } - + if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle); int res; try { res = ActivityManagerNative.getDefault().stopUser(userHandle, @@ -730,12 +737,13 @@ public class UserManagerService extends IUserManager.Stub { } void finishRemoveUser(int userHandle) { + if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle); synchronized (mInstallLock) { synchronized (mPackagesLock) { removeUserStateLocked(userHandle); } } - + if (DBG) Slog.i(LOG_TAG, "Removed user " + userHandle + ", sending broadcast"); // Let other services shutdown any activity long ident = Binder.clearCallingIdentity(); try { @@ -804,10 +812,11 @@ public class UserManagerService extends IUserManager.Stub { num++; } } - int[] newUsers = new int[num]; + final int[] newUsers = new int[num]; + int n = 0; for (int i = 0; i < mUsers.size(); i++) { if (!mUsers.valueAt(i).partial) { - newUsers[i] = mUsers.keyAt(i); + newUsers[n++] = mUsers.keyAt(i); } } mUserIds = newUsers; @@ -840,13 +849,14 @@ public class UserManagerService extends IUserManager.Stub { */ private int getNextAvailableIdLocked() { synchronized (mPackagesLock) { - int i = MIN_USER_ID; + int i = mNextUserId; while (i < Integer.MAX_VALUE) { if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) { break; } i++; } + mNextUserId = i + 1; return i; } } diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java index 4e692a2..b94bceb 100644 --- a/services/java/com/android/server/power/PowerManagerService.java +++ b/services/java/com/android/server/power/PowerManagerService.java @@ -107,6 +107,8 @@ public final class PowerManagerService extends IPowerManager.Stub private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9; // Dirty bit: screen on blocker state became held or unheld private static final int DIRTY_SCREEN_ON_BLOCKER_RELEASED = 1 << 10; + // Dirty bit: dock state changed + private static final int DIRTY_DOCK_STATE = 1 << 11; // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp(). // The screen should be off or in the process of being turned off by the display controller. @@ -269,6 +271,9 @@ public final class PowerManagerService extends IPowerManager.Stub // draining faster than it is charging and the user activity timeout has expired. private int mBatteryLevelWhenDreamStarted; + // The current dock state. + private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + // True if the device should wake up when plugged or unplugged. private boolean mWakeUpWhenPluggedOrUnpluggedConfig; @@ -281,6 +286,9 @@ public final class PowerManagerService extends IPowerManager.Stub // True if dreams should be activated on sleep. private boolean mDreamsActivateOnSleepSetting; + // True if dreams should be activated on dock. + private boolean mDreamsActivateOnDockSetting; + // The screen off timeout setting value in milliseconds. private int mScreenOffTimeoutSetting; @@ -440,6 +448,10 @@ public final class PowerManagerService extends IPowerManager.Stub filter.addAction(Intent.ACTION_USER_SWITCHED); mContext.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler); + filter = new IntentFilter(); + filter.addAction(Intent.ACTION_DOCK_EVENT); + mContext.registerReceiver(new DockReceiver(), filter, null, mHandler); + // Register for settings changes. final ContentResolver resolver = mContext.getContentResolver(); resolver.registerContentObserver(Settings.Secure.getUriFor( @@ -448,6 +460,9 @@ public final class PowerManagerService extends IPowerManager.Stub resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP), false, mSettingsObserver, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK), + false, mSettingsObserver, UserHandle.USER_ALL); resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.SCREEN_OFF_TIMEOUT), false, mSettingsObserver, UserHandle.USER_ALL); @@ -487,6 +502,9 @@ public final class PowerManagerService extends IPowerManager.Stub mDreamsActivateOnSleepSetting = (Settings.Secure.getIntForUser(resolver, Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 0, UserHandle.USER_CURRENT) != 0); + mDreamsActivateOnDockSetting = (Settings.Secure.getIntForUser(resolver, + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, 0, + UserHandle.USER_CURRENT) != 0); mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver, Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT, UserHandle.USER_CURRENT); @@ -1339,13 +1357,14 @@ public final class PowerManagerService extends IPowerManager.Stub private boolean updateWakefulnessLocked(int dirty) { boolean changed = false; if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED - | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE)) != 0) { + | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE + | DIRTY_DOCK_STATE)) != 0) { if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) { if (DEBUG_SPEW) { Slog.d(TAG, "updateWakefulnessLocked: Bed time..."); } final long time = SystemClock.uptimeMillis(); - if (mDreamsActivateOnSleepSetting) { + if (shouldNapAtBedTimeLocked()) { changed = napNoUpdateLocked(time); } else { changed = goToSleepNoUpdateLocked(time, @@ -1357,6 +1376,16 @@ public final class PowerManagerService extends IPowerManager.Stub } /** + * Returns true if the device should automatically nap and start dreaming when the user + * activity timeout has expired and it's bedtime. + */ + private boolean shouldNapAtBedTimeLocked() { + return mDreamsActivateOnSleepSetting + || (mDreamsActivateOnDockSetting + && mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED); + } + + /** * Returns true if the device should go to sleep now. * Also used when exiting a dream to determine whether we should go back * to being fully awake or else go to sleep for good. @@ -2124,6 +2153,7 @@ public final class PowerManagerService extends IPowerManager.Stub pw.println(" mPlugType=" + mPlugType); pw.println(" mBatteryLevel=" + mBatteryLevel); pw.println(" mBatteryLevelWhenDreamStarted=" + mBatteryLevelWhenDreamStarted); + pw.println(" mDockState=" + mDockState); pw.println(" mStayOn=" + mStayOn); pw.println(" mProximityPositive=" + mProximityPositive); pw.println(" mBootCompleted=" + mBootCompleted); @@ -2149,6 +2179,7 @@ public final class PowerManagerService extends IPowerManager.Stub pw.println(" mDreamsSupportedConfig=" + mDreamsSupportedConfig); pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting); pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting); + pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting); pw.println(" mScreenOffTimeoutSetting=" + mScreenOffTimeoutSetting); pw.println(" mMaximumScreenOffTimeoutFromDeviceAdmin=" + mMaximumScreenOffTimeoutFromDeviceAdmin + " (enforced=" @@ -2267,6 +2298,21 @@ public final class PowerManagerService extends IPowerManager.Stub } } + private final class DockReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + synchronized (mLock) { + int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, + Intent.EXTRA_DOCK_STATE_UNDOCKED); + if (mDockState != dockState) { + mDockState = dockState; + mDirty |= DIRTY_DOCK_STATE; + updatePowerStateLocked(); + } + } + } + } + private final class SettingsObserver extends ContentObserver { public SettingsObserver(Handler handler) { super(handler); |
