• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.tv.onboarding;
18 
19 import android.app.Fragment;
20 import android.content.ActivityNotFoundException;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.PackageManager;
25 import android.media.tv.TvInputInfo;
26 import android.os.Bundle;
27 import android.support.annotation.NonNull;
28 import android.widget.Toast;
29 import com.android.tv.R;
30 import com.android.tv.SetupPassthroughActivity;
31 import com.android.tv.TvSingletons;
32 import com.android.tv.common.ui.setup.SetupActivity;
33 import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
34 import com.android.tv.common.util.CommonUtils;
35 import com.android.tv.common.util.PermissionUtils;
36 import com.android.tv.data.ChannelDataManager;
37 import com.android.tv.util.OnboardingUtils;
38 import com.android.tv.util.SetupUtils;
39 import com.android.tv.util.TvInputManagerHelper;
40 import dagger.android.AndroidInjection;
41 import dagger.android.ContributesAndroidInjector;
42 import javax.inject.Inject;
43 
44 public class OnboardingActivity extends SetupActivity {
45     private static final String KEY_INTENT_AFTER_COMPLETION = "key_intent_after_completion";
46 
47     private static final int PERMISSIONS_REQUEST_READ_TV_LISTINGS = 1;
48 
49     private static final int SHOW_RIPPLE_DURATION_MS = 266;
50 
51     private static final int REQUEST_CODE_START_SETUP_ACTIVITY = 1;
52 
53     @Inject ChannelDataManager mChannelDataManager;
54     private TvInputManagerHelper mInputManager;
55     @Inject SetupUtils mSetupUtils;
56     private final ChannelDataManager.Listener mChannelListener =
57             new ChannelDataManager.Listener() {
58                 @Override
59                 public void onLoadFinished() {
60                     mChannelDataManager.removeListener(this);
61                     mSetupUtils.markNewChannelsBrowsable();
62                 }
63 
64                 @Override
65                 public void onChannelListUpdated() {}
66 
67                 @Override
68                 public void onChannelBrowsableChanged() {}
69             };
70 
71     /**
72      * Returns an intent to start {@link OnboardingActivity}.
73      *
74      * @param context context to create an intent. Should not be {@code null}.
75      * @param intentAfterCompletion intent which will be used to start a new activity when this
76      *     activity finishes. Should not be {@code null}.
77      */
buildIntent( @onNull Context context, @NonNull Intent intentAfterCompletion)78     public static Intent buildIntent(
79             @NonNull Context context, @NonNull Intent intentAfterCompletion) {
80         return new Intent(context, OnboardingActivity.class)
81                 .putExtra(OnboardingActivity.KEY_INTENT_AFTER_COMPLETION, intentAfterCompletion);
82     }
83 
84     @Override
onCreate(Bundle savedInstanceState)85     protected void onCreate(Bundle savedInstanceState) {
86         AndroidInjection.inject(this);
87         super.onCreate(savedInstanceState);
88         TvSingletons singletons = TvSingletons.getSingletons(this);
89         mInputManager = singletons.getTvInputManagerHelper();
90         if (PermissionUtils.hasAccessAllEpg(this) || PermissionUtils.hasReadTvListings(this)) {
91             // Make the channels of the new inputs which have been setup outside Live TV
92             // browsable.
93             if (mChannelDataManager.isDbLoadFinished()) {
94                 mSetupUtils.markNewChannelsBrowsable();
95             } else {
96                 mChannelDataManager.addListener(mChannelListener);
97             }
98         } else {
99             requestPermissions(
100                     new String[] {PermissionUtils.PERMISSION_READ_TV_LISTINGS},
101                     PERMISSIONS_REQUEST_READ_TV_LISTINGS);
102         }
103     }
104 
105     @Override
onDestroy()106     protected void onDestroy() {
107         if (mChannelDataManager != null) {
108             mChannelDataManager.removeListener(mChannelListener);
109         }
110         super.onDestroy();
111     }
112 
113     @Override
onCreateInitialFragment()114     protected Fragment onCreateInitialFragment() {
115         if (PermissionUtils.hasAccessAllEpg(this) || PermissionUtils.hasReadTvListings(this)) {
116             return OnboardingUtils.isFirstRunWithCurrentVersion(this)
117                     ? new WelcomeFragment()
118                     : new SetupSourcesFragment();
119         }
120         return null;
121     }
122 
123     @Override
onRequestPermissionsResult( int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)124     public void onRequestPermissionsResult(
125             int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
126         if (requestCode == PERMISSIONS_REQUEST_READ_TV_LISTINGS) {
127             if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
128                 finish();
129                 Intent intentForNextActivity =
130                         getIntent().getParcelableExtra(KEY_INTENT_AFTER_COMPLETION);
131                 startActivity(buildIntent(this, intentForNextActivity));
132             } else {
133                 Toast.makeText(
134                                 this,
135                                 R.string.msg_read_tv_listing_permission_denied,
136                                 Toast.LENGTH_LONG)
137                         .show();
138                 finish();
139             }
140         }
141     }
142 
finishActivity()143     private void finishActivity() {
144         Intent intentForNextActivity = getIntent().getParcelableExtra(KEY_INTENT_AFTER_COMPLETION);
145         if (intentForNextActivity != null) {
146             startActivity(intentForNextActivity);
147         }
148         finish();
149     }
150 
showMerchantCollection()151     private void showMerchantCollection() {
152         executeActionWithDelay(
153                 () -> startActivity(OnboardingUtils.ONLINE_STORE_INTENT), SHOW_RIPPLE_DURATION_MS);
154     }
155 
156     @Override
executeAction(String category, int actionId, Bundle params)157     protected boolean executeAction(String category, int actionId, Bundle params) {
158         switch (category) {
159             case WelcomeFragment.ACTION_CATEGORY:
160                 switch (actionId) {
161                     case WelcomeFragment.ACTION_NEXT:
162                         OnboardingUtils.setFirstRunWithCurrentVersionCompleted(
163                                 OnboardingActivity.this);
164                         showFragment(new SetupSourcesFragment(), false);
165                         return true;
166                 }
167                 break;
168             case SetupSourcesFragment.ACTION_CATEGORY:
169                 switch (actionId) {
170                     case SetupSourcesFragment.ACTION_ONLINE_STORE:
171                         showMerchantCollection();
172                         return true;
173                     case SetupSourcesFragment.ACTION_SETUP_INPUT:
174                         {
175                             String inputId =
176                                     params.getString(
177                                             SetupSourcesFragment.ACTION_PARAM_KEY_INPUT_ID);
178                             TvInputInfo input = mInputManager.getTvInputInfo(inputId);
179                             Intent intent = CommonUtils.createSetupIntent(input);
180                             if (intent == null) {
181                                 Toast.makeText(
182                                                 this,
183                                                 R.string.msg_no_setup_activity,
184                                                 Toast.LENGTH_SHORT)
185                                         .show();
186                                 return true;
187                             }
188                             // Even though other app can handle the intent, the setup launched by
189                             // Live
190                             // channels should go through Live channels SetupPassthroughActivity.
191                             intent.setComponent(
192                                     new ComponentName(this, SetupPassthroughActivity.class));
193                             try {
194                                 // Now we know that the user intends to set up this input. Grant
195                                 // permission for writing EPG data.
196                                 SetupUtils.grantEpgPermission(
197                                         this, input.getServiceInfo().packageName);
198                                 startActivityForResult(intent, REQUEST_CODE_START_SETUP_ACTIVITY);
199                             } catch (ActivityNotFoundException e) {
200                                 Toast.makeText(
201                                                 this,
202                                                 getString(
203                                                         R.string.msg_unable_to_start_setup_activity,
204                                                         input.loadLabel(this)),
205                                                 Toast.LENGTH_SHORT)
206                                         .show();
207                             }
208                             return true;
209                         }
210                     case SetupMultiPaneFragment.ACTION_DONE:
211                         {
212                             ChannelDataManager manager =
213                                     TvSingletons.getSingletons(OnboardingActivity.this)
214                                             .getChannelDataManager();
215                             if (manager.getChannelCount() == 0) {
216                                 finish();
217                             } else {
218                                 finishActivity();
219                             }
220                             return true;
221                         }
222                 }
223                 break;
224         }
225         return false;
226     }
227 
228     /** Exports {@link OnboardingActivity} for Dagger codegen to create the appropriate injector. */
229     @dagger.Module
230     public abstract static class Module {
231         @ContributesAndroidInjector
contributeOnboardingActivityInjector()232         abstract OnboardingActivity contributeOnboardingActivityInjector();
233     }
234 }
235