/** * Wire * Copyright (C) 2016 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.waz.zclient.utils; import android.content.Context; import android.content.pm.PackageManager; import com.waz.api.AudioAssetForUpload; import com.waz.api.AudioEffect; import com.waz.api.ContactMethod; import com.waz.api.IConversation; import com.waz.api.Message; import com.waz.api.Permission; import com.waz.api.User; import com.waz.zclient.R; import com.waz.zclient.controllers.drawing.DrawingController; import com.waz.zclient.controllers.tracking.events.connect.SelectedTopUser; import com.waz.zclient.controllers.tracking.events.connect.SelectedUserFromSearchEvent; import com.waz.zclient.controllers.tracking.events.connect.SentConnectRequestEvent; import com.waz.zclient.controllers.tracking.events.connect.SentInviteToContactEvent; import com.waz.zclient.controllers.tracking.events.optionsmenu.OptionsMenuItemSelectedEvent; import com.waz.zclient.core.controllers.tracking.attributes.CompletedMediaType; import com.waz.zclient.core.controllers.tracking.attributes.ConversationType; import com.waz.zclient.core.controllers.tracking.attributes.OpenedMediaAction; import com.waz.zclient.core.controllers.tracking.events.media.CompletedMediaActionEvent; import com.waz.zclient.core.controllers.tracking.events.media.OpenedMediaActionEvent; import com.waz.zclient.core.controllers.tracking.events.media.SentAudioMessageEvent; import com.waz.zclient.core.controllers.tracking.events.media.SentPictureEvent; import com.waz.zclient.core.controllers.tracking.events.settings.ChangedContactsPermissionEvent; import com.waz.zclient.core.controllers.tracking.events.settings.ChangedSoundNotificationLevelEvent; import com.waz.zclient.core.stores.connect.IConnectStore; import com.waz.zclient.pages.extendedcursor.image.ImagePreviewLayout; import com.waz.zclient.pages.main.pickuser.SearchResultAdapter; import com.waz.zclient.tracking.GlobalTrackingController; import com.waz.zclient.ui.optionsmenu.OptionsMenuItem; import java.util.Locale; public class TrackingUtils { public static void tagOptionsMenuSelectedEvent(GlobalTrackingController trackingController, OptionsMenuItem optionsMenuItem, IConversation.Type conversationType, boolean inConversationList, boolean openedBySwipe) { OptionsMenuItemSelectedEvent.Action action = getEventAction(optionsMenuItem); if (action == null) { return; } ConversationType type = conversationType == IConversation.Type.GROUP ? ConversationType.GROUP_CONVERSATION : ConversationType.ONE_TO_ONE_CONVERSATION; OptionsMenuItemSelectedEvent.Context context = inConversationList ? OptionsMenuItemSelectedEvent.Context.LIST : OptionsMenuItemSelectedEvent.Context.PARTICIPANTS; OptionsMenuItemSelectedEvent.Method method = openedBySwipe ? OptionsMenuItemSelectedEvent.Method.SWIPE : OptionsMenuItemSelectedEvent.Method.TAP; trackingController.tagEvent(new OptionsMenuItemSelectedEvent(action, context, type, method)); } public static OptionsMenuItemSelectedEvent.Action getEventAction(OptionsMenuItem optionsMenuItem) { OptionsMenuItemSelectedEvent.Action action = null; switch (optionsMenuItem) { case ARCHIVE: action = OptionsMenuItemSelectedEvent.Action.ARCHIVE; break; case UNARCHIVE: action = OptionsMenuItemSelectedEvent.Action.UNARCHIVE; break; case SILENCE: action = OptionsMenuItemSelectedEvent.Action.SILENCE; break; case UNSILENCE: action = OptionsMenuItemSelectedEvent.Action.NOTIFY; break; case BLOCK: action = OptionsMenuItemSelectedEvent.Action.BLOCK; break; case UNBLOCK: action = OptionsMenuItemSelectedEvent.Action.UNBLOCK; break; case DELETE: action = OptionsMenuItemSelectedEvent.Action.DELETE; break; case LEAVE: action = OptionsMenuItemSelectedEvent.Action.LEAVE; break; case RENAME: action = OptionsMenuItemSelectedEvent.Action.RENAME; break; } return action; } public static void tagSentInviteToContactEvent(GlobalTrackingController trackingController, ContactMethod.Kind contactMethodKind, boolean isResending, boolean fromContactSearch) { SentInviteToContactEvent event = new SentInviteToContactEvent(contactMethodKind == ContactMethod.Kind.EMAIL ? SentInviteToContactEvent.Method.EMAIL : SentInviteToContactEvent.Method.PHONE, isResending, fromContactSearch); trackingController.tagEvent(event); } public static void tagSentConnectRequestFromUserProfileEvent(GlobalTrackingController trackingController, IConnectStore.UserRequester userRequester, int numSharedUsers) { SentConnectRequestEvent.EventContext eventContext; switch (userRequester) { case SEARCH: eventContext = SentConnectRequestEvent.EventContext.STARTUI; break; case PARTICIPANTS: eventContext = SentConnectRequestEvent.EventContext.PARTICIPANTS; break; default: eventContext = SentConnectRequestEvent.EventContext.UNKNOWN; break; } SentConnectRequestEvent event = new SentConnectRequestEvent(eventContext, numSharedUsers); trackingController.tagEvent(event); } public static String messageTypeForMessageSelection(Message.Type messageType) { String type; switch (messageType) { case TEXT: type = "text"; break; case ASSET: type = "image"; break; case ANY_ASSET: type = "file"; break; case RICH_MEDIA: type = "rich_media"; break; case VIDEO_ASSET: type = "video"; break; case AUDIO_ASSET: type = "audio"; break; case KNOCK: type = "ping"; break; default: type = messageType.name().toLowerCase(Locale.getDefault()); break; } return type; } public static void tagChangedContactsPermissionEvent(GlobalTrackingController trackingController, String[] permissions, int[] grantResults) { for (int i = 0; i < permissions.length; i++) { String permission = permissions[i]; if (!permission.contains(Permission.READ_CONTACTS.toString())) { continue; } boolean grantedContactsPermission = grantResults[i] == PackageManager.PERMISSION_GRANTED; trackingController.tagEvent(new ChangedContactsPermissionEvent(grantedContactsPermission, false)); } } public static void tagChangedSoundNotificationLevelEvent(GlobalTrackingController trackingController, String preferenceString, Context context) { ChangedSoundNotificationLevelEvent.Level level = ChangedSoundNotificationLevelEvent.Level.ALL_SOUNDS; if (preferenceString.equals(context.getString(R.string.pref_sound_value_none))) { level = ChangedSoundNotificationLevelEvent.Level.NO_SOUNDS; } else if (preferenceString.equals(context.getString(R.string.pref_sound_value_some))) { level = ChangedSoundNotificationLevelEvent.Level.SOME_SOUNDS; } trackingController.tagEvent(new ChangedSoundNotificationLevelEvent(level)); } public static void tagSentAudioMessageEvent(GlobalTrackingController trackingController, AudioAssetForUpload audioAssetForUpload, AudioEffect appliedAudioEffect, boolean fromMinimisedState, boolean sentWithQuickAction, IConversation conversation) { int durationSec = (int) audioAssetForUpload.getDuration().getSeconds(); SentAudioMessageEvent.AudioEffectType audioEffectType = SentAudioMessageEvent.AudioEffectType.NONE; if (appliedAudioEffect != null) { switch (appliedAudioEffect) { case PITCH_UP_INSANE: audioEffectType = SentAudioMessageEvent.AudioEffectType.HELIUM; break; case PITCH_DOWN_INSANE: audioEffectType = SentAudioMessageEvent.AudioEffectType.JELLY_FISH; break; case PACE_UP_MED: audioEffectType = SentAudioMessageEvent.AudioEffectType.HARE; break; case REVERB_MAX: audioEffectType = SentAudioMessageEvent.AudioEffectType.CATHEDRAL; break; case CHORUS_MAX: audioEffectType = SentAudioMessageEvent.AudioEffectType.ALIEN; break; case VOCODER_MED: audioEffectType = SentAudioMessageEvent.AudioEffectType.ROBOT; break; case PITCH_UP_DOWN_MAX: audioEffectType = SentAudioMessageEvent.AudioEffectType.ROLLERCOASTER; break; } } trackingController.tagEvent(new SentAudioMessageEvent(durationSec, audioEffectType, sentWithQuickAction, fromMinimisedState, conversation)); } public static void onSentTextMessage(GlobalTrackingController trackingController, IConversation conversation) { trackingController.tagEvent(new CompletedMediaActionEvent(CompletedMediaType.TEXT, conversation.getType().name(), conversation.isOtto(), conversation.isEphemeral(), String.valueOf(conversation.getEphemeralExpiration().duration().toSeconds()))); } public static void onSentGifMessage(GlobalTrackingController trackingController, IConversation conversation) { trackingController.tagEvent(new CompletedMediaActionEvent(CompletedMediaType.TEXT, conversation.getType().name(), conversation.isOtto(), conversation.isEphemeral(), String.valueOf(conversation.getEphemeralExpiration().duration().toSeconds()))); trackingController.tagEvent(new SentPictureEvent(SentPictureEvent.Source.GIPHY, conversation.getType().name(), SentPictureEvent.Method.DEFAULT, SentPictureEvent.SketchSource.NONE, conversation.isOtto(), conversation.isEphemeral(), String.valueOf(conversation.getEphemeralExpiration().duration().toSeconds()))); } public static void onSentSketchMessage(GlobalTrackingController trackingController, IConversation conversation, DrawingController.DrawingDestination drawingDestination) { SentPictureEvent.SketchSource sketchSource = SentPictureEvent.SketchSource.NONE; switch (drawingDestination) { case CAMERA_PREVIEW_VIEW: sketchSource = SentPictureEvent.SketchSource.CAMERA_GALLERY; break; case SKETCH_BUTTON: sketchSource = SentPictureEvent.SketchSource.SKETCH_BUTTON; break; case SINGLE_IMAGE_VIEW: sketchSource = SentPictureEvent.SketchSource.IMAGE_FULL_VIEW; break; } trackingController.tagEvent(new SentPictureEvent(SentPictureEvent.Source.SKETCH, conversation.getType().name(), SentPictureEvent.Method.DEFAULT, sketchSource, conversation.isOtto(), conversation.isEphemeral(), String.valueOf(conversation.getEphemeralExpiration().duration().toSeconds()))); } public static void onSentLocationMessage(GlobalTrackingController trackingController, IConversation conversation) { trackingController.tagEvent(new CompletedMediaActionEvent(CompletedMediaType.LOCATION, conversation.getType().name(), conversation.isOtto(), conversation.isEphemeral(), String.valueOf(conversation.getEphemeralExpiration().duration().toSeconds()))); } public static void onSentPhotoMessageFromSharing(GlobalTrackingController trackingController, IConversation conversation) { trackingController.tagEvent(new SentPictureEvent(SentPictureEvent.Source.SHARING, conversation.getType().name(), SentPictureEvent.Method.DEFAULT, SentPictureEvent.SketchSource.NONE, conversation.isOtto(), conversation.isEphemeral(), String.valueOf(conversation.getEphemeralExpiration().duration().toSeconds()))); } public static void onSentPhotoMessage(GlobalTrackingController trackingController, IConversation conversation, SentPictureEvent.Source source, SentPictureEvent.Method method) { trackingController.tagEvent(new SentPictureEvent(source, conversation.getType().name(), method, SentPictureEvent.SketchSource.NONE, conversation.isOtto(), conversation.isEphemeral(), String.valueOf(conversation.getEphemeralExpiration().duration().toSeconds()))); } public static void onSentPhotoMessage(GlobalTrackingController trackingController, IConversation conversation, ImagePreviewLayout.Source source) { SentPictureEvent.Source eventSource = source == ImagePreviewLayout.Source.CAMERA ? SentPictureEvent.Source.CAMERA : SentPictureEvent.Source.GALLERY; SentPictureEvent.Method eventMethod = SentPictureEvent.Method.DEFAULT; switch (source) { case CAMERA: case IN_APP_GALLERY: eventMethod = SentPictureEvent.Method.KEYBOARD; break; case DEVICE_GALLERY: eventMethod = SentPictureEvent.Method.FULL_SCREEN; break; } onSentPhotoMessage(trackingController, conversation, eventSource, eventMethod); } public static void onSentPingMessage(GlobalTrackingController trackingController, IConversation conversation) { boolean isGroupConversation = conversation.getType() == IConversation.Type.GROUP; trackingController.tagEvent(OpenedMediaActionEvent.cursorAction(OpenedMediaAction.PING, conversation)); trackingController.tagEvent(new CompletedMediaActionEvent(CompletedMediaType.PING, isGroupConversation ? "GROUP" : "ONE_TO_ONE", conversation.isOtto(), conversation.isEphemeral(), String.valueOf(conversation.getEphemeralExpiration().duration().toSeconds()))); } public static void onUserSelectedInStartUI(GlobalTrackingController trackingController, User user, boolean isTopUser, boolean isAddingToConversation, int position, SearchResultAdapter adapter) { int itemType = adapter.getItemViewType(position); if (itemType < 0) { return; } if (isTopUser) { trackingController.tagEvent(new SelectedTopUser(position + 1)); } else { switch (itemType) { case SearchResultAdapter.ITEM_TYPE_CONNECTED_USER: trackingController.tagEvent(new SelectedUserFromSearchEvent(user.getConnectionStatus().toString(), isAddingToConversation, SelectedUserFromSearchEvent.Section.CONTACTS, position)); break; case SearchResultAdapter.ITEM_TYPE_OTHER_USER: trackingController.tagEvent(new SelectedUserFromSearchEvent(user.getConnectionStatus().toString(), isAddingToConversation, SelectedUserFromSearchEvent.Section.DIRECTORY, adapter.getOtherUserInternalPosition(position))); break; } } } }