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