1 /*
2  * Copyright (C) 2011 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.nfc;
18 
19 import com.android.nfc.beam.SendUi;
20 
21 import android.app.NotificationManager;
22 import android.content.Context;
23 import android.content.res.Configuration;
24 import android.os.Vibrator;
25 
26 /**
27  * Manages vibration, sound and animation for P2P events.
28  */
29 public class P2pEventManager implements P2pEventListener, SendUi.Callback {
30     static final String TAG = "NfcP2pEventManager";
31     static final boolean DBG = true;
32 
33     static final long[] VIBRATION_PATTERN = {0, 100, 10000};
34 
35     final Context mContext;
36     final NfcService mNfcService;
37     final P2pEventListener.Callback mCallback;
38     final Vibrator mVibrator;
39     final NotificationManager mNotificationManager;
40     final SendUi mSendUi;
41 
42     // only used on UI thread
43     boolean mSending;
44     boolean mNdefSent;
45     boolean mNdefReceived;
46     boolean mInDebounce;
47 
P2pEventManager(Context context, P2pEventListener.Callback callback)48     public P2pEventManager(Context context, P2pEventListener.Callback callback) {
49         mNfcService = NfcService.getInstance();
50         mContext = context;
51         mCallback = callback;
52         mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
53         mNotificationManager = (NotificationManager) mContext.getSystemService(
54                 Context.NOTIFICATION_SERVICE);
55 
56         mSending = false;
57         final int uiModeType = mContext.getResources().getConfiguration().uiMode
58                 & Configuration.UI_MODE_TYPE_MASK;
59         if (uiModeType == Configuration.UI_MODE_TYPE_APPLIANCE) {
60             // "Appliances" don't intrinsically have a way of confirming this, so we
61             // don't use the UI and just autoconfirm where necessary.
62             // Don't instantiate SendUi or else we'll use memory and never reclaim it.
63             mSendUi = null;
64         } else {
65             mSendUi = new SendUi(context, this);
66         }
67     }
68 
69     @Override
onP2pInRange()70     public void onP2pInRange() {
71         mNdefSent = false;
72         mNdefReceived = false;
73         mInDebounce = false;
74 
75         if (mSendUi != null) {
76             mSendUi.takeScreenshot();
77         }
78     }
79 
80     @Override
onP2pNfcTapRequested()81     public void onP2pNfcTapRequested() {
82         mNfcService.playSound(NfcService.SOUND_START);
83         mNdefSent = false;
84         mNdefReceived = false;
85         mInDebounce = false;
86 
87         mVibrator.vibrate(VIBRATION_PATTERN, -1);
88         if (mSendUi != null) {
89             mSendUi.takeScreenshot();
90             mSendUi.showPreSend(true);
91         }
92     }
93 
94     @Override
onP2pTimeoutWaitingForLink()95     public void onP2pTimeoutWaitingForLink() {
96         if (mSendUi != null) {
97             mSendUi.finish(SendUi.FINISH_SCALE_UP);
98         }
99     }
100 
101     @Override
onP2pSendConfirmationRequested()102     public void onP2pSendConfirmationRequested() {
103         mNfcService.playSound(NfcService.SOUND_START);
104         mVibrator.vibrate(VIBRATION_PATTERN, -1);
105         if (mSendUi != null) {
106             mSendUi.showPreSend(false);
107         } else {
108             mCallback.onP2pSendConfirmed();
109         }
110     }
111 
112     @Override
onP2pSendComplete()113     public void onP2pSendComplete() {
114         mNfcService.playSound(NfcService.SOUND_END);
115         mVibrator.vibrate(VIBRATION_PATTERN, -1);
116         if (mSendUi != null) {
117             mSendUi.finish(SendUi.FINISH_SEND_SUCCESS);
118         }
119         mSending = false;
120         mNdefSent = true;
121     }
122 
123     @Override
onP2pHandoverNotSupported()124     public void onP2pHandoverNotSupported() {
125         mNfcService.playSound(NfcService.SOUND_ERROR);
126         mVibrator.vibrate(VIBRATION_PATTERN, -1);
127         mSendUi.finishAndToast(SendUi.FINISH_SCALE_UP,
128                 mContext.getString(R.string.beam_handover_not_supported));
129         mSending = false;
130         mNdefSent = false;
131     }
132 
133     @Override
onP2pHandoverBusy()134     public void onP2pHandoverBusy() {
135         mNfcService.playSound(NfcService.SOUND_ERROR);
136         mVibrator.vibrate(VIBRATION_PATTERN, -1);
137         mSendUi.finishAndToast(SendUi.FINISH_SCALE_UP, mContext.getString(R.string.beam_busy));
138         mSending = false;
139         mNdefSent = false;
140     }
141 
142     @Override
onP2pReceiveComplete(boolean playSound)143     public void onP2pReceiveComplete(boolean playSound) {
144         mVibrator.vibrate(VIBRATION_PATTERN, -1);
145         if (playSound) mNfcService.playSound(NfcService.SOUND_END);
146         if (mSendUi != null) {
147             // TODO we still don't have a nice receive solution
148             // The sanest solution right now is just to scale back up what we had
149             // and start the new activity. It is not perfect, but at least it is
150             // consistent behavior. All other variants involve making the old
151             // activity screenshot disappear, and then removing the animation
152             // window hoping the new activity has started by then. This just goes
153             // wrong too often and can look weird.
154             mSendUi.finish(SendUi.FINISH_SCALE_UP);
155         }
156         mNdefReceived = true;
157     }
158 
159     @Override
onP2pOutOfRange()160     public void onP2pOutOfRange() {
161         if (mSending) {
162             mNfcService.playSound(NfcService.SOUND_ERROR);
163             mSending = false;
164         }
165         if (!mNdefSent && !mNdefReceived && mSendUi != null) {
166             mSendUi.finish(SendUi.FINISH_SCALE_UP);
167         }
168         mInDebounce = false;
169     }
170 
171     @Override
onSendConfirmed()172     public void onSendConfirmed() {
173         if (!mSending) {
174             if (mSendUi != null) {
175                 mSendUi.showStartSend();
176             }
177             mCallback.onP2pSendConfirmed();
178         }
179         mSending = true;
180 
181     }
182 
183     @Override
onCanceled()184     public void onCanceled() {
185         mSendUi.finish(SendUi.FINISH_SCALE_UP);
186         mCallback.onP2pCanceled();
187     }
188 
189     @Override
onP2pSendDebounce()190     public void onP2pSendDebounce() {
191         mInDebounce = true;
192         mNfcService.playSound(NfcService.SOUND_ERROR);
193         if (mSendUi != null) {
194             mSendUi.showSendHint();
195         }
196     }
197 
198     @Override
onP2pResumeSend()199     public void onP2pResumeSend() {
200         mVibrator.vibrate(VIBRATION_PATTERN, -1);
201         mNfcService.playSound(NfcService.SOUND_START);
202         if (mInDebounce) {
203             if (mSendUi != null) {
204                 mSendUi.showStartSend();
205             }
206         }
207         mInDebounce = false;
208     }
209 
210     @Override
isP2pIdle()211     public boolean isP2pIdle() {
212         if (mSendUi != null && !mSendUi.isSendUiInIdleState()) {
213             return false;
214         }
215         return true;
216     }
217 }
218