• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.nearby.halfsheet;
18 
19 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
20 
21 import static com.android.nearby.halfsheet.constants.Constant.ACTION_FAST_PAIR_HALF_SHEET_BAN_STATE_RESET;
22 import static com.android.nearby.halfsheet.constants.Constant.ACTION_FAST_PAIR_HALF_SHEET_CANCEL;
23 import static com.android.nearby.halfsheet.constants.Constant.ACTION_HALF_SHEET_FOREGROUND_STATE;
24 import static com.android.nearby.halfsheet.constants.Constant.DEVICE_PAIRING_FRAGMENT_TYPE;
25 import static com.android.nearby.halfsheet.constants.Constant.EXTRA_HALF_SHEET_FOREGROUND;
26 import static com.android.nearby.halfsheet.constants.Constant.EXTRA_HALF_SHEET_INFO;
27 import static com.android.nearby.halfsheet.constants.Constant.EXTRA_HALF_SHEET_IS_RETROACTIVE;
28 import static com.android.nearby.halfsheet.constants.Constant.EXTRA_HALF_SHEET_IS_SUBSEQUENT_PAIR;
29 import static com.android.nearby.halfsheet.constants.Constant.EXTRA_HALF_SHEET_TYPE;
30 import static com.android.nearby.halfsheet.constants.Constant.TAG;
31 import static com.android.nearby.halfsheet.constants.FastPairConstants.EXTRA_MODEL_ID;
32 import static com.android.nearby.halfsheet.constants.UserActionHandlerBase.EXTRA_MAC_ADDRESS;
33 import static com.android.nearby.halfsheet.fragment.DevicePairingFragment.APP_LAUNCH_FRAGMENT_TYPE;
34 
35 import android.content.Intent;
36 import android.os.Bundle;
37 import android.util.Log;
38 import android.widget.TextView;
39 
40 import androidx.annotation.NonNull;
41 import androidx.annotation.Nullable;
42 import androidx.fragment.app.FragmentActivity;
43 
44 import com.android.nearby.halfsheet.fragment.DevicePairingFragment;
45 import com.android.nearby.halfsheet.fragment.HalfSheetModuleFragment;
46 import com.android.nearby.halfsheet.utils.BroadcastUtils;
47 
48 import com.google.protobuf.InvalidProtocolBufferException;
49 
50 import java.util.Locale;
51 
52 import service.proto.Cache;
53 
54 /**
55  * A class show Fast Pair related information in Half sheet format.
56  */
57 public class HalfSheetActivity extends FragmentActivity {
58     @Nullable
59     private HalfSheetModuleFragment mHalfSheetModuleFragment;
60     @Nullable
61     private Cache.ScanFastPairStoreItem mScanFastPairStoreItem;
62 
63     @Override
onCreate(@ullable Bundle savedInstanceState)64     protected void onCreate(@Nullable Bundle savedInstanceState) {
65         super.onCreate(savedInstanceState);
66         byte[] infoArray = getIntent().getByteArrayExtra(EXTRA_HALF_SHEET_INFO);
67         String fragmentType = getIntent().getStringExtra(EXTRA_HALF_SHEET_TYPE);
68         if (infoArray == null || fragmentType == null) {
69             Log.d(
70                     "HalfSheetActivity",
71                     "exit flag off or do not have enough half sheet information.");
72             finish();
73             return;
74         }
75 
76         switch (fragmentType) {
77             case DEVICE_PAIRING_FRAGMENT_TYPE:
78                 mHalfSheetModuleFragment = DevicePairingFragment.newInstance(getIntent(),
79                         savedInstanceState);
80                 if (mHalfSheetModuleFragment == null) {
81                     Log.d(TAG, "device pairing fragment has error.");
82                     finish();
83                     return;
84                 }
85                 break;
86             case APP_LAUNCH_FRAGMENT_TYPE:
87                 // currentFragment = AppLaunchFragment.newInstance(getIntent());
88                 if (mHalfSheetModuleFragment == null) {
89                     Log.v(TAG, "app launch fragment has error.");
90                     finish();
91                     return;
92                 }
93                 break;
94             default:
95                 Log.w(TAG, "there is no valid type for half sheet");
96                 finish();
97                 return;
98         }
99         if (mHalfSheetModuleFragment != null) {
100             getSupportFragmentManager()
101                     .beginTransaction()
102                     .replace(R.id.fragment_container, mHalfSheetModuleFragment)
103                     .commit();
104         }
105         setContentView(R.layout.fast_pair_half_sheet);
106 
107         // If the user taps on the background, then close the activity.
108         // Unless they tap on the card itself, then ignore the tap.
109         findViewById(R.id.background).setOnClickListener(v -> onCancelClicked());
110         findViewById(R.id.card)
111                 .setOnClickListener(
112                         v -> Log.v(TAG, "card view is clicked noop"));
113         try {
114             mScanFastPairStoreItem =
115                     Cache.ScanFastPairStoreItem.parseFrom(infoArray);
116         } catch (InvalidProtocolBufferException e) {
117             Log.w(
118                     TAG, "error happens when pass info to half sheet");
119         }
120     }
121 
122     @Override
onStart()123     protected void onStart() {
124         super.onStart();
125         BroadcastUtils.sendBroadcast(
126                 this,
127                 new Intent(ACTION_HALF_SHEET_FOREGROUND_STATE)
128                         .putExtra(EXTRA_HALF_SHEET_FOREGROUND, true));
129     }
130 
131     @Override
onSaveInstanceState(@onNull Bundle savedInstanceState)132     protected void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
133         super.onSaveInstanceState(savedInstanceState);
134         if (mHalfSheetModuleFragment != null) {
135             mHalfSheetModuleFragment.onSaveInstanceState(savedInstanceState);
136         }
137     }
138 
139     @Override
onBackPressed()140     public void onBackPressed() {
141         super.onBackPressed();
142         sendHalfSheetCancelBroadcast();
143     }
144 
145     @Override
onUserLeaveHint()146     protected void onUserLeaveHint() {
147         super.onUserLeaveHint();
148         sendHalfSheetCancelBroadcast();
149     }
150 
151     @Override
onNewIntent(Intent intent)152     protected void onNewIntent(Intent intent) {
153         super.onNewIntent(intent);
154         String fragmentType = getIntent().getStringExtra(EXTRA_HALF_SHEET_TYPE);
155         if (fragmentType == null) {
156             return;
157         }
158         if (fragmentType.equals(DEVICE_PAIRING_FRAGMENT_TYPE)
159                 && intent.getExtras() != null
160                 && intent.getByteArrayExtra(EXTRA_HALF_SHEET_INFO) != null) {
161             try {
162                 Cache.ScanFastPairStoreItem testScanFastPairStoreItem =
163                         Cache.ScanFastPairStoreItem.parseFrom(
164                                 intent.getByteArrayExtra(EXTRA_HALF_SHEET_INFO));
165                 if (mScanFastPairStoreItem != null
166                         && !testScanFastPairStoreItem.getAddress().equals(
167                         mScanFastPairStoreItem.getAddress())
168                         && testScanFastPairStoreItem.getModelId().equals(
169                         mScanFastPairStoreItem.getModelId())) {
170                     Log.d(TAG, "possible factory reset happens");
171                     halfSheetStateChange();
172                 }
173             } catch (InvalidProtocolBufferException | NullPointerException e) {
174                 Log.w(TAG, "error happens when pass info to half sheet");
175             }
176         }
177     }
178 
179     /** This function should be called when user click empty area and cancel button. */
onCancelClicked()180     public void onCancelClicked() {
181         Log.d(TAG, "Cancels the half sheet and paring.");
182         sendHalfSheetCancelBroadcast();
183         finish();
184     }
185 
186     /** Changes the half sheet foreground state to false. */
halfSheetStateChange()187     public void halfSheetStateChange() {
188         BroadcastUtils.sendBroadcast(
189                 this,
190                 new Intent(ACTION_HALF_SHEET_FOREGROUND_STATE)
191                         .putExtra(EXTRA_HALF_SHEET_FOREGROUND, false));
192         finish();
193     }
194 
195 
196     /**
197      * Changes the half sheet ban state to active.
198      * Sometimes users leave half sheet to go to fast pair info page,
199      * we do not want the behavior to be counted as dismiss.
200      */
sendBanStateResetBroadcast()201     public void sendBanStateResetBroadcast() {
202         if (mScanFastPairStoreItem == null) {
203             return;
204         }
205         BroadcastUtils.sendBroadcast(
206                 this,
207                 new Intent(ACTION_FAST_PAIR_HALF_SHEET_BAN_STATE_RESET)
208                         .putExtra(EXTRA_MODEL_ID, mScanFastPairStoreItem.getModelId()
209                                 .toLowerCase(Locale.ROOT)));
210     }
211 
sendHalfSheetCancelBroadcast()212     private void sendHalfSheetCancelBroadcast() {
213         BroadcastUtils.sendBroadcast(
214                 this,
215                 new Intent(ACTION_HALF_SHEET_FOREGROUND_STATE)
216                         .putExtra(EXTRA_HALF_SHEET_FOREGROUND, false));
217         if (mScanFastPairStoreItem == null) {
218             return;
219         }
220         BroadcastUtils.sendBroadcast(
221                 this,
222                 new Intent(ACTION_FAST_PAIR_HALF_SHEET_CANCEL)
223                         .putExtra(EXTRA_MODEL_ID,
224                                 mScanFastPairStoreItem.getModelId().toLowerCase(Locale.ROOT))
225                         .putExtra(EXTRA_HALF_SHEET_TYPE,
226                                 getIntent().getStringExtra(EXTRA_HALF_SHEET_TYPE))
227                         .putExtra(
228                                 EXTRA_HALF_SHEET_IS_SUBSEQUENT_PAIR,
229                                 getIntent().getBooleanExtra(EXTRA_HALF_SHEET_IS_SUBSEQUENT_PAIR,
230                                         false))
231                         .putExtra(
232                                 EXTRA_HALF_SHEET_IS_RETROACTIVE,
233                                 getIntent().getBooleanExtra(EXTRA_HALF_SHEET_IS_RETROACTIVE,
234                                         false))
235                         .putExtra(EXTRA_MAC_ADDRESS, mScanFastPairStoreItem.getAddress()),
236                 ACCESS_FINE_LOCATION);
237     }
238 
239     @Override
setTitle(CharSequence title)240     public void setTitle(CharSequence title) {
241         super.setTitle(title);
242         TextView toolbarTitle = findViewById(R.id.toolbar_title);
243         toolbarTitle.setText(title);
244     }
245 }
246