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文件


    
        
        
        
        
        
    

果然有HOME的属性

# 解决办法:
  • 在开机广播中加入priority属性,这样能提高收到开机广播的顺序。
    
        
        
        
        
    
  • 修改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 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;
}

你可能感兴趣的:(Android,ROM)