1 /* 2 * Copyright (C) 2018 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.quickstep.logging; 18 19 import static androidx.core.util.Preconditions.checkNotNull; 20 import static androidx.core.util.Preconditions.checkState; 21 22 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS; 23 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER; 24 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.SEARCH_RESULT_CONTAINER; 25 import static com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers.ContainerCase.DEVICE_SEARCH_RESULT_CONTAINER; 26 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORKSPACE_SNAPSHOT; 27 import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__ALLAPPS; 28 import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__BACKGROUND; 29 import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__HOME; 30 import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__OVERVIEW; 31 32 import android.content.Context; 33 import android.util.Log; 34 import android.util.StatsEvent; 35 import android.view.View; 36 37 import androidx.annotation.NonNull; 38 import androidx.annotation.Nullable; 39 import androidx.annotation.WorkerThread; 40 import androidx.slice.SliceItem; 41 42 import com.android.launcher3.LauncherAppState; 43 import com.android.launcher3.Utilities; 44 import com.android.launcher3.logger.LauncherAtom; 45 import com.android.launcher3.logger.LauncherAtom.ContainerInfo; 46 import com.android.launcher3.logger.LauncherAtom.FolderContainer.ParentContainerCase; 47 import com.android.launcher3.logger.LauncherAtom.FolderIcon; 48 import com.android.launcher3.logger.LauncherAtom.FromState; 49 import com.android.launcher3.logger.LauncherAtom.ToState; 50 import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer; 51 import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers; 52 import com.android.launcher3.logging.InstanceId; 53 import com.android.launcher3.logging.StatsLogManager; 54 import com.android.launcher3.model.AllAppsList; 55 import com.android.launcher3.model.BaseModelUpdateTask; 56 import com.android.launcher3.model.BgDataModel; 57 import com.android.launcher3.model.data.FolderInfo; 58 import com.android.launcher3.model.data.ItemInfo; 59 import com.android.launcher3.util.Executors; 60 import com.android.launcher3.util.LogConfig; 61 import com.android.launcher3.views.ActivityContext; 62 import com.android.systemui.shared.system.InteractionJankMonitorWrapper; 63 import com.android.systemui.shared.system.SysUiStatsLog; 64 65 import java.util.Optional; 66 import java.util.OptionalInt; 67 import java.util.concurrent.CopyOnWriteArrayList; 68 69 /** 70 * This class calls StatsLog compile time generated methods. 71 * 72 * To see if the logs are properly sent to statsd, execute following command. 73 * <ul> 74 * $ wwdebug (to turn on the logcat printout) 75 * $ wwlogcat (see logcat with grep filter on) 76 * $ statsd_testdrive (see how ww is writing the proto to statsd buffer) 77 * </ul> 78 */ 79 public class StatsLogCompatManager extends StatsLogManager { 80 81 private static final String TAG = "StatsLog"; 82 private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG); 83 private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0); 84 // LauncherAtom.ItemInfo.getDefaultInstance() should be used but until launcher proto migrates 85 // from nano to lite, bake constant to prevent robo test failure. 86 private static final int DEFAULT_PAGE_INDEX = -2; 87 private static final int FOLDER_HIERARCHY_OFFSET = 100; 88 private static final int SEARCH_RESULT_HIERARCHY_OFFSET = 200; 89 private static final int EXTENDED_CONTAINERS_HIERARCHY_OFFSET = 300; 90 private static final int ATTRIBUTE_MULTIPLIER = 100; 91 92 public static final CopyOnWriteArrayList<StatsLogConsumer> LOGS_CONSUMER = 93 new CopyOnWriteArrayList<>(); 94 95 private final Context mContext; 96 StatsLogCompatManager(Context context)97 public StatsLogCompatManager(Context context) { 98 mContext = context; 99 } 100 101 @Override createLogger()102 protected StatsLogger createLogger() { 103 return new StatsCompatLogger(mContext, mActivityContext); 104 } 105 106 /** 107 * Synchronously writes an itemInfo to stats log 108 */ 109 @WorkerThread writeSnapshot(LauncherAtom.ItemInfo info, InstanceId instanceId)110 public static void writeSnapshot(LauncherAtom.ItemInfo info, InstanceId instanceId) { 111 if (IS_VERBOSE) { 112 Log.d(TAG, String.format("\nwriteSnapshot(%d):\n%s", instanceId.getId(), info)); 113 } 114 if (!Utilities.ATLEAST_R) { 115 return; 116 } 117 SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_SNAPSHOT, 118 LAUNCHER_WORKSPACE_SNAPSHOT.getId() /* event_id */, 119 info.getAttribute().getNumber() * ATTRIBUTE_MULTIPLIER 120 + info.getItemCase().getNumber() /* target_id */, 121 instanceId.getId() /* instance_id */, 122 0 /* uid */, 123 getPackageName(info) /* package_name */, 124 getComponentName(info) /* component_name */, 125 getGridX(info, false) /* grid_x */, 126 getGridY(info, false) /* grid_y */, 127 getPageId(info) /* page_id */, 128 getGridX(info, true) /* grid_x_parent */, 129 getGridY(info, true) /* grid_y_parent */, 130 getParentPageId(info) /* page_id_parent */, 131 getHierarchy(info) /* hierarchy */, 132 info.getIsWork() /* is_work_profile */, 133 info.getAttribute().getNumber() /* origin */, 134 getCardinality(info) /* cardinality */, 135 info.getWidget().getSpanX(), 136 info.getWidget().getSpanY(), 137 getFeatures(info)); 138 } 139 140 /** 141 * Builds {@link StatsEvent} from {@link LauncherAtom.ItemInfo}. Used for pulled atom callback 142 * implementation. 143 */ buildStatsEvent(LauncherAtom.ItemInfo info, @Nullable InstanceId instanceId)144 public static StatsEvent buildStatsEvent(LauncherAtom.ItemInfo info, 145 @Nullable InstanceId instanceId) { 146 return SysUiStatsLog.buildStatsEvent( 147 SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT, // atom ID, 148 LAUNCHER_WORKSPACE_SNAPSHOT.getId(), // event_id = 1; 149 info.getAttribute().getNumber() * ATTRIBUTE_MULTIPLIER 150 + info.getItemCase().getNumber(), // item_id = 2; 151 instanceId == null ? 0 : instanceId.getId(), //instance_id = 3; 152 0, //uid = 4 [(is_uid) = true]; 153 getPackageName(info), // package_name = 5; 154 getComponentName(info), // component_name = 6; 155 getGridX(info, false), //grid_x = 7 [default = -1]; 156 getGridY(info, false), //grid_y = 8 [default = -1]; 157 getPageId(info), // page_id = 9 [default = -2]; 158 getGridX(info, true), //grid_x_parent = 10 [default = -1]; 159 getGridY(info, true), //grid_y_parent = 11 [default = -1]; 160 getParentPageId(info), //page_id_parent = 12 [default = -2]; 161 getHierarchy(info), // container_id = 13; 162 info.getIsWork(), // is_work_profile = 14; 163 info.getAttribute().getNumber(), // attribute_id = 15; 164 getCardinality(info), // cardinality = 16; 165 info.getWidget().getSpanX(), // span_x = 17 [default = 1]; 166 info.getWidget().getSpanY() // span_y = 18 [default = 1]; 167 ); 168 } 169 170 /** 171 * Helps to construct and write statsd compatible log message. 172 */ 173 private static class StatsCompatLogger implements StatsLogger { 174 175 private static final ItemInfo DEFAULT_ITEM_INFO = new ItemInfo(); 176 177 private final Context mContext; 178 private final Optional<ActivityContext> mActivityContext; 179 private ItemInfo mItemInfo = DEFAULT_ITEM_INFO; 180 private InstanceId mInstanceId = DEFAULT_INSTANCE_ID; 181 private OptionalInt mRank = OptionalInt.empty(); 182 private Optional<ContainerInfo> mContainerInfo = Optional.empty(); 183 private int mSrcState = LAUNCHER_STATE_UNSPECIFIED; 184 private int mDstState = LAUNCHER_STATE_UNSPECIFIED; 185 private Optional<FromState> mFromState = Optional.empty(); 186 private Optional<ToState> mToState = Optional.empty(); 187 private Optional<String> mEditText = Optional.empty(); 188 private SliceItem mSliceItem; 189 private LauncherAtom.Slice mSlice; 190 StatsCompatLogger(Context context, ActivityContext activityContext)191 StatsCompatLogger(Context context, ActivityContext activityContext) { 192 mContext = context; 193 mActivityContext = Optional.ofNullable(activityContext); 194 } 195 196 @Override withItemInfo(ItemInfo itemInfo)197 public StatsLogger withItemInfo(ItemInfo itemInfo) { 198 if (mContainerInfo.isPresent()) { 199 throw new IllegalArgumentException( 200 "ItemInfo and ContainerInfo are mutual exclusive; cannot log both."); 201 } 202 this.mItemInfo = itemInfo; 203 return this; 204 } 205 206 @Override withInstanceId(InstanceId instanceId)207 public StatsLogger withInstanceId(InstanceId instanceId) { 208 this.mInstanceId = instanceId; 209 return this; 210 } 211 212 @Override withRank(int rank)213 public StatsLogger withRank(int rank) { 214 this.mRank = OptionalInt.of(rank); 215 return this; 216 } 217 218 @Override withSrcState(int srcState)219 public StatsLogger withSrcState(int srcState) { 220 this.mSrcState = srcState; 221 return this; 222 } 223 224 @Override withDstState(int dstState)225 public StatsLogger withDstState(int dstState) { 226 this.mDstState = dstState; 227 return this; 228 } 229 230 @Override withContainerInfo(ContainerInfo containerInfo)231 public StatsLogger withContainerInfo(ContainerInfo containerInfo) { 232 checkState(mItemInfo == DEFAULT_ITEM_INFO, 233 "ItemInfo and ContainerInfo are mutual exclusive; cannot log both."); 234 this.mContainerInfo = Optional.of(containerInfo); 235 return this; 236 } 237 238 @Override withFromState(FromState fromState)239 public StatsLogger withFromState(FromState fromState) { 240 this.mFromState = Optional.of(fromState); 241 return this; 242 } 243 244 @Override withToState(ToState toState)245 public StatsLogger withToState(ToState toState) { 246 this.mToState = Optional.of(toState); 247 return this; 248 } 249 250 @Override withEditText(String editText)251 public StatsLogger withEditText(String editText) { 252 this.mEditText = Optional.of(editText); 253 return this; 254 } 255 256 @Override withSliceItem(@onNull SliceItem sliceItem)257 public StatsLogger withSliceItem(@NonNull SliceItem sliceItem) { 258 checkState(mItemInfo == DEFAULT_ITEM_INFO && mSlice == null, 259 "ItemInfo, Slice and SliceItem are mutual exclusive; cannot set more than one" 260 + " of them."); 261 this.mSliceItem = checkNotNull(sliceItem, "expected valid sliceItem but received null"); 262 return this; 263 } 264 265 @Override withSlice(LauncherAtom.Slice slice)266 public StatsLogger withSlice(LauncherAtom.Slice slice) { 267 checkState(mItemInfo == DEFAULT_ITEM_INFO && mSliceItem == null, 268 "ItemInfo, Slice and SliceItem are mutual exclusive; cannot set more than one" 269 + " of them."); 270 checkNotNull(slice, "expected valid slice but received null"); 271 checkNotNull(slice.getUri(), "expected valid slice uri but received null"); 272 this.mSlice = slice; 273 return this; 274 } 275 276 @Override log(EventEnum event)277 public void log(EventEnum event) { 278 if (!Utilities.ATLEAST_R) { 279 return; 280 } 281 LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); 282 283 if (mSlice == null && mSliceItem != null) { 284 mSlice = LauncherAtom.Slice.newBuilder().setUri( 285 mSliceItem.getSlice().getUri().toString()).build(); 286 } 287 288 if (mSlice != null) { 289 Executors.MODEL_EXECUTOR.execute( 290 () -> { 291 LauncherAtom.ItemInfo.Builder itemInfoBuilder = 292 LauncherAtom.ItemInfo.newBuilder().setSlice(mSlice); 293 mContainerInfo.ifPresent(itemInfoBuilder::setContainerInfo); 294 write(event, applyOverwrites(itemInfoBuilder.build())); 295 }); 296 return; 297 } 298 299 if (mItemInfo.container < 0 || appState == null) { 300 // Write log on the model thread so that logs do not go out of order 301 // (for eg: drop comes after drag) 302 Executors.MODEL_EXECUTOR.execute( 303 () -> write(event, applyOverwrites(mItemInfo.buildProto()))); 304 } else { 305 // Item is inside the folder, fetch folder info in a BG thread 306 // and then write to StatsLog. 307 appState.getModel().enqueueModelUpdateTask( 308 new BaseModelUpdateTask() { 309 @Override 310 public void execute(LauncherAppState app, BgDataModel dataModel, 311 AllAppsList apps) { 312 FolderInfo folderInfo = dataModel.folders.get(mItemInfo.container); 313 write(event, applyOverwrites(mItemInfo.buildProto(folderInfo))); 314 } 315 }); 316 } 317 } 318 319 @Override sendToInteractionJankMonitor(EventEnum event, View view)320 public void sendToInteractionJankMonitor(EventEnum event, View view) { 321 if (!(event instanceof LauncherEvent)) { 322 return; 323 } 324 switch ((LauncherEvent) event) { 325 case LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN: 326 InteractionJankMonitorWrapper.begin( 327 view, 328 InteractionJankMonitorWrapper.CUJ_ALL_APPS_SCROLL); 329 break; 330 case LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END: 331 InteractionJankMonitorWrapper.end( 332 InteractionJankMonitorWrapper.CUJ_ALL_APPS_SCROLL); 333 break; 334 default: 335 break; 336 } 337 } 338 applyOverwrites(LauncherAtom.ItemInfo atomInfo)339 private LauncherAtom.ItemInfo applyOverwrites(LauncherAtom.ItemInfo atomInfo) { 340 LauncherAtom.ItemInfo.Builder itemInfoBuilder = atomInfo.toBuilder(); 341 342 mRank.ifPresent(itemInfoBuilder::setRank); 343 mContainerInfo.ifPresent(itemInfoBuilder::setContainerInfo); 344 345 mActivityContext.ifPresent(activityContext -> 346 activityContext.applyOverwritesToLogItem(itemInfoBuilder)); 347 348 if (mFromState.isPresent() || mToState.isPresent() || mEditText.isPresent()) { 349 FolderIcon.Builder folderIconBuilder = itemInfoBuilder 350 .getFolderIcon() 351 .toBuilder(); 352 mFromState.ifPresent(folderIconBuilder::setFromLabelState); 353 mToState.ifPresent(folderIconBuilder::setToLabelState); 354 mEditText.ifPresent(folderIconBuilder::setLabelInfo); 355 itemInfoBuilder.setFolderIcon(folderIconBuilder); 356 } 357 return itemInfoBuilder.build(); 358 } 359 360 @WorkerThread write(EventEnum event, LauncherAtom.ItemInfo atomInfo)361 private void write(EventEnum event, LauncherAtom.ItemInfo atomInfo) { 362 InstanceId instanceId = mInstanceId; 363 int srcState = mSrcState; 364 int dstState = mDstState; 365 if (IS_VERBOSE) { 366 String name = (event instanceof Enum) ? ((Enum) event).name() : 367 event.getId() + ""; 368 369 Log.d(TAG, instanceId == DEFAULT_INSTANCE_ID 370 ? String.format("\n%s (State:%s->%s)\n%s", name, getStateString(srcState), 371 getStateString(dstState), atomInfo) 372 : String.format("\n%s (State:%s->%s) (InstanceId:%s)\n%s", name, 373 getStateString(srcState), getStateString(dstState), instanceId, 374 atomInfo)); 375 } 376 377 for (StatsLogConsumer consumer : LOGS_CONSUMER) { 378 consumer.consume(event, atomInfo); 379 } 380 381 SysUiStatsLog.write( 382 SysUiStatsLog.LAUNCHER_EVENT, 383 SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */, 384 srcState, 385 dstState, 386 null /* launcher extensions, deprecated */, 387 false /* quickstep_enabled, deprecated */, 388 event.getId() /* event_id */, 389 atomInfo.getAttribute().getNumber() * ATTRIBUTE_MULTIPLIER 390 + atomInfo.getItemCase().getNumber() /* target_id */, 391 instanceId.getId() /* instance_id TODO */, 392 0 /* uid TODO */, 393 getPackageName(atomInfo) /* package_name */, 394 getComponentName(atomInfo) /* component_name */, 395 getGridX(atomInfo, false) /* grid_x */, 396 getGridY(atomInfo, false) /* grid_y */, 397 getPageId(atomInfo) /* page_id */, 398 getGridX(atomInfo, true) /* grid_x_parent */, 399 getGridY(atomInfo, true) /* grid_y_parent */, 400 getParentPageId(atomInfo) /* page_id_parent */, 401 getHierarchy(atomInfo) /* hierarchy */, 402 atomInfo.getIsWork() /* is_work_profile */, 403 atomInfo.getRank() /* rank */, 404 atomInfo.getFolderIcon().getFromLabelState().getNumber() /* fromState */, 405 atomInfo.getFolderIcon().getToLabelState().getNumber() /* toState */, 406 atomInfo.getFolderIcon().getLabelInfo() /* edittext */, 407 getCardinality(atomInfo) /* cardinality */, 408 getFeatures(atomInfo) /* features */); 409 } 410 } 411 getCardinality(LauncherAtom.ItemInfo info)412 private static int getCardinality(LauncherAtom.ItemInfo info) { 413 switch (info.getContainerInfo().getContainerCase()) { 414 case PREDICTED_HOTSEAT_CONTAINER: 415 return info.getContainerInfo().getPredictedHotseatContainer().getCardinality(); 416 case TASK_BAR_CONTAINER: 417 return info.getContainerInfo().getTaskBarContainer().getCardinality(); 418 case SEARCH_RESULT_CONTAINER: 419 return info.getContainerInfo().getSearchResultContainer().getQueryLength(); 420 case EXTENDED_CONTAINERS: 421 ExtendedContainers extendedCont = info.getContainerInfo().getExtendedContainers(); 422 if (extendedCont.getContainerCase() == DEVICE_SEARCH_RESULT_CONTAINER) { 423 DeviceSearchResultContainer deviceSearchResultCont = extendedCont 424 .getDeviceSearchResultContainer(); 425 return deviceSearchResultCont.hasQueryLength() ? deviceSearchResultCont 426 .getQueryLength() : -1; 427 } 428 default: 429 return info.getFolderIcon().getCardinality(); 430 } 431 } 432 getPackageName(LauncherAtom.ItemInfo info)433 private static String getPackageName(LauncherAtom.ItemInfo info) { 434 switch (info.getItemCase()) { 435 case APPLICATION: 436 return info.getApplication().getPackageName(); 437 case SHORTCUT: 438 return info.getShortcut().getShortcutName(); 439 case WIDGET: 440 return info.getWidget().getPackageName(); 441 case TASK: 442 return info.getTask().getPackageName(); 443 case SEARCH_ACTION_ITEM: 444 return info.getSearchActionItem().getPackageName(); 445 default: 446 return null; 447 } 448 } 449 getComponentName(LauncherAtom.ItemInfo info)450 private static String getComponentName(LauncherAtom.ItemInfo info) { 451 switch (info.getItemCase()) { 452 case APPLICATION: 453 return info.getApplication().getComponentName(); 454 case SHORTCUT: 455 return info.getShortcut().getShortcutName(); 456 case WIDGET: 457 return info.getWidget().getComponentName(); 458 case TASK: 459 return info.getTask().getComponentName(); 460 case SEARCH_ACTION_ITEM: 461 return info.getSearchActionItem().getTitle(); 462 case SLICE: 463 return info.getSlice().getUri(); 464 default: 465 return null; 466 } 467 } 468 getGridX(LauncherAtom.ItemInfo info, boolean parent)469 private static int getGridX(LauncherAtom.ItemInfo info, boolean parent) { 470 if (info.getContainerInfo().getContainerCase() == FOLDER) { 471 if (parent) { 472 return info.getContainerInfo().getFolder().getWorkspace().getGridX(); 473 } else { 474 return info.getContainerInfo().getFolder().getGridX(); 475 } 476 } else { 477 return info.getContainerInfo().getWorkspace().getGridX(); 478 } 479 } 480 getGridY(LauncherAtom.ItemInfo info, boolean parent)481 private static int getGridY(LauncherAtom.ItemInfo info, boolean parent) { 482 if (info.getContainerInfo().getContainerCase() == FOLDER) { 483 if (parent) { 484 return info.getContainerInfo().getFolder().getWorkspace().getGridY(); 485 } else { 486 return info.getContainerInfo().getFolder().getGridY(); 487 } 488 } else { 489 return info.getContainerInfo().getWorkspace().getGridY(); 490 } 491 } 492 getPageId(LauncherAtom.ItemInfo info)493 private static int getPageId(LauncherAtom.ItemInfo info) { 494 if (info.hasTask()) { 495 return info.getTask().getIndex(); 496 } 497 switch (info.getContainerInfo().getContainerCase()) { 498 case FOLDER: 499 return info.getContainerInfo().getFolder().getPageIndex(); 500 case HOTSEAT: 501 return info.getContainerInfo().getHotseat().getIndex(); 502 case PREDICTED_HOTSEAT_CONTAINER: 503 return info.getContainerInfo().getPredictedHotseatContainer().getIndex(); 504 case TASK_BAR_CONTAINER: 505 return info.getContainerInfo().getTaskBarContainer().getIndex(); 506 default: 507 return info.getContainerInfo().getWorkspace().getPageIndex(); 508 } 509 } 510 getParentPageId(LauncherAtom.ItemInfo info)511 private static int getParentPageId(LauncherAtom.ItemInfo info) { 512 switch (info.getContainerInfo().getContainerCase()) { 513 case FOLDER: 514 if (info.getContainerInfo().getFolder().getParentContainerCase() 515 == ParentContainerCase.HOTSEAT) { 516 return info.getContainerInfo().getFolder().getHotseat().getIndex(); 517 } 518 return info.getContainerInfo().getFolder().getWorkspace().getPageIndex(); 519 case SEARCH_RESULT_CONTAINER: 520 return info.getContainerInfo().getSearchResultContainer().getWorkspace() 521 .getPageIndex(); 522 default: 523 return info.getContainerInfo().getWorkspace().getPageIndex(); 524 } 525 } 526 getHierarchy(LauncherAtom.ItemInfo info)527 private static int getHierarchy(LauncherAtom.ItemInfo info) { 528 if (info.getContainerInfo().getContainerCase() == FOLDER) { 529 return info.getContainerInfo().getFolder().getParentContainerCase().getNumber() 530 + FOLDER_HIERARCHY_OFFSET; 531 } else if (info.getContainerInfo().getContainerCase() == SEARCH_RESULT_CONTAINER) { 532 return info.getContainerInfo().getSearchResultContainer().getParentContainerCase() 533 .getNumber() + SEARCH_RESULT_HIERARCHY_OFFSET; 534 } else if (info.getContainerInfo().getContainerCase() == EXTENDED_CONTAINERS) { 535 return info.getContainerInfo().getExtendedContainers().getContainerCase().getNumber() 536 + EXTENDED_CONTAINERS_HIERARCHY_OFFSET; 537 } else { 538 return info.getContainerInfo().getContainerCase().getNumber(); 539 } 540 } 541 getStateString(int state)542 private static String getStateString(int state) { 543 switch (state) { 544 case LAUNCHER_UICHANGED__DST_STATE__BACKGROUND: 545 return "BACKGROUND"; 546 case LAUNCHER_UICHANGED__DST_STATE__HOME: 547 return "HOME"; 548 case LAUNCHER_UICHANGED__DST_STATE__OVERVIEW: 549 return "OVERVIEW"; 550 case LAUNCHER_UICHANGED__DST_STATE__ALLAPPS: 551 return "ALLAPPS"; 552 default: 553 return "INVALID"; 554 } 555 } 556 getFeatures(LauncherAtom.ItemInfo info)557 private static int getFeatures(LauncherAtom.ItemInfo info) { 558 if (info.getItemCase().equals(LauncherAtom.ItemInfo.ItemCase.WIDGET)) { 559 return info.getWidget().getWidgetFeatures(); 560 } 561 return 0; 562 } 563 564 565 /** 566 * Interface to get stats log while it is dispatched to the system 567 */ 568 public interface StatsLogConsumer { 569 570 @WorkerThread consume(EventEnum event, LauncherAtom.ItemInfo atomInfo)571 void consume(EventEnum event, LauncherAtom.ItemInfo atomInfo); 572 } 573 } 574