Android 开机如何跨过Luancher界面直接显示定制的app?

问题背景

我们知道android启动后会先到Launcher主界面,但是对于定制开发机来说一般是开机后自启一个app。
从app收到开机广播后一般会有2秒左右的时间应用才起来,所以中间有2-3秒停留在Launcher界面上,这样看起来怪怪的。

分析

首先看为什么会首先启动Laucnher

在AMS执行到systemReady的时候,会启动startHomeActivityLocked的方法

 public void systemReady(final Runnable goingCallback) {
    ....
    startHomeActivityLocked(currentUserId, "systemReady");
    ....
}

这个方法实际是去寻找了CATEGORY_HOME属性的app,我们看一下Luancher的Manifest文件

<activity
    android:name="com.android.launcher3.Launcher"
    android:launchMode="singleTask"
    android:clearTaskOnLaunch="true"
    android:stateNotNeeded="true"
    android:theme="@style/LauncherTheme"
    android:windowSoftInputMode="adjustPan"
    android:configChanges="keyboard|keyboardHidden|navigation"
    android:resumeWhilePausing="true"
    android:taskAffinity=""
    android:enabled="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.HOME" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.MONKEY"/>
        </intent-filter>
    </activity>

果然有HOME的属性

# 解决办法:
  • 在开机广播中加入priority属性,这样能提高收到开机广播的顺序。
    <intent-filter android:priority="2147483647">
        <!--.接收启动完成的广播-->
        <category android:name="android.intent.category.DEFAULT" />
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.media.AUDIO_BECOMING_NOISY" />
    </intent-filter>
  • 修改Laucnher apk的category,去掉HOME的属性,把自己的app改为HOME,这样开机就直接启动自己的app了。这样做的缺点是不方便用户切到主界面去做其他操作,app得提供去laucnher的入口,同时还得考虑原本home按键的安排;也得考虑一直点击返回按钮后的安排;默认这两个按钮都会返回到HOME属性的app。
还有没有其他办法呢?

我考虑一种解决办法是延长开机动画的时间,让开机动画掩盖Laucnher的启动,当应用app收到开机广播启动后,再停止开机动画,这样就可以无缝切换了。

frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java 中,内部类KeyguardShowDelegate中有个onDrawn回调,可以在回调中去停止动画。具体方案是在回调中延时并查询前台进程,如果起来了就可以停止动画了。

   // A delegate class to map a particular invocation with a ShowListener object.
    private final class KeyguardShowDelegate extends IKeyguardDrawnCallback.Stub {
        private DrawnListener mDrawnListener;
        private int cnt_seconds = 0;
        KeyguardShowDelegate(DrawnListener drawnListener) {
            mDrawnListener = drawnListener;
        }

        @Override
        public void onDrawn() throws RemoteException {
            if (DEBUG) Log.v(TAG, "**** SHOWN CALLED ****");
	    //keyguard drawn complete ,can exit bootanim
	   
		try {
            cnt_seconds = 0;
            while( !isActivityForeground() && cnt_seconds < WAIT_SENSETIME_APP_TIME){
                Thread.sleep(1000);
                cnt_seconds++;
            }
            //ensure app has launch completed 
            Thread.sleep(1000);
			} catch (Exception e) {
		}
	    android.os.SystemProperties.set("service.bootanim.exit", "1");
        SystemService.stop("bootanim");
		android.os.SystemProperties.set("sys.bootvideo.closed", "1");
	    }
            if (mDrawnListener != null) {
                mDrawnListener.onDrawn();
            }
            hideScrim();
        }
    };

isActivityForeground()根据实际情况自己去实现就好了,这里给个例子。

private boolean isActivityForeground() {

    ActivityManager am = (ActivityManager) mContext.getSystemService(
                Context.ACTIVITY_SERVICE);
        List<RunningTaskInfo> list = am.getRunningTasks(1);
        if (list != null && list.size() > 0) {
            ComponentName cpn = list.get(0).topActivity;
			Log.d(TAG,cpn.getClassName());
            if ( cpn.getClassName().startsWith("com.xx.xxx") ) {
                Log.d(TAG," app is foreground!");
                return true;
        }
    }
    Log.d(TAG," app is background!");
    return false;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值