| /* | |
| * Copyright (C) 2016 Google Inc. All Rights Reserved. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package com.example.android.wearable.wear.wearhighbandwidthnetworking; | |
| import android.app.Activity; | |
| import android.content.Context; | |
| import android.content.Intent; | |
| import android.net.ConnectivityManager; | |
| import android.net.Network; | |
| import android.net.NetworkCapabilities; | |
| import android.net.NetworkRequest; | |
| import android.os.Bundle; | |
| import android.os.Handler; | |
| import android.os.Message; | |
| import android.util.Log; | |
| import android.view.View; | |
| import android.view.WindowManager; | |
| import android.widget.ImageView; | |
| import android.widget.TextView; | |
| import java.util.concurrent.TimeUnit; | |
| /** | |
| * This sample demonstrates how to determine if a high-bandwidth network is available for use cases | |
| * that require a minimum network bandwidth, such as streaming media or downloading large files. | |
| * In addition, the sample demonstrates best practices for asking a user to add a new Wi-Fi network | |
| * for high-bandwidth network operations, if currently available networks are inadequate. | |
| */ | |
| public class MainActivity extends Activity { | |
| private static final String LOG_TAG = MainActivity.class.getSimpleName(); | |
| // Intent action for sending the user directly to the add Wi-Fi network activity. | |
| private static final String ACTION_ADD_NETWORK_SETTINGS = | |
| "com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS"; | |
| // Message to notify the network request timout handler that too much time has passed. | |
| private static final int MESSAGE_CONNECTIVITY_TIMEOUT = 1; | |
| // How long the app should wait trying to connect to a sufficient high-bandwidth network before | |
| // asking the user to add a new Wi-Fi network. | |
| private static final long NETWORK_CONNECTIVITY_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10); | |
| // The minimum network bandwidth required by the app for high-bandwidth operations. | |
| private static final int MIN_NETWORK_BANDWIDTH_KBPS = 10000; | |
| private ConnectivityManager mConnectivityManager; | |
| private ConnectivityManager.NetworkCallback mNetworkCallback; | |
| // Handler for dealing with network connection timeouts. | |
| private Handler mHandler; | |
| private ImageView mConnectivityIcon; | |
| private TextView mConnectivityText; | |
| private View mButton; | |
| private ImageView mButtonIcon; | |
| private TextView mButtonText; | |
| private TextView mInfoText; | |
| private View mProgressBar; | |
| // Tags added to the button in the UI to detect what operation the user has requested. | |
| // These are required since the app reuses the button for different states of the app/UI. | |
| // See onButtonClick() for how these tags are used. | |
| static final String TAG_REQUEST_NETWORK = "REQUEST_NETWORK"; | |
| static final String TAG_RELEASE_NETWORK = "RELEASE_NETWORK"; | |
| static final String TAG_ADD_WIFI = "ADD_WIFI"; | |
| // These constants are used by setUiState() to determine what information to display in the UI, | |
| // as this app reuses UI components for the various states of the app, which is dependent on | |
| // the state of the network. | |
| static final int UI_STATE_REQUEST_NETWORK = 1; | |
| static final int UI_STATE_REQUESTING_NETWORK = 2; | |
| static final int UI_STATE_NETWORK_CONNECTED = 3; | |
| static final int UI_STATE_CONNECTION_TIMEOUT = 4; | |
| @Override | |
| protected void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| setContentView(R.layout.activity_main); | |
| getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); | |
| mConnectivityIcon = (ImageView) findViewById(R.id.connectivity_icon); | |
| mConnectivityText = (TextView) findViewById(R.id.connectivity_text); | |
| mProgressBar = findViewById(R.id.progress_bar); | |
| mButton = findViewById(R.id.button); | |
| mButton.setTag(TAG_REQUEST_NETWORK); | |
| mButtonIcon = (ImageView) findViewById(R.id.button_icon); | |
| mButtonText = (TextView) findViewById(R.id.button_label); | |
| mInfoText = (TextView) findViewById(R.id.info_text); | |
| mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); | |
| mHandler = new Handler() { | |
| @Override | |
| public void handleMessage(Message msg) { | |
| switch (msg.what) { | |
| case MESSAGE_CONNECTIVITY_TIMEOUT: | |
| Log.d(LOG_TAG, "Network connection timeout"); | |
| setUiState(UI_STATE_CONNECTION_TIMEOUT); | |
| unregisterNetworkCallback(); | |
| break; | |
| } | |
| } | |
| }; | |
| } | |
| @Override | |
| public void onStop() { | |
| releaseHighBandwidthNetwork(); | |
| super.onStop(); | |
| } | |
| @Override | |
| public void onResume() { | |
| super.onResume(); | |
| if (isNetworkHighBandwidth()) { | |
| setUiState(UI_STATE_NETWORK_CONNECTED); | |
| } else { | |
| setUiState(UI_STATE_REQUEST_NETWORK); | |
| } | |
| } | |
| private void unregisterNetworkCallback() { | |
| if (mNetworkCallback != null) { | |
| Log.d(LOG_TAG, "Unregistering network callback"); | |
| mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); | |
| mNetworkCallback = null; | |
| } | |
| } | |
| // Determine if there is a high-bandwidth network exists. Checks both the active | |
| // and bound networks. Returns false if no network is available (low or high-bandwidth). | |
| private boolean isNetworkHighBandwidth() { | |
| Network network = mConnectivityManager.getBoundNetworkForProcess(); | |
| network = network == null ? mConnectivityManager.getActiveNetwork() : network; | |
| if (network == null) { | |
| return false; | |
| } | |
| // requires android.permission.ACCESS_NETWORK_STATE | |
| int bandwidth = mConnectivityManager | |
| .getNetworkCapabilities(network).getLinkDownstreamBandwidthKbps(); | |
| if (bandwidth >= MIN_NETWORK_BANDWIDTH_KBPS) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| private void requestHighBandwidthNetwork() { | |
| // Before requesting a high-bandwidth network, ensure prior requests are invalidated. | |
| unregisterNetworkCallback(); | |
| Log.d(LOG_TAG, "Requesting high-bandwidth network"); | |
| // Requesting an unmetered network may prevent you from connecting to the cellular | |
| // network on the user's watch or phone; however, unless you explicitly ask for permission | |
| // to a access the user's cellular network, you should request an unmetered network. | |
| NetworkRequest request = new NetworkRequest.Builder() | |
| .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) | |
| .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) | |
| .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) | |
| .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) | |
| .build(); | |
| mNetworkCallback = new ConnectivityManager.NetworkCallback() { | |
| @Override | |
| public void onAvailable(final Network network) { | |
| mHandler.removeMessages(MESSAGE_CONNECTIVITY_TIMEOUT); | |
| runOnUiThread(new Runnable() { | |
| @Override | |
| public void run() { | |
| // requires android.permission.INTERNET | |
| if (!mConnectivityManager.bindProcessToNetwork(network)) { | |
| Log.e(LOG_TAG, "ConnectivityManager.bindProcessToNetwork()" | |
| + " requires android.permission.INTERNET"); | |
| setUiState(UI_STATE_REQUEST_NETWORK); | |
| } else { | |
| Log.d(LOG_TAG, "Network available"); | |
| setUiState(UI_STATE_NETWORK_CONNECTED); | |
| } | |
| } | |
| }); | |
| } | |
| @Override | |
| public void onCapabilitiesChanged(Network network, | |
| NetworkCapabilities networkCapabilities) { | |
| runOnUiThread(new Runnable() { | |
| @Override | |
| public void run() { | |
| Log.d(LOG_TAG, "Network capabilities changed"); | |
| } | |
| }); | |
| } | |
| @Override | |
| public void onLost(Network network) { | |
| Log.d(LOG_TAG, "Network lost"); | |
| runOnUiThread(new Runnable() { | |
| @Override | |
| public void run() { | |
| setUiState(UI_STATE_REQUEST_NETWORK); | |
| } | |
| }); | |
| } | |
| }; | |
| // requires android.permission.CHANGE_NETWORK_STATE | |
| mConnectivityManager.requestNetwork(request, mNetworkCallback); | |
| mHandler.sendMessageDelayed( | |
| mHandler.obtainMessage(MESSAGE_CONNECTIVITY_TIMEOUT), | |
| NETWORK_CONNECTIVITY_TIMEOUT_MS); | |
| } | |
| private void releaseHighBandwidthNetwork() { | |
| mConnectivityManager.bindProcessToNetwork(null); | |
| unregisterNetworkCallback(); | |
| } | |
| private void addWifiNetwork() { | |
| // requires android.permission.CHANGE_WIFI_STATE | |
| startActivity(new Intent(ACTION_ADD_NETWORK_SETTINGS)); | |
| } | |
| /** | |
| * Click handler for the button in the UI. The view tag is used to determine the specific | |
| * function of the button. | |
| * | |
| * @param view The view that was clicked | |
| */ | |
| public void onButtonClick(View view) { | |
| switch (view.getTag().toString()) { | |
| case TAG_REQUEST_NETWORK: | |
| requestHighBandwidthNetwork(); | |
| setUiState(UI_STATE_REQUESTING_NETWORK); | |
| break; | |
| case TAG_RELEASE_NETWORK: | |
| releaseHighBandwidthNetwork(); | |
| setUiState(UI_STATE_REQUEST_NETWORK); | |
| break; | |
| case TAG_ADD_WIFI: | |
| addWifiNetwork(); | |
| break; | |
| } | |
| } | |
| // Sets the text and icons the connectivity indicator, button, and info text in the app UI, | |
| // which are all reused for the various states of the app and network connectivity. Also, | |
| // will show/hide a progress bar, which is dependent on the state of the network connectivity | |
| // request. | |
| private void setUiState(int uiState) { | |
| switch (uiState) { | |
| case UI_STATE_REQUEST_NETWORK: | |
| if (isNetworkHighBandwidth()) { | |
| mConnectivityIcon.setImageResource(R.drawable.ic_cloud_happy); | |
| mConnectivityText.setText(R.string.network_fast); | |
| } else { | |
| mConnectivityIcon.setImageResource(R.drawable.ic_cloud_sad); | |
| mConnectivityText.setText(R.string.network_slow); | |
| } | |
| mButton.setTag(TAG_REQUEST_NETWORK); | |
| mButtonIcon.setImageResource(R.drawable.ic_fast_network); | |
| mButtonText.setText(R.string.button_request_network); | |
| mInfoText.setText(R.string.info_request_network); | |
| break; | |
| case UI_STATE_REQUESTING_NETWORK: | |
| mConnectivityIcon.setImageResource(R.drawable.ic_cloud_disconnected); | |
| mConnectivityText.setText(R.string.network_connecting); | |
| mProgressBar.setVisibility(View.VISIBLE); | |
| mInfoText.setVisibility(View.GONE); | |
| mButton.setVisibility(View.GONE); | |
| break; | |
| case UI_STATE_NETWORK_CONNECTED: | |
| if (isNetworkHighBandwidth()) { | |
| mConnectivityIcon.setImageResource(R.drawable.ic_cloud_happy); | |
| mConnectivityText.setText(R.string.network_fast); | |
| } else { | |
| mConnectivityIcon.setImageResource(R.drawable.ic_cloud_sad); | |
| mConnectivityText.setText(R.string.network_slow); | |
| } | |
| mProgressBar.setVisibility(View.GONE); | |
| mInfoText.setVisibility(View.VISIBLE); | |
| mButton.setVisibility(View.VISIBLE); | |
| mButton.setTag(TAG_RELEASE_NETWORK); | |
| mButtonIcon.setImageResource(R.drawable.ic_no_network); | |
| mButtonText.setText(R.string.button_release_network); | |
| mInfoText.setText(R.string.info_release_network); | |
| break; | |
| case UI_STATE_CONNECTION_TIMEOUT: | |
| mConnectivityIcon.setImageResource(R.drawable.ic_cloud_disconnected); | |
| mConnectivityText.setText(R.string.network_disconnected); | |
| mProgressBar.setVisibility(View.GONE); | |
| mInfoText.setVisibility(View.VISIBLE); | |
| mButton.setVisibility(View.VISIBLE); | |
| mButton.setTag(TAG_ADD_WIFI); | |
| mButtonIcon.setImageResource(R.drawable.ic_wifi_network); | |
| mButtonText.setText(R.string.button_add_wifi); | |
| mInfoText.setText(R.string.info_add_wifi); | |
| break; | |
| } | |
| } | |
| } |