com.nick.scalpel.core.AutoBindWirer.java Source code

Java tutorial

Introduction

Here is the source code for com.nick.scalpel.core.AutoBindWirer.java

Source

/*
 * Copyright (c) 2016 Nick Guo
 *
 * 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.nick.scalpel.core;

import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.view.View;

import com.nick.scalpel.config.Configuration;
import com.nick.scalpel.core.utils.Preconditions;
import com.nick.scalpel.core.utils.ReflectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class AutoBindWirer extends AbsFieldWirer {

    LifeCycleManager mLifeCycleManager;

    public AutoBindWirer(Configuration configuration, LifeCycleManager manager) {
        super(configuration);
        this.mLifeCycleManager = manager;
    }

    @Override
    public Class<? extends Annotation> annotationClass() {
        return AutoBind.class;
    }

    @Override
    public void wire(Activity activity, Field field) {
        wire(activity.getApplicationContext(), activity, field);
    }

    @Override
    public void wire(Fragment fragment, Field field) {
        wire(fragment.getActivity(), fragment, field);
    }

    @Override
    public void wire(Service service, Field field) {
        wire(service.getApplicationContext(), service, field);
    }

    @Override
    public void wire(final Context context, final Object object, final Field field) {
        ReflectionUtils.makeAccessible(field);
        Object fieldObject = ReflectionUtils.getField(field, object);
        if (fieldObject != null)
            return;

        // FIXME: 21/03/16 Ensure it is an AIDL service.
        boolean isIInterface = field.getType().isInterface();
        Preconditions.checkState(isIInterface,
                "Field:" + field.getName() + " is not an AIDL interface, is:" + field.getType());

        AutoBind autoBind = field.getAnnotation(AutoBind.class);
        String action = autoBind.action();
        String pkg = autoBind.pkg();
        int flags = autoBind.flags();
        String callback = autoBind.callback();
        boolean startService = autoBind.startService();
        boolean isExplicit = !TextUtils.isEmpty(action) && !TextUtils.isEmpty(pkg);
        Preconditions.checkState(isExplicit, "Action and PackageName should be specified");

        boolean autoUnbind = autoBind.autoUnbind();
        boolean isActivity = object instanceof Activity;
        Preconditions.checkState(!autoUnbind || isActivity, "Auto unbind only work for activities.");

        AutoBind.Callback callbackInstance = null;
        if (!TextUtils.isEmpty(callback)) {
            Object callbackObject = null;
            switch (callback) {
            case "this":
                callbackObject = object;
                break;
            default:
                Field callbackField = ReflectionUtils.findField(object, callback);
                if (callbackField != null) {
                    ReflectionUtils.makeAccessible(callbackField);
                    callbackObject = ReflectionUtils.getField(callbackField, object);
                }
            }
            boolean isCallback = callbackObject instanceof AutoBind.Callback;
            Preconditions.checkState(isCallback, "Field:" + callback + " is not an instance of Callback.");
            callbackInstance = (AutoBind.Callback) callbackObject;
        }

        final Intent intent = new Intent(action);
        intent.setPackage(pkg);

        if (startService)
            context.startService(intent);

        final AutoBind.Callback finalCallbackInstance = callbackInstance;
        final ServiceConnection connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Class serviceClass = field.getType();
                String stubClassName = serviceClass.getName() + "$Stub";
                try {
                    Class stubClass = Class.forName(stubClassName);
                    Method asInterface = ReflectionUtils.findMethod(stubClass, "asInterface", IBinder.class);
                    Object result = ReflectionUtils.invokeMethod(asInterface, null, service);
                    ReflectionUtils.setField(field, object, result);
                    // Callback result.
                    if (finalCallbackInstance != null)
                        finalCallbackInstance.onServiceBound(name, this, intent);
                } catch (ClassNotFoundException e) {
                    throw new IllegalArgumentException(e);
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                if (finalCallbackInstance != null)
                    finalCallbackInstance.onServiceDisconnected(name);
            }
        };
        //noinspection ResourceType
        context.bindService(intent, connection, flags);

        if (autoUnbind) {
            final String fieldName = field.getName();
            boolean registered = mLifeCycleManager
                    .registerActivityLifecycleCallbacks(new LifeCycleCallbackAdapter() {
                        @Override
                        public void onActivityDestroyed(Activity activity) {
                            super.onActivityDestroyed(activity);
                            if (activity == object) {
                                logV("unBind service for: " + fieldName);
                                context.unbindService(connection);
                                mLifeCycleManager.unRegisterActivityLifecycleCallbacks(this);
                            }
                        }
                    });
            if (!registered) {
                logE("Failed to register life cycle callback!");
            }
        }
    }

    @Override
    public void wire(View root, Object object, Field field) {
        wire(root.getContext(), object, field);
    }
}