用于在 Android 中打开/关闭相机手电筒的小部件

发布于 2024-12-05 16:49:58 字数 3880 浏览 1 评论 0原文

我正在开发一个用于打开/关闭手机摄像头 LED 的小部件。

我制作了一个可以像切换按钮(开/关)一样工作的小部件。

行为如下:有时,当我启用小部件时,LED 灯保持亮起。 但它不会打开/关闭相机 LED,但会更改图标。

我无法弄清楚真正的问题是什么。

同样的事情在活动(火炬灯应用程序)中工作得很好。

谁能解释一下我该如何解决我的问题?

我哪里出错了?

你可以看一下我到目前为止所做的代码

onUpdate 方法

@Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {

         //super.onUpdate(context, appWidgetManager, appWidgetIds);

        remoteViews = new RemoteViews( context.getPackageName(), R.layout.widgetlayout);
        watchWidget = new ComponentName( context, FlashLightWidget.class );

        Intent intentClick = new Intent(context,FlashLightWidget.class);
        intentClick.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, ""+appWidgetIds[0]);

        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetIds[0],intentClick, 0);
        remoteViews.setOnClickPendingIntent(R.id.myToggleWidget, pendingIntent);
        appWidgetManager.updateAppWidget( watchWidget, remoteViews );
        ctx=context;      
    }

onReceive 方法如下:

@Override

    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub

        remoteViews = new RemoteViews( context.getPackageName(), R.layout.widgetlayout);
        if (intent.getAction()==null) {
            Bundle extras = intent.getExtras();
            if(extras!=null) {
                 if(status)
                    {
                        status=false;
                        remoteViews.setImageViewResource(R.id.myToggleWidget, R.drawable.shutdown1);
                        processOnClick();
                        Toast.makeText(context,"Status==false-onclick",Toast.LENGTH_SHORT).show();
                    }
                    else
                    {
                        status = true;
                        remoteViews.setImageViewResource(R.id.myToggleWidget, R.drawable.shutdown2);
                        processOffClick();
                        Toast.makeText(context,"Status==true--Ofclick",Toast.LENGTH_SHORT).show();
                    }
                }

                watchWidget = new ComponentName( context, FlashLightWidget.class );

                (AppWidgetManager.getInstance(context)).updateAppWidget( watchWidget, remoteViews );
           }
        }
  }

processOffClick 方法

private void processOffClick() {

        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.setPreviewCallback(null);
            mCamera.release();      
            mCamera = null;
        }
    }

processOnClick方法

private void processOnClick() {

    if(mCamera==null)
    {
        try {
            mCamera = Camera.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    if (mCamera != null) {

        Parameters params = mCamera.getParameters();
        List<String> flashModes = params.getSupportedFlashModes();

        if (flashModes == null) {
            return;
        } else {

                params.setFlashMode(Parameters.FLASH_MODE_OFF);
                mCamera.setParameters(params);
                mCamera.startPreview();

            String flashMode = params.getFlashMode();

            if (!Parameters.FLASH_MODE_TORCH.equals(flashMode)) {

                if (flashModes.contains(Parameters.FLASH_MODE_TORCH)) {
                    params.setFlashMode(Parameters.FLASH_MODE_TORCH);
                    mCamera.setParameters(params);

                } 

            }
        }
    } else if (mCamera == null) {
        //Toast.makeText(ctx, "Camera not found", Toast.LENGTH_LONG).show();
        return;
    }
}

I am developing a widget for turning on/off camera led of phone.

I have made a widget that can work like toggle button (on/off).

Behavior is like follows : Sometimes the led light remains on when i enable the widget.
But it doesnot turn on/off the camera led but it changes the icon.

I am not able to figure out whats the actual problem.

The same thing works fine in Activity (Torch Light Application).

Can anyone please explain me how can i solve my problem ?

Where i am going wrong ?

You can look at the code below that i have done so far

onUpdate method

@Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {

         //super.onUpdate(context, appWidgetManager, appWidgetIds);

        remoteViews = new RemoteViews( context.getPackageName(), R.layout.widgetlayout);
        watchWidget = new ComponentName( context, FlashLightWidget.class );

        Intent intentClick = new Intent(context,FlashLightWidget.class);
        intentClick.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, ""+appWidgetIds[0]);

        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetIds[0],intentClick, 0);
        remoteViews.setOnClickPendingIntent(R.id.myToggleWidget, pendingIntent);
        appWidgetManager.updateAppWidget( watchWidget, remoteViews );
        ctx=context;      
    }

onReceive method is as follows :

@Override

    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub

        remoteViews = new RemoteViews( context.getPackageName(), R.layout.widgetlayout);
        if (intent.getAction()==null) {
            Bundle extras = intent.getExtras();
            if(extras!=null) {
                 if(status)
                    {
                        status=false;
                        remoteViews.setImageViewResource(R.id.myToggleWidget, R.drawable.shutdown1);
                        processOnClick();
                        Toast.makeText(context,"Status==false-onclick",Toast.LENGTH_SHORT).show();
                    }
                    else
                    {
                        status = true;
                        remoteViews.setImageViewResource(R.id.myToggleWidget, R.drawable.shutdown2);
                        processOffClick();
                        Toast.makeText(context,"Status==true--Ofclick",Toast.LENGTH_SHORT).show();
                    }
                }

                watchWidget = new ComponentName( context, FlashLightWidget.class );

                (AppWidgetManager.getInstance(context)).updateAppWidget( watchWidget, remoteViews );
           }
        }
  }

processOffClick method

private void processOffClick() {

        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.setPreviewCallback(null);
            mCamera.release();      
            mCamera = null;
        }
    }

processOnClick method

private void processOnClick() {

    if(mCamera==null)
    {
        try {
            mCamera = Camera.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    if (mCamera != null) {

        Parameters params = mCamera.getParameters();
        List<String> flashModes = params.getSupportedFlashModes();

        if (flashModes == null) {
            return;
        } else {

                params.setFlashMode(Parameters.FLASH_MODE_OFF);
                mCamera.setParameters(params);
                mCamera.startPreview();

            String flashMode = params.getFlashMode();

            if (!Parameters.FLASH_MODE_TORCH.equals(flashMode)) {

                if (flashModes.contains(Parameters.FLASH_MODE_TORCH)) {
                    params.setFlashMode(Parameters.FLASH_MODE_TORCH);
                    mCamera.setParameters(params);

                } 

            }
        }
    } else if (mCamera == null) {
        //Toast.makeText(ctx, "Camera not found", Toast.LENGTH_LONG).show();
        return;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦毁影碎の 2024-12-12 16:49:59

我遇到过类似的情况,我需要在 UI 线程上运行某些 android 代码......这仅在 Activity 中可用。我的解决方案 - 具有完全透明布局的活动。因此,当您完成操作时,您只会看到主屏幕(尽管没有响应),在您的情况下,这应该很快。

I had a similar situation where I need to run certain android code on the UI thread ... which is only available in an Activity. My solution - an activity with a completely transparent layout. So you just see your home screen (albeit unresponsive) while you complete your actions, which in your case should be pretty quick.

浪推晚风 2024-12-12 16:49:59

我有一个解决方案,虽然不是很好,但是有效。让小部件调用一个活动,并在活动中打开闪光灯,然后关闭活动。关闭它也是一样。如果这在活动中有效,那么该解决方案将有效。它不优雅但有效。我试过了。

I have one solution that is not great but works. Have the widget call an Activity, and in the Activity turn the flash on, and later close the Activity. The same to turn it off. If this works in the Activity then this solution will work. It's not elegant but works. I tried it.

别再吹冷风 2024-12-12 16:49:58

过了好久,我才有空解决这个问题。

这就是我所做的。

FlashlightWidgetProvider 类:

public class FlashlightWidgetProvider extends AppWidgetProvider {

        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                        int[] appWidgetIds) {

                Intent receiver = new Intent(context, FlashlightWidgetReceiver.class);
                receiver.setAction("COM_FLASHLIGHT");
                receiver.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
                PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, receiver, 0);

                RemoteViews views = new RemoteViews(context.getPackageName(),
                                R.layout.widget_layout);
                views.setOnClickPendingIntent(R.id.button, pendingIntent);

                appWidgetManager.updateAppWidget(appWidgetIds, views);

        }
}

FlashlightWidgetReceiver 的广播接收器:

public class FlashlightWidgetReceiver extends BroadcastReceiver {
            private static boolean isLightOn = false;
            private static Camera camera;

            @Override
            public void onReceive(Context context, Intent intent) {
                    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);

                    if(isLightOn) {
                            views.setImageViewResource(R.id.button, R.drawable.off);
                    } else {
                            views.setImageViewResource(R.id.button, R.drawable.on);
                    }

                    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
                    appWidgetManager.updateAppWidget(new ComponentName(context,     FlashlightWidgetProvider.class),
                                                                                     views);

                    if (isLightOn) {
                            if (camera != null) {
                                    camera.stopPreview();
                                    camera.release();
                                    camera = null;
                                    isLightOn = false;
                            }

                    } else {
                            // Open the default i.e. the first rear facing camera.
                            camera = Camera.open();

                            if(camera == null) {
                                    Toast.makeText(context, R.string.no_camera, Toast.LENGTH_SHORT).show();
                            } else {
                                    // Set the torch flash mode
                                    Parameters param = camera.getParameters();
                                    param.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                                    try {
                                            camera.setParameters(param);
                                            camera.startPreview();
                                            isLightOn = true;
                                    } catch (Exception e) {
                                            Toast.makeText(context, R.string.no_flash, Toast.LENGTH_SHORT).show();
                                    }
                            }
                    }
            }
    }

Manifest.xml 文件中所需的权限:

<uses-permission android:name="android.permission.CAMERA"></uses-permission>

同时在 Manifest.xml 文件中注册接收器:

<receiver android:name=".FlashlightWidgetProvider" android:icon="@drawable/on" android:label="@string/app_name">
         <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
         </intent-filter>

         <meta-data android:name="android.appwidget.provider"
                        android:resource="@xml/flashlight_appwidget_info" />
</receiver>

<receiver android:name="FlashlightWidgetReceiver">
        <intent-filter>
               <action android:name="COM_FLASHLIGHT"></action>
        </intent-filter>
 </receiver>

重要注意:如果您的手机支持 FLASH_MODE_TORCH,则此代码非常有效。

我已经在 Samsung Galaxy Ace 2.2.1 & 中进行了测试。 2.3.3.该代码不起作用,因为该设备没有 FLASH_MODE_TORCH。

在 HTC Salsa、Wildfire 中工作正常。

如果有人可以在这里测试并发布结果,那就最好了。

After a long time, I got free to solve this problem.

Here is what I did.

FlashlightWidgetProvider class :

public class FlashlightWidgetProvider extends AppWidgetProvider {

        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                        int[] appWidgetIds) {

                Intent receiver = new Intent(context, FlashlightWidgetReceiver.class);
                receiver.setAction("COM_FLASHLIGHT");
                receiver.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
                PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, receiver, 0);

                RemoteViews views = new RemoteViews(context.getPackageName(),
                                R.layout.widget_layout);
                views.setOnClickPendingIntent(R.id.button, pendingIntent);

                appWidgetManager.updateAppWidget(appWidgetIds, views);

        }
}

and BroadcastReceiver for FlashlightWidgetReceiver :

public class FlashlightWidgetReceiver extends BroadcastReceiver {
            private static boolean isLightOn = false;
            private static Camera camera;

            @Override
            public void onReceive(Context context, Intent intent) {
                    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);

                    if(isLightOn) {
                            views.setImageViewResource(R.id.button, R.drawable.off);
                    } else {
                            views.setImageViewResource(R.id.button, R.drawable.on);
                    }

                    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
                    appWidgetManager.updateAppWidget(new ComponentName(context,     FlashlightWidgetProvider.class),
                                                                                     views);

                    if (isLightOn) {
                            if (camera != null) {
                                    camera.stopPreview();
                                    camera.release();
                                    camera = null;
                                    isLightOn = false;
                            }

                    } else {
                            // Open the default i.e. the first rear facing camera.
                            camera = Camera.open();

                            if(camera == null) {
                                    Toast.makeText(context, R.string.no_camera, Toast.LENGTH_SHORT).show();
                            } else {
                                    // Set the torch flash mode
                                    Parameters param = camera.getParameters();
                                    param.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                                    try {
                                            camera.setParameters(param);
                                            camera.startPreview();
                                            isLightOn = true;
                                    } catch (Exception e) {
                                            Toast.makeText(context, R.string.no_flash, Toast.LENGTH_SHORT).show();
                                    }
                            }
                    }
            }
    }

Permission required in Manifest.xml file :

<uses-permission android:name="android.permission.CAMERA"></uses-permission>

Also register receivers in Manifest.xml file :

<receiver android:name=".FlashlightWidgetProvider" android:icon="@drawable/on" android:label="@string/app_name">
         <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
         </intent-filter>

         <meta-data android:name="android.appwidget.provider"
                        android:resource="@xml/flashlight_appwidget_info" />
</receiver>

<receiver android:name="FlashlightWidgetReceiver">
        <intent-filter>
               <action android:name="COM_FLASHLIGHT"></action>
        </intent-filter>
 </receiver>

Important Note : This code works perfect if your phone has FLASH_MODE_TORCH supported.

I have tested in Samsung Galaxy Ace 2.2.1 & 2.3.3. The code is not working because that device has no FLASH_MODE_TORCH.

Works fine in HTC Salsa, Wildfire..

If anyone can test and post results here, it would be best.

平安喜乐 2024-12-12 16:49:58

处理来自 RemoteViews 的点击的最佳技术是创建一个调用服务的 PendingIntent ,并在该服务中执行您想要的“操作”服务,包括您的小部件的任何其他 RemoteViews 更新。您可以在意图附加中发送相关数据。该服务在最后调用 stopSelf(),因此它会关闭。

您无法维护 BroadcastReceiver 中的任何状态;系统在任何可用线程上运行这些,并且在调用 onReceive() 后不会维护对您的实例的任何引用。不保证在调用 BroadcastReceiver 之间维护您的 mCamera 变量。

如果您确实需要维护状态,则必须在服务中执行此操作,并且不要使用 stopSelf() (直到适当的时间)。

您不需要 UI 线程来使用 Camera 类,除非您正在执行图像预览,这需要 SurfaceHolder (并且意味着 UI)。但是,您必须激活事件循环,否则 Camera 不会向您发送回调,这是一个问题,因为 Camera 主要是异步的。您可以在服务中执行此操作(请参阅HandlerThread)并保持服务运行,直到release()所有内容。无论哪个线程调用 Camera.open() 都会收到回调。

每个人都真正阅读过 App Widgets 部分吗?
http://developer.android.com/guide/topics/appwidgets/index.html

< strong>使用 AppWidgetProvider 类部分几乎说明了我在这里所说的内容。

The best technique for handling clicks from a RemoteViews is to create a PendingIntent that calls a service, and perform the "stuff" you want in the service, including any additional RemoteViews updates for your widget. You can send along the relevant data in the intent extras. The service calls stopSelf() at the end, so it shuts off.

You cannot maintain any state in an BroadcastReceiver; the system runs those on any available thread, and doesn't maintain any reference to your instance after calling onReceive(). Your mCamera variable is not guaranteed to be maintained between invocations of your BroadcastReceiver.

If you really need to maintain state, you must do it in the service, and don't use stopSelf() (until an appropriate time).

You do not need a UI thread to use the Camera class, unless you are doing image preview, which requires a SurfaceHolder (and implies a UI). You must, however, have an event loop active, or Camera will not post callbacks to you, which is a problem since Camera is primarily asynchronous. You can do this within a service (see HandlerThread) and keep your service running until it's time to release() everything. Whichever thread calls Camera.open() will receive callbacks.

Did everyone actually read the section on App Widgets?
http://developer.android.com/guide/topics/appwidgets/index.html

Using the AppWidgetProvider Class section says pretty much what I am saying here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文