1 /* 2 * Copyright (C) 2016 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.tv.analytics; 18 19 import android.content.Context; 20 import android.os.Handler; 21 import android.os.Looper; 22 import android.support.annotation.MainThread; 23 import com.android.tv.data.ChannelDataManager; 24 import com.android.tv.data.api.Channel; 25 import com.android.tv.util.RecurringRunner; 26 import java.util.List; 27 import java.util.concurrent.TimeUnit; 28 29 /** 30 * Periodically sends analytics data with the channel count. 31 * 32 * <p> 33 * 34 * <p>This should only be started from a user activity like {@link com.android.tv.MainActivity}. 35 */ 36 @MainThread 37 public class SendChannelStatusRunnable implements Runnable { 38 private static final long SEND_CHANNEL_STATUS_INTERVAL_MS = TimeUnit.DAYS.toMillis(1); 39 startChannelStatusRecurringRunner( Context context, Tracker tracker, ChannelDataManager channelDataManager)40 public static RecurringRunner startChannelStatusRecurringRunner( 41 Context context, Tracker tracker, ChannelDataManager channelDataManager) { 42 43 final SendChannelStatusRunnable sendChannelStatusRunnable = 44 new SendChannelStatusRunnable(channelDataManager, tracker); 45 46 Runnable onStopRunnable = () -> sendChannelStatusRunnable.setDbLoadListener(null); 47 final RecurringRunner recurringRunner = 48 new RecurringRunner( 49 context, 50 SEND_CHANNEL_STATUS_INTERVAL_MS, 51 sendChannelStatusRunnable, 52 onStopRunnable); 53 54 if (channelDataManager.isDbLoadFinished()) { 55 sendChannelStatusRunnable.setDbLoadListener(null); 56 recurringRunner.start(); 57 } else { 58 // Start the recurring runnable after the channel DB is finished loading. 59 sendChannelStatusRunnable.setDbLoadListener( 60 new ChannelDataManager.Listener() { 61 @Override 62 public void onLoadFinished() { 63 // This is called inside an iterator of Listeners so the remove step is 64 // done 65 // via a post on the main thread 66 new Handler(Looper.getMainLooper()) 67 .post(() -> sendChannelStatusRunnable.setDbLoadListener(null)); 68 recurringRunner.start(); 69 } 70 71 @Override 72 public void onChannelListUpdated() {} 73 74 @Override 75 public void onChannelBrowsableChanged() {} 76 }); 77 } 78 return recurringRunner; 79 } 80 81 private final ChannelDataManager mChannelDataManager; 82 private final Tracker mTracker; 83 private ChannelDataManager.Listener mListener; 84 SendChannelStatusRunnable(ChannelDataManager channelDataManager, Tracker tracker)85 private SendChannelStatusRunnable(ChannelDataManager channelDataManager, Tracker tracker) { 86 mChannelDataManager = channelDataManager; 87 mTracker = tracker; 88 } 89 90 @Override run()91 public void run() { 92 int browsableChannelCount = 0; 93 List<Channel> channelList = mChannelDataManager.getChannelList(); 94 for (Channel channel : channelList) { 95 if (channel.isBrowsable()) { 96 ++browsableChannelCount; 97 } 98 } 99 mTracker.sendChannelCount(browsableChannelCount, channelList.size()); 100 } 101 setDbLoadListener(ChannelDataManager.Listener listener)102 private void setDbLoadListener(ChannelDataManager.Listener listener) { 103 if (mListener != null) { 104 mChannelDataManager.removeListener(mListener); 105 } 106 mListener = listener; 107 if (listener != null) { 108 mChannelDataManager.addListener(listener); 109 } 110 } 111 } 112