1 /* 2 * Copyright (c) 2008-2009, Motorola, Inc. 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * - Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * - Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * - Neither the name of the Motorola, Inc. nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 package com.android.bluetooth.opp; 34 35 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; 36 37 import android.bluetooth.AlertActivity; 38 import android.bluetooth.BluetoothProfile; 39 import android.bluetooth.BluetoothProtoEnums; 40 import android.content.BroadcastReceiver; 41 import android.content.ContentValues; 42 import android.content.Context; 43 import android.content.DialogInterface; 44 import android.content.Intent; 45 import android.content.IntentFilter; 46 import android.net.Uri; 47 import android.os.Bundle; 48 import android.os.Handler; 49 import android.os.Message; 50 import android.text.format.Formatter; 51 import android.util.Log; 52 import android.view.KeyEvent; 53 import android.view.View; 54 import android.widget.TextView; 55 import android.widget.Toast; 56 57 import com.android.bluetooth.BluetoothMethodProxy; 58 import com.android.bluetooth.BluetoothStatsLog; 59 import com.android.bluetooth.R; 60 import com.android.bluetooth.content_profiles.ContentProfileErrorReportUtils; 61 import com.android.internal.annotations.VisibleForTesting; 62 63 /** This class is designed to ask user to confirm if accept incoming file; */ 64 // Next tag value for ContentProfileErrorReportUtils.report(): 1 65 public class BluetoothOppIncomingFileConfirmActivity extends AlertActivity { 66 private static final String TAG = "BluetoothIncomingFileConfirmActivity"; 67 68 @VisibleForTesting static final int DISMISS_TIMEOUT_DIALOG = 0; 69 70 @VisibleForTesting static final int DISMISS_TIMEOUT_DIALOG_VALUE = 2000; 71 72 private static final String PREFERENCE_USER_TIMEOUT = "user_timeout"; 73 74 private BluetoothOppTransferInfo mTransInfo; 75 76 private Uri mUri; 77 78 private ContentValues mUpdateValues; 79 80 private boolean mTimeout = false; 81 82 private BroadcastReceiver mReceiver = null; 83 84 @Override onCreate(Bundle savedInstanceState)85 protected void onCreate(Bundle savedInstanceState) { 86 setTheme(R.style.Theme_Material_Settings_Floating); 87 Log.v(TAG, "onCreate(): action = " + getIntent().getAction()); 88 super.onCreate(savedInstanceState); 89 90 getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); 91 Intent intent = getIntent(); 92 mUri = intent.getData(); 93 mTransInfo = new BluetoothOppTransferInfo(); 94 mTransInfo = BluetoothOppUtility.queryRecord(this, mUri); 95 if (mTransInfo == null) { 96 Log.w(TAG, "Error: Can not get data from db"); 97 ContentProfileErrorReportUtils.report( 98 BluetoothProfile.OPP, 99 BluetoothProtoEnums.BLUETOOTH_OPP_INCOMING_FILE_CONFIRM_ACTIVITY, 100 BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_ERROR, 101 0); 102 finish(); 103 return; 104 } 105 106 mAlertBuilder.setTitle(getString(R.string.incoming_file_confirm_content)); 107 mAlertBuilder.setView(createView()); 108 mAlertBuilder.setPositiveButton( 109 R.string.incoming_file_confirm_ok, (dialog, which) -> onIncomingFileConfirmOk()); 110 mAlertBuilder.setNegativeButton( 111 R.string.incoming_file_confirm_cancel, 112 (dialog, which) -> onIncomingFileConfirmCancel()); 113 114 setupAlert(); 115 Log.v(TAG, "mTimeout: " + mTimeout); 116 if (mTimeout) { 117 onTimeout(); 118 } 119 120 Log.v(TAG, "BluetoothIncomingFileConfirmActivity: Got uri:" + mUri); 121 122 mReceiver = 123 new BroadcastReceiver() { 124 @Override 125 public void onReceive(Context context, Intent intent) { 126 if (!BluetoothShare.USER_CONFIRMATION_TIMEOUT_ACTION.equals( 127 intent.getAction())) { 128 return; 129 } 130 onTimeout(); 131 } 132 }; 133 IntentFilter filter = new IntentFilter(BluetoothShare.USER_CONFIRMATION_TIMEOUT_ACTION); 134 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 135 registerReceiver(mReceiver, filter); 136 } 137 createView()138 private View createView() { 139 View view = getLayoutInflater().inflate(R.layout.incoming_dialog, null); 140 141 ((TextView) view.findViewById(R.id.from_content)).setText(mTransInfo.mDeviceName); 142 String fileName = mTransInfo.mFileName; 143 if (fileName != null) { 144 fileName = fileName.replace('\t', ' ').replace('\n', ' ').replace('\r', ' '); 145 } 146 ((TextView) view.findViewById(R.id.filename_content)).setText(fileName); 147 ((TextView) view.findViewById(R.id.size_content)) 148 .setText(Formatter.formatFileSize(this, mTransInfo.mTotalBytes)); 149 150 return view; 151 } 152 onIncomingFileConfirmOk()153 private void onIncomingFileConfirmOk() { 154 if (!mTimeout) { 155 // Update database 156 mUpdateValues = new ContentValues(); 157 mUpdateValues.put( 158 BluetoothShare.USER_CONFIRMATION, BluetoothShare.USER_CONFIRMATION_CONFIRMED); 159 BluetoothMethodProxy.getInstance() 160 .contentResolverUpdate( 161 this.getContentResolver(), mUri, mUpdateValues, null, null); 162 163 Toast.makeText(this, getString(R.string.bt_toast_1), Toast.LENGTH_SHORT).show(); 164 } 165 } 166 onIncomingFileConfirmCancel()167 private void onIncomingFileConfirmCancel() { 168 // Update database 169 mUpdateValues = new ContentValues(); 170 mUpdateValues.put( 171 BluetoothShare.USER_CONFIRMATION, BluetoothShare.USER_CONFIRMATION_DENIED); 172 BluetoothMethodProxy.getInstance() 173 .contentResolverUpdate(this.getContentResolver(), mUri, mUpdateValues, null, null); 174 } 175 176 @Override onKeyDown(int keyCode, KeyEvent event)177 public boolean onKeyDown(int keyCode, KeyEvent event) { 178 if (keyCode == KeyEvent.KEYCODE_BACK) { 179 Log.d(TAG, "onKeyDown() called; Key: back key"); 180 finish(); 181 return true; 182 } 183 return false; 184 } 185 186 @Override onDestroy()187 protected void onDestroy() { 188 super.onDestroy(); 189 if (mReceiver != null) { 190 unregisterReceiver(mReceiver); 191 } 192 } 193 194 @Override onRestoreInstanceState(Bundle savedInstanceState)195 protected void onRestoreInstanceState(Bundle savedInstanceState) { 196 super.onRestoreInstanceState(savedInstanceState); 197 mTimeout = savedInstanceState.getBoolean(PREFERENCE_USER_TIMEOUT); 198 Log.v(TAG, "onRestoreInstanceState() mTimeout: " + mTimeout); 199 if (mTimeout) { 200 onTimeout(); 201 } 202 } 203 204 @Override onSaveInstanceState(Bundle outState)205 protected void onSaveInstanceState(Bundle outState) { 206 super.onSaveInstanceState(outState); 207 Log.v(TAG, "onSaveInstanceState() mTimeout: " + mTimeout); 208 outState.putBoolean(PREFERENCE_USER_TIMEOUT, mTimeout); 209 } 210 onTimeout()211 private void onTimeout() { 212 mTimeout = true; 213 214 changeTitle( 215 getString(R.string.incoming_file_confirm_timeout_content, mTransInfo.mDeviceName)); 216 changeButtonVisibility(DialogInterface.BUTTON_NEGATIVE, View.GONE); 217 changeButtonText( 218 DialogInterface.BUTTON_POSITIVE, 219 getString(R.string.incoming_file_confirm_timeout_ok)); 220 221 BluetoothMethodProxy.getInstance() 222 .handlerSendMessageDelayed( 223 mTimeoutHandler, DISMISS_TIMEOUT_DIALOG, DISMISS_TIMEOUT_DIALOG_VALUE); 224 } 225 226 private final Handler mTimeoutHandler = 227 new Handler() { 228 @Override 229 public void handleMessage(Message msg) { 230 switch (msg.what) { 231 case DISMISS_TIMEOUT_DIALOG: 232 Log.v(TAG, "Received DISMISS_TIMEOUT_DIALOG msg."); 233 finish(); 234 break; 235 default: 236 break; 237 } 238 } 239 }; 240 } 241