1 /* 2 * Copyright (C) 2015 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.usbtuner.setup; 18 19 import android.app.Fragment; 20 import android.app.FragmentManager; 21 import android.app.Notification; 22 import android.app.NotificationManager; 23 import android.app.PendingIntent; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.res.Resources; 28 import android.graphics.Bitmap; 29 import android.graphics.BitmapFactory; 30 import android.media.tv.TvContract; 31 import android.os.Bundle; 32 import android.support.v4.app.NotificationCompat; 33 import android.view.KeyEvent; 34 35 import com.android.tv.common.TvCommonConstants; 36 import com.android.tv.common.TvCommonUtils; 37 import com.android.tv.common.ui.setup.SetupActivity; 38 import com.android.tv.common.ui.setup.SetupFragment; 39 import com.android.tv.common.ui.setup.SetupMultiPaneFragment; 40 import com.android.usbtuner.R; 41 import com.android.usbtuner.UsbTunerPreferences; 42 import com.android.usbtuner.tvinput.UsbTunerTvInputService; 43 44 /** 45 * An activity that serves USB tuner setup process. 46 */ 47 public class TunerSetupActivity extends SetupActivity { 48 // For the recommendation card 49 private static final String TV_ACTIVITY_CLASS_NAME = "com.android.tv.TvActivity"; 50 private static final String NOTIFY_TAG = "UsbTunerSetup"; 51 private static final int NOTIFY_ID = 1000; 52 private static final String TAG_DRAWABLE = "drawable"; 53 private static final String TAG_ICON = "ic_launcher_s"; 54 55 private static final int CHANNEL_MAP_SCAN_FILE[] = { 56 R.raw.ut_us_atsc_center_frequencies_8vsb, 57 R.raw.ut_us_cable_standard_center_frequencies_qam256, 58 R.raw.ut_us_all, 59 R.raw.ut_kr_atsc_center_frequencies_8vsb, 60 R.raw.ut_kr_cable_standard_center_frequencies_qam256, 61 R.raw.ut_kr_all, 62 R.raw.ut_kr_dev_cj_cable_center_frequencies_qam256}; 63 64 private ScanFragment mLastScanFragment; 65 66 @Override onCreateInitialFragment()67 protected Fragment onCreateInitialFragment() { 68 SetupFragment fragment = new WelcomeFragment(); 69 fragment.setShortDistance(SetupFragment.FRAGMENT_EXIT_TRANSITION 70 | SetupFragment.FRAGMENT_REENTER_TRANSITION); 71 return fragment; 72 } 73 74 @Override executeAction(String category, int actionId)75 protected void executeAction(String category, int actionId) { 76 switch (category) { 77 case WelcomeFragment.ACTION_CATEGORY: 78 switch (actionId) { 79 case SetupMultiPaneFragment.ACTION_DONE: 80 // If the scan was performed, then the result should be OK. 81 setResult(mLastScanFragment == null ? RESULT_CANCELED : RESULT_OK); 82 finish(); 83 break; 84 default: { 85 SetupFragment fragment = new ConnectionTypeFragment(); 86 fragment.setShortDistance(SetupFragment.FRAGMENT_ENTER_TRANSITION 87 | SetupFragment.FRAGMENT_RETURN_TRANSITION); 88 showFragment(fragment, true); 89 break; 90 } 91 } 92 break; 93 case ConnectionTypeFragment.ACTION_CATEGORY: 94 mLastScanFragment = new ScanFragment(); 95 Bundle args = new Bundle(); 96 args.putInt(ScanFragment.EXTRA_FOR_CHANNEL_SCAN_FILE, CHANNEL_MAP_SCAN_FILE[actionId]); 97 mLastScanFragment.setArguments(args); 98 showFragment(mLastScanFragment, true); 99 break; 100 case ScanFragment.ACTION_CATEGORY: 101 switch (actionId) { 102 case ScanFragment.ACTION_CANCEL: 103 getFragmentManager().popBackStack(); 104 break; 105 case ScanFragment.ACTION_FINISH: 106 SetupFragment fragment = new ScanResultFragment(); 107 fragment.setShortDistance(SetupFragment.FRAGMENT_EXIT_TRANSITION 108 | SetupFragment.FRAGMENT_REENTER_TRANSITION); 109 showFragment(fragment, true); 110 break; 111 } 112 break; 113 case ScanResultFragment.ACTION_CATEGORY: 114 switch (actionId) { 115 case SetupMultiPaneFragment.ACTION_DONE: 116 setResult(RESULT_OK); 117 finish(); 118 break; 119 default: 120 SetupFragment fragment = new ConnectionTypeFragment(); 121 fragment.setShortDistance(SetupFragment.FRAGMENT_ENTER_TRANSITION 122 | SetupFragment.FRAGMENT_RETURN_TRANSITION); 123 showFragment(fragment, true); 124 break; 125 } 126 break; 127 } 128 } 129 130 @Override onKeyUp(int keyCode, KeyEvent event)131 public boolean onKeyUp(int keyCode, KeyEvent event) { 132 if (keyCode == KeyEvent.KEYCODE_BACK) { 133 FragmentManager manager = getFragmentManager(); 134 int count = manager.getBackStackEntryCount(); 135 if (count > 0) { 136 String lastTag = manager.getBackStackEntryAt(count - 1).getName(); 137 if (ScanResultFragment.class.getCanonicalName().equals(lastTag) && count >= 2) { 138 // Pops fragment including ScanFragment. 139 manager.popBackStack(manager.getBackStackEntryAt(count - 2).getName(), 140 FragmentManager.POP_BACK_STACK_INCLUSIVE); 141 return true; 142 } else if (ScanFragment.class.getCanonicalName().equals(lastTag)) { 143 mLastScanFragment.finishScan(true); 144 return true; 145 } 146 } 147 } 148 return super.onKeyUp(keyCode, event); 149 } 150 151 /** 152 * A callback to be invoked when the TvInputService is enabled or disabled. 153 * 154 * @param context a {@link Context} instance 155 * @param enabled {@code true} for the {@link UsbTunerTvInputService} to be enabled; 156 * otherwise {@code false} 157 */ onTvInputEnabled(Context context, boolean enabled)158 public static void onTvInputEnabled(Context context, boolean enabled) { 159 // Send a recommendation card for USB channel tuner setup 160 // if there's no channels and the USB tuner TV input setup has been not done. 161 boolean channelScanDoneOnPreference = UsbTunerPreferences.isScanDone(context); 162 int channelCountOnPreference = UsbTunerPreferences.getScannedChannelCount(context); 163 if (enabled && !channelScanDoneOnPreference && channelCountOnPreference == 0) { 164 UsbTunerPreferences.setShouldShowSetupActivity(context, true); 165 sendRecommendationCard(context); 166 } else { 167 UsbTunerPreferences.setShouldShowSetupActivity(context, false); 168 cancelRecommendationCard(context); 169 } 170 } 171 172 /** 173 * Returns a {@link Intent} to launch the USB tuner TV input service. 174 * 175 * @param context a {@link Context} instance 176 */ createSetupActivity(Context context)177 public static Intent createSetupActivity(Context context) { 178 String inputId = TvContract.buildInputId(new ComponentName(context.getPackageName(), 179 UsbTunerTvInputService.class.getName())); 180 181 // Make an intent to launch the setup activity of USB tuner TV input. 182 Intent intent = TvCommonUtils.createSetupIntent( 183 new Intent(context, TunerSetupActivity.class), inputId); 184 intent.putExtra(TvCommonConstants.EXTRA_INPUT_ID, inputId); 185 Intent tvActivityIntent = new Intent(); 186 tvActivityIntent.setComponent(new ComponentName(context, TV_ACTIVITY_CLASS_NAME)); 187 intent.putExtra(TvCommonConstants.EXTRA_ACTIVITY_AFTER_COMPLETION, tvActivityIntent); 188 return intent; 189 } 190 191 /** 192 * Returns a {@link PendingIntent} to launch the USB tuner TV input service. 193 * 194 * @param context a {@link Context} instance 195 */ createPendingIntentForSetupActivity(Context context)196 private static PendingIntent createPendingIntentForSetupActivity(Context context) { 197 return PendingIntent.getActivity(context, 0, createSetupActivity(context), 198 PendingIntent.FLAG_UPDATE_CURRENT); 199 } 200 201 /** 202 * Sends the recommendation card to start the USB tuner TV input setup activity. 203 * 204 * @param context a {@link Context} instance 205 */ sendRecommendationCard(Context context)206 private static void sendRecommendationCard(Context context) { 207 Resources resources = context.getResources(); 208 String focusedTitle = resources.getString( 209 R.string.ut_setup_recommendation_card_focused_title); 210 String title = resources.getString(R.string.ut_setup_recommendation_card_title); 211 Bitmap largeIcon = BitmapFactory.decodeResource(resources, 212 R.drawable.recommendation_antenna); 213 214 // Build and send the notification. 215 Notification notification = new NotificationCompat.BigPictureStyle( 216 new NotificationCompat.Builder(context) 217 .setAutoCancel(false) 218 .setContentTitle(focusedTitle) 219 .setContentText(title) 220 .setContentInfo(title) 221 .setCategory(Notification.CATEGORY_RECOMMENDATION) 222 .setLargeIcon(largeIcon) 223 .setSmallIcon(resources.getIdentifier( 224 TAG_ICON, TAG_DRAWABLE, context.getPackageName())) 225 .setContentIntent(createPendingIntentForSetupActivity(context))) 226 .build(); 227 NotificationManager notificationManager = (NotificationManager) context 228 .getSystemService(Context.NOTIFICATION_SERVICE); 229 notificationManager.notify(NOTIFY_TAG, NOTIFY_ID, notification); 230 } 231 232 /** 233 * Cancels the previously shown recommendation card. 234 * 235 * @param context a {@link Context} instance 236 */ cancelRecommendationCard(Context context)237 public static void cancelRecommendationCard(Context context) { 238 NotificationManager notificationManager = (NotificationManager) context 239 .getSystemService(Context.NOTIFICATION_SERVICE); 240 notificationManager.cancel(NOTIFY_TAG, NOTIFY_ID); 241 } 242 } 243