Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69a4817e authored by Daniel Sandler's avatar Daniel Sandler
Browse files

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
parent efbe2d78
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -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"
+40 −0
Original line number Diff line number Diff line
@@ -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) {
+65 −0
Original line number Diff line number Diff line
@@ -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;
}
+7 −0
Original line number Diff line number Diff line
@@ -312,6 +312,10 @@ public interface IActivityManager extends IInterface {
    
    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;
}
+29 −0
Original line number Diff line number Diff line
@@ -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
Loading