1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.launcher3; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.os.Bundle; 24 import android.util.Log; 25 import android.view.View; 26 import android.view.ViewParent; 27 28 public class Stats { 29 30 /** 31 * Implemented by containers to provide a launch source for a given child. 32 */ 33 public interface LaunchSourceProvider { fillInLaunchSourceData(View v, Bundle sourceData)34 void fillInLaunchSourceData(View v, Bundle sourceData); 35 } 36 37 /** 38 * Helpers to add the source to a launch intent. 39 */ 40 public static class LaunchSourceUtils { 41 /** 42 * Create a default bundle for LaunchSourceProviders to fill in their data. 43 */ createSourceData()44 public static Bundle createSourceData() { 45 Bundle sourceData = new Bundle(); 46 sourceData.putString(SOURCE_EXTRA_CONTAINER, CONTAINER_HOMESCREEN); 47 // Have default container/sub container pages 48 sourceData.putInt(SOURCE_EXTRA_CONTAINER_PAGE, 0); 49 sourceData.putInt(SOURCE_EXTRA_SUB_CONTAINER_PAGE, 0); 50 return sourceData; 51 } 52 53 /** 54 * Finds the next launch source provider in the parents of the view hierarchy and populates 55 * the source data from that provider. 56 */ populateSourceDataFromAncestorProvider(View v, Bundle sourceData)57 public static void populateSourceDataFromAncestorProvider(View v, Bundle sourceData) { 58 if (v == null) { 59 return; 60 } 61 62 Stats.LaunchSourceProvider provider = null; 63 ViewParent parent = v.getParent(); 64 while (parent != null && parent instanceof View) { 65 if (parent instanceof Stats.LaunchSourceProvider) { 66 provider = (Stats.LaunchSourceProvider) parent; 67 break; 68 } 69 parent = parent.getParent(); 70 } 71 72 if (provider != null) { 73 provider.fillInLaunchSourceData(v, sourceData); 74 } else if (LauncherAppState.isDogfoodBuild()) { 75 throw new RuntimeException("Expected LaunchSourceProvider"); 76 } 77 } 78 } 79 80 private static final boolean DEBUG_BROADCASTS = false; 81 82 public static final String ACTION_LAUNCH = "com.android.launcher3.action.LAUNCH"; 83 public static final String EXTRA_INTENT = "intent"; 84 public static final String EXTRA_CONTAINER = "container"; 85 public static final String EXTRA_SCREEN = "screen"; 86 public static final String EXTRA_CELLX = "cellX"; 87 public static final String EXTRA_CELLY = "cellY"; 88 public static final String EXTRA_SOURCE = "source"; 89 90 public static final String SOURCE_EXTRA_CONTAINER = "container"; 91 public static final String SOURCE_EXTRA_CONTAINER_PAGE = "container_page"; 92 public static final String SOURCE_EXTRA_SUB_CONTAINER = "sub_container"; 93 public static final String SOURCE_EXTRA_SUB_CONTAINER_PAGE = "sub_container_page"; 94 95 public static final String CONTAINER_SEARCH_BOX = "search_box"; 96 public static final String CONTAINER_ALL_APPS = "all_apps"; 97 public static final String CONTAINER_HOMESCREEN = "homescreen"; // aka. Workspace 98 public static final String CONTAINER_HOTSEAT = "hotseat"; 99 100 public static final String SUB_CONTAINER_FOLDER = "folder"; 101 public static final String SUB_CONTAINER_ALL_APPS_A_Z = "a-z"; 102 public static final String SUB_CONTAINER_ALL_APPS_PREDICTION = "prediction"; 103 public static final String SUB_CONTAINER_ALL_APPS_SEARCH = "search"; 104 105 private final Launcher mLauncher; 106 private final String mLaunchBroadcastPermission; 107 Stats(Launcher launcher)108 public Stats(Launcher launcher) { 109 mLauncher = launcher; 110 mLaunchBroadcastPermission = 111 launcher.getResources().getString(R.string.receive_launch_broadcasts_permission); 112 113 if (DEBUG_BROADCASTS) { 114 launcher.registerReceiver( 115 new BroadcastReceiver() { 116 @Override 117 public void onReceive(Context context, Intent intent) { 118 Log.v("Stats", "got broadcast: " + intent + " for launched intent: " 119 + intent.getStringExtra(EXTRA_INTENT)); 120 } 121 }, 122 new IntentFilter(ACTION_LAUNCH), 123 mLaunchBroadcastPermission, 124 null 125 ); 126 } 127 } 128 recordLaunch(View v, Intent intent, ShortcutInfo shortcut)129 public void recordLaunch(View v, Intent intent, ShortcutInfo shortcut) { 130 intent = new Intent(intent); 131 intent.setSourceBounds(null); 132 133 final String flat = intent.toUri(0); 134 Intent broadcastIntent = new Intent(ACTION_LAUNCH).putExtra(EXTRA_INTENT, flat); 135 136 if (shortcut != null) { 137 broadcastIntent.putExtra(EXTRA_CONTAINER, shortcut.container) 138 .putExtra(EXTRA_SCREEN, shortcut.screenId) 139 .putExtra(EXTRA_CELLX, shortcut.cellX) 140 .putExtra(EXTRA_CELLY, shortcut.cellY); 141 } 142 143 Bundle sourceExtras = LaunchSourceUtils.createSourceData(); 144 LaunchSourceUtils.populateSourceDataFromAncestorProvider(v, sourceExtras); 145 broadcastIntent.putExtra(EXTRA_SOURCE, sourceExtras); 146 147 String[] packages = mLauncher.getResources().getStringArray(R.array.launch_broadcast_targets); 148 for(String p: packages) { 149 broadcastIntent.setPackage(p); 150 mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission); 151 } 152 } 153 } 154