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
This commit is contained in:
@ -19543,6 +19543,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="isImmersive"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="isTaskRoot"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
@ -20496,6 +20507,19 @@
|
||||
<parameter name="uri" type="android.net.Uri">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setImmersive"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="i" type="boolean">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setIntent"
|
||||
return="void"
|
||||
abstract="false"
|
||||
|
@ -3720,6 +3720,46 @@ public class Activity extends ContextThemeWrapper
|
||||
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) {
|
||||
|
@ -1268,6 +1268,31 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
|
||||
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 @@ class ActivityManagerProxy implements IActivityManager
|
||||
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;
|
||||
}
|
||||
|
@ -311,6 +311,10 @@ public interface IActivityManager extends IInterface {
|
||||
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 @@ public interface IActivityManager extends IInterface {
|
||||
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;
|
||||
}
|
||||
|
@ -8725,6 +8725,35 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
}
|
||||
}
|
||||
|
||||
public void setImmersive(IBinder token, boolean immersive) {
|
||||
synchronized(this) {
|
||||
int index = (token != null) ? indexOfTokenLocked(token) : -1;
|
||||
if (index < 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
HistoryRecord r = (HistoryRecord)mHistory.get(index);
|
||||
r.immersive = immersive;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isImmersive(IBinder token) {
|
||||
synchronized (this) {
|
||||
int index = (token != null) ? indexOfTokenLocked(token) : -1;
|
||||
if (index < 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
HistoryRecord r = (HistoryRecord)mHistory.get(index);
|
||||
return r.immersive;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTopActivityImmersive() {
|
||||
synchronized (this) {
|
||||
HistoryRecord r = topRunningActivityLocked(null);
|
||||
return (r != null) ? r.immersive : false;
|
||||
}
|
||||
}
|
||||
|
||||
public final void enterSafeMode() {
|
||||
synchronized(this) {
|
||||
// It only makes sense to do this before the system is ready
|
||||
|
@ -101,6 +101,7 @@ class HistoryRecord extends IApplicationToken.Stub {
|
||||
boolean idle; // has the activity gone idle?
|
||||
boolean hasBeenLaunched;// has this activity ever been launched?
|
||||
boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
|
||||
boolean immersive; // immersive mode (don't interrupt if possible)
|
||||
|
||||
String stringName; // for caching of toString().
|
||||
|
||||
@ -153,6 +154,7 @@ class HistoryRecord extends IApplicationToken.Stub {
|
||||
pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
|
||||
pw.print(" inHistory="); pw.print(inHistory);
|
||||
pw.print(" persistent="); pw.print(persistent);
|
||||
pw.print(" immersive="); pw.print(immersive);
|
||||
pw.print(" launchMode="); pw.println(launchMode);
|
||||
pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen);
|
||||
pw.print(" visible="); pw.print(visible);
|
||||
@ -278,6 +280,8 @@ class HistoryRecord extends IApplicationToken.Stub {
|
||||
} else {
|
||||
isHomeActivity = false;
|
||||
}
|
||||
|
||||
immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
|
||||
} else {
|
||||
realActivity = null;
|
||||
taskAffinity = null;
|
||||
@ -289,6 +293,7 @@ class HistoryRecord extends IApplicationToken.Stub {
|
||||
packageName = null;
|
||||
fullscreen = true;
|
||||
isHomeActivity = false;
|
||||
immersive = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user