1b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar/*
264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar * Copyright (C) 2017 The Android Open Source Project
3b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar *
4b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
5b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar * you may not use this file except in compliance with the License.
6b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar * You may obtain a copy of the License at
7b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar *
8b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
9b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar *
10b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar * Unless required by applicable law or agreed to in writing, software
11b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
12b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar * See the License for the specific language governing permissions and
14b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar * limitations under the License.
15b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar */
16b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
1764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarpackage android.arch.lifecycle;
18b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
19b86bef286718da421268bc52cf4fab7cccb3104cSergey Vasilinetsimport android.arch.lifecycle.Lifecycle.Event;
20b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
2119b41105359a52aeb80070dec40247241231f05dYigit Boyarimport java.lang.reflect.InvocationTargetException;
22b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyarimport java.lang.reflect.Method;
23b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyarimport java.util.ArrayList;
24b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyarimport java.util.HashMap;
25b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyarimport java.util.List;
26b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyarimport java.util.Map;
27daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinetsimport java.util.Map.Entry;
28b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
29b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar/**
30b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar * An internal implementation of {@link GenericLifecycleObserver} that relies on reflection.
31b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar */
32b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyarclass ReflectiveGenericLifecycleObserver implements GenericLifecycleObserver {
33b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    private final Object mWrapped;
34b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    private final CallbackInfo mInfo;
35b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    @SuppressWarnings("WeakerAccess")
36b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    static final Map<Class, CallbackInfo> sInfoCache = new HashMap<>();
37b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
38b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    ReflectiveGenericLifecycleObserver(Object wrapped) {
39b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        mWrapped = wrapped;
40b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        mInfo = getInfo(mWrapped.getClass());
41b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    }
42b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
43b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    @Override
44b86bef286718da421268bc52cf4fab7cccb3104cSergey Vasilinets    public void onStateChanged(LifecycleOwner source, Event event) {
450bc2a6a0aae3c50591dd09ba324d884a902187caSergey Vasilinets        invokeCallbacks(mInfo, source, event);
46b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    }
47b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
48044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets    private void invokeMethodsForEvent(List<MethodReference> handlers, LifecycleOwner source,
49044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets            Event event) {
50044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets        if (handlers != null) {
51044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets            for (int i = handlers.size() - 1; i >= 0; i--) {
52044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets                MethodReference reference = handlers.get(i);
530bc2a6a0aae3c50591dd09ba324d884a902187caSergey Vasilinets                invokeCallback(reference, source, event);
54b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            }
55b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        }
56044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets    }
57044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets
58044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets    @SuppressWarnings("ConstantConditions")
59044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets    private void invokeCallbacks(CallbackInfo info, LifecycleOwner source, Event event) {
60daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        invokeMethodsForEvent(info.mEventToHandlers.get(event), source, event);
61daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        invokeMethodsForEvent(info.mEventToHandlers.get(Event.ON_ANY), source, event);
62b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    }
63b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
640bc2a6a0aae3c50591dd09ba324d884a902187caSergey Vasilinets    private void invokeCallback(MethodReference reference, LifecycleOwner source, Event event) {
65044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets        //noinspection TryWithIdenticalCatches
66044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets        try {
67044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets            switch (reference.mCallType) {
68044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets                case CALL_TYPE_NO_ARG:
69044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets                    reference.mMethod.invoke(mWrapped);
70044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets                    break;
71044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets                case CALL_TYPE_PROVIDER:
72044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets                    reference.mMethod.invoke(mWrapped, source);
73044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets                    break;
74044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets                case CALL_TYPE_PROVIDER_WITH_EVENT:
75044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets                    reference.mMethod.invoke(mWrapped, source, event);
76044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets                    break;
77b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            }
78044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets        } catch (InvocationTargetException e) {
79044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets            throw new RuntimeException("Failed to call observer method", e.getCause());
80044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets        } catch (IllegalAccessException e) {
81044fe16ec17aeb265ad988fe601cbac6e6bd39a4Sergey Vasilinets            throw new RuntimeException(e);
82b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        }
83b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    }
84b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
85b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    private static CallbackInfo getInfo(Class klass) {
86b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        CallbackInfo existing = sInfoCache.get(klass);
87b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        if (existing != null) {
88b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            return existing;
89b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        }
90b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        existing = createInfo(klass);
91b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        return existing;
92b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    }
93b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
94daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets    private static void verifyAndPutHandler(Map<MethodReference, Event> handlers,
95daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            MethodReference newHandler, Event newEvent, Class klass) {
96daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        Event event = handlers.get(newHandler);
97daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        if (event != null && newEvent != event) {
98daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            Method method = newHandler.mMethod;
99daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            throw new IllegalArgumentException(
100daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                    "Method " + method.getName() + " in " + klass.getName()
101daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                            + " already declared with different @OnLifecycleEvent value: previous"
102daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                            + " value " + event + ", new value " + newEvent);
103daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        }
104daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        if (event == null) {
105daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            handlers.put(newHandler, newEvent);
106daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        }
107daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets    }
108daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets
109b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    private static CallbackInfo createInfo(Class klass) {
110daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        Class superclass = klass.getSuperclass();
111daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        Map<MethodReference, Event> handlerToEvent = new HashMap<>();
112daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        if (superclass != null) {
113daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            CallbackInfo superInfo = getInfo(superclass);
114daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            if (superInfo != null) {
115daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                handlerToEvent.putAll(superInfo.mHandlerToEvent);
116daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            }
117daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        }
118daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets
119b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        Method[] methods = klass.getDeclaredMethods();
120daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets
121daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        Class[] interfaces = klass.getInterfaces();
122daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        for (Class intrfc : interfaces) {
123daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            for (Entry<MethodReference, Event> entry : getInfo(intrfc).mHandlerToEvent.entrySet()) {
124daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                verifyAndPutHandler(handlerToEvent, entry.getKey(), entry.getValue(), klass);
125daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            }
126daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        }
127daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets
128b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        for (Method method : methods) {
1294c90a591fe9521ebf90a319bb90846f5c193f4eaYigit Boyar            OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);
130b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            if (annotation == null) {
131b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar                continue;
132b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            }
133b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            Class<?>[] params = method.getParameterTypes();
134b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            int callType = CALL_TYPE_NO_ARG;
135b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            if (params.length > 0) {
136b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar                callType = CALL_TYPE_PROVIDER;
137e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets                if (!params[0].isAssignableFrom(LifecycleOwner.class)) {
138b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar                    throw new IllegalArgumentException(
139e13540a25fe5460240b6db0e18858c32d16f5399Sergey Vasilinets                            "invalid parameter type. Must be one and instanceof LifecycleOwner");
140b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar                }
141b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            }
1425ef35b172e9d0e082ba0e544f0c591bf6e1507f0Sergey Vasilinets            Event event = annotation.value();
1435ef35b172e9d0e082ba0e544f0c591bf6e1507f0Sergey Vasilinets
144b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            if (params.length > 1) {
1454c90a591fe9521ebf90a319bb90846f5c193f4eaYigit Boyar                callType = CALL_TYPE_PROVIDER_WITH_EVENT;
146b86bef286718da421268bc52cf4fab7cccb3104cSergey Vasilinets                if (!params[1].isAssignableFrom(Event.class)) {
147b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar                    throw new IllegalArgumentException(
1484c90a591fe9521ebf90a319bb90846f5c193f4eaYigit Boyar                            "invalid parameter type. second arg must be an event");
149b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar                }
1505ef35b172e9d0e082ba0e544f0c591bf6e1507f0Sergey Vasilinets                if (event != Event.ON_ANY) {
1515ef35b172e9d0e082ba0e544f0c591bf6e1507f0Sergey Vasilinets                    throw new IllegalArgumentException(
1525ef35b172e9d0e082ba0e544f0c591bf6e1507f0Sergey Vasilinets                            "Second arg is supported only for ON_ANY value");
1535ef35b172e9d0e082ba0e544f0c591bf6e1507f0Sergey Vasilinets                }
154b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            }
155b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            if (params.length > 2) {
156b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar                throw new IllegalArgumentException("cannot have more than 2 params");
157b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            }
158daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            MethodReference methodReference = new MethodReference(callType, method);
159daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            verifyAndPutHandler(handlerToEvent, methodReference, event, klass);
160b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        }
161daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        CallbackInfo info = new CallbackInfo(handlerToEvent);
162b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        sInfoCache.put(klass, info);
163b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        return info;
164b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    }
165b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
166b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    @SuppressWarnings("WeakerAccess")
167b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    static class CallbackInfo {
168daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        final Map<Event, List<MethodReference>> mEventToHandlers;
169daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        final Map<MethodReference, Event> mHandlerToEvent;
170daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets
171daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        CallbackInfo(Map<MethodReference, Event> handlerToEvent) {
172daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            mHandlerToEvent = handlerToEvent;
173daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            mEventToHandlers = new HashMap<>();
174daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            for (Entry<MethodReference, Event> entry : handlerToEvent.entrySet()) {
175daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                Event event = entry.getValue();
176daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                List<MethodReference> methodReferences = mEventToHandlers.get(event);
177daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                if (methodReferences == null) {
178daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                    methodReferences = new ArrayList<>();
179daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                    mEventToHandlers.put(event, methodReferences);
180daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                }
181daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                methodReferences.add(entry.getKey());
182daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            }
183b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        }
184b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    }
185b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
186b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    @SuppressWarnings("WeakerAccess")
187b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    static class MethodReference {
188b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        final int mCallType;
189b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        final Method mMethod;
190b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
191daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        MethodReference(int callType, Method method) {
192b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            mCallType = callType;
193b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar            mMethod = method;
194b86bef286718da421268bc52cf4fab7cccb3104cSergey Vasilinets            mMethod.setAccessible(true);
195b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar        }
196daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets
197daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        @Override
198daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        public boolean equals(Object o) {
199daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            if (this == o) {
200daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                return true;
201daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            }
202daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            if (o == null || getClass() != o.getClass()) {
203daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets                return false;
204daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            }
205daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets
206daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            MethodReference that = (MethodReference) o;
207daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            return mCallType == that.mCallType && mMethod.getName().equals(that.mMethod.getName());
208daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        }
209daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets
210daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        @Override
211daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        public int hashCode() {
212daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets            return 31 * mCallType + mMethod.getName().hashCode();
213daa68aab1adbf8c5b5c64d2b34a60955da742f1dSergey Vasilinets        }
214b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    }
215b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar
216b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    private static final int CALL_TYPE_NO_ARG = 0;
217b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar    private static final int CALL_TYPE_PROVIDER = 1;
2184c90a591fe9521ebf90a319bb90846f5c193f4eaYigit Boyar    private static final int CALL_TYPE_PROVIDER_WITH_EVENT = 2;
219b18b96e1ff52c6ee522b592005f0525511e5d083Yigit Boyar}
220