// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.chrome.browser.printing; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import org.chromium.base.ActivityState; import org.chromium.base.ApplicationStatus; import org.chromium.base.ApplicationStatus.ActivityStateListener; import org.chromium.base.ThreadUtils; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.share.ShareHelper; import org.chromium.chrome.browser.util.IntentUtils; import java.lang.ref.WeakReference; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * A simple activity that allows Chrome to expose print as an option in the share menu. */ public class PrintShareActivity extends AppCompatActivity { private static Set<Activity> sPendingShareActivities = Collections.synchronizedSet(new HashSet<Activity>()); private static ActivityStateListener sStateListener; /** * Enable the print sharing option. * * @param activity The activity that will be triggering the share action. The activitiy's * state will be tracked to disable the print option when the share operation * has been completed. * @param callback The callback to be triggered after the print option has been enabled. This * may or may not be synchronous depending on whether this will require * interacting with the Android framework. */ public static void enablePrintShareOption(final Activity activity, final Runnable callback) { ThreadUtils.assertOnUiThread(); if (sStateListener == null) { sStateListener = new ActivityStateListener() { @Override public void onActivityStateChange(Activity activity, int newState) { if (newState == ActivityState.PAUSED) return; unregisterActivity(activity); } }; } ApplicationStatus.registerStateListenerForAllActivities(sStateListener); boolean wasEmpty = sPendingShareActivities.isEmpty(); sPendingShareActivities.add(activity); if (wasEmpty) { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { if (sPendingShareActivities.isEmpty()) return null; activity.getPackageManager().setComponentEnabledSetting( new ComponentName(activity, PrintShareActivity.class), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); return null; } @Override protected void onPostExecute(Void result) { callback.run(); } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { callback.run(); } } private static void unregisterActivity(final Activity activity) { sPendingShareActivities.remove(activity); if (!sPendingShareActivities.isEmpty()) return; ApplicationStatus.unregisterActivityStateListener(sStateListener); new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { if (!sPendingShareActivities.isEmpty()) return null; activity.getPackageManager().setComponentEnabledSetting( new ComponentName(activity, PrintShareActivity.class), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); try { Intent intent = getIntent(); if (intent == null) return; if (!Intent.ACTION_SEND.equals(intent.getAction())) return; if (!IntentUtils.safeHasExtra(getIntent(), ShareHelper.EXTRA_TASK_ID)) return; handlePrintAction(); } finally { finish(); } } private void handlePrintAction() { int triggeringTaskId = IntentUtils.safeGetIntExtra(getIntent(), ShareHelper.EXTRA_TASK_ID, 0); List<WeakReference<Activity>> activities = ApplicationStatus.getRunningActivities(); ChromeActivity triggeringActivity = null; for (int i = 0; i < activities.size(); i++) { Activity activity = activities.get(i).get(); if (activity == null) continue; // Since the share intent is triggered without NEW_TASK or NEW_DOCUMENT, the task ID // of this activity will match that of the triggering activity. if (activity.getTaskId() == triggeringTaskId && activity instanceof ChromeActivity) { triggeringActivity = (ChromeActivity) activity; break; } } if (triggeringActivity == null) return; unregisterActivity(triggeringActivity); triggeringActivity.onMenuOrKeyboardAction(R.id.print_id, true); } }