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
17package com.android.nfc;
18
19import com.android.nfc.beam.SendUi;
20
21import android.app.NotificationManager;
22import android.content.Context;
23import android.content.res.Configuration;
24import android.os.Vibrator;
25
26/**
27 * Manages vibration, sound and animation for P2P events.
28 */
29public 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
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
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
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
95    public void onP2pTimeoutWaitingForLink() {
96        if (mSendUi != null) {
97            mSendUi.finish(SendUi.FINISH_SCALE_UP);
98        }
99    }
100
101    @Override
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
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
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
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
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
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
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
184    public void onCanceled() {
185        mSendUi.finish(SendUi.FINISH_SCALE_UP);
186        mCallback.onP2pCanceled();
187    }
188
189    @Override
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
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}
211