为何在Launcher中有时Camera图标不显示

碰到过因为launcher图标固定,所以点击图标后会报错的:

2169 I/ActivityManager(  562): START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.android.camera2/com.android.camera.CameraLauncher} from pid 1075
2170 E/ActivityManager(  562): err = -2, aInfo = null, Component = ComponentInfo{com.android.camera2/com.android.camera.CameraLauncher}
2171 I/DefaultWorkspaceFragment( 1075): App not found

后来发现启动失败的原因是

resolve act=android.intent.action.MAIN
 cat=[android.intent.category.LAUNCHER] flg=0x10000000 
cmp=com.android.camera2/com.android.camera.CameraLauncher

这个Intent并没有找到对应的ActivityInfo。

整个的确认思路是

  1. com.android.camera2安装成功了吗?
  2. 怎么确认安装成功的,是否有执行 adb shell pm list packages -f 确认camera2在列表里?
  3. com.android.camera2/com.android.camera.CameraLauncher​这个activity是enabled的吗,是否检查过AndroidManfiest ?

依次确认后:

  1. camera.apk是安装了的。
  2. 执行​adb shell pm enable com.android.camera2/com.android.camera.CameraLauncher后
    Component {com.android.camera2/com.android.camera.CameraLauncher} new state: enabled

相机可以打开了,从而确认是Activity被disable了。

依次追代码查看camera icon被取消的逻辑思路:

  1. 在camera模块的源码中我们发现DisableCameraReceiver的这样一个类,是继承自BroadcastReceiver一个广播接收器,在AndroidManifest.xml中发现这个reciver的intent-filter为,当系统启动之后,该模块就会收到这条系统广播,然后进行相应的处理。
path: packages/apps/Camera/src/com/android/camera/DisableCameraReceiver.Java
  @Override
    public void onReceive(Context context, Intent intent) {
        // Disable camera-related activities if there is no camera.
        boolean needCameraActivity = FeatureSwitcher.isOnlyCheckBackCamera()
            ? hasBackCamera()
            : hasCamera();


        if (!needCameraActivity) {
            Log.i(TAG, "disable all camera activities");
            for (int i = 0; i < ACTIVITIES.length; i++) {
                disableComponent(context, ACTIVITIES[i]);
            }
        }


        // Disable this receiver so it won't run again.
        disableComponent(context, "com.android.camera.DisableCameraReceiver");
    }
  1. 可以看到,是通过disableComponent(xx, xx);来实现对camera应用的隐藏。
    private void disableComponent(Context context, String klass) {
        ComponentName name = new ComponentName(context, klass);
        PackageManager pm = context.getPackageManager();


        // We need the DONT_KILL_APP flag, otherwise we will be killed
        // immediately because we are in the same app.
        pm.setComponentEnabledSetting(name,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);
    }
  1. 是否需要隐藏camera应用,是通过needCameraActivity的值来判断的,如果其值为true,则显示camera应用,否则,就隐藏掉。那么needCameraActivity的值则是通过hasCamera()这个方法读取出来的。
    private boolean hasCamera() {
        int n = FrameworksClassFactory.getNumberOfCameras();
        Log.i(TAG, "number of camera: " + n);
        return (n > 0);
    }
path:  packages/apps/Camera/src/com/android/camera/FrameworksClassFactory.java
    public static int getNumberOfCameras() {
        if (MOCK_CAMERA) {
            return MockCamera.getNumberOfCameras();
        } else {
            return Camera.getNumberOfCameras();
        }
    }
  1. 通过阅读代码可以了解到,是通过frameworks/base/core/java/android/hardware/Camera.java中的getNumberOfCameras()方法来获取camera的个数。通过这个函数声明,我们知道,这是一个本地方法,是通过JNI调用来获取的。
  public native static int getNumberOfCameras();
  1. 最后在 frameworks/av/camera/CameraBase.cpp中发现对getNumberOfCameras()函数的实现。
int CameraBase::getNumberOfCameras() {
    const sp cs = getCameraService();


    if (!cs.get()) {
        // as required by the public Java APIs
        return 0;
    }
    return cs->getNumberOfCameras();
}
  1. cs是CameraService的一个弱引用,找到frameworks/av/services/camera/libcameraservice/CameraService.cpp中的getNumberOfCameras()函数。
int32_t CameraService::getNumberOfCameras() {
    LOG1("[getNumberOfCameras] NumberOfCameras:%d \n", mNumberOfCameras);
    return mNumberOfCameras;
}
  1. mNumberOfCameras是一个全局变量,定义在CameraService.h中,其赋值的地方在CameraService.cpp中,
void CameraService::onFirstRef()
{
    LOG1("CameraService::onFirstRef");


    BnCameraService::onFirstRef();


    if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
                (const hw_module_t **)&mModule) < 0) {
        ALOGE("Could not load camera HAL module");
        mNumberOfCameras = 0;
    }    else {
        ALOGI("Loaded \"%s\" camera module", mModule->common.name);
        mNumberOfCameras = mModule->get_number_of_cameras();
        if (mNumberOfCameras > MAX_CAMERAS) {
            ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
                    mNumberOfCameras, MAX_CAMERAS);
            mNumberOfCameras = MAX_CAMERAS;
        }
        //for (int i = 0; i < mNumberOfCameras; i++) {
        for (int i = 0; i < MAX_CAMERAS; i++) { // workaround for MATV
            LOG1("setCameraFree(%d)", i);
            setCameraFree(i);
        }


        if (mModule->common.module_api_version >=
                CAMERA_MODULE_API_VERSION_2_1) {
            mModule->set_callbacks(this);
        }


        CameraDeviceFactory::registerService(this);
    }
}

至此,整个隐藏camera应用的流程分析完成,通过对Camera的个数的判断,来解析是否有必要显示此应用的图标。

你可能感兴趣的:(为何在Launcher中有时Camera图标不显示)