Using Android Flashlight With A Widget

Using Android flashlight with a widget,

Introduction and Background

 
Here it goes, I got a new cell phone this month. I like it very much, but one thing that it doesn't come with is the toolkit for basic utilities. One of them is the flashlight application that triggers the device to activate or deactivate the flashlight as required. Android does support you to have Camera API consumed in your application (after all, the flashlight is provided to for photos or videos and not as a floodlight). So, I was thinking that I should get an application from the Play Store, right? No! Although it would provide me with an "elegant" solution to my flashlight problem, what about the army of advertisement I will have to go through, or the unclear UI of the application. So I thought I should build an application for myself to be able to trigger the flashlight on or off.
 
Since I made it for myself, why not teach you guys too, so that you can use the same application, or build on top of it and share it with me so that I can also use your skills. The source code will be available and the application is being published to Google's Play Store.
 
In this article, I will discuss Android programming for Camera API and a small overview of Widget programming in Android applications. Although this type of application is very basic and straight-forward, at least it will provide you with a very basic idea of using Camera API in devices and to manage those background services using widgets on your home screen.
 
It is not that hard to create a similar application, but still, in many ways, it may be a tough job to be able to create a widget that responds to user interaction for triggering the service that we are going to use to activate or deactivate the flashlight. In the coming sections, you will learn how to create a similar application keeping the "simple UI" in mind and how you can program a widget to keep the application concept even simpler.
 
Pre-requisites
 
You are not required to have an advanced understanding of Android APIs or how Linux works, later permissions and rest of the stuff will be talked about in the article. But I will try to make sure that I am as clearer as a beginner in this concept would want me to be.
 

Writing the Android application

 
In this section, I will talk about building the application. I will slice it in two different sections, one for building the service for flashlight application and the next section comes for building the Widget for our application to allow users to be able to trigger the service from any screen.
 
During both two sections, I will keep the "level of my English" pretty much simple for everyone to be able to understand what I mean to say in every paragraph.
 
At this stage, I will recommend creating a new Android application. There have been many great tutorials on "How to create an Android project" and you may consider reading one of them to learn how to create a new project because I won't be covering the "basic" topic in this article.
 

Building the back-end service

 
First of all, we need to define the service that needs to be executed each time. Android APIs allow us to use the hardware components to an extent. The extent is over as soon as we try to use a component to its sub-components. The flashlight comes with a Camera in an Android device, which means that you cannot use the flashlight separately, you have to be using the Camera. That is when hacking begins, and you start using the Camera but only to use the flashlight and not the image or video capture.
 
The object that takes our interest is Camera object from android. hardware package. The object allows us to create connections to the provided cameras on the device, check if there are any cameras, and also allows us to create our own special applications that make use of cameras, such as the ones being used while creating Instagram-inspired applications. So we will also use the same object to trigger the request to Android OS to let our application use the camera for a while.
 

Setting the permissions for our application

 
Like all other processes in a Linux environment, we first need to set up the permissions for our application to be able to use. Without permissions, our application is going to end up having RuntimeExceptions. Thus, before going any further, open your application's manifest and write the following permissions to it.
  1. <uses-permission android:name="android.permission.FLASHLIGHT" android:permissionGroup="android.permission-group.HARDWARE_CONTROLS" android:protectionLevel="normal" />    
  2. <uses-permission android:name="android.permission.CAMERA" />    
  3. <uses-permission android:name="android.hardware.camera.flash" />    
  4. <uses-feature android:name="android.hardware.camera" android:required="false" />    
  5. <uses-feature android:name="android.hardware.camera.flash" android:required="false" />   
The above code is just the set of permissions needed. We also need to able to use the flash, thus we set them up separately. One thing to note is that although everything that comes with a camera is controlled by the camera, however, our application needs to have permission to use each and every component including a flashlight. Camera won't allow your application to natively communicate with the components if your manifest does not share the permissions details; thus a RuntimeException.
 
The <uses-feature> element allows us to indicate that our application requires these features and is of no use without them. Of course, our application would be of no use, if there is no flashlight found in the device. The attribute android: required allows us to set a condition for our application to be installed, or ignore depending on the existence of that hardware feature. You can set it to either true or false, denoting that the feature is required.
 
That is it for permissions, we just need to use the Camera object and then ask it to turn on the flashlight for us, as long as we want. 
 
Creating the MainActivity
 
In Android programming, MainActivity is a conventional name to be used for the first activity, Android Studio enforces (or well, simply, uses) this name for the very first activity. So, in our MainActivity, we are going to create a button that enables us to trigger the Camera object. The actual code that does that would be shown later, in this section only the activity will be discussed.
 
First of all, create a button that can be clicked to trigger the service.
 
Android Studio
Figure 1- Android Studio displaying the rendering of MainActivity, with a Button object and some text.
 
Pay attention to the button itself, the Button would trigger the service, here is the XML code (if it is of any interest)
 
Hide Copy Code
  1. <Button    
  2. style="?android:attr/buttonStyleSmall"    
  3. android:layout_width="wrap_content"    
  4. android:layout_height="wrap_content"    
  5. android:text="@string/turn_on_string"    
  6. android:id="@+id/turn_on_button"    
  7. android:layout_alignParentBottom="true"    
  8. android:layout_centerHorizontal="true"/>   
    Handling user interaction in the Activity
     
    You must have noticed that I have not yet attached any "onClick" attribute to the Button object. That is not "by design", I forgot to add that event there and it struck my mind when I was pasting the code here.
     
    Anyways, I did that in the code-behind and attached the click listeners to the button. The button listener, in turn, triggers the back-end service of our application to activate (or deactivate) the flashlight in our device. The following code does the trick for that,
    1. // Find the button from the view.    
    2. final Button button = (Button) findViewById(R.id.turn_on_button);    
    3. // Attach the event handler    
    4. button.setOnClickListener(new View.OnClickListener()    
    5. {    
    6.     @Override    
    7.     public void onClick(View v)    
    8.     {    
    9.         // Create an intent (Empty at the point)    
    10.         Intent serviceIntent = new Intent(getApplicationContext(), FlashlightIntentService.class);    
    11.         if (button.getText().toString().equals(getString(R.string.turn_on_string)))    
    12.         {    
    13.             // Turn on the flashlight    
    14.             serviceIntent.setAction(FlashlightIntentService.ACTION_TURN_ON);    
    15.             startService(serviceIntent);    
    16.             button.setText(R.string.turn_off_string);    
    17.         }    
    18.         else    
    19.         {    
    20.             // Turn off the flashlight    
    21.             serviceIntent.setAction(FlashlightIntentService.ACTION_TURN_OFF);    
    22.             startService(serviceIntent);    
    23.             button.setText(R.string.turn_on_string);    
    24.         }    
    25.     }    
    26. });   
    One thing I may have missed is the background service, I want to talk about it later. But, if you want to know where FlashlightIntentService. ACTION_TURN_ON does comes from, please look at the actions of the service. The above program simply attaches an event handler to the button, the button can then be used by the user to trigger this service. You may also see that we are using a service, by the function, startService(serviceIntent).
     
    I tried to keep the application as concise and compact as I could, that is why I created a separate service to handle the requests instead of hardcoding every command in the MainActivity. It will also let me update the service to add any further features to the service. This lets me manage the UI interaction in the UI thread, and to perform the background actions in a background thread.
     
    Building the background service — FlashlightIntentService
     
    All of our logic relies on this back-end service of our application. I have implemented all of the "if-then-else" concepts in this one service and provided two actions, one for each, on or off. The backend service needs to be executed on a separate thread, because we want to use it in our widget also. So even if there is no instance of MainActivity we still need our users to be able to use the service. At this moment, create a new IntentService in your application, name it what you want. I named the IntentService as FlashlightIntentService. You should consider using the same name to avoid any conflict.
     

    What actions will the application or service perform?

     
     
    Our service just performs the following two actions in our application.
    1. Turns the flashlight on.
    2. Turns the flashlight off.
    Simple, so we need two actions in our service to denote the command that needs to be executed. In Android, we define these actions as static constant (final) strings. These strings can then be used by different activities to create Intent, and our service can check what the current action is, for the intent that triggered our service. Have a look at how the actions are defined,
    1. // ACTIONS    
    2. public static final String ACTION_TURN_ON = "com.wordpress.afzaalahmadzeeshan.flashlight_app.TURN_ON";    
    3. public static final String ACTION_TURN_OFF = "com.wordpress.afzaalahmadzeeshan.flashlight_app.TURN_OFF";  
    These two can now be accessed by any activity since they are public. We can create our intents and then usesetAction(String) to set an action for that intent. In Android programming, actions define what the activity (or user) actually wants to do. In the topic above, these actions are being used to define the behavior of that button above.
     
    Tip- For more on IntentService vs Service, please read this Stack Overflow thread.
     
    Establishing the "secure" connection to the camera.
     
    When the service starts, we also want to establish a connection to our camera device. In Android, there may be many factors that we may need to take care of while working with devices provided by the Android device itself. Such as Camera, the camera may be in use by another application, it may also be not available or permission may not be available to the application and so on.
     
    In these cases, we use a try...catch block to establish the connection and also to process if there are some troubles while establishing the connection. Most common problem is, "Failed to connect to camera service". The problem means that some other application is currently using the camera and you cannot use it right now. This also is a result of "memory leak", as an application may have ended but forgot to release the camera resource, which is why, always clean up resources before you end your application's activity.
     
    However, the following function does it, it tries to connect to the service and in case of any error, it notifies the user.
     
    Hide Shrink Copy Code
    1. private void fillFields()    
    2. {    
    3.     // Initialize the fields    
    4.     canWork = this.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);    
    5.    
    6.     // Get the IDs if any.    
    7.     ids = AppWidgetManager.getInstance(this).getAppWidgetIds(new ComponentName(this, FlashLightWidget.class));    
    8.     // If flash feature is available    
    9.     if (canWork)    
    10.     {    
    11.         // Get the camera instance    
    12.         if (camera == null)    
    13.         {    
    14.             // Only if the camera object is null. Otherwise,    
    15.             // we may have captured the camera instance in last visit.    
    16.             try    
    17.             {    
    18.                 camera = Camera.open(); // Try to open the camera    
    19.                 // Set the properties.    
    20.                 Camera.Parameters p = camera.getParameters();    
    21.                 // Set it to flash mode    
    22.                 p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);    
    23.                 camera.setParameters(p);    
    24.             }    
    25.             catch (Exception ignored)    
    26.             {    
    27.                 notifyUser();    
    28.             }    
    29.         }    
    30.     }    
    31.     else    
    32.     {    
    33.         // If flash is not available, notify the user    
    34.         notifyUser();    
    35.     }    
    36. }   
      There is one function that may interest you, notifyUser. This function is more like "in case of emergency" function. It displays a notification to the user, if the flashlight is not available, or if a camera cannot be connected to the application. In these situations, our application simply notifies the users about the problem.
      1. private void notifyUser()    
      2. {    
      3.     NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_flash_on_white_24dp).setContentTitle("Cannot access flashlight").setContentText("Camera application may be running in a background application.");    
      4.     int mId = 1234;    
      5.     NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);    
      6.     // mId allows you to update the notification later on.    
      7.     mNotificationManager.notify(mId, mBuilder.build());    
      8. }   
        I don't want to talk about this notification builder thing, it is pretty much easy and can easily be understood from Android documentations. Now that we have defined the function that we need to be executed that fills our variables and objects, we have also looked in the "methods" to avoid any unwanted exceptions to be raised as we are using the application in a real device. We may want to continue to the next step to actually handle the requests coming from users. In the next section, you will see how to actually perform actions.
         

        Handling the Intents and Actions

         
        Every IntentService object has a function onHandleIntent(Intent) which triggers a background worker thread that is responsible for performing the actions on a background thread. It saves your UI thread and doesn't freeze it.
         
        I have already managed everything to be in their own spots (functions!) and now in this function, I can only call them to do the work for me. I can then manage what to do when and when to do what! Pretty much simple, right? Have a look below.
        1. @Override    
        2. protected void onHandleIntent(Intent intent)    
        3. {    
        4.     // Fill the fields    
        5.     fillFields();    
        6.     // Handle the intent    
        7.     if (intent.getAction().equals(ACTION_TURN_OFF))    
        8.     {    
        9.         alter(false);    
        10.     }    
        11.     else if (intent.getAction().equals(ACTION_TURN_ON))    
        12.     {    
        13.         alter(true);    
        14.     }    
        15. }   
        So now you see, how I actually handled the intent. The intent is actually being passed to a worker thread which will now be handling how to process the request based on the connections established to the camera and all other similar stuff. Otherwise, it will just display an error message.
         
        In the intent handler, you can see there is only one function that accepts a boolean value. Then our thread will work on it. The function is declared and defined as follows,
        1. private void alter(boolean on)    
        2. {    
        3.     if (canWork)    
        4.     {    
        5.         if (on)    
        6.         {    
        7.             try    
        8.             {    
        9.                 // Start the "flashlight"    
        10.                 camera.startPreview();    
        11.                 FlashLightWidget.lightOn = true;    
        12.                 notifyWidgets();    
        13.             }    
        14.             catch (Exception e)    
        15.             {    
        16.                 Toast.makeText(FlashlightIntentService.this, e.getMessage(), Toast.LENGTH_SHORT).show();    
        17.             }    
        18.         }    
        19.         else    
        20.         {    
        21.             try    
        22.             {    
        23.                 // Stop everything and just release the resource    
        24.                 camera.stopPreview();    
        25.                 camera.release();    
        26.                 camera = null;    
        27.                 FlashLightWidget.lightOn = false;    
        28.                 notifyWidgets();    
        29.             }    
        30.             catch (Exception e)    
        31.             {    
        32.                 Toast.makeText(FlashlightIntentService.this, e.getMessage(), Toast.LENGTH_SHORT).show();    
        33.             }    
        34.         }    
        35.     }    
        36.     else    
        37.     {    
        38.         notifyUser();    
        39.     }    
        40. }   
        In the above function, I am either triggering the camera to be active, or I am closing it. That depends on the value of "on", a parameter which is passed to the function.
         
        Well, at this stage, the application just works. If you click on the button it does turn the flashlight on and so on. But, I wanted to have something "even better". I wanted to use a Widget in my device to be able to use it, I mean I don't want to start the activity to get the flashlight on. I wanted to use a widget, that I can press on and the light be started. So, the next section is dedicated to that.
         
        flashlight
        Figure 2: Using the application through activity.
         
        flashlight
        Figure 3: The button says, "TURN OFF" because the flashlight is currently active.
         
        This is it for the section of Activity. The activity also relies on the service. This is why, when we will build the widget we won't be calling the activity to start, instead we will make a direct call to the background service and trigger it to activate the flashlight for us. Pretty much simple it is.
         

        Developing the Android Widget for our application

         
        In this section, you will learn how to create an Android Widget. Of course, the title was just a cover-up for teaching you Android basics, but let's just stick to the "Android Flashlight Widget" for now.
         
        Android Widgets are small screens, or apps, on the home screen of your device. You can use them to trigger any service, intent, activity or what-ever Android is capable of. Widgets are a shortcut to your application. We will use the same good concept of using the shortcut and will use it to trigger the service.
         

        Building the UI for Widget

         
        Like all other Android applications or activities, Android widget also has a UI for our users that they can use to interact with your application. In many ways, the widgets are not necessarily required to start your application, that is where you use a service, in our case, it is an IntentService.
         
        Layouts for widgets are also XML files, with a layout, some Android controls that are rendered over the screen for users. If you have created a new widget, Android Studio may have created a default layout for you, if you haven't, then create one and edit the layout file by the following XML markup.
        1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    
        2. android:layout_width="match_parent"    
        3. android:layout_height="match_parent"    
        4. android:padding="@dimen/widget_margin">    
        5.     
        6. <ImageView    
        7.    android:layout_width="wrap_content"    
        8.    android:layout_height="wrap_content"    
        9.    android:id="@+id/button_switch_widget"    
        10.    android:layout_alignParentTop="true"    
        11.    android:layout_alignParentLeft="true"    
        12.    android:layout_alignParentStart="true"    
        13.    android:layout_margin="15dp"/>      
        14. </RelativeLayout>   
          The above layout is very simple. It just contains a single ImageView control that is used to preview the image that we are going to use to allow the user to interact. I also made sure that the widget is not "resizable" so that it spans over one single screen block grid only. If you are going to show extra details, you can consider adding your widget to be re-sizable to extra grids too. But I don't want to do that, so I just left it.
           

          Managing the back-end code

           
          The class that works on the back of our widget extends, AppWidgetProvider. This class provides us with basic functions that we may use to perform actions, like to manage what happens if a new widget is created, or what happens if a widget is removed and so on.
           
          I have just tried to override and provide the logic for one function, the one that updates the application. I have not bothered to maintain or proceed with other functions, like, onEnabled(Context) or onDisabled(Context), etc. I have also provided a custom function, which can be triggered by an external object, like from our service. This is only possible if we have a static function in our object which can be called without having to have an instance of the object in our scope.
           
          The following function is what handles our application's widget's state through code-behind.
          1. static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId)    
          2. {    
          3.     // Construct the RemoteViews object    
          4.     RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.flash_light_widget);    
          5.     if (lightOn)    
          6.     {    
          7.         // Flash light active    
          8.         Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.light_active_45);    
          9.         views.setImageViewBitmap(R.id.button_switch_widget, bitmap);    
          10.         // Create the intent, set the action    
          11.         Intent underlyingIntent = new Intent(context, FlashlightIntentService.class);    
          12.         underlyingIntent.setAction(FlashlightIntentService.ACTION_TURN_OFF);    
          13.         // Create the pending intent    
          14.         PendingIntent turnOffIntent = PendingIntent.getService(context, 1, underlyingIntent, PendingIntent.FLAG_UPDATE_CURRENT);    
          15.         views.setOnClickPendingIntent(R.id.button_switch_widget, turnOffIntent);    
          16.     }    
          17.     else    
          18.     {    
          19.         // Flash light off    
          20.         Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.light_deactive_45);    
          21.         views.setImageViewBitmap(R.id.button_switch_widget, bitmap);    
          22.         // Create the intent, set the action    
          23.         Intent underlyingIntent = new Intent(context, FlashlightIntentService.class);    
          24.         underlyingIntent.setAction(FlashlightIntentService.ACTION_TURN_ON);    
          25.         // Create the pending intent    
          26.         PendingIntent turnOnIntent = PendingIntent.getService(context, 1, underlyingIntent, PendingIntent.FLAG_UPDATE_CURRENT);    
          27.         views.setOnClickPendingIntent(R.id.button_switch_widget, turnOnIntent);    
          28.     }    
          29.     // Instruct the widget manager to update the widget    
          30.     appWidgetManager.updateAppWidget(appWidgetId, views);    
          31. }   
            The code does everything in our widget side. Widget depends on this code, it updates the widget and also allows user to communicate with the service to trigger the flashlight. I also used a few icons from Google's Material icon set and created one myself, all of them are available to be downloaded from GitHub's repository. What this code does, is simple. It just enables the user to use the widget and trigger intents based on current state.
             
            If the light is currently on, it will enable the user to turn it off, otherwise, it would turn it on. That is all that this code does.
             
            I have used the widget in, like 4 Android devices that I have at home and it works on them. There is a preview of this widget on my device.
             
            Application Widget
            Figure 4: Application Widget being viewed on my own device. Flashlight currently off.
             
            Once you trigger the flashlight using this widget, widget changes the drawable that is being used at the moment on the screen and "it looks like" the flashlight is active. You can tell that by looking at the following screen too.
             
            Flashlight
            Figure 5: Flashlight currently active, widget depicts this by changing the drawable resource.
             
            This demonstrates how you can use the application. Of course, you cannot see the flashlight because that is not included in the screenshot, but it works. This is it for now. I hope, you would find this article useful.
             

            Point of Interest - and common tips

             
            In this article, you have learned how to actually create an application that can trigger the flashlight activity in your application. I have made sure to keep the application from terminating un-expectedly, but you also need to focus on a few things. First of all, if you are using any resource, remember to close the stream and release the resource before terminating. In the application above, I have managed to do so in the MainActivity's onPause function.
            1. @Override    
            2. public void onPause()    
            3. {    
            4.     if (FlashLightWidget.lightOn)    
            5.     {    
            6.         // Light is on, turn it off.    
            7.         Intent intent = new Intent(this, FlashlightIntentService.class);    
            8.         intent.setAction(FlashlightIntentService.ACTION_TURN_OFF);    
            9.         startService(intent);    
            10.     }    
            11.     super.onPause();    
            12. }   
              It doesn't cost much to determine wether the resource has been released or not, but it will always have a good UX if you make sure that you do clean up resources.
               

              Summary

               
              Rest is just a simple Android application based on native Android APIs. I hope you liked the article. If you find something difficult, or easy, please let me know in the comments.


              Similar Articles