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