1*90c8c64dSAndroid Build Coastguard Worker /*
2*90c8c64dSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*90c8c64dSAndroid Build Coastguard Worker  *
4*90c8c64dSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*90c8c64dSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*90c8c64dSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*90c8c64dSAndroid Build Coastguard Worker  *
8*90c8c64dSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*90c8c64dSAndroid Build Coastguard Worker  *
10*90c8c64dSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*90c8c64dSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*90c8c64dSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*90c8c64dSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*90c8c64dSAndroid Build Coastguard Worker  * limitations under the License.
15*90c8c64dSAndroid Build Coastguard Worker  */
16*90c8c64dSAndroid Build Coastguard Worker 
17*90c8c64dSAndroid Build Coastguard Worker package com.example.android.bluetoothadvertisements;
18*90c8c64dSAndroid Build Coastguard Worker 
19*90c8c64dSAndroid Build Coastguard Worker import android.bluetooth.le.AdvertiseCallback;
20*90c8c64dSAndroid Build Coastguard Worker import android.content.BroadcastReceiver;
21*90c8c64dSAndroid Build Coastguard Worker import android.content.Context;
22*90c8c64dSAndroid Build Coastguard Worker import android.content.Intent;
23*90c8c64dSAndroid Build Coastguard Worker import android.content.IntentFilter;
24*90c8c64dSAndroid Build Coastguard Worker import android.os.Bundle;
25*90c8c64dSAndroid Build Coastguard Worker import android.support.v4.app.Fragment;
26*90c8c64dSAndroid Build Coastguard Worker import android.view.LayoutInflater;
27*90c8c64dSAndroid Build Coastguard Worker import android.view.View;
28*90c8c64dSAndroid Build Coastguard Worker import android.view.ViewGroup;
29*90c8c64dSAndroid Build Coastguard Worker import android.widget.Switch;
30*90c8c64dSAndroid Build Coastguard Worker import android.widget.Toast;
31*90c8c64dSAndroid Build Coastguard Worker 
32*90c8c64dSAndroid Build Coastguard Worker /**
33*90c8c64dSAndroid Build Coastguard Worker  * Allows user to start & stop Bluetooth LE Advertising of their device.
34*90c8c64dSAndroid Build Coastguard Worker  */
35*90c8c64dSAndroid Build Coastguard Worker public class AdvertiserFragment extends Fragment implements View.OnClickListener {
36*90c8c64dSAndroid Build Coastguard Worker 
37*90c8c64dSAndroid Build Coastguard Worker     /**
38*90c8c64dSAndroid Build Coastguard Worker      * Lets user toggle BLE Advertising.
39*90c8c64dSAndroid Build Coastguard Worker      */
40*90c8c64dSAndroid Build Coastguard Worker     private Switch mSwitch;
41*90c8c64dSAndroid Build Coastguard Worker 
42*90c8c64dSAndroid Build Coastguard Worker     /**
43*90c8c64dSAndroid Build Coastguard Worker      * Listens for notifications that the {@code AdvertiserService} has failed to start advertising.
44*90c8c64dSAndroid Build Coastguard Worker      * This Receiver deals with Fragment UI elements and only needs to be active when the Fragment
45*90c8c64dSAndroid Build Coastguard Worker      * is on-screen, so it's defined and registered in code instead of the Manifest.
46*90c8c64dSAndroid Build Coastguard Worker      */
47*90c8c64dSAndroid Build Coastguard Worker     private BroadcastReceiver advertisingFailureReceiver;
48*90c8c64dSAndroid Build Coastguard Worker 
49*90c8c64dSAndroid Build Coastguard Worker     @Override
onCreate(Bundle savedInstanceState)50*90c8c64dSAndroid Build Coastguard Worker     public void onCreate(Bundle savedInstanceState) {
51*90c8c64dSAndroid Build Coastguard Worker         super.onCreate(savedInstanceState);
52*90c8c64dSAndroid Build Coastguard Worker 
53*90c8c64dSAndroid Build Coastguard Worker         advertisingFailureReceiver = new BroadcastReceiver() {
54*90c8c64dSAndroid Build Coastguard Worker 
55*90c8c64dSAndroid Build Coastguard Worker             /**
56*90c8c64dSAndroid Build Coastguard Worker              * Receives Advertising error codes from {@code AdvertiserService} and displays error messages
57*90c8c64dSAndroid Build Coastguard Worker              * to the user. Sets the advertising toggle to 'false.'
58*90c8c64dSAndroid Build Coastguard Worker              */
59*90c8c64dSAndroid Build Coastguard Worker             @Override
60*90c8c64dSAndroid Build Coastguard Worker             public void onReceive(Context context, Intent intent) {
61*90c8c64dSAndroid Build Coastguard Worker 
62*90c8c64dSAndroid Build Coastguard Worker                 int errorCode = intent.getIntExtra(AdvertiserService.ADVERTISING_FAILED_EXTRA_CODE, -1);
63*90c8c64dSAndroid Build Coastguard Worker 
64*90c8c64dSAndroid Build Coastguard Worker                 mSwitch.setChecked(false);
65*90c8c64dSAndroid Build Coastguard Worker 
66*90c8c64dSAndroid Build Coastguard Worker                 String errorMessage = getString(R.string.start_error_prefix);
67*90c8c64dSAndroid Build Coastguard Worker                 switch (errorCode) {
68*90c8c64dSAndroid Build Coastguard Worker                     case AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED:
69*90c8c64dSAndroid Build Coastguard Worker                         errorMessage += " " + getString(R.string.start_error_already_started);
70*90c8c64dSAndroid Build Coastguard Worker                         break;
71*90c8c64dSAndroid Build Coastguard Worker                     case AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE:
72*90c8c64dSAndroid Build Coastguard Worker                         errorMessage += " " + getString(R.string.start_error_too_large);
73*90c8c64dSAndroid Build Coastguard Worker                         break;
74*90c8c64dSAndroid Build Coastguard Worker                     case AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED:
75*90c8c64dSAndroid Build Coastguard Worker                         errorMessage += " " + getString(R.string.start_error_unsupported);
76*90c8c64dSAndroid Build Coastguard Worker                         break;
77*90c8c64dSAndroid Build Coastguard Worker                     case AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR:
78*90c8c64dSAndroid Build Coastguard Worker                         errorMessage += " " + getString(R.string.start_error_internal);
79*90c8c64dSAndroid Build Coastguard Worker                         break;
80*90c8c64dSAndroid Build Coastguard Worker                     case AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS:
81*90c8c64dSAndroid Build Coastguard Worker                         errorMessage += " " + getString(R.string.start_error_too_many);
82*90c8c64dSAndroid Build Coastguard Worker                         break;
83*90c8c64dSAndroid Build Coastguard Worker                     case AdvertiserService.ADVERTISING_TIMED_OUT:
84*90c8c64dSAndroid Build Coastguard Worker                         errorMessage = " " + getString(R.string.advertising_timedout);
85*90c8c64dSAndroid Build Coastguard Worker                         break;
86*90c8c64dSAndroid Build Coastguard Worker                     default:
87*90c8c64dSAndroid Build Coastguard Worker                         errorMessage += " " + getString(R.string.start_error_unknown);
88*90c8c64dSAndroid Build Coastguard Worker                 }
89*90c8c64dSAndroid Build Coastguard Worker 
90*90c8c64dSAndroid Build Coastguard Worker                 Toast.makeText(getActivity(), errorMessage, Toast.LENGTH_LONG).show();
91*90c8c64dSAndroid Build Coastguard Worker             }
92*90c8c64dSAndroid Build Coastguard Worker         };
93*90c8c64dSAndroid Build Coastguard Worker     }
94*90c8c64dSAndroid Build Coastguard Worker 
95*90c8c64dSAndroid Build Coastguard Worker     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)96*90c8c64dSAndroid Build Coastguard Worker     public View onCreateView(LayoutInflater inflater, ViewGroup container,
97*90c8c64dSAndroid Build Coastguard Worker                              Bundle savedInstanceState) {
98*90c8c64dSAndroid Build Coastguard Worker 
99*90c8c64dSAndroid Build Coastguard Worker         View view = inflater.inflate(R.layout.fragment_advertiser, container, false);
100*90c8c64dSAndroid Build Coastguard Worker 
101*90c8c64dSAndroid Build Coastguard Worker         mSwitch = (Switch) view.findViewById(R.id.advertise_switch);
102*90c8c64dSAndroid Build Coastguard Worker         mSwitch.setOnClickListener(this);
103*90c8c64dSAndroid Build Coastguard Worker 
104*90c8c64dSAndroid Build Coastguard Worker         return view;
105*90c8c64dSAndroid Build Coastguard Worker     }
106*90c8c64dSAndroid Build Coastguard Worker 
107*90c8c64dSAndroid Build Coastguard Worker     /**
108*90c8c64dSAndroid Build Coastguard Worker      * When app comes on screen, check if BLE Advertisements are running, set switch accordingly,
109*90c8c64dSAndroid Build Coastguard Worker      * and register the Receiver to be notified if Advertising fails.
110*90c8c64dSAndroid Build Coastguard Worker      */
111*90c8c64dSAndroid Build Coastguard Worker     @Override
onResume()112*90c8c64dSAndroid Build Coastguard Worker     public void onResume() {
113*90c8c64dSAndroid Build Coastguard Worker         super.onResume();
114*90c8c64dSAndroid Build Coastguard Worker 
115*90c8c64dSAndroid Build Coastguard Worker         if (AdvertiserService.running) {
116*90c8c64dSAndroid Build Coastguard Worker             mSwitch.setChecked(true);
117*90c8c64dSAndroid Build Coastguard Worker         } else {
118*90c8c64dSAndroid Build Coastguard Worker             mSwitch.setChecked(false);
119*90c8c64dSAndroid Build Coastguard Worker         }
120*90c8c64dSAndroid Build Coastguard Worker 
121*90c8c64dSAndroid Build Coastguard Worker         IntentFilter failureFilter = new IntentFilter(AdvertiserService.ADVERTISING_FAILED);
122*90c8c64dSAndroid Build Coastguard Worker         getActivity().registerReceiver(advertisingFailureReceiver, failureFilter);
123*90c8c64dSAndroid Build Coastguard Worker 
124*90c8c64dSAndroid Build Coastguard Worker     }
125*90c8c64dSAndroid Build Coastguard Worker 
126*90c8c64dSAndroid Build Coastguard Worker     /**
127*90c8c64dSAndroid Build Coastguard Worker      * When app goes off screen, unregister the Advertising failure Receiver to stop memory leaks.
128*90c8c64dSAndroid Build Coastguard Worker      * (and because the app doesn't care if Advertising fails while the UI isn't active)
129*90c8c64dSAndroid Build Coastguard Worker      */
130*90c8c64dSAndroid Build Coastguard Worker     @Override
onPause()131*90c8c64dSAndroid Build Coastguard Worker     public void onPause() {
132*90c8c64dSAndroid Build Coastguard Worker         super.onPause();
133*90c8c64dSAndroid Build Coastguard Worker         getActivity().unregisterReceiver(advertisingFailureReceiver);
134*90c8c64dSAndroid Build Coastguard Worker     }
135*90c8c64dSAndroid Build Coastguard Worker 
136*90c8c64dSAndroid Build Coastguard Worker     /**
137*90c8c64dSAndroid Build Coastguard Worker      * Returns Intent addressed to the {@code AdvertiserService} class.
138*90c8c64dSAndroid Build Coastguard Worker      */
getServiceIntent(Context c)139*90c8c64dSAndroid Build Coastguard Worker     private static Intent getServiceIntent(Context c) {
140*90c8c64dSAndroid Build Coastguard Worker         return new Intent(c, AdvertiserService.class);
141*90c8c64dSAndroid Build Coastguard Worker     }
142*90c8c64dSAndroid Build Coastguard Worker 
143*90c8c64dSAndroid Build Coastguard Worker     /**
144*90c8c64dSAndroid Build Coastguard Worker      * Called when switch is toggled - starts or stops advertising.
145*90c8c64dSAndroid Build Coastguard Worker      */
146*90c8c64dSAndroid Build Coastguard Worker     @Override
onClick(View v)147*90c8c64dSAndroid Build Coastguard Worker     public void onClick(View v) {
148*90c8c64dSAndroid Build Coastguard Worker         // Is the toggle on?
149*90c8c64dSAndroid Build Coastguard Worker         boolean on = ((Switch) v).isChecked();
150*90c8c64dSAndroid Build Coastguard Worker 
151*90c8c64dSAndroid Build Coastguard Worker         if (on) {
152*90c8c64dSAndroid Build Coastguard Worker             startAdvertising();
153*90c8c64dSAndroid Build Coastguard Worker         } else {
154*90c8c64dSAndroid Build Coastguard Worker             stopAdvertising();
155*90c8c64dSAndroid Build Coastguard Worker         }
156*90c8c64dSAndroid Build Coastguard Worker     }
157*90c8c64dSAndroid Build Coastguard Worker 
158*90c8c64dSAndroid Build Coastguard Worker     /**
159*90c8c64dSAndroid Build Coastguard Worker      * Starts BLE Advertising by starting {@code AdvertiserService}.
160*90c8c64dSAndroid Build Coastguard Worker      */
startAdvertising()161*90c8c64dSAndroid Build Coastguard Worker     private void startAdvertising() {
162*90c8c64dSAndroid Build Coastguard Worker         Context c = getActivity();
163*90c8c64dSAndroid Build Coastguard Worker         c.startService(getServiceIntent(c));
164*90c8c64dSAndroid Build Coastguard Worker     }
165*90c8c64dSAndroid Build Coastguard Worker 
166*90c8c64dSAndroid Build Coastguard Worker     /**
167*90c8c64dSAndroid Build Coastguard Worker      * Stops BLE Advertising by stopping {@code AdvertiserService}.
168*90c8c64dSAndroid Build Coastguard Worker      */
stopAdvertising()169*90c8c64dSAndroid Build Coastguard Worker     private void stopAdvertising() {
170*90c8c64dSAndroid Build Coastguard Worker         Context c = getActivity();
171*90c8c64dSAndroid Build Coastguard Worker         c.stopService(getServiceIntent(c));
172*90c8c64dSAndroid Build Coastguard Worker         mSwitch.setChecked(false);
173*90c8c64dSAndroid Build Coastguard Worker     }
174*90c8c64dSAndroid Build Coastguard Worker 
175*90c8c64dSAndroid Build Coastguard Worker }