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 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 = 47 new Runnable() { 48 @Override 49 public void run() { 50 sendChannelStatusRunnable.setDbLoadListener(null); 51 } 52 }; 53 final RecurringRunner recurringRunner = 54 new RecurringRunner( 55 context, 56 SEND_CHANNEL_STATUS_INTERVAL_MS, 57 sendChannelStatusRunnable, 58 onStopRunnable); 59 60 if (channelDataManager.isDbLoadFinished()) { 61 sendChannelStatusRunnable.setDbLoadListener(null); 62 recurringRunner.start(); 63 } else { 64 // Start the recurring runnable after the channel DB is finished loading. 65 sendChannelStatusRunnable.setDbLoadListener( 66 new ChannelDataManager.Listener() { 67 @Override 68 public void onLoadFinished() { 69 // This is called inside an iterator of Listeners so the remove step is 70 // done 71 // via a post on the main thread 72 new Handler(Looper.getMainLooper()) 73 .post( 74 new Runnable() { 75 @Override 76 public void run() { 77 sendChannelStatusRunnable.setDbLoadListener( 78 null); 79 } 80 }); 81 recurringRunner.start(); 82 } 83 84 @Override 85 public void onChannelListUpdated() {} 86 87 @Override 88 public void onChannelBrowsableChanged() {} 89 }); 90 } 91 return recurringRunner; 92 } 93 94 private final ChannelDataManager mChannelDataManager; 95 private final Tracker mTracker; 96 private ChannelDataManager.Listener mListener; 97 98 private SendChannelStatusRunnable(ChannelDataManager channelDataManager, Tracker tracker) { 99 mChannelDataManager = channelDataManager; 100 mTracker = tracker; 101 } 102 103 @Override 104 public void run() { 105 int browsableChannelCount = 0; 106 List<Channel> channelList = mChannelDataManager.getChannelList(); 107 for (Channel channel : channelList) { 108 if (channel.isBrowsable()) { 109 ++browsableChannelCount; 110 } 111 } 112 mTracker.sendChannelCount(browsableChannelCount, channelList.size()); 113 } 114 115 private void setDbLoadListener(ChannelDataManager.Listener listener) { 116 if (mListener != null) { 117 mChannelDataManager.removeListener(mListener); 118 } 119 mListener = listener; 120 if (listener != null) { 121 mChannelDataManager.addListener(listener); 122 } 123 } 124 } 125