Abhishek V
Abhishek V

Reputation: 12526

Android Wear : launching an activty in the handheld on clicking notification action button in wear

I want to start an activity in the handheld app and send some data when the user clicks on notification action button in the wear. I am using below code to build the notification in the wear.

public Notification buildNotification(Context context) {
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
                new Intent(context, MainActivity.class), 0);

        return buildBasicNotification(context).extend(new Notification.WearableExtender()
                .setContentIcon(R.drawable.content_icon_small)
                .setContentIconGravity(Gravity.START))
                .addAction(new Notification.Action(R.drawable.ic_launcher,
                        "Action A", pendingIntent))


                .build();
    }

Is it possible to start the activity in handheld through pending intent only or should we start an service/activity in the wear on clicking action button and from that activity/service send message to the device through message api. Any help would be appreciated!

Upvotes: 2

Views: 3260

Answers (1)

ianhanniballake
ianhanniballake

Reputation: 199805

Your Wearable app is completely separate from the handheld app, with the only communication path being using the message/data APIs so unfortunately there is no way to directly trigger an action on the handheld from a notification generated on the Wearable.

You are correct in the approach that needs to be taken, however:

  1. Create a PendingIntent for your action that starts a service (an IntentService works perfectly)
  2. In that service:
    1. Connect to a GoogleApiClient
    2. If a connected device is found, start a ConfirmationActivity using an OPEN_ON_PHONE_ANIMATION (this displays a visible sign to your user that your app is opening something on their handheld)
    3. Send a message to the connected device using a set path (say, notification/open)
  3. In your handheld app, implement a WearableListenerService which will receive your message in the background:
    1. In the onMessageReceived() call, check the received message's path for the path you set (i.e., messageEvent.getPath().equals("notification/open"))
    2. If it matches, then start the appropriate activity on your handheld.

This approach is used in Muzei when starting the watch face having never activated the live wallpaper in the handheld app. Code covering each of these sections can be found on the Github repository.

Specifically, steps 1 and 2 can be found in ActivateMuzeiIntentService:

public static void showNotification(Context context) {
    Notification.Builder builder = new Notification.Builder(context);
    // Set up your notification as normal

    // Create the launch intent, in this case setting it as the content action
    Intent launchMuzeiIntent = new Intent(context, 
        ActivateMuzeiIntentService.class);
    PendingIntent pendingIntent = PendingIntent.getService(context, 0, 
        launchMuzeiIntent, 0);
    builder.addAction(new Notification.Action.Builder(R.drawable.ic_open_on_phone,
            context.getString(R.string.common_open_on_phone), pendingIntent)
            .extend(new Notification.Action.WearableExtender()
                    .setAvailableOffline(false))
            .build());
    builder.extend(new Notification.WearableExtender()
            .setContentAction(0));

    // Send the notification with notificationManager.notify as usual
}

protected void onHandleIntent(Intent intent) {
    // Open on Phone action
    GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Wearable.API)
            .build();
    ConnectionResult connectionResult =
            googleApiClient.blockingConnect(30, TimeUnit.SECONDS);
    if (!connectionResult.isSuccess()) {
        Log.e(TAG, "Failed to connect to GoogleApiClient.");
        return;
    }
    List<Node> nodes =  Wearable.NodeApi.getConnectedNodes(googleApiClient)
        .await().getNodes();
    // Ensure there is a connected device
    if (!nodes.isEmpty()) {
        // Show the open on phone animation
        Intent openOnPhoneIntent = new Intent(this, ConfirmationActivity.class);
        openOnPhoneIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        openOnPhoneIntent.putExtra(ConfirmationActivity.EXTRA_ANIMATION_TYPE,
                ConfirmationActivity.OPEN_ON_PHONE_ANIMATION);
        startActivity(openOnPhoneIntent);
        // Clear the notification
        NotificationManager notificationManager = (NotificationManager)
                getSystemService(NOTIFICATION_SERVICE);
        notificationManager.cancel(NOTIFICATION_ID);
        // Send the message to the phone to open Muzei
        for (Node node : nodes) {
            Wearable.MessageApi.sendMessage(googleApiClient, node.getId(),
                    "notification/open", null).await();
        }
    }
    googleApiClient.disconnect();
}

And then the step 3 on the handheld side are handled by MuzeiWearableListenerService:

public void onMessageReceived(MessageEvent messageEvent) {
    String path = messageEvent.getPath();
    if (path.equals("notification/open")) {

        // In this case, we launch the launch intent for the application
        // but it could be anything
        PackageManager packageManager = getPackageManager();
        Intent mainIntent = packageManager.getLaunchIntentForPackage(
            getPackageName());
        startActivity(mainIntent);
    }
}

Upvotes: 11

Related Questions