16

I have been trying to push data to the android wear emulator. But all in vain. My listener on the emulator is not receiving any calls whatsoever. If anyone else has tried working on wear and pushing data to wear please HELP.

This is what my receiver code looks like

 private GoogleApiClient mGoogleApiClient;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_qrcode_generation);

    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Wearable.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();

    final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
    stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
        @Override
        public void onLayoutInflated(WatchViewStub stub) {
            ivQrImage = (ImageView) stub.findViewById(R.id.ivQRImage);
        }
    });
}

@Override
public void onDataChanged(DataEventBuffer dataEvents) {
    for (DataEvent event : dataEvents) {
        if (event.getType() == DataEvent.TYPE_CHANGED &&
                event.getDataItem().getUri().getPath().equals("/image")) {
            final DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem());
            final Asset profileAsset = dataMapItem.getDataMap().getAsset("profileImage");
            final Bitmap bitmap = loadBitmapFromAsset(profileAsset);
            Log.d(TAG, ""+bitmap);
            if (null != bitmap) {
                ivQrImage.setImageBitmap(bitmap);
                bitmap.recycle();
            }

        }
    }
}

@Override
protected void onStart() {
    super.onStart();

    mGoogleApiClient.connect();
}

@Override
protected void onStop() {
    if (null != mGoogleApiClient && mGoogleApiClient.isConnected()) {
        Wearable.DataApi.removeListener(mGoogleApiClient, this);
        mGoogleApiClient.disconnect();
    }
    super.onStop();
}

public Bitmap loadBitmapFromAsset(Asset asset) {
    if (asset == null) {
        throw new IllegalArgumentException("Asset must be non-null");
    }
    ConnectionResult result =
            mGoogleApiClient.blockingConnect(TIMEOUT_MS, TimeUnit.MILLISECONDS);
    if (!result.isSuccess()) {
        return null;
    }
    // convert asset into a file descriptor and block until it's ready
    InputStream assetInputStream = Wearable.DataApi.getFdForAsset(
            mGoogleApiClient, asset).await().getInputStream();
    mGoogleApiClient.disconnect();

    if (assetInputStream == null) {
        Log.w(TAG, "Requested an unknown Asset.");
        return null;
    }
    // decode the stream into a bitmap
    return BitmapFactory.decodeStream(assetInputStream);
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    Log.d(TAG,"Connection Failed");
}

@Override
public void onConnected(Bundle bundle) {
    Wearable.DataApi.addListener(mGoogleApiClient, this);
    Wearable.MessageApi.addListener(mGoogleApiClient, this);
}

This is how I am pushing

private void pushImageToWear() {

    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.qr_code);
    Asset asset = createAssetFromBitmap(bitmap);
    PutDataMapRequest dataMap = PutDataMapRequest.create("/image");
    dataMap.getDataMap().putAsset("profileImage", asset);
    PutDataRequest request = dataMap.asPutDataRequest();
    PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi
            .putDataItem(mGoogleApiClient, request);

}

I also have the following in my manifest for the Android Wear activity

<activity
        android:name=".QRCodeReceptionActivity"
        android:label="@string/app_name"
        android:exported="true"
        android:allowEmbedded="true"
        android:taskAffinity=""
        android:theme="@android:style/Theme.DeviceDefault.Light">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

P.S. There is nothing extraordinary which I am doing. Just followed the tutorial given on the developer site.

iZBasit
  • 1,314
  • 1
  • 15
  • 30
  • So I've used the message api to a real device and it's worked for me. It might help give you a push in the right direction but I doubt it will solve your problem. https://github.com/kentarosu/AndroidWearAndLifx – gatlingxyz Jul 10 '14 at 12:33
  • Does your onConnected ever get called? – gatlingxyz Jul 10 '14 at 12:35
  • @kentarosu Yes! onConnected does get called. – iZBasit Jul 10 '14 at 12:36
  • @autocrat Have you tried using `NodeApi` first to see if the nodes are actually connected? – matiash Jul 10 '14 at 15:40
  • @matiash Nope. I directly jumped to pushing images. I am going to try out the other two tonight. – iZBasit Jul 10 '14 at 15:46
  • @autocrat OK, I suggested that just to determine whether the problem is with the assets, or more generally that the devices are not properly paired. – matiash Jul 10 '14 at 16:04
  • 3
    Have you tried the DataLayer sample included with the Android Wear SDK? That shows a complete example of sending messages from phone to wearable that you can test out to make sure everything is working before you start trying to debug your own code. – Wayne Piekarski Jul 10 '14 at 16:11

4 Answers4

35

Sorry that I use Answer, but I need a reputation of 50 to comment :(

I had the same problem here https://stackoverflow.com/... , but now I fixed it.

Ok I share with you all problems I ran into:

First in the AndroidManifest.xml files on the mobile add the following:

<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

Second what confused me a bit was, that onDataChanged() is only called when the DataItem inside is really "changed". So it works maybe for the first time, but later nothing will happen.

I changed the code on the mobile, so everytime I try to send data it has a different timestamp:

Asset asset = createAssetFromBitmap(bitmap);
        PutDataMapRequest request = PutDataMapRequest.create("/image");
        DataMap map = request.getDataMap();
        map.putLong("time", new Date().getTime()); // MOST IMPORTANT LINE FOR TIMESTAMP
        map.putAsset("profileImage", asset);
        Wearable.DataApi.putDataItem(mGoogleApiClient, request.asPutDataRequest());

I found out in this IO Video

The rest of the code looks like yours. I hope this help.

UhrArt
  • 504
  • 5
  • 8
  • 1
    I think you have hit the spot. I guess adding the integer should solve my problem. But frankly speaking this should have not been the case. Anyways I will try and let you know. – iZBasit Jul 11 '14 at 12:11
  • 2
    OK, I have full proof now! I had some ongoing issues, so I went over the DataLayer Sample in detail. The Google Dev inserted in every dataitem a line with a timestamp. Now everything works. – UhrArt Jul 24 '14 at 10:11
  • And here is you commenting skill won ;-) Thanks – Thibaud David Mar 16 '15 at 18:14
  • 1
    Good Job with the timestamp finding. – Ran Mar 24 '15 at 10:06
  • I used count previously but it got resetted into 0 after the app closes so there were occasions that no change was detected. Your timestamp saved my life. – paradite Mar 30 '15 at 14:22
  • Adding the GMS version fixed it for me. – Marc Dec 09 '15 at 08:44
  • 3
    You can reduce overhead a little bit by calling `System.currentTimeInMillis()` instead of creating a `new Date()`object which calls `System.currentTimeInMillis()` under the hood anyway, and returns it's value when you call `getTime()`. #perfsmatters – Louis CAD Feb 19 '16 at 10:17
5

I also had this problem, and it took hours to solve. My recommendation? Create a new project using Android Studio and select Android Wear and Phone + Tablet as the project types. This will give you the skeleton of a working project, then its just a matter of porting over to your existing project the differences from the Auto-generated skeleton.

For me, the problem ended up being a combination of the following:

  • In your defaultConfig build entry, the applicationId must be the same for both your wearable and mobile app, for example: defaultConfig { applicationId "com.rukkus.app" ... }
  • The mobile app must add the wearApp as a dependency, like so: dependencies { ... wearApp project(':wear') }

Additionally (and admittedly Im not sure that this is necessary), in the samples the Google Dev's connect to the Google API in the onCreate of the WearableListenerService (instead of in the onDataChanged method as the documentation illustrates). So my onCreate looks like this in the WearableListenerService:

@Override
public void onCreate() {
    super.onCreate();

    // create Google Client
    GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this.ctx)
            .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
                @Override
                public void onConnectionFailed(ConnectionResult result){

                }
            })
            .addApi(Wearable.API).build();    

    //connect the client
    googleApiClient.connect();
    Log.i(TAG, "**creating google API client now**");
}

This took longer than I'd like to admit to get working, so hopefully this helps some future Googler out.

Bobby
  • 6,840
  • 1
  • 22
  • 25
3

Your device applicationId and wearable applicationId must match, as @Bobby stated in his answer. I did not need to have the wearable app as a dependency.

Tom
  • 6,946
  • 2
  • 47
  • 63
3

I discovered another cause to add to the checklist. The wearable and mobile apps must be built with the same versions of the wear libraries. Check the versions in your gradle dependencies.

compile 'com.google.android.support:wearable:1.3.0'
compile 'com.google.android.gms:play-services-wearable:8.1.0'

(I do not have enough reputation points to comment)

Jaiprakash Soni
  • 4,100
  • 5
  • 36
  • 67
sidecarcat
  • 482
  • 5
  • 12