Immersive activity API.
An Activity can declare itself to be "immersive" either by
setting android:immersive="true" in AndroidManifest or by
calling setImmersive(true).
Immersive activities "should" not be interrupted, for
example by Notifications with an associated
fullScreenIntent. (In the future we may even prevent any
non-system application from successfully calling
startActivity() if the foreground activity is immersive.)
Notifications with FLAG_HIGH_PRIORITY set will be shown to
the user in some less-obtrusive way if the frontmost
activity is immersive.
Change-Id: I8d0c25cc4e22371c27cbf2bb6372d2c95d57b2d7
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a962391..9b9ae52 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3720,6 +3720,46 @@
return null;
}
+ /**
+ * Bit indicating that this activity is "immersive" and should not be
+ * interrupted by notifications if possible.
+ *
+ * This value is initially set by the manifest property
+ * <code>android:immersive</code> but may be changed at runtime by
+ * {@link #setImmersive}.
+ *
+ * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE
+ */
+ public boolean isImmersive() {
+ try {
+ return ActivityManagerNative.getDefault().isImmersive(mToken);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Adjust the current immersive mode setting.
+ *
+ * Note that changing this value will have no effect on the activity's
+ * {@link android.content.pm.ActivityInfo} structure; that is, if
+ * <code>android:immersive</code> is set to <code>true</code>
+ * in the application's manifest entry for this activity, the {@link
+ * android.content.pm.ActivityInfo#flags ActivityInfo.flags} member will
+ * always have its {@link android.content.pm.ActivityInfo#FLAG_IMMERSIVE
+ * FLAG_IMMERSIVE} bit set.
+ *
+ * @see #isImmersive
+ * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE
+ */
+ public void setImmersive(boolean i) {
+ try {
+ ActivityManagerNative.getDefault().setImmersive(mToken, i);
+ } catch (RemoteException e) {
+ // pass
+ }
+ }
+
// ------------------ Internal API ------------------
final void setParent(Activity parent) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 2c1f2daf..63b2f08 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1268,6 +1268,31 @@
reply.writeNoException();
return true;
}
+
+ case IS_IMMERSIVE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ reply.writeInt(isImmersive(token) ? 1 : 0);
+ reply.writeNoException();
+ return true;
+ }
+
+ case SET_IMMERSIVE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ boolean imm = data.readInt() == 1;
+ setImmersive(token, imm);
+ reply.writeNoException();
+ return true;
+ }
+
+ case IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ reply.writeInt(isTopActivityImmersive() ? 1 : 0);
+ reply.writeNoException();
+ return true;
+ }
+
}
return super.onTransact(code, data, reply, flags);
@@ -2802,5 +2827,45 @@
reply.recycle();
}
+ public void setImmersive(IBinder token, boolean immersive)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ data.writeInt(immersive ? 1 : 0);
+ mRemote.transact(SET_IMMERSIVE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ public boolean isImmersive(IBinder token)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(IS_IMMERSIVE_TRANSACTION, data, reply, 0);
+ boolean res = reply.readInt() == 1;
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
+ public boolean isTopActivityImmersive()
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION, data, reply, 0);
+ boolean res = reply.readInt() == 1;
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 542bc41..3a86ead 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -311,6 +311,10 @@
public boolean isUserAMonkey() throws RemoteException;
public void finishHeavyWeightApp() throws RemoteException;
+
+ public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
+ public boolean isImmersive(IBinder token) throws RemoteException;
+ public boolean isTopActivityImmersive() throws RemoteException;
/*
* Private non-Binder interfaces
@@ -524,4 +528,7 @@
int GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+107;
int FINISH_HEAVY_WEIGHT_APP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+108;
int HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+109;
+ int IS_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+110;
+ int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111;
+ int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112;
}