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