/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * 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.android.car;

import android.car.CarAppFocusManager;
import android.car.IAppFocus;
import android.car.IAppFocusListener;
import android.car.IAppFocusOwnershipCallback;
import android.content.Context;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
 * App focus service ensures only one instance of application type is active at a time.
 */
public class AppFocusService extends IAppFocus.Stub implements CarServiceBase,
        BinderInterfaceContainer.BinderEventHandler<IAppFocusOwnershipCallback> {
    private static final boolean DBG = false;
    private static final boolean DBG_EVENT = false;

    private final SystemActivityMonitoringService mSystemActivityMonitoringService;

    private final Object mLock = new Object();

    @VisibleForTesting
    @GuardedBy("mLock")
    final ClientHolder mAllChangeClients;

    @VisibleForTesting
    @GuardedBy("mLock")
    final OwnershipClientHolder mAllOwnershipClients;

    /** K: appType, V: client owning it */
    @GuardedBy("mLock")
    private final SparseArray<OwnershipClientInfo> mFocusOwners = new SparseArray<>();

    @GuardedBy("mLock")
    private final Set<Integer> mActiveAppTypes = new ArraySet<>();

    @GuardedBy("mLock")
    private final List<FocusOwnershipCallback> mFocusOwnershipCallbacks = new ArrayList<>();

    private final BinderInterfaceContainer.BinderEventHandler<IAppFocusListener>
            mAllBinderEventHandler = bInterface -> { /* nothing to do.*/ };

    private final HandlerThread mHandlerThread = CarServiceUtils.getHandlerThread(
            getClass().getSimpleName());
    private final DispatchHandler mDispatchHandler = new DispatchHandler(mHandlerThread.getLooper(),
            this);

    public AppFocusService(Context context,
            SystemActivityMonitoringService systemActivityMonitoringService) {
        mSystemActivityMonitoringService = systemActivityMonitoringService;
        mAllChangeClients = new ClientHolder(mAllBinderEventHandler);
        mAllOwnershipClients = new OwnershipClientHolder(this);
    }

    @Override
    public void registerFocusListener(IAppFocusListener listener, int appType) {
        synchronized (mLock) {
            ClientInfo info = (ClientInfo) mAllChangeClients.getBinderInterface(listener);
            if (info == null) {
                info = new ClientInfo(mAllChangeClients, listener, Binder.getCallingUid(),
                        Binder.getCallingPid(), appType);
                mAllChangeClients.addBinderInterface(info);
            } else {
                info.addAppType(appType);
            }
        }
    }

    @Override
    public void unregisterFocusListener(IAppFocusListener listener, int appType) {
        synchronized (mLock) {
            ClientInfo info = (ClientInfo) mAllChangeClients.getBinderInterface(listener);
            if (info == null) {
                return;
            }
            info.removeAppType(appType);
            if (info.getAppTypes().isEmpty()) {
                mAllChangeClients.removeBinder(listener);
            }
        }
    }

    @Override
    public int[] getActiveAppTypes() {
        synchronized (mLock) {
            return mActiveAppTypes.stream().mapToInt(Integer::intValue).toArray();
        }
    }

    @Override
    public boolean isOwningFocus(IAppFocusOwnershipCallback callback, int appType) {
        OwnershipClientInfo info;
        synchronized (mLock) {
            info = (OwnershipClientInfo) mAllOwnershipClients.getBinderInterface(callback);
        }
        if (info == null) {
            return false;
        }
        return info.getOwnedAppTypes().contains(appType);
    }

    @Override
    public int requestAppFocus(IAppFocusOwnershipCallback callback, int appType) {
        synchronized (mLock) {
            OwnershipClientInfo info =
                    (OwnershipClientInfo) mAllOwnershipClients.getBinderInterface(callback);
            if (info == null) {
                info = new OwnershipClientInfo(mAllOwnershipClients, callback,
                        Binder.getCallingUid(), Binder.getCallingPid());
                mAllOwnershipClients.addBinderInterface(info);
            }
            Set<Integer> alreadyOwnedAppTypes = info.getOwnedAppTypes();
            if (!alreadyOwnedAppTypes.contains(appType)) {
                OwnershipClientInfo ownerInfo = mFocusOwners.get(appType);
                if (ownerInfo != null && ownerInfo != info) {
                    if (mSystemActivityMonitoringService.isInForeground(
                            ownerInfo.getPid(), ownerInfo.getUid())
                            && !mSystemActivityMonitoringService.isInForeground(
                            info.getPid(), info.getUid())) {
                        Log.w(CarLog.TAG_APP_FOCUS, "Focus request failed for non-foreground app("
                                + "pid=" + info.getPid() + ", uid=" + info.getUid() + ")."
                                + "Foreground app (pid=" + ownerInfo.getPid() + ", uid="
                                + ownerInfo.getUid() + ") owns it.");
                        return CarAppFocusManager.APP_FOCUS_REQUEST_FAILED;
                    }
                    ownerInfo.removeOwnedAppType(appType);
                    mDispatchHandler.requestAppFocusOwnershipLossDispatch(
                            ownerInfo.binderInterface, appType);
                    if (DBG) {
                        Log.i(CarLog.TAG_APP_FOCUS, "losing app type "
                                + appType + "," + ownerInfo.toString());
                    }
                }
                updateFocusOwner(appType, info);
            }
            info.addOwnedAppType(appType);
            mDispatchHandler.requestAppFocusOwnershipGrantDispatch(
                    info.binderInterface, appType);
            if (mActiveAppTypes.add(appType)) {
                if (DBG) {
                    Log.i(CarLog.TAG_APP_FOCUS, "adding active app type " + appType + ","
                            + info.toString());
                }
                for (BinderInterfaceContainer.BinderInterface<IAppFocusListener> client :
                        mAllChangeClients.getInterfaces()) {
                    ClientInfo clientInfo = (ClientInfo) client;
                    // dispatch events only when there is change after filter and the listener
                    // is not coming from the current caller.
                    if (clientInfo.getAppTypes().contains(appType)) {
                        mDispatchHandler.requestAppFocusChangeDispatch(clientInfo.binderInterface,
                                appType, true);
                    }
                }
            }
        }
        return CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED;
    }

    @Override
    public void abandonAppFocus(IAppFocusOwnershipCallback callback, int appType) {
        synchronized (mLock) {
            OwnershipClientInfo info =
                    (OwnershipClientInfo) mAllOwnershipClients.getBinderInterface(callback);
            if (info == null) {
                // ignore as this client cannot have owned anything.
                return;
            }
            if (!mActiveAppTypes.contains(appType)) {
                // ignore as none of them are active;
                return;
            }
            Set<Integer> currentlyOwnedAppTypes = info.getOwnedAppTypes();
            if (!currentlyOwnedAppTypes.contains(appType)) {
                // ignore as listener doesn't own focus.
                return;
            }
            if (mFocusOwners.contains(appType)) {
                mFocusOwners.remove(appType);
                mActiveAppTypes.remove(appType);
                info.removeOwnedAppType(appType);
                if (DBG) {
                    Log.i(CarLog.TAG_APP_FOCUS, "abandoning focus " + appType
                            + "," + info.toString());
                }
                for (FocusOwnershipCallback ownershipCallback : mFocusOwnershipCallbacks) {
                    ownershipCallback.onFocusAbandoned(appType, info.mUid, info.mPid);
                }
                for (BinderInterfaceContainer.BinderInterface<IAppFocusListener> client :
                        mAllChangeClients.getInterfaces()) {
                    ClientInfo clientInfo = (ClientInfo) client;
                    if (clientInfo.getAppTypes().contains(appType)) {
                        mDispatchHandler.requestAppFocusChangeDispatch(clientInfo.binderInterface,
                                appType, false);
                    }
                }
            }
        }
    }

    @Override
    public void init() {
        // nothing to do
    }

    @VisibleForTesting
    public Looper getLooper() {
        return mHandlerThread.getLooper();

    }

    @Override
    public void release() {
        synchronized (mLock) {
            mAllChangeClients.clear();
            mAllOwnershipClients.clear();
            mFocusOwners.clear();
            mActiveAppTypes.clear();
        }
    }

    @Override
    public void onBinderDeath(
            BinderInterfaceContainer.BinderInterface<IAppFocusOwnershipCallback> bInterface) {
        OwnershipClientInfo info = (OwnershipClientInfo) bInterface;
        synchronized (mLock) {
            for (Integer appType : info.getOwnedAppTypes()) {
                abandonAppFocus(bInterface.binderInterface, appType);
            }
        }
    }

    @Override
    public void dump(PrintWriter writer) {
        writer.println("**AppFocusService**");
        synchronized (mLock) {
            writer.println("mActiveAppTypes:" + mActiveAppTypes);
            for (BinderInterfaceContainer.BinderInterface<IAppFocusOwnershipCallback> client :
                    mAllOwnershipClients.getInterfaces()) {
                OwnershipClientInfo clientInfo = (OwnershipClientInfo) client;
                writer.println(clientInfo.toString());
            }
        }
    }

    /**
     * Returns true if process with given uid and pid owns provided focus.
     */
    public boolean isFocusOwner(int uid, int pid, int appType) {
        synchronized (mLock) {
            if (mFocusOwners.contains(appType)) {
                OwnershipClientInfo clientInfo = mFocusOwners.get(appType);
                return clientInfo.getUid() == uid && clientInfo.getPid() == pid;
            }
        }
        return false;
    }

    /**
     * Defines callback functions that will be called when ownership has been changed.
     */
    public interface FocusOwnershipCallback {
        void onFocusAcquired(int appType, int uid, int pid);
        void onFocusAbandoned(int appType, int uid, int pid);
    }

    /**
     * Registers callback.
     *
     * If any focus already acquired it will trigger
     * {@link FocusOwnershipCallback#onFocusAcquired} call immediately in the same thread.
     */
    public void registerContextOwnerChangedCallback(FocusOwnershipCallback callback) {
        SparseArray<OwnershipClientInfo> owners;
        synchronized (mLock) {
            mFocusOwnershipCallbacks.add(callback);
            owners = mFocusOwners.clone();
        }
        for (int idx = 0; idx < owners.size(); idx++) {
            int key = owners.keyAt(idx);
            OwnershipClientInfo clientInfo = owners.valueAt(idx);
            callback.onFocusAcquired(key, clientInfo.getUid(), clientInfo.getPid());
        }
    }

    /**
     * Unregisters provided callback.
     */
    public void unregisterContextOwnerChangedCallback(FocusOwnershipCallback callback) {
        synchronized (mLock) {
            mFocusOwnershipCallbacks.remove(callback);
        }
    }

    private void updateFocusOwner(int appType, OwnershipClientInfo owner) {
        CarServiceUtils.runOnMain(() -> {
            List<FocusOwnershipCallback> focusOwnershipCallbacks;
            synchronized (mLock) {
                mFocusOwners.put(appType, owner);
                focusOwnershipCallbacks = new ArrayList<>(mFocusOwnershipCallbacks);
            }
            for (FocusOwnershipCallback callback : focusOwnershipCallbacks) {
                callback.onFocusAcquired(appType, owner.getUid(), owner.getPid());
            }
        });
    }

    private void dispatchAppFocusOwnershipLoss(IAppFocusOwnershipCallback callback, int appType) {
        try {
            callback.onAppFocusOwnershipLost(appType);
        } catch (RemoteException e) {
        }
    }

    private void dispatchAppFocusOwnershipGrant(IAppFocusOwnershipCallback callback, int appType) {
        try {
            callback.onAppFocusOwnershipGranted(appType);
        } catch (RemoteException e) {
        }
    }

    private void dispatchAppFocusChange(IAppFocusListener listener, int appType, boolean active) {
        try {
            listener.onAppFocusChanged(appType, active);
        } catch (RemoteException e) {
        }
    }

    @VisibleForTesting
    static class ClientHolder extends BinderInterfaceContainer<IAppFocusListener> {
        private ClientHolder(BinderEventHandler<IAppFocusListener> holder) {
            super(holder);
        }
    }

    @VisibleForTesting
    static class OwnershipClientHolder extends
            BinderInterfaceContainer<IAppFocusOwnershipCallback> {
        private OwnershipClientHolder(AppFocusService service) {
            super(service);
        }
    }

    private class ClientInfo extends
            BinderInterfaceContainer.BinderInterface<IAppFocusListener> {
        private final int mUid;
        private final int mPid;

        @GuardedBy("AppFocusService.mLock")
        private final Set<Integer> mAppTypes = new ArraySet<>();

        private ClientInfo(ClientHolder holder, IAppFocusListener binder, int uid, int pid,
                int appType) {
            super(holder, binder);
            this.mUid = uid;
            this.mPid = pid;
            this.mAppTypes.add(appType);
        }

        private Set<Integer> getAppTypes() {
            synchronized (mLock) {
                return Collections.unmodifiableSet(mAppTypes);
            }
        }

        private boolean addAppType(Integer appType) {
            synchronized (mLock) {
                return mAppTypes.add(appType);
            }
        }

        private boolean removeAppType(Integer appType) {
            synchronized (mLock) {
                return mAppTypes.remove(appType);
            }
        }

        @Override
        public String toString() {
            synchronized (mLock) {
                return "ClientInfo{mUid=" + mUid + ",mPid=" + mPid
                        + ",appTypes=" + mAppTypes + "}";
            }
        }
    }

    private class OwnershipClientInfo extends
            BinderInterfaceContainer.BinderInterface<IAppFocusOwnershipCallback> {
        private final int mUid;
        private final int mPid;

        @GuardedBy("AppFocusService.mLock")
        private final Set<Integer> mOwnedAppTypes = new ArraySet<>();

        private OwnershipClientInfo(OwnershipClientHolder holder, IAppFocusOwnershipCallback binder,
                int uid, int pid) {
            super(holder, binder);
            this.mUid = uid;
            this.mPid = pid;
        }

        private Set<Integer> getOwnedAppTypes() {
            if (DBG_EVENT) {
                Log.i(CarLog.TAG_APP_FOCUS, "getOwnedAppTypes " + mOwnedAppTypes);
            }
            synchronized (mLock) {
                return Collections.unmodifiableSet(mOwnedAppTypes);
            }
        }

        private boolean addOwnedAppType(Integer appType) {
            if (DBG_EVENT) {
                Log.i(CarLog.TAG_APP_FOCUS, "addOwnedAppType " + appType);
            }
            synchronized (mLock) {
                return mOwnedAppTypes.add(appType);
            }
        }

        private boolean removeOwnedAppType(Integer appType) {
            if (DBG_EVENT) {
                Log.i(CarLog.TAG_APP_FOCUS, "removeOwnedAppType " + appType);
            }
            synchronized (mLock) {
                return mOwnedAppTypes.remove(appType);
            }
        }

        int getUid() {
            return mUid;
        }

        int getPid() {
            return mPid;
        }

        @Override
        public String toString() {
            synchronized (mLock) {
                return "ClientInfo{mUid=" + mUid + ",mPid=" + mPid
                        + ",owned=" + mOwnedAppTypes + "}";
            }
        }
    }

    private static final class DispatchHandler extends Handler {
        private static final String TAG = DispatchHandler.class.getSimpleName();

        private static final int MSG_DISPATCH_OWNERSHIP_LOSS = 0;
        private static final int MSG_DISPATCH_OWNERSHIP_GRANT = 1;
        private static final int MSG_DISPATCH_FOCUS_CHANGE = 2;

        private final WeakReference<AppFocusService> mService;

        private DispatchHandler(Looper looper, AppFocusService service) {
            super(looper);
            mService = new WeakReference<AppFocusService>(service);
        }

        private void requestAppFocusOwnershipLossDispatch(IAppFocusOwnershipCallback callback,
                int appType) {
            Message msg = obtainMessage(MSG_DISPATCH_OWNERSHIP_LOSS, appType, 0, callback);
            sendMessage(msg);
        }

        private void requestAppFocusOwnershipGrantDispatch(IAppFocusOwnershipCallback callback,
                int appType) {
            Message msg = obtainMessage(MSG_DISPATCH_OWNERSHIP_GRANT, appType, 0, callback);
            sendMessage(msg);
        }

        private void requestAppFocusChangeDispatch(IAppFocusListener listener, int appType,
                boolean active) {
            Message msg = obtainMessage(MSG_DISPATCH_FOCUS_CHANGE, appType, active ? 1 : 0,
                    listener);
            sendMessage(msg);
        }

        @Override
        public void handleMessage(Message msg) {
            AppFocusService service = mService.get();
            if (service == null) {
                Log.i(TAG, "handleMessage null service");
                return;
            }
            switch (msg.what) {
                case MSG_DISPATCH_OWNERSHIP_LOSS:
                    service.dispatchAppFocusOwnershipLoss((IAppFocusOwnershipCallback) msg.obj,
                            msg.arg1);
                    break;
                case MSG_DISPATCH_OWNERSHIP_GRANT:
                    service.dispatchAppFocusOwnershipGrant((IAppFocusOwnershipCallback) msg.obj,
                            msg.arg1);
                    break;
                case MSG_DISPATCH_FOCUS_CHANGE:
                    service.dispatchAppFocusChange((IAppFocusListener) msg.obj, msg.arg1,
                            msg.arg2 == 1);
                    break;
                default:
                    Log.e(CarLog.TAG_APP_FOCUS, "Can't dispatch message: " + msg);
            }
        }
    }
}
