Click here to Skip to main content
13,735,244 members
Click here to Skip to main content
Add your own
alternative version

Stats

6.2K views
1 bookmarked
Posted 1 Dec 2017
Licenced CPOL

How to Create an Android Application Widget using the Apache Cordova Plugin ACE

, 1 Dec 2017
Rate this:
Please Sign up or sign in to vote.
This post contains steps on how to set up an Android application widget in an hybrid mobile application using Apache Cordova and the plugin ACE from Microsoft.

Introduction

I wanted to build a mobile hybrid application with the format of an Android application widget that can provide you information at the home screen.

Since I've been using for other projects Apache cordova, I looked for a solution with it and I found a plug in called ACE. It was build by Microsoft. I had a hard time making it work, so I decided to write what needs to be done step by step.

Background

It helped me a lot to understand how an Android application widget works, to read the Android official documentation at https://developer.android.com/guide/topics/appwidgets/index.html.

Also, you should take a look to Microsoft ACE plug in official documentation for the application widget at http://microsoft.github.io/ace/docs/native-ui/#four.

Using the Code

These are the steps you should follow to create an application widget using ACE:

Step 1: Add the plug in to Your Project

Following instructions at the github ACE home page (https://github.com/Microsoft/ace), you can use:

cordova plug in add plug in

Or in Visual Studio, open config.xml at the root of your project and under plugins, custom make it point to https://github.com/microsoft/ace.git or to a local copy.

Step 2: Customize Your AndroidManifest.xml

At the project's platform/Android, you will find the AndroidManifest.xml automatically generate for your project. We need to modify it to add the widget.

Ace documentation tells you to copy this XML to the native/android/res folder of your project, but like this your changes will be replicated to the platform/android manifest during building.

The manifest must be copied at native/android (outside the res folder) and the final result should be like this:

<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="yourversion" 

 android:versionName="versionname" package="your.package.name" 

 xmlns:android="http://schemas.android.com/apk/res/android">
    <supports-screens android:anyDensity="true" android:largeScreens="true" 

     android:normalScreens="true" android:resizeable="true" android:smallScreens="true" 

     android:xlargeScreens="true" />
    <uses-permission android:name="android.permission.INTERNET" />
    <application android:hardwareAccelerated="true" android:icon="@drawable/icon" 

     android:label="@string/app_name" android:supportsRtl="true">
        <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" 

         android:label="@string/activity_name" android:launchMode="singleTop" 

         android:name="MainActivity" android:windowSoftInputMode="adjustResize">
            <intent-filter android:label="@string/launcher_name">
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name="your.package.name.ListWidgetProvider">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider" 

                               android:resource="@xml/list_widget_info" />
        </receiver>
        <service android:exported="false" android:name="run.ace.AppWidgetService" 

           android:permission="android.permission.BIND_REMOTEVIEWS" />
        <activity android:name="run.ace.AceActivity" 

             xmlns:android="http://schemas.android.com/apk/res/android" />
    </application>
    <uses-sdk android:minSdkVersion="yourminsdk" android:targetSdkVersion="yourtargetsdk" />
</manifest>

Step 3: Create the Application Widget Provider Info

It's an XML file describing the metadata of the application widget among other properties: used layout, the size (my example uses four columns and one row of the home screen), if it's resizable, etc.

This file should be at native/android/res/xml folder and should be called list_widget_info.xml (matching the android:resource attribute of the meta-data of the receiver at the manifest).

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider

  xmlns:android="http://schemas.android.com/apk/res/android"

    android:minWidth="250dp"

  android:minHeight="40dp"

      android:resizeMode="horizontal|vertical"

  android:updatePeriodMillis="86400000"

  android:previewImage="@drawable/list_widget_preview"

  android:initialLayout="@layout/list_widget_layout">
</appwidget-provider>

Step 4: Add a Preview Image for the Widget

Add the preview image as native/android/res/drawable/list_widget_preview.png. It will be the one displayed in the list of widgets.

This image may be the same used for the application, which is at res/icons/android at your project.

Step 5: Add the Widget Layout

The layout used by the widget should be added as native/android/res/layout/list_widget_layout.xml.

This widget will display a list. Here, you could change styles as background color or font color.

<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@+id/list_widget_view"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:gravity="center"

    android:loopViews="true" />

Step 6: Define the Widget Layout Item

The following should be saved as native/android/res/layout/list_widget_item.xml. ACE documentation wrongly called it list_widget_view, where list_widget_view is the id of the layout and not the item.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@+id/list_widget_item"

    android:layout_width="match_parent"

    android:layout_height="match_parent">
  <TextView

    android:id="@+id/list_widget_item_text"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:layout_margin="10dp"

    android:textColor="#ffffff"

    android:textSize="40px" />
</FrameLayout>

Step 7: Add the Widget Provider Class

This code should be added as native/android/src/your/package/name/ListWidgetProvider.java.

It should match the receiver Android name at the manifest (your.package.name.ListWidgetProvider).

package your.package.name;

public class ListWidgetProvider extends run.ace.AppWidgetProvider
{

@Override
protected int getLayoutResourceId(android.content.Context context)
{
return run.ace.NativeHost.getResourceId("list_widget_layout", "layout", context);
}

@Override
 protected int getViewResourceId(android.content.Context context)
 {
return run.ace.NativeHost.getResourceId("list_widget_view", "id", context);
}

@Override
 protected int getItemResourceId(android.content.Context context)
 {
return run.ace.NativeHost.getResourceId("list_widget_item", "id", context);
}

@Override
 protected int getItemTextResourceId(android.content.Context context)
 {
return run.ace.NativeHost.getResourceId("list_widget_item_text", "id", context);
}

@Override
protected int getItemLayoutResourceId(android.content.Context context)
 {
return run.ace.NativeHost.getResourceId("list_widget_item", "layout", context);
}
}

Step 8: Populate the Application Widget

ACE provides you with an AppWidgetData class and an AppWidgetService class.

If you run the application at this stage, the widget will display the default message the AppWidgetService assigns to the AppWidgetData at creation:

public void onCreate() {

AppWidgetData.add("Run the app to populate this widget.", _context);
// TODO: Should we refresh data on app resume in some cases?
    }

So, let's add the JavaScript code the ACE documentation suggest to the start page:

if (ace.platform == "Android") {
  setupWidget();
}

function setupWidget() {
  // Handle the app being resumed by a widget click:
  ace.addEventListener("android.intentchanged", checkForWidgetActivation);

  ace.android.appWidget.clear();  

  for (var i = 0; i < 10; i++) {
    ace.android.appWidget.add("Item with index " + i);
  }
}

function checkForWidgetActivation() {
    if (ace.platform != "Android") {
        return;
    }

    ace.android.getIntent().invoke("getIntExtra", "widgetSelectionIndex", -1, function (value) {
        // value is the index of the item clicked
        // or -1 if no item has been clicked
    });
}

You will have the following error:

ace is no defined.

For this object to be defined, code added shouldn't be called before the device is ready like this:

document.addEventListener('deviceready', onDeviceReady.bind(this), false);

function onDeviceReady() {
        if (ace.platform == "Android") {
            setupWidget();
        }
    };

Next, you should customize the content of the application widget with something different to "Item with index " + i and everything should be working fine.

Points of Interest

You could research more about the Android app widget by simply creating one in Android Studio.

History

  • 1st December, 2017: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Silvia Campo
Canada Canada
No Biography provided

You may also be interested in...

Pro
Pro

Comments and Discussions

 
Answercordova Pin
Member 1364163724-Jan-18 9:11
memberMember 1364163724-Jan-18 9:11 
QuestionSingle button widget Pin
Valery Patrizia Madiedo Gómez4-Jan-18 10:26
memberValery Patrizia Madiedo Gómez4-Jan-18 10:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01-2016 | 2.8.180920.1 | Last Updated 1 Dec 2017
Article Copyright 2017 by Silvia Campo
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid