| /* |
| * 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; |
| } |
| } |
| } |