package jp.co.cyberagent.stf.monitor; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.util.Log; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import jp.co.cyberagent.stf.proto.Wire; import jp.co.cyberagent.stf.io.MessageWritable; import jp.co.cyberagent.stf.util.BrowserUtil; public class BrowserPackageMonitor extends AbstractMonitor { private static final String TAG = "STFBrowserPackageMonitor"; private Set<Browser> browsers = new HashSet<Browser>(); public BrowserPackageMonitor(Context context, MessageWritable writer) { super(context, writer); } @Override public void run() { BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); String pkg = intent.getData().getEncodedSchemeSpecificPart(); if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { Log.i(TAG, String.format("Package %s was added", pkg)); } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { Log.i(TAG, String.format("Package %s changed", pkg)); } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { Log.i(TAG, String.format("Package %s was removed", pkg)); } report(writer, false); } }; IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); context.registerReceiver(receiver, filter); try { synchronized (this) { while (!isInterrupted()) { wait(); } } } catch (InterruptedException e) { // Okay } finally { context.unregisterReceiver(receiver); } } @Override public void peek(MessageWritable writer) { report(writer, true); } synchronized private void report(MessageWritable writer, boolean force) { PackageManager pm = context.getPackageManager(); Set<Browser> removeBrowsers = new HashSet<Browser>(browsers); Set<Browser> newBrowsers = new HashSet<Browser>(); List<ResolveInfo> browserInfoList = BrowserUtil.getBrowsers(context); ResolveInfo defaultBrowser = BrowserUtil.getDefaultBrowser(context); ArrayList<Wire.BrowserApp> apps = new ArrayList<Wire.BrowserApp>(); for (ResolveInfo info : browserInfoList) { ApplicationInfo appInfo = info.activityInfo.applicationInfo; Browser browser = new Browser( pm.getApplicationLabel(appInfo).toString(), BrowserUtil.getComponent(info), BrowserUtil.isSameBrowser(info, defaultBrowser), (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 || (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 ); if (browsers.contains(browser)) { removeBrowsers.remove(browser); } else { newBrowsers.add(browser); } apps.add(Wire.BrowserApp.newBuilder() .setName(browser.name) .setComponent(browser.component) .setSelected(browser.selected) .setSystem(browser.system) .build()); } if (!force && removeBrowsers.isEmpty() && newBrowsers.isEmpty()) { return; } Log.i(TAG, "Browser list changed"); browsers.removeAll(removeBrowsers); browsers.addAll(newBrowsers); writer.write(Wire.Envelope.newBuilder() .setType(Wire.MessageType.EVENT_BROWSER_PACKAGE) .setMessage(Wire.BrowserPackageEvent.newBuilder() .setSelected(defaultBrowser != null) .addAllApps(apps) .build() .toByteString()) .build()); } private static class Browser { private String name; private String component; private boolean selected; private boolean system; public Browser(String name, String component, boolean selected, boolean system) { this.name = name; this.component = component; this.selected = selected; this.system = system; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Browser browser = (Browser) o; if (selected != browser.selected) return false; if (!component.equals(browser.component)) return false; if (!name.equals(browser.name)) return false; return true; } @Override public int hashCode() { int result = name.hashCode(); result = 31 * result + component.hashCode(); result = 31 * result + (selected ? 1 : 0); return result; } } }