Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Verified Commit db013606 authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

Update Wearable

- Add support for deleting dataitems
- Refactoring
- Update wearable-lib
parent 4ea10d90
Loading
Loading
Loading
Loading
Compare 5c24adaa to 666ef2a8
Original line number Diff line number Diff line
Subproject commit 5c24adaa3928de68167ce31c0fa5b9b1a3256677
Subproject commit 666ef2a8628b1c76701a2d5f138d4fd90751b5e9
+174 −7
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package org.microg.gms.common;

import android.os.IInterface;
import android.support.annotation.NonNull;
import android.util.Log;

import java.lang.reflect.InvocationHandler;
@@ -25,17 +26,22 @@ import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class MultiListenerProxy<T extends IInterface> implements InvocationHandler {
    private static final String TAG = "GmsMultiListener";

    public static <T extends IInterface> T get(Class<T> tClass, final Collection<T> listeners) {
        return (T) Proxy.newProxyInstance(tClass.getClassLoader(), new Class[]{tClass}, new MultiListenerProxy<T>(listeners));
        return get(tClass, new CollectionListenerPool<T>(listeners));
    }

    private final Collection<T> listeners;
    public static <T extends IInterface> T get(Class<T> tClass, final ListenerPool<T> listenerPool) {
        return (T) Proxy.newProxyInstance(tClass.getClassLoader(), new Class[]{tClass}, new MultiListenerProxy<T>(listenerPool));
    }

    private final ListenerPool<T> listeners;

    private MultiListenerProxy(Collection<T> listeners) {
    private MultiListenerProxy(ListenerPool<T> listeners) {
        this.listeners = listeners;
    }

@@ -44,14 +50,175 @@ public class MultiListenerProxy<T extends IInterface> implements InvocationHandl
        for (T listener : new HashSet<T>(listeners)) {
            try {
                method.invoke(listener, args);
            } catch (IllegalAccessException e) {
            } catch (Exception e) {
                Log.w(TAG, e);
                listeners.remove(listener);
            } catch (InvocationTargetException e) {
                Log.w(TAG, e.getTargetException());
                listeners.remove(listener);
            }
        }
        return null;
    }

    public static abstract class ListenerPool<T> implements Collection<T> {
        @Override
        public boolean addAll(Collection<? extends T> collection) {
            return false;
        }

        @Override
        public boolean add(T object) {
            return false;
        }

        @Override
        public boolean containsAll(Collection<?> collection) {
            for (Object o : collection) {
                if (!contains(o)) return false;
            }
            return true;
        }

        @Override
        public boolean removeAll(Collection<?> collection) {
            boolean x = true;
            for (Object o : collection) {
                if (!remove(o)) x = false;
            }
            return x;
        }

        @Override
        public boolean retainAll(Collection<?> collection) {
            return false;
        }

        @NonNull
        @Override
        public Object[] toArray() {
            throw new IllegalArgumentException();
        }

        @NonNull
        @Override
        public <T1> T1[] toArray(T1[] array) {
            throw new IllegalArgumentException();
        }
    }

    private static class CollectionListenerPool<T> extends ListenerPool<T> {

        private Collection<T> listeners;

        public CollectionListenerPool(Collection<T> listeners) {
            this.listeners = listeners;
        }

        @Override
        public void clear() {
            listeners.clear();
        }

        @Override
        public boolean contains(Object object) {
            return listeners.contains(object);
        }

        @Override
        public boolean isEmpty() {
            return listeners.isEmpty();
        }

        @NonNull
        @Override
        public Iterator<T> iterator() {
            return listeners.iterator();
        }

        @Override
        public boolean remove(Object object) {
            return listeners.remove(object);
        }

        @Override
        public int size() {
            return listeners.size();
        }
    }

    public static class MultiCollectionListenerPool<T> extends ListenerPool<T> {
        private Collection<? extends Collection<T>> multiCol;

        public MultiCollectionListenerPool(Collection<? extends Collection<T>> multiCol) {
            this.multiCol = multiCol;
        }

        @Override
        public void clear() {
            for (Collection<T> ts : multiCol) {
                ts.clear();
            }
        }

        @Override
        public boolean contains(Object object) {
            for (Collection<T> ts : multiCol) {
                if (ts.contains(object)) return true;
            }
            return false;
        }

        @Override
        public boolean isEmpty() {
            for (Collection<T> ts : multiCol) {
                if (!ts.isEmpty()) return false;
            }
            return true;
        }

        @NonNull
        @Override
        public Iterator<T> iterator() {
            final Iterator<? extends Collection<T>> interMed = multiCol.iterator();
            return new Iterator<T>() {
                private Iterator<T> med;

                @Override
                public boolean hasNext() {
                    while ((med == null || !med.hasNext()) && interMed.hasNext()) {
                        med = interMed.next().iterator();
                    }
                    return med != null && med.hasNext();
                }

                @Override
                public T next() {
                    while (med == null || !med.hasNext()) {
                        med = interMed.next().iterator();
                    }
                    return med.next();
                }

                @Override
                public void remove() {
                    med.remove();
                }
            };
        }

        @Override
        public boolean remove(Object object) {
            for (Collection<T> ts : multiCol) {
                if (ts.remove(object)) return true;
            }
            return false;
        }

        @Override
        public int size() {
            int sum = 0;
            for (Collection<T> ts : multiCol) {
                sum += ts.size();
            }
            return sum;
        }
    }
}
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright 2013-2016 microG Project Team
 *
 * 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 org.microg.gms.wearable;

import android.content.Context;
import android.content.SharedPreferences;

import java.util.UUID;

public class ClockworkNodePreferences {

    private static final String CLOCKWORK_NODE_PREFERENCES = "cw_node";
    private static final String CLOCKWORK_NODE_PREFERENCE_NODE_ID = "node_id";
    private static final String CLOCKWORK_NODE_PREFERENCE_NEXT_SEQ_ID_BLOCK = "nextSeqIdBlock";

    private static final Object lock = new Object();
    private static long seqIdBlock;
    private static long seqIdInBlock = -1;

    private Context context;

    public ClockworkNodePreferences(Context context) {
        this.context = context;
    }

    public String getLocalNodeId() {
        SharedPreferences preferences = context.getSharedPreferences(CLOCKWORK_NODE_PREFERENCES, Context.MODE_PRIVATE);
        String nodeId = preferences.getString(CLOCKWORK_NODE_PREFERENCE_NODE_ID, null);
        if (nodeId == null) {
            nodeId = UUID.randomUUID().toString();
            preferences.edit().putString(CLOCKWORK_NODE_PREFERENCE_NODE_ID, nodeId).apply();
        }
        return nodeId;
    }

    public long getNextSeqId() {
        synchronized (lock) {
            SharedPreferences preferences = context.getSharedPreferences(CLOCKWORK_NODE_PREFERENCES, Context.MODE_PRIVATE);
            if (seqIdInBlock < 0) seqIdInBlock = 1000;
            if (seqIdInBlock >= 1000) {
                seqIdBlock = preferences.getLong(CLOCKWORK_NODE_PREFERENCE_NEXT_SEQ_ID_BLOCK, 100);
                preferences.edit().putLong(CLOCKWORK_NODE_PREFERENCE_NEXT_SEQ_ID_BLOCK, seqIdBlock + seqIdInBlock).apply();
                seqIdInBlock = 0;
            }
            return seqIdBlock + seqIdInBlock++;
        }
    }
}
+8 −3
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ public class MessageHandler extends ServerMessageListener {
                .networkId(networkId)
                .peerAndroidId(androidId)
                .unknown4(3)
                .unknown5(1)
                .peerVersion(1)
                .build());
        this.wearable = wearable;
        this.thisNodeId = config.nodeId;
@@ -83,6 +83,12 @@ public class MessageHandler extends ServerMessageListener {
        }
    }

    @Override
    public void onDisconnected() {
        wearable.onDisconnectReceived(getConnection(), thisNodeId, getRemoteConnect());
        super.onDisconnected();
    }

    @Override
    public void onSetAsset(SetAsset setAsset) {
        Log.d(TAG, "onSetAsset: " + setAsset);
@@ -132,8 +138,7 @@ public class MessageHandler extends ServerMessageListener {
    @Override
    public void onRpcRequest(Request rpcRequest) {
        Log.d(TAG, "onRpcRequest: " + rpcRequest);
        if (TextUtils.isEmpty(rpcRequest.targetNodeId)) {
            // TODO: That's probably not how it should go!
        if (TextUtils.isEmpty(rpcRequest.targetNodeId) || rpcRequest.targetNodeId.equals(thisNodeId)) {
            MessageEventParcelable messageEvent = new MessageEventParcelable();
            messageEvent.data = rpcRequest.rawData != null ? rpcRequest.rawData.toByteArray() : null;
            messageEvent.path = rpcRequest.path;
+0 −68
Original line number Diff line number Diff line
/*
 * Copyright 2013-2015 microG Project Team
 *
 * 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 org.microg.gms.wearable;

import android.util.Log;

import com.google.android.gms.wearable.ConnectionConfiguration;

import org.microg.wearable.SocketWearableConnection;
import org.microg.wearable.WearableConnection;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

class NetworkConnectionThread extends Thread {
    private static final String TAG = "GmsWearNetConnThr";
    private static final int WEAR_TCP_PORT = 5601;

    private ConnectionConfiguration config;
    private ServerSocket socket;
    private MessageHandler handler;
    private WearableConnection wearableConnection;

    public NetworkConnectionThread(WearableImpl wearable, ConnectionConfiguration config) {
        this.config = config;
        this.handler  = new MessageHandler(wearable, config);
    }

    public void close() {
        try {
            socket.close();
        } catch (IOException e) {
            Log.w(TAG, e);
        }
    }

    public WearableConnection getWearableConnection() {
        return wearableConnection;
    }

    @Override
    public void run() {
        try {
            socket = new ServerSocket(WEAR_TCP_PORT);
            Log.d(TAG, "Listening for connections on TCP :" + WEAR_TCP_PORT);
            Socket accepted = socket.accept();
            (wearableConnection = new SocketWearableConnection(accepted, handler)).run();
            Log.d(TAG, "Connection terminated, me too");
        } catch (IOException e) {
            Log.w(TAG, e);
        }
    }
}
Loading