1 /* 2 * Copyright (C) 2014 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.wearable.datalayer; 18 19 import static com.example.android.wearable.datalayer.DataLayerListenerService.LOGD; 20 21 import android.app.Activity; 22 import android.content.Context; 23 import android.graphics.Bitmap; 24 import android.graphics.BitmapFactory; 25 import android.graphics.drawable.BitmapDrawable; 26 import android.os.Bundle; 27 import android.os.Handler; 28 import android.util.Log; 29 import android.view.LayoutInflater; 30 import android.view.View; 31 import android.view.ViewGroup; 32 import android.view.WindowManager; 33 import android.widget.ArrayAdapter; 34 import android.widget.ListView; 35 import android.widget.TextView; 36 37 import com.google.android.gms.common.ConnectionResult; 38 import com.google.android.gms.common.api.GoogleApiClient; 39 import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; 40 import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener; 41 import com.google.android.gms.common.data.FreezableUtils; 42 import com.google.android.gms.wearable.Asset; 43 import com.google.android.gms.wearable.DataApi; 44 import com.google.android.gms.wearable.DataEvent; 45 import com.google.android.gms.wearable.DataEventBuffer; 46 import com.google.android.gms.wearable.DataMapItem; 47 import com.google.android.gms.wearable.MessageApi; 48 import com.google.android.gms.wearable.MessageEvent; 49 import com.google.android.gms.wearable.Node; 50 import com.google.android.gms.wearable.NodeApi; 51 import com.google.android.gms.wearable.Wearable; 52 53 import java.io.InputStream; 54 import java.util.List; 55 56 /** 57 * Shows events and photo from the Wearable APIs. 58 */ 59 public class MainActivity extends Activity implements ConnectionCallbacks, 60 OnConnectionFailedListener, DataApi.DataListener, MessageApi.MessageListener, 61 NodeApi.NodeListener { 62 63 private static final String TAG = "MainActivity"; 64 65 private GoogleApiClient mGoogleApiClient; 66 private ListView mDataItemList; 67 private TextView mIntroText; 68 private DataItemAdapter mDataItemListAdapter; 69 private View mLayout; 70 private Handler mHandler; 71 72 @Override 73 public void onCreate(Bundle b) { 74 super.onCreate(b); 75 mHandler = new Handler(); 76 LOGD(TAG, "onCreate"); 77 setContentView(R.layout.main_activity); 78 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 79 mDataItemList = (ListView) findViewById(R.id.dataItem_list); 80 mIntroText = (TextView) findViewById(R.id.intro); 81 mLayout = findViewById(R.id.layout); 82 83 // Stores data events received by the local broadcaster. 84 mDataItemListAdapter = new DataItemAdapter(this, android.R.layout.simple_list_item_1); 85 mDataItemList.setAdapter(mDataItemListAdapter); 86 87 mGoogleApiClient = new GoogleApiClient.Builder(this) 88 .addApi(Wearable.API) 89 .addConnectionCallbacks(this) 90 .addOnConnectionFailedListener(this) 91 .build(); 92 } 93 94 @Override 95 protected void onResume() { 96 super.onResume(); 97 mGoogleApiClient.connect(); 98 } 99 100 @Override 101 protected void onPause() { 102 super.onPause(); 103 Wearable.DataApi.removeListener(mGoogleApiClient, this); 104 Wearable.MessageApi.removeListener(mGoogleApiClient, this); 105 Wearable.NodeApi.removeListener(mGoogleApiClient, this); 106 mGoogleApiClient.disconnect(); 107 } 108 109 @Override 110 public void onConnected(Bundle connectionHint) { 111 LOGD(TAG, "onConnected(): Successfully connected to Google API client"); 112 Wearable.DataApi.addListener(mGoogleApiClient, this); 113 Wearable.MessageApi.addListener(mGoogleApiClient, this); 114 Wearable.NodeApi.addListener(mGoogleApiClient, this); 115 } 116 117 @Override 118 public void onConnectionSuspended(int cause) { 119 LOGD(TAG, "onConnectionSuspended(): Connection to Google API client was suspended"); 120 } 121 122 @Override 123 public void onConnectionFailed(ConnectionResult result) { 124 Log.e(TAG, "onConnectionFailed(): Failed to connect, with result: " + result); 125 } 126 127 private void generateEvent(final String title, final String text) { 128 runOnUiThread(new Runnable() { 129 @Override 130 public void run() { 131 mIntroText.setVisibility(View.INVISIBLE); 132 mDataItemListAdapter.add(new Event(title, text)); 133 } 134 }); 135 } 136 137 @Override 138 public void onDataChanged(DataEventBuffer dataEvents) { 139 LOGD(TAG, "onDataChanged(): " + dataEvents); 140 141 final List<DataEvent> events = FreezableUtils.freezeIterable(dataEvents); 142 dataEvents.close(); 143 for (DataEvent event : events) { 144 if (event.getType() == DataEvent.TYPE_CHANGED) { 145 String path = event.getDataItem().getUri().getPath(); 146 if (DataLayerListenerService.IMAGE_PATH.equals(path)) { 147 DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem()); 148 Asset photo = dataMapItem.getDataMap() 149 .getAsset(DataLayerListenerService.IMAGE_KEY); 150 final Bitmap bitmap = loadBitmapFromAsset(mGoogleApiClient, photo); 151 mHandler.post(new Runnable() { 152 @Override 153 public void run() { 154 Log.d(TAG, "Setting background image.."); 155 mLayout.setBackground(new BitmapDrawable(getResources(), bitmap)); 156 } 157 }); 158 159 } else if (DataLayerListenerService.COUNT_PATH.equals(path)) { 160 LOGD(TAG, "Data Changed for COUNT_PATH"); 161 generateEvent("DataItem Changed", event.getDataItem().toString()); 162 } else { 163 LOGD(TAG, "Unrecognized path: " + path); 164 } 165 166 } else if (event.getType() == DataEvent.TYPE_DELETED) { 167 generateEvent("DataItem Deleted", event.getDataItem().toString()); 168 } else { 169 generateEvent("Unknown data event type", "Type = " + event.getType()); 170 } 171 } 172 } 173 174 /** 175 * Extracts {@link android.graphics.Bitmap} data from the 176 * {@link com.google.android.gms.wearable.Asset} 177 */ 178 private Bitmap loadBitmapFromAsset(GoogleApiClient apiClient, Asset asset) { 179 if (asset == null) { 180 throw new IllegalArgumentException("Asset must be non-null"); 181 } 182 183 InputStream assetInputStream = Wearable.DataApi.getFdForAsset( 184 apiClient, asset).await().getInputStream(); 185 186 if (assetInputStream == null) { 187 Log.w(TAG, "Requested an unknown Asset."); 188 return null; 189 } 190 return BitmapFactory.decodeStream(assetInputStream); 191 } 192 193 @Override 194 public void onMessageReceived(MessageEvent event) { 195 LOGD(TAG, "onMessageReceived: " + event); 196 generateEvent("Message", event.toString()); 197 } 198 199 @Override 200 public void onPeerConnected(Node node) { 201 generateEvent("Node Connected", node.getId()); 202 } 203 204 @Override 205 public void onPeerDisconnected(Node node) { 206 generateEvent("Node Disconnected", node.getId()); 207 } 208 209 private static class DataItemAdapter extends ArrayAdapter<Event> { 210 211 private final Context mContext; 212 213 public DataItemAdapter(Context context, int unusedResource) { 214 super(context, unusedResource); 215 mContext = context; 216 } 217 218 @Override 219 public View getView(int position, View convertView, ViewGroup parent) { 220 ViewHolder holder; 221 if (convertView == null) { 222 holder = new ViewHolder(); 223 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( 224 Context.LAYOUT_INFLATER_SERVICE); 225 convertView = inflater.inflate(android.R.layout.two_line_list_item, null); 226 convertView.setTag(holder); 227 holder.text1 = (TextView) convertView.findViewById(android.R.id.text1); 228 holder.text2 = (TextView) convertView.findViewById(android.R.id.text2); 229 } else { 230 holder = (ViewHolder) convertView.getTag(); 231 } 232 Event event = getItem(position); 233 holder.text1.setText(event.title); 234 holder.text2.setText(event.text); 235 return convertView; 236 } 237 238 private class ViewHolder { 239 240 TextView text1; 241 TextView text2; 242 } 243 } 244 245 private class Event { 246 247 String title; 248 String text; 249 250 public Event(String title, String text) { 251 this.title = title; 252 this.text = text; 253 } 254 } 255 } 256