Skip to content

Most visited

Recently visited

navigation
WearHighBandwidthNetworking / src / com.example.android.wearable.wear.wearhighbandwidthnetworking /

MainActivity.java

1
/*
2
 * Copyright (C) 2016 Google Inc. All Rights Reserved.
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
package com.example.android.wearable.wear.wearhighbandwidthnetworking;
17
 
18
import android.app.Activity;
19
import android.content.Context;
20
import android.content.Intent;
21
import android.net.ConnectivityManager;
22
import android.net.Network;
23
import android.net.NetworkCapabilities;
24
import android.net.NetworkRequest;
25
import android.os.Bundle;
26
import android.os.Handler;
27
import android.os.Message;
28
import android.util.Log;
29
import android.view.View;
30
import android.view.WindowManager;
31
import android.widget.ImageView;
32
import android.widget.TextView;
33
 
34
import java.util.concurrent.TimeUnit;
35
 
36
/**
37
 * This sample demonstrates how to determine if a high-bandwidth network is available for use cases
38
 * that require a minimum network bandwidth, such as streaming media or downloading large files.
39
 * In addition, the sample demonstrates best practices for asking a user to add a new Wi-Fi network
40
 * for high-bandwidth network operations, if currently available networks are inadequate.
41
 */
42
public class MainActivity extends Activity  {
43
    private static final String LOG_TAG = MainActivity.class.getSimpleName();
44
 
45
    // Intent action for sending the user directly to the add Wi-Fi network activity.
46
    private static final String ACTION_ADD_NETWORK_SETTINGS =
47
            "com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS";
48
 
49
    // Message to notify the network request timout handler that too much time has passed.
50
    private static final int MESSAGE_CONNECTIVITY_TIMEOUT = 1;
51
 
52
    // How long the app should wait trying to connect to a sufficient high-bandwidth network before
53
    // asking the user to add a new Wi-Fi network.
54
    private static final long NETWORK_CONNECTIVITY_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
55
 
56
    // The minimum network bandwidth required by the app for high-bandwidth operations.
57
    private static final int MIN_NETWORK_BANDWIDTH_KBPS = 10000;
58
 
59
    private ConnectivityManager mConnectivityManager;
60
    private ConnectivityManager.NetworkCallback mNetworkCallback;
61
 
62
    // Handler for dealing with network connection timeouts.
63
    private Handler mHandler;
64
 
65
    private ImageView mConnectivityIcon;
66
    private TextView mConnectivityText;
67
 
68
    private View mButton;
69
    private ImageView mButtonIcon;
70
    private TextView mButtonText;
71
    private TextView mInfoText;
72
    private View mProgressBar;
73
 
74
    // Tags added to the button in the UI to detect what operation the user has requested.
75
    // These are required since the app reuses the button for different states of the app/UI.
76
    // See onButtonClick() for how these tags are used.
77
    static final String TAG_REQUEST_NETWORK = "REQUEST_NETWORK";
78
    static final String TAG_RELEASE_NETWORK = "RELEASE_NETWORK";
79
    static final String TAG_ADD_WIFI = "ADD_WIFI";
80
 
81
    // These constants are used by setUiState() to determine what information to display in the UI,
82
    // as this app reuses UI components for the various states of the app, which is dependent on
83
    // the state of the network.
84
    static final int UI_STATE_REQUEST_NETWORK = 1;
85
    static final int UI_STATE_REQUESTING_NETWORK = 2;
86
    static final int UI_STATE_NETWORK_CONNECTED = 3;
87
    static final int UI_STATE_CONNECTION_TIMEOUT = 4;
88
 
89
    @Override
90
    protected void onCreate(Bundle savedInstanceState) {
91
        super.onCreate(savedInstanceState);
92
        setContentView(R.layout.activity_main);
93
 
94
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
95
 
96
        mConnectivityIcon = (ImageView) findViewById(R.id.connectivity_icon);
97
        mConnectivityText = (TextView) findViewById(R.id.connectivity_text);
98
 
99
        mProgressBar = findViewById(R.id.progress_bar);
100
 
101
        mButton = findViewById(R.id.button);
102
        mButton.setTag(TAG_REQUEST_NETWORK);
103
        mButtonIcon = (ImageView) findViewById(R.id.button_icon);
104
        mButtonText = (TextView) findViewById(R.id.button_label);
105
 
106
        mInfoText = (TextView) findViewById(R.id.info_text);
107
 
108
        mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
109
 
110
        mHandler = new Handler() {
111
            @Override
112
            public void handleMessage(Message msg) {
113
                switch (msg.what) {
114
                    case MESSAGE_CONNECTIVITY_TIMEOUT:
115
                        Log.d(LOG_TAG, "Network connection timeout");
116
                        setUiState(UI_STATE_CONNECTION_TIMEOUT);
117
                        unregisterNetworkCallback();
118
                        break;
119
                }
120
            }
121
        };
122
    }
123
 
124
    @Override
125
    public void onStop() {
126
        releaseHighBandwidthNetwork();
127
        super.onStop();
128
    }
129
 
130
    @Override
131
    public void onResume() {
132
        super.onResume();
133
 
134
        if (isNetworkHighBandwidth()) {
135
            setUiState(UI_STATE_NETWORK_CONNECTED);
136
        } else {
137
            setUiState(UI_STATE_REQUEST_NETWORK);
138
        }
139
    }
140
 
141
    private void unregisterNetworkCallback() {
142
        if (mNetworkCallback != null) {
143
            Log.d(LOG_TAG, "Unregistering network callback");
144
            mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
145
            mNetworkCallback = null;
146
        }
147
    }
148
 
149
    // Determine if there is a high-bandwidth network exists. Checks both the active
150
    // and bound networks. Returns false if no network is available (low or high-bandwidth).
151
    private boolean isNetworkHighBandwidth() {
152
        Network network = mConnectivityManager.getBoundNetworkForProcess();
153
        network = network == null ? mConnectivityManager.getActiveNetwork() : network;
154
        if (network == null) {
155
            return false;
156
        }
157
 
158
        // requires android.permission.ACCESS_NETWORK_STATE
159
        int bandwidth = mConnectivityManager
160
                .getNetworkCapabilities(network).getLinkDownstreamBandwidthKbps();
161
 
162
        if (bandwidth >= MIN_NETWORK_BANDWIDTH_KBPS) {
163
            return true;
164
        }
165
 
166
        return false;
167
    }
168
 
169
    private void requestHighBandwidthNetwork() {
170
        // Before requesting a high-bandwidth network, ensure prior requests are invalidated.
171
        unregisterNetworkCallback();
172
 
173
        Log.d(LOG_TAG, "Requesting high-bandwidth network");
174
 
175
        // Requesting an unmetered network may prevent you from connecting to the cellular
176
        // network on the user's watch or phone; however, unless you explicitly ask for permission
177
        // to a access the user's cellular network, you should request an unmetered network.
178
        NetworkRequest request = new NetworkRequest.Builder()
179
                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
180
                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
181
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
182
                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
183
                .build();
184
 
185
        mNetworkCallback = new ConnectivityManager.NetworkCallback() {
186
            @Override
187
            public void onAvailable(final Network network) {
188
                mHandler.removeMessages(MESSAGE_CONNECTIVITY_TIMEOUT);
189
 
190
                runOnUiThread(new Runnable() {
191
                    @Override
192
                    public void run() {
193
                        // requires android.permission.INTERNET
194
                        if (!mConnectivityManager.bindProcessToNetwork(network)) {
195
                            Log.e(LOG_TAG, "ConnectivityManager.bindProcessToNetwork()"
196
                                    + " requires android.permission.INTERNET");
197
                            setUiState(UI_STATE_REQUEST_NETWORK);
198
                        } else {
199
                            Log.d(LOG_TAG, "Network available");
200
                            setUiState(UI_STATE_NETWORK_CONNECTED);
201
                        }
202
                    }
203
                });
204
            }
205
 
206
            @Override
207
            public void onCapabilitiesChanged(Network network,
208
                                              NetworkCapabilities networkCapabilities) {
209
                runOnUiThread(new Runnable() {
210
                    @Override
211
                    public void run() {
212
                        Log.d(LOG_TAG, "Network capabilities changed");
213
                    }
214
                });
215
            }
216
 
217
            @Override
218
            public void onLost(Network network) {
219
                Log.d(LOG_TAG, "Network lost");
220
 
221
                runOnUiThread(new Runnable() {
222
                    @Override
223
                    public void run() {
224
                        setUiState(UI_STATE_REQUEST_NETWORK);
225
                    }
226
                });
227
            }
228
        };
229
 
230
        // requires android.permission.CHANGE_NETWORK_STATE
231
        mConnectivityManager.requestNetwork(request, mNetworkCallback);
232
 
233
        mHandler.sendMessageDelayed(
234
                mHandler.obtainMessage(MESSAGE_CONNECTIVITY_TIMEOUT),
235
                NETWORK_CONNECTIVITY_TIMEOUT_MS);
236
    }
237
 
238
    private void releaseHighBandwidthNetwork() {
239
        mConnectivityManager.bindProcessToNetwork(null);
240
        unregisterNetworkCallback();
241
    }
242
 
243
    private void addWifiNetwork() {
244
        // requires android.permission.CHANGE_WIFI_STATE
245
        startActivity(new Intent(ACTION_ADD_NETWORK_SETTINGS));
246
    }
247
 
248
    /**
249
     * Click handler for the button in the UI. The view tag is used to determine the specific
250
     * function of the button.
251
     *
252
     * @param view The view that was clicked
253
     */
254
    public void onButtonClick(View view) {
255
        switch (view.getTag().toString()) {
256
            case TAG_REQUEST_NETWORK:
257
                requestHighBandwidthNetwork();
258
                setUiState(UI_STATE_REQUESTING_NETWORK);
259
                break;
260
 
261
            case TAG_RELEASE_NETWORK:
262
                releaseHighBandwidthNetwork();
263
                setUiState(UI_STATE_REQUEST_NETWORK);
264
                break;
265
 
266
            case TAG_ADD_WIFI:
267
                addWifiNetwork();
268
                break;
269
        }
270
    }
271
 
272
    // Sets the text and icons the connectivity indicator, button, and info text in the app UI,
273
    // which are all reused for the various states of the app and network connectivity. Also,
274
    // will show/hide a progress bar, which is dependent on the state of the network connectivity
275
    // request.
276
    private void setUiState(int uiState) {
277
        switch (uiState) {
278
            case UI_STATE_REQUEST_NETWORK:
279
                if (isNetworkHighBandwidth()) {
280
                    mConnectivityIcon.setImageResource(R.drawable.ic_cloud_happy);
281
                    mConnectivityText.setText(R.string.network_fast);
282
                } else {
283
                    mConnectivityIcon.setImageResource(R.drawable.ic_cloud_sad);
284
                    mConnectivityText.setText(R.string.network_slow);
285
                }
286
 
287
                mButton.setTag(TAG_REQUEST_NETWORK);
288
                mButtonIcon.setImageResource(R.drawable.ic_fast_network);
289
                mButtonText.setText(R.string.button_request_network);
290
                mInfoText.setText(R.string.info_request_network);
291
 
292
                break;
293
 
294
            case UI_STATE_REQUESTING_NETWORK:
295
                mConnectivityIcon.setImageResource(R.drawable.ic_cloud_disconnected);
296
                mConnectivityText.setText(R.string.network_connecting);
297
 
298
                mProgressBar.setVisibility(View.VISIBLE);
299
                mInfoText.setVisibility(View.GONE);
300
                mButton.setVisibility(View.GONE);
301
 
302
                break;
303
 
304
            case UI_STATE_NETWORK_CONNECTED:
305
                if (isNetworkHighBandwidth()) {
306
                    mConnectivityIcon.setImageResource(R.drawable.ic_cloud_happy);
307
                    mConnectivityText.setText(R.string.network_fast);
308
                } else {
309
                    mConnectivityIcon.setImageResource(R.drawable.ic_cloud_sad);
310
                    mConnectivityText.setText(R.string.network_slow);
311
                }
312
 
313
                mProgressBar.setVisibility(View.GONE);
314
                mInfoText.setVisibility(View.VISIBLE);
315