blob: b85e6eee6bb8cbb9714e7a29d5ff88d45aeee043 [file] [log] [blame]
/*
* Copyright (C) 2021 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.clockwork.power;
import static android.os.PowerManager.WAKE_REASON_APPLICATION;
import static com.android.clockwork.power.IWearPowerService.OFFLOAD_BACKEND_TYPE_DISPLAYOFFLOAD;
import static com.android.clockwork.power.IWearPowerService.OFFLOAD_BACKEND_TYPE_NA;
import static com.android.clockwork.power.IWearPowerService.OFFLOAD_BACKEND_TYPE_SIDEKICK;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.ComponentName;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
import android.view.Display;
import com.android.internal.util.IndentingPrintWriter;
import com.google.android.clockwork.ambient.offload.IDisplayOffloadService;
import com.google.android.clockwork.sidekick.ISidekickService;
import com.google.android.clockwork.sidekick.SidekickServiceConstants;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Mediator that handles different offload backends.
*/
public class WearDisplayOffloadMediator {
@Retention(RetentionPolicy.SOURCE)
@IntDef(
value = {
OFFLOAD_BACKEND_TYPE_NA,
OFFLOAD_BACKEND_TYPE_SIDEKICK,
OFFLOAD_BACKEND_TYPE_DISPLAYOFFLOAD
})
public @interface OffloadBackendType {
}
private static final boolean DEBUG = Build.IS_DEBUGGABLE;
private static final String TAG = "WearDisplayOffloadMediator";
private final @Nullable
IDisplayOffloadService mDisplayOffloadService;
private final @Nullable
ISidekickService mSidekickService;
private final IActivityTaskManager mActivityTaskManagerService;
private @OffloadBackendType
int mOffloadBackendType = OFFLOAD_BACKEND_TYPE_NA;
private PowerManager mPowerManager;
private WallpaperManager mWallpaperManager;
private DisplayManager mDisplayManager;
private final String mSysUiPackageName;
public WearDisplayOffloadMediator(Context context) {
// Find DisplayOffloadService.
mDisplayOffloadService = IDisplayOffloadService.Stub.asInterface(
ServiceManager.getService(IDisplayOffloadService.NAME));
if (mDisplayOffloadService != null) {
Log.i(TAG, "Found DisplayOffloadService");
}
// Find SidekickService and check if HAL is up.
ISidekickService sidekickService = ISidekickService.Stub.asInterface(
ServiceManager.getService(SidekickServiceConstants.NAME));
if (sidekickService != null) {
try {
if (!sidekickService.sidekickExists()) {
sidekickService = null;
} else {
Log.i(TAG, "Found SidekickService");
}
} catch (RemoteException e) {
Log.w(TAG, "ISidekickService threw " + e);
sidekickService = null;
}
}
mSidekickService = sidekickService;
mActivityTaskManagerService = IActivityTaskManager.Stub.asInterface(
ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE));
mSysUiPackageName =
Settings.Global.getString(context.getContentResolver(),
Settings.Global.Wearable.CLOCKWORK_SYSUI_PACKAGE);
// Prioritize using DisplayOffload
if (mDisplayOffloadService != null) {
mOffloadBackendType = OFFLOAD_BACKEND_TYPE_DISPLAYOFFLOAD;
} else if (mSidekickService != null) {
mOffloadBackendType = OFFLOAD_BACKEND_TYPE_SIDEKICK;
} else {
mOffloadBackendType = OFFLOAD_BACKEND_TYPE_NA;
return;
}
mPowerManager = context.getSystemService(PowerManager.class);
mDisplayManager = context.getSystemService(DisplayManager.class);
mWallpaperManager = context.getSystemService(WallpaperManager.class);
Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
mWallpaperManager.addOnColorsChangedListener(
(WallpaperColors colors, int which) -> {
ComponentName topActivity = null;
try {
ActivityTaskManager.RootTaskInfo stackInfo =
mActivityTaskManagerService.getFocusedRootTaskInfo();
topActivity = stackInfo == null ? null : stackInfo.topActivity;
} catch (RemoteException e) {
Log.e(TAG, "Unable to load top stack info");
}
String topActivityPackageName =
topActivity == null ? null : topActivity.getPackageName();
if (mSysUiPackageName.equals(topActivityPackageName) &&
display.getState() == Display.STATE_DOZE_SUSPEND) {
mPowerManager.wakeUp(SystemClock.uptimeMillis(),
WAKE_REASON_APPLICATION,
"WearDisplayOffloadMediator: new style in ambient");
}
}, null);
}
public int offloadBackendGetType() {
return mOffloadBackendType;
}
public void setShouldControlDisplay(boolean shouldControlDisplay) {
if (DEBUG) {
Log.i(TAG, "setShouldControlDisplay: should=" + shouldControlDisplay);
}
// Only SidekickService is using this call
if (mOffloadBackendType == OFFLOAD_BACKEND_TYPE_SIDEKICK) {
try {
mSidekickService.setShouldControlDisplay(shouldControlDisplay);
} catch (RemoteException e) {
Log.w(TAG, "setShouldControlDisplay: ISidekickService threw " + e);
}
} else {
if (DEBUG) {
Log.i(TAG, "setShouldControlDisplay: Sidekick is not available, do nothing.");
}
}
}
public boolean offloadBackendReadyToDisplay() {
if (mOffloadBackendType == OFFLOAD_BACKEND_TYPE_SIDEKICK) {
try {
return mSidekickService.readyToDisplay();
} catch (RemoteException e) {
Log.w(TAG, "offloadBackendReadyToDisplay: ISidekickService threw " + e);
}
} else if (mOffloadBackendType == OFFLOAD_BACKEND_TYPE_DISPLAYOFFLOAD) {
try {
return mDisplayOffloadService.readyToDisplay();
} catch (RemoteException e) {
Log.w(TAG, "offloadBackendReadyToDisplay: IDisplayOffloadService threw " + e);
}
}
if (DEBUG) {
Log.i(TAG, "offloadBackendReadyToDisplay: no backend is ready to display.");
}
return false;
}
public void dump(IndentingPrintWriter ipw) {
ipw.println("======== WearDisplayOffloadMediator ========");
ipw.println();
ipw.increaseIndent();
ipw.print("Offload Backends Available:");
if (mSidekickService != null) ipw.print(" Sidekick");
if (mOffloadBackendType == OFFLOAD_BACKEND_TYPE_SIDEKICK) ipw.print("[In Use]");
if (mDisplayOffloadService != null) ipw.print(" DisplayOffload");
if (mOffloadBackendType == OFFLOAD_BACKEND_TYPE_DISPLAYOFFLOAD) ipw.print("[In Use]");
ipw.println();
ipw.decreaseIndent();
ipw.println();
}
}