From ff02d49e464c2fe92ba625a3046f31aa042e5d32 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Mon, 5 Aug 2013 02:12:05 -0400 Subject: [PATCH] Initial implementation: Broadcasts on app launch. Look for com.android.launcher3.action.LAUNCH to be sent when an icon is clicked in Launcher. (Restricted to com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS which is a signature permission right now. This is specifically tracking apps launched via shortcut icon; any other method of launching apps (notifications, recents, internal navigation, etc.) is outside of Launcher's purview and hence not broadcast. The broadcast currently includes, in the "intent" extra, the Uri flattening of the specific shortcut clicked. The file /data/data//files/launches.log contains a binary log of all such launches, including additional info like screen# that should probably be in the broadcast too. This info is summarized in .../stats.log, which encodes a simple histogram of app launches since basically forever. This should probably be done over a sliding window, which will require more processing on startup. Bug: 10031590 Change-Id: Ifc5921d5dc20701c67678cbfdc89b03cacd62028 --- AndroidManifest.xml | 6 + src/com/android/launcher3/Launcher.java | 9 +- src/com/android/launcher3/Stats.java | 202 ++++++++++++++++++++++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 src/com/android/launcher3/Stats.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index b9f75cf5d9..f885a6c631 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -50,6 +50,11 @@ android:label="@string/permlab_write_settings" android:description="@string/permdesc_write_settings"/> + + @@ -60,6 +65,7 @@ + mIntents; + ArrayList mHistogram; + + public Stats(Launcher launcher) { + mLauncher = launcher; + + loadStats(); + + if (LOCAL_LAUNCH_LOG) { + try { + mLog = new DataOutputStream(mLauncher.openFileOutput(LOG_FILE_NAME, Context.MODE_APPEND)); + mLog.writeInt(LOG_TAG_VERSION); + mLog.writeInt(LOG_VERSION); + } catch (FileNotFoundException e) { + Log.e(TAG, "unable to create stats log: " + e); + mLog = null; + } catch (IOException e) { + Log.e(TAG, "unable to write to stats log: " + e); + mLog = null; + } + } + + if (DEBUG_BROADCASTS) { + launcher.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + android.util.Log.v("Stats", "got broadcast: " + intent + " for launched intent: " + + intent.getStringExtra(EXTRA_INTENT)); + } + }, + new IntentFilter(ACTION_LAUNCH), + PERM_LAUNCH, + null + ); + } + } + + public void incrementLaunch(String intentStr) { + int pos = mIntents.indexOf(intentStr); + if (pos < 0) { + mIntents.add(intentStr); + mHistogram.add(1); + } else { + mHistogram.set(pos, mHistogram.get(pos) + 1); + } + } + + public void recordLaunch(Intent intent, ShortcutInfo shortcut) { + intent = new Intent(intent); + intent.setSourceBounds(null); + + final String flat = intent.toUri(0); + + mLauncher.sendBroadcast( + new Intent(ACTION_LAUNCH) + .putExtra(EXTRA_INTENT, flat) + .putExtra(EXTRA_CONTAINER, shortcut.container) + .putExtra(EXTRA_SCREEN, shortcut.screenId) + .putExtra(EXTRA_CELLX, shortcut.cellX) + .putExtra(EXTRA_CELLY, shortcut.cellY), + PERM_LAUNCH); + + incrementLaunch(flat); + + if (FLUSH_IMMEDIATELY) { + saveStats(); + } + + if (LOCAL_LAUNCH_LOG && mLog != null) { + try { + mLog.writeInt(LOG_TAG_LAUNCH); + mLog.writeLong(System.currentTimeMillis()); + mLog.writeShort((short) shortcut.container); + mLog.writeShort((short) shortcut.screenId); + mLog.writeShort((short) shortcut.cellX); + mLog.writeShort((short) shortcut.cellY); + mLog.writeUTF(flat); + if (FLUSH_IMMEDIATELY) { + mLog.flush(); // TODO: delayed writes + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private void saveStats() { + DataOutputStream stats = null; + try { + stats = new DataOutputStream(mLauncher.openFileOutput(STATS_FILE_NAME + ".tmp", Context.MODE_PRIVATE)); + stats.writeInt(STATS_VERSION); + final int N = mHistogram.size(); + stats.writeInt(N); + for (int i=0; i(INITIAL_STATS_SIZE); + mHistogram = new ArrayList(INITIAL_STATS_SIZE); + DataInputStream stats = null; + try { + stats = new DataInputStream(mLauncher.openFileInput(STATS_FILE_NAME)); + final int version = stats.readInt(); + if (version == STATS_VERSION) { + final int N = stats.readInt(); + for (int i=0; i