SmartspaceManager initial implementation
Bug: 176851064 Test: Deployed on Phone,CTS tests Change-Id: I3e03628d4d0e0aec0b6442f0ee8949ac378a1572
This commit is contained in:
@@ -138,6 +138,7 @@ package android {
|
||||
field public static final String MANAGE_ROTATION_RESOLVER = "android.permission.MANAGE_ROTATION_RESOLVER";
|
||||
field public static final String MANAGE_SEARCH_UI = "android.permission.MANAGE_SEARCH_UI";
|
||||
field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
|
||||
field public static final String MANAGE_SMARTSPACE = "android.permission.MANAGE_SMARTSPACE";
|
||||
field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
|
||||
field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
|
||||
field public static final String MANAGE_TEST_NETWORKS = "android.permission.MANAGE_TEST_NETWORKS";
|
||||
@@ -1493,6 +1494,169 @@ package android.app.search {
|
||||
|
||||
}
|
||||
|
||||
package android.app.smartspace {
|
||||
|
||||
public final class SmartspaceAction implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @Nullable public CharSequence getContentDescription();
|
||||
method @Nullable public android.os.Bundle getExtras();
|
||||
method @Nullable public android.graphics.drawable.Icon getIcon();
|
||||
method @NonNull public String getId();
|
||||
method @Nullable public android.content.Intent getIntent();
|
||||
method @Nullable public android.app.PendingIntent getPendingIntent();
|
||||
method @Nullable public CharSequence getSubtitle();
|
||||
method @NonNull public CharSequence getTitle();
|
||||
method @Nullable public android.os.UserHandle getUserHandle();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.SmartspaceAction> CREATOR;
|
||||
}
|
||||
|
||||
public static final class SmartspaceAction.Builder {
|
||||
ctor public SmartspaceAction.Builder(@NonNull String, @NonNull String);
|
||||
method @NonNull public android.app.smartspace.SmartspaceAction build();
|
||||
method @NonNull public android.app.smartspace.SmartspaceAction.Builder setContentDescription(@Nullable CharSequence);
|
||||
method @NonNull public android.app.smartspace.SmartspaceAction.Builder setExtras(@Nullable android.os.Bundle);
|
||||
method @NonNull public android.app.smartspace.SmartspaceAction.Builder setIcon(@Nullable android.graphics.drawable.Icon);
|
||||
method @NonNull public android.app.smartspace.SmartspaceAction.Builder setIntent(@Nullable android.content.Intent);
|
||||
method @NonNull public android.app.smartspace.SmartspaceAction.Builder setPendingIntent(@Nullable android.app.PendingIntent);
|
||||
method @NonNull public android.app.smartspace.SmartspaceAction.Builder setSubtitle(@Nullable CharSequence);
|
||||
method @NonNull public android.app.smartspace.SmartspaceAction.Builder setUserHandle(@Nullable android.os.UserHandle);
|
||||
}
|
||||
|
||||
public final class SmartspaceConfig implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @Nullable public android.os.Bundle getExtras();
|
||||
method @NonNull public String getPackageName();
|
||||
method @NonNull public int getSmartspaceTargetCount();
|
||||
method @NonNull public String getUiSurface();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.SmartspaceConfig> CREATOR;
|
||||
}
|
||||
|
||||
public static final class SmartspaceConfig.Builder {
|
||||
ctor public SmartspaceConfig.Builder(@NonNull android.content.Context, @NonNull String);
|
||||
method @NonNull public android.app.smartspace.SmartspaceConfig build();
|
||||
method @NonNull public android.app.smartspace.SmartspaceConfig.Builder setExtras(@NonNull android.os.Bundle);
|
||||
method @NonNull public android.app.smartspace.SmartspaceConfig.Builder setSmartspaceTargetCount(int);
|
||||
}
|
||||
|
||||
public final class SmartspaceManager {
|
||||
method @NonNull public android.app.smartspace.SmartspaceSession createSmartspaceSession(@NonNull android.app.smartspace.SmartspaceConfig);
|
||||
}
|
||||
|
||||
public final class SmartspaceSession implements java.lang.AutoCloseable {
|
||||
method public void close();
|
||||
method public void destroy();
|
||||
method protected void finalize();
|
||||
method public void notifySmartspaceEvent(@NonNull android.app.smartspace.SmartspaceTargetEvent);
|
||||
method public void registerSmartspaceUpdates(@NonNull java.util.concurrent.Executor, @NonNull android.app.smartspace.SmartspaceSession.Callback);
|
||||
method public void requestSmartspaceUpdate();
|
||||
method public void unregisterSmartspaceUpdates(@NonNull android.app.smartspace.SmartspaceSession.Callback);
|
||||
}
|
||||
|
||||
public static interface SmartspaceSession.Callback {
|
||||
method public void onTargetsAvailable(@NonNull java.util.List<android.app.smartspace.SmartspaceTarget>);
|
||||
}
|
||||
|
||||
public final class SmartspaceSessionId implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @Nullable public String getId();
|
||||
method @NonNull public int getUserId();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.SmartspaceSessionId> CREATOR;
|
||||
}
|
||||
|
||||
public final class SmartspaceTarget implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @NonNull public java.util.List<android.app.smartspace.SmartspaceAction> getActionChips();
|
||||
method @Nullable public String getAssociatedSmartspaceTargetId();
|
||||
method @Nullable public android.app.smartspace.SmartspaceAction getBaseAction();
|
||||
method @NonNull public android.content.ComponentName getComponentName();
|
||||
method @NonNull public long getCreationTimeMillis();
|
||||
method @NonNull public long getExpiryTimeMillis();
|
||||
method @NonNull public int getFeatureType();
|
||||
method @Nullable public android.app.smartspace.SmartspaceAction getHeaderAction();
|
||||
method @NonNull public java.util.List<android.app.smartspace.SmartspaceAction> getIconGrid();
|
||||
method @NonNull public float getScore();
|
||||
method @Nullable public android.net.Uri getSliceUri();
|
||||
method @NonNull public String getSmartspaceTargetId();
|
||||
method @Nullable public String getSourceNotificationKey();
|
||||
method @NonNull public android.os.UserHandle getUserHandle();
|
||||
method @Nullable public android.appwidget.AppWidgetProviderInfo getWidgetId();
|
||||
method @NonNull public boolean isSensitive();
|
||||
method @NonNull public boolean shouldShowExpanded();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.SmartspaceTarget> CREATOR;
|
||||
field public static final int FEATURE_ALARM = 7; // 0x7
|
||||
field public static final int FEATURE_BEDTIME_ROUTINE = 16; // 0x10
|
||||
field public static final int FEATURE_CALENDAR = 2; // 0x2
|
||||
field public static final int FEATURE_COMMUTE_TIME = 3; // 0x3
|
||||
field public static final int FEATURE_CONSENT = 11; // 0xb
|
||||
field public static final int FEATURE_ETA_MONITORING = 18; // 0x12
|
||||
field public static final int FEATURE_FITNESS_TRACKING = 17; // 0x11
|
||||
field public static final int FEATURE_FLIGHT = 4; // 0x4
|
||||
field public static final int FEATURE_LOYALTY_CARD = 14; // 0xe
|
||||
field public static final int FEATURE_MEDIA = 15; // 0xf
|
||||
field public static final int FEATURE_MISSED_CALL = 19; // 0x13
|
||||
field public static final int FEATURE_ONBOARDING = 8; // 0x8
|
||||
field public static final int FEATURE_PACKAGE_TRACKING = 20; // 0x14
|
||||
field public static final int FEATURE_REMINDER = 6; // 0x6
|
||||
field public static final int FEATURE_SHOPPING_LIST = 13; // 0xd
|
||||
field public static final int FEATURE_SPORTS = 9; // 0x9
|
||||
field public static final int FEATURE_STOCK_PRICE_CHANGE = 12; // 0xc
|
||||
field public static final int FEATURE_STOPWATCH = 22; // 0x16
|
||||
field public static final int FEATURE_TIMER = 21; // 0x15
|
||||
field public static final int FEATURE_TIPS = 5; // 0x5
|
||||
field public static final int FEATURE_UNDEFINED = 0; // 0x0
|
||||
field public static final int FEATURE_UPCOMING_ALARM = 23; // 0x17
|
||||
field public static final int FEATURE_WEATHER = 1; // 0x1
|
||||
field public static final int FEATURE_WEATHER_ALERT = 10; // 0xa
|
||||
}
|
||||
|
||||
public static final class SmartspaceTarget.Builder {
|
||||
ctor public SmartspaceTarget.Builder(@NonNull String, @NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget build();
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setActionChips(@NonNull java.util.List<android.app.smartspace.SmartspaceAction>);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setAssociatedSmartspaceTargetId(@NonNull String);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setBaseAction(@NonNull android.app.smartspace.SmartspaceAction);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setCreationTimeMillis(@NonNull long);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setExpiryTimeMillis(@NonNull long);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setFeatureType(@NonNull int);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setHeaderAction(@NonNull android.app.smartspace.SmartspaceAction);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setIconGrid(@NonNull java.util.List<android.app.smartspace.SmartspaceAction>);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setScore(@NonNull float);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setSensitive(@NonNull boolean);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setShouldShowExpanded(@NonNull boolean);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setSliceUri(@NonNull android.net.Uri);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setSourceNotificationKey(@NonNull String);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setWidgetId(@NonNull android.appwidget.AppWidgetProviderInfo);
|
||||
}
|
||||
|
||||
public final class SmartspaceTargetEvent implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @NonNull public int getEventType();
|
||||
method @Nullable public String getSmartspaceActionId();
|
||||
method @Nullable public android.app.smartspace.SmartspaceTarget getSmartspaceTarget();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.SmartspaceTargetEvent> CREATOR;
|
||||
field public static final int EVENT_TARGET_BLOCK = 5; // 0x5
|
||||
field public static final int EVENT_TARGET_DISMISS = 4; // 0x4
|
||||
field public static final int EVENT_TARGET_INTERACTION = 1; // 0x1
|
||||
field public static final int EVENT_TARGET_IN_VIEW = 2; // 0x2
|
||||
field public static final int EVENT_TARGET_OUT_OF_VIEW = 3; // 0x3
|
||||
field public static final int EVENT_UI_SURFACE_IN_VIEW = 6; // 0x6
|
||||
field public static final int EVENT_UI_SURFACE_OUT_OF_VIEW = 7; // 0x7
|
||||
}
|
||||
|
||||
public static final class SmartspaceTargetEvent.Builder {
|
||||
ctor public SmartspaceTargetEvent.Builder(int);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTargetEvent build();
|
||||
method @NonNull public android.app.smartspace.SmartspaceTargetEvent.Builder setSmartspaceActionId(@NonNull String);
|
||||
method @NonNull public android.app.smartspace.SmartspaceTargetEvent.Builder setSmartspaceTarget(@NonNull android.app.smartspace.SmartspaceTarget);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.app.time {
|
||||
|
||||
public final class TimeManager {
|
||||
@@ -1953,6 +2117,7 @@ package android.content {
|
||||
field public static final String ROLLBACK_SERVICE = "rollback";
|
||||
field public static final String SEARCH_UI_SERVICE = "search_ui";
|
||||
field public static final String SECURE_ELEMENT_SERVICE = "secure_element";
|
||||
field public static final String SMARTSPACE_SERVICE = "smartspace";
|
||||
field public static final String STATS_MANAGER = "stats";
|
||||
field public static final String STATUS_BAR_SERVICE = "statusbar";
|
||||
field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
|
||||
@@ -10057,6 +10222,21 @@ package android.service.settings.suggestions {
|
||||
|
||||
}
|
||||
|
||||
package android.service.smartspace {
|
||||
|
||||
public abstract class SmartspaceService extends android.app.Service {
|
||||
ctor public SmartspaceService();
|
||||
method @MainThread public abstract void notifySmartspaceEvent(@NonNull android.app.smartspace.SmartspaceSessionId, @NonNull android.app.smartspace.SmartspaceTargetEvent);
|
||||
method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
|
||||
method public abstract void onCreateSmartspaceSession(@NonNull android.app.smartspace.SmartspaceConfig, @NonNull android.app.smartspace.SmartspaceSessionId);
|
||||
method @MainThread public abstract void onDestroy(@NonNull android.app.smartspace.SmartspaceSessionId);
|
||||
method public abstract void onDestroySmartspaceSession(@NonNull android.app.smartspace.SmartspaceSessionId);
|
||||
method @MainThread public abstract void onRequestSmartspaceUpdate(@NonNull android.app.smartspace.SmartspaceSessionId);
|
||||
method public final void updateSmartspaceTargets(@NonNull android.app.smartspace.SmartspaceSessionId, @NonNull java.util.List<android.app.smartspace.SmartspaceTarget>);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.service.storage {
|
||||
|
||||
public abstract class ExternalStorageService extends android.app.Service {
|
||||
|
||||
@@ -6,9 +6,11 @@ ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
|
||||
BuilderSetStyle: android.net.IpSecTransform.Builder#buildTunnelModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex):
|
||||
Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.net.IpSecTransform.Builder.buildTunnelModeTransform(java.net.InetAddress,android.net.IpSecManager.SecurityParameterIndex)
|
||||
|
||||
|
||||
ExecutorRegistration: android.media.MediaPlayer#setOnRtpRxNoticeListener(android.content.Context, android.media.MediaPlayer.OnRtpRxNoticeListener, android.os.Handler):
|
||||
Registration methods should have overload that accepts delivery Executor: `setOnRtpRxNoticeListener`
|
||||
|
||||
|
||||
|
||||
GenericException: android.app.prediction.AppPredictor#finalize():
|
||||
|
||||
GenericException: android.hardware.location.ContextHubClient#finalize():
|
||||
@@ -21,6 +23,8 @@ GenericException: android.service.autofill.augmented.FillWindow#finalize():
|
||||
|
||||
IntentBuilderName: android.app.search.SearchAction#getIntent():
|
||||
|
||||
IntentBuilderName: android.app.smartspace.SmartspaceAction#getIntent():
|
||||
Methods creating an Intent should be named `create<Foo>Intent()`, was `getIntent`
|
||||
|
||||
|
||||
KotlinKeyword: android.app.Notification#when:
|
||||
@@ -83,6 +87,10 @@ MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(
|
||||
|
||||
|
||||
|
||||
OnNameExpected: android.service.smartspace.SmartspaceService#notifySmartspaceEvent(android.app.smartspace.SmartspaceSessionId, android.app.smartspace.SmartspaceTargetEvent):
|
||||
Methods implemented by developers should follow the on<Something> style, was `notifySmartspaceEvent`
|
||||
|
||||
|
||||
ProtectedMember: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context):
|
||||
|
||||
ProtectedMember: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
|
||||
@@ -187,11 +195,10 @@ SamShouldBeLast: android.media.AudioRecordingMonitor#registerAudioRecordingCallb
|
||||
|
||||
SamShouldBeLast: android.media.AudioRouting#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
|
||||
|
||||
SamShouldBeLast: android.media.MediaPlayer#setOnRtpRxNoticeListener(android.content.Context, android.media.MediaPlayer.OnRtpRxNoticeListener, android.os.Handler):
|
||||
SAM-compatible parameters (such as parameter 2, "listener", in android.media.MediaPlayer.setOnRtpRxNoticeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
|
||||
|
||||
SamShouldBeLast: android.media.AudioTrack#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
|
||||
|
||||
SamShouldBeLast: android.media.MediaPlayer#setOnRtpRxNoticeListener(android.content.Context, android.media.MediaPlayer.OnRtpRxNoticeListener, android.os.Handler):
|
||||
SAM-compatible parameters (such as parameter 2, "listener", in android.media.MediaPlayer.setOnRtpRxNoticeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
|
||||
SamShouldBeLast: android.media.MediaRecorder#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
|
||||
|
||||
SamShouldBeLast: android.media.MediaRecorder#registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback):
|
||||
@@ -258,3 +265,5 @@ UserHandleName: android.app.search.SearchAction.Builder#setUserHandle(android.os
|
||||
Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `setUserHandle`
|
||||
UserHandleName: android.app.search.SearchTarget.Builder#setUserHandle(android.os.UserHandle):
|
||||
|
||||
UserHandleName: android.app.smartspace.SmartspaceAction.Builder#setUserHandle(android.os.UserHandle):
|
||||
Method taking UserHandle should be named `doFooAsUser` or `queryFooForUser`, was `setUserHandle`
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.app.prediction.AppPredictionManager;
|
||||
import android.app.role.RoleFrameworkInitializer;
|
||||
import android.app.search.SearchUiManager;
|
||||
import android.app.slice.SliceManager;
|
||||
import android.app.smartspace.SmartspaceManager;
|
||||
import android.app.time.TimeManager;
|
||||
import android.app.timedetector.TimeDetector;
|
||||
import android.app.timedetector.TimeDetectorImpl;
|
||||
@@ -1223,6 +1224,16 @@ public final class SystemServiceRegistry {
|
||||
}
|
||||
});
|
||||
|
||||
registerService(Context.SMARTSPACE_SERVICE, SmartspaceManager.class,
|
||||
new CachedServiceFetcher<SmartspaceManager>() {
|
||||
@Override
|
||||
public SmartspaceManager createService(ContextImpl ctx)
|
||||
throws ServiceNotFoundException {
|
||||
IBinder b = ServiceManager.getService(Context.SMARTSPACE_SERVICE);
|
||||
return b == null ? null : new SmartspaceManager(ctx);
|
||||
}
|
||||
});
|
||||
|
||||
registerService(Context.APP_PREDICTION_SERVICE, AppPredictionManager.class,
|
||||
new CachedServiceFetcher<AppPredictionManager>() {
|
||||
@Override
|
||||
|
||||
27
core/java/android/app/smartspace/ISmartspaceCallback.aidl
Normal file
27
core/java/android/app/smartspace/ISmartspaceCallback.aidl
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
import android.content.pm.ParceledListSlice;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ISmartspaceCallback {
|
||||
|
||||
void onResult(in ParceledListSlice result);
|
||||
}
|
||||
45
core/java/android/app/smartspace/ISmartspaceManager.aidl
Normal file
45
core/java/android/app/smartspace/ISmartspaceManager.aidl
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
import android.app.smartspace.SmartspaceTarget;
|
||||
import android.app.smartspace.SmartspaceTargetEvent;
|
||||
import android.app.smartspace.SmartspaceSessionId;
|
||||
import android.app.smartspace.SmartspaceConfig;
|
||||
import android.app.smartspace.ISmartspaceCallback;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
interface ISmartspaceManager {
|
||||
|
||||
void createSmartspaceSession(in SmartspaceConfig config, in SmartspaceSessionId sessionId,
|
||||
in IBinder token);
|
||||
|
||||
void notifySmartspaceEvent(in SmartspaceSessionId sessionId, in SmartspaceTargetEvent event);
|
||||
|
||||
void requestSmartspaceUpdate(in SmartspaceSessionId sessionId);
|
||||
|
||||
void registerSmartspaceUpdates(in SmartspaceSessionId sessionId,
|
||||
in ISmartspaceCallback callback);
|
||||
|
||||
void unregisterSmartspaceUpdates(in SmartspaceSessionId sessionId,
|
||||
in ISmartspaceCallback callback);
|
||||
|
||||
void destroySmartspaceSession(in SmartspaceSessionId sessionId);
|
||||
}
|
||||
353
core/java/android/app/smartspace/SmartspaceAction.java
Normal file
353
core/java/android/app/smartspace/SmartspaceAction.java
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A {@link SmartspaceAction} represents an action which can be taken by a user by tapping on either
|
||||
* the title, the subtitle or on the icon. Supported instances are Intents, PendingIntents or a
|
||||
* ShortcutInfo (by putting the ShortcutInfoId in the bundle). These actions can be called from
|
||||
* another process or within the client process.
|
||||
*
|
||||
* Clients can also receive conditional Intents/PendingIntents in the extras bundle which are
|
||||
* supposed to be fired when the conditions are met. For example, a user can invoke a dismiss/block
|
||||
* action on a game score card but the intention is to only block the team and not the entire
|
||||
* feature.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class SmartspaceAction implements Parcelable {
|
||||
|
||||
private static final String TAG = "SmartspaceAction";
|
||||
|
||||
/** A unique Id of this {@link SmartspaceAction}. */
|
||||
@NonNull
|
||||
private final String mId;
|
||||
|
||||
/** An Icon which can be displayed in the UI. */
|
||||
@Nullable
|
||||
private final Icon mIcon;
|
||||
|
||||
/** Title associated with an action. */
|
||||
@NonNull
|
||||
private final CharSequence mTitle;
|
||||
|
||||
/** Subtitle associated with an action. */
|
||||
@Nullable
|
||||
private final CharSequence mSubtitle;
|
||||
|
||||
@Nullable
|
||||
private final CharSequence mContentDescription;
|
||||
|
||||
@Nullable
|
||||
private final PendingIntent mPendingIntent;
|
||||
|
||||
@Nullable
|
||||
private final Intent mIntent;
|
||||
|
||||
@Nullable
|
||||
private final UserHandle mUserHandle;
|
||||
|
||||
@Nullable
|
||||
private Bundle mExtras;
|
||||
|
||||
SmartspaceAction(Parcel in) {
|
||||
mId = in.readString();
|
||||
mIcon = in.readTypedObject(Icon.CREATOR);
|
||||
mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
||||
mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
||||
mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
|
||||
mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
|
||||
mIntent = in.readTypedObject(Intent.CREATOR);
|
||||
mUserHandle = in.readTypedObject(UserHandle.CREATOR);
|
||||
mExtras = in.readTypedObject(Bundle.CREATOR);
|
||||
}
|
||||
|
||||
private SmartspaceAction(
|
||||
@NonNull String id,
|
||||
@Nullable Icon icon,
|
||||
@NonNull CharSequence title,
|
||||
@Nullable CharSequence subtitle,
|
||||
@Nullable CharSequence contentDescription,
|
||||
@Nullable PendingIntent pendingIntent,
|
||||
@Nullable Intent intent,
|
||||
@Nullable UserHandle userHandle,
|
||||
@Nullable Bundle extras) {
|
||||
mId = Objects.requireNonNull(id);
|
||||
mIcon = icon;
|
||||
mTitle = Objects.requireNonNull(title);
|
||||
mSubtitle = subtitle;
|
||||
mContentDescription = contentDescription;
|
||||
mPendingIntent = pendingIntent;
|
||||
mIntent = intent;
|
||||
mUserHandle = userHandle;
|
||||
mExtras = extras;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique id of this object.
|
||||
*/
|
||||
public @NonNull String getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an icon representing the action.
|
||||
*/
|
||||
public @Nullable Icon getIcon() {
|
||||
return mIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a title representing the action.
|
||||
*/
|
||||
public @NonNull CharSequence getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a subtitle representing the action.
|
||||
*/
|
||||
public @Nullable CharSequence getSubtitle() {
|
||||
return mSubtitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a content description representing the action.
|
||||
*/
|
||||
public @Nullable CharSequence getContentDescription() {
|
||||
return mContentDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action intent.
|
||||
*/
|
||||
public @Nullable PendingIntent getPendingIntent() {
|
||||
return mPendingIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the intent.
|
||||
*/
|
||||
public @Nullable Intent getIntent() {
|
||||
return mIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user handle.
|
||||
*/
|
||||
public @Nullable UserHandle getUserHandle() {
|
||||
return mUserHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extra bundle for this object.
|
||||
*/
|
||||
public @Nullable Bundle getExtras() {
|
||||
return mExtras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof SmartspaceAction)) return false;
|
||||
SmartspaceAction that = (SmartspaceAction) o;
|
||||
return mId.equals(that.mId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel out, int flags) {
|
||||
out.writeString(mId);
|
||||
out.writeTypedObject(mIcon, flags);
|
||||
TextUtils.writeToParcel(mTitle, out, flags);
|
||||
TextUtils.writeToParcel(mSubtitle, out, flags);
|
||||
TextUtils.writeToParcel(mContentDescription, out, flags);
|
||||
out.writeTypedObject(mPendingIntent, flags);
|
||||
out.writeTypedObject(mIntent, flags);
|
||||
out.writeTypedObject(mUserHandle, flags);
|
||||
out.writeBundle(mExtras);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SmartspaceAction{"
|
||||
+ "mId='" + mId + '\''
|
||||
+ ", mIcon=" + mIcon
|
||||
+ ", mTitle=" + mTitle
|
||||
+ ", mSubtitle=" + mSubtitle
|
||||
+ ", mContentDescription=" + mContentDescription
|
||||
+ ", mPendingIntent=" + mPendingIntent
|
||||
+ ", mIntent=" + mIntent
|
||||
+ ", mUserHandle=" + mUserHandle
|
||||
+ ", mExtras=" + mExtras
|
||||
+ '}';
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<SmartspaceAction> CREATOR =
|
||||
new Creator<SmartspaceAction>() {
|
||||
public SmartspaceAction createFromParcel(Parcel in) {
|
||||
return new SmartspaceAction(in);
|
||||
}
|
||||
public SmartspaceAction[] newArray(int size) {
|
||||
return new SmartspaceAction[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A builder for Smartspace action object.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final class Builder {
|
||||
@NonNull
|
||||
private String mId;
|
||||
|
||||
@Nullable
|
||||
private Icon mIcon;
|
||||
|
||||
@NonNull
|
||||
private CharSequence mTitle;
|
||||
|
||||
@Nullable
|
||||
private CharSequence mSubtitle;
|
||||
|
||||
@Nullable
|
||||
private CharSequence mContentDescription;
|
||||
|
||||
@Nullable
|
||||
private PendingIntent mPendingIntent;
|
||||
|
||||
@Nullable
|
||||
private Intent mIntent;
|
||||
|
||||
@Nullable
|
||||
private UserHandle mUserHandle;
|
||||
|
||||
@Nullable
|
||||
private Bundle mExtras;
|
||||
|
||||
/**
|
||||
* Id and title are required.
|
||||
*/
|
||||
public Builder(@NonNull String id, @NonNull String title) {
|
||||
mId = Objects.requireNonNull(id);
|
||||
mTitle = Objects.requireNonNull(title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the icon.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setIcon(
|
||||
@Nullable Icon icon) {
|
||||
mIcon = icon;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subtitle.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSubtitle(
|
||||
@Nullable CharSequence subtitle) {
|
||||
mSubtitle = subtitle;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content description.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setContentDescription(
|
||||
@Nullable CharSequence contentDescription) {
|
||||
mContentDescription = contentDescription;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pending intent.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setPendingIntent(@Nullable PendingIntent pendingIntent) {
|
||||
mPendingIntent = pendingIntent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user handle.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setUserHandle(@Nullable UserHandle userHandle) {
|
||||
mUserHandle = userHandle;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the intent.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setIntent(@Nullable Intent intent) {
|
||||
mIntent = intent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the extra.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setExtras(@Nullable Bundle extras) {
|
||||
mExtras = extras;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new SmartspaceAction instance.
|
||||
*
|
||||
* @throws IllegalStateException if no target is set
|
||||
*/
|
||||
@NonNull
|
||||
public SmartspaceAction build() {
|
||||
return new SmartspaceAction(mId, mIcon, mTitle, mSubtitle, mContentDescription,
|
||||
mPendingIntent, mIntent, mUserHandle, mExtras);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
core/java/android/app/smartspace/SmartspaceConfig.aidl
Normal file
19
core/java/android/app/smartspace/SmartspaceConfig.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
parcelable SmartspaceConfig;
|
||||
202
core/java/android/app/smartspace/SmartspaceConfig.java
Normal file
202
core/java/android/app/smartspace/SmartspaceConfig.java
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A {@link SmartspaceConfig} instance is supposed to be created by a smartspace client for each
|
||||
* UISurface. The client can specify some initialization conditions for the UISurface like its name,
|
||||
* expected number of smartspace cards etc. The clients can also specify if they want periodic
|
||||
* updates or their desired maximum refresh frequency.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class SmartspaceConfig implements Parcelable {
|
||||
|
||||
/**
|
||||
* The least number of smartspace targets expected to be predicted by the backend. The backend
|
||||
* will always try to satisfy this threshold but it is not guaranteed to always meet it.
|
||||
*/
|
||||
private final int mSmartspaceTargetCount;
|
||||
|
||||
/**
|
||||
* A {@link mUiSurface} is the name of the surface which will be used to display the cards. A
|
||||
* few examples are homescreen, lockscreen, aod etc.
|
||||
*/
|
||||
@NonNull
|
||||
private final String mUiSurface;
|
||||
|
||||
/** Package name of the client. */
|
||||
@NonNull
|
||||
private String mPackageName;
|
||||
|
||||
/** Send other client UI configurations in extras.
|
||||
*
|
||||
* This can include:
|
||||
*
|
||||
* - Desired maximum update frequency
|
||||
* - Request to get periodic updates
|
||||
* - Request to support multiple clients for the same UISurface.
|
||||
*/
|
||||
@Nullable
|
||||
private final Bundle mExtras;
|
||||
|
||||
private SmartspaceConfig(@NonNull String uiSurface, int numPredictedTargets,
|
||||
@NonNull String packageName, @Nullable Bundle extras) {
|
||||
mUiSurface = uiSurface;
|
||||
mSmartspaceTargetCount = numPredictedTargets;
|
||||
mPackageName = packageName;
|
||||
mExtras = extras;
|
||||
}
|
||||
|
||||
private SmartspaceConfig(Parcel parcel) {
|
||||
mUiSurface = parcel.readString();
|
||||
mSmartspaceTargetCount = parcel.readInt();
|
||||
mPackageName = parcel.readString();
|
||||
mExtras = parcel.readBundle();
|
||||
}
|
||||
|
||||
/** Returns the package name of the prediction context. */
|
||||
@NonNull
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
/** Returns the number of smartspace targets requested by the user. */
|
||||
@NonNull
|
||||
public int getSmartspaceTargetCount() {
|
||||
return mSmartspaceTargetCount;
|
||||
}
|
||||
|
||||
/** Returns the UISurface requested by the client. */
|
||||
@NonNull
|
||||
public String getUiSurface() {
|
||||
return mUiSurface;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Bundle getExtras() {
|
||||
return mExtras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(mUiSurface);
|
||||
dest.writeInt(mSmartspaceTargetCount);
|
||||
dest.writeString(mPackageName);
|
||||
dest.writeBundle(mExtras);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
SmartspaceConfig that = (SmartspaceConfig) o;
|
||||
return mSmartspaceTargetCount == that.mSmartspaceTargetCount
|
||||
&& Objects.equals(mUiSurface, that.mUiSurface)
|
||||
&& Objects.equals(mPackageName, that.mPackageName)
|
||||
&& Objects.equals(mExtras, that.mExtras);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mSmartspaceTargetCount, mUiSurface, mPackageName, mExtras);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Creator
|
||||
*/
|
||||
@NonNull
|
||||
public static final Creator<SmartspaceConfig> CREATOR =
|
||||
new Creator<SmartspaceConfig>() {
|
||||
public SmartspaceConfig createFromParcel(Parcel parcel) {
|
||||
return new SmartspaceConfig(parcel);
|
||||
}
|
||||
|
||||
public SmartspaceConfig[] newArray(int size) {
|
||||
return new SmartspaceConfig[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A builder for {@link SmartspaceConfig}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final class Builder {
|
||||
@NonNull
|
||||
private int mSmartspaceTargetCount = 5; // Default count is 5
|
||||
@NonNull
|
||||
private final String mUiSurface;
|
||||
@NonNull
|
||||
private final String mPackageName;
|
||||
@NonNull
|
||||
private Bundle mExtras = Bundle.EMPTY;
|
||||
|
||||
/**
|
||||
* @param context The {@link Context} which is used to fetch the package name.
|
||||
* @param uiSurface the UI Surface name associated with this context.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public Builder(@NonNull Context context, @NonNull String uiSurface) {
|
||||
mPackageName = context.getPackageName();
|
||||
this.mUiSurface = uiSurface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to set the expected number of cards for this context.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSmartspaceTargetCount(int smartspaceTargetCount) {
|
||||
this.mSmartspaceTargetCount = smartspaceTargetCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to send a bundle containing extras for the {@link SmartspaceConfig}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setExtras(@NonNull Bundle extras) {
|
||||
this.mExtras = extras;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of {@link SmartspaceConfig}.
|
||||
*/
|
||||
@NonNull
|
||||
public SmartspaceConfig build() {
|
||||
return new SmartspaceConfig(mUiSurface, mSmartspaceTargetCount, mPackageName, mExtras);
|
||||
}
|
||||
}
|
||||
}
|
||||
64
core/java/android/app/smartspace/SmartspaceManager.java
Normal file
64
core/java/android/app/smartspace/SmartspaceManager.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Smartspace is a container in Android which is used to show contextual content powered by the
|
||||
* intelligence service running on the device. A smartspace container can be on AoD, lockscreen or
|
||||
* on the homescreen and can show personalized cards which are either derived from on device or
|
||||
* online signals.
|
||||
*
|
||||
* {@link SmartspaceManager} is a system service that provides methods to create Smartspace session
|
||||
* clients. An instance of this class is returned when a client calls
|
||||
* <code> context.getSystemService("smartspace"); </code>.
|
||||
*
|
||||
* After receiving the service, a client must call
|
||||
* {@link SmartspaceManager#createSmartspaceSession(SmartspaceConfig)} with a corresponding
|
||||
* {@link SmartspaceConfig} to get an instance of {@link SmartspaceSession}.
|
||||
* This session is then a client's point of contact with the api. They can send events, request for
|
||||
* updates using the session. It is client's duty to call {@link SmartspaceSession#destroy()} to
|
||||
* destroy the session once they no longer need it.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class SmartspaceManager {
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public SmartspaceManager(Context context) {
|
||||
mContext = Objects.requireNonNull(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Smartspace session.
|
||||
*/
|
||||
@NonNull
|
||||
public SmartspaceSession createSmartspaceSession(
|
||||
@NonNull SmartspaceConfig smartspaceConfig) {
|
||||
return new SmartspaceSession(mContext, smartspaceConfig);
|
||||
}
|
||||
}
|
||||
284
core/java/android/app/smartspace/SmartspaceSession.java
Normal file
284
core/java/android/app/smartspace/SmartspaceSession.java
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.smartspace.ISmartspaceCallback.Stub;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import dalvik.system.CloseGuard;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Client API to share information about the Smartspace UI state and execute query.
|
||||
*
|
||||
* <p>
|
||||
* Usage: <pre> {@code
|
||||
*
|
||||
* class MyActivity {
|
||||
* private SmartspaceSession mSmartspaceSession;
|
||||
*
|
||||
* void onCreate() {
|
||||
* mSmartspaceSession = mSmartspaceManager.createSmartspaceSession(smartspaceConfig)
|
||||
* mSmartspaceSession.registerSmartspaceUpdates(...)
|
||||
* }
|
||||
*
|
||||
* void onStart() {
|
||||
* mSmartspaceSession.requestSmartspaceUpdate()
|
||||
* }
|
||||
*
|
||||
* void onTouch(...) OR
|
||||
* void onStateTransitionStarted(...) OR
|
||||
* void onResume(...) OR
|
||||
* void onStop(...) {
|
||||
* mSmartspaceSession.notifyEvent(event);
|
||||
* }
|
||||
*
|
||||
* void onDestroy() {
|
||||
* mSmartspaceSession.unregisterPredictionUpdates()
|
||||
* mSmartspaceSession.destroy();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class SmartspaceSession implements AutoCloseable {
|
||||
|
||||
private static final String TAG = SmartspaceSession.class.getSimpleName();
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final android.app.smartspace.ISmartspaceManager mInterface;
|
||||
private final CloseGuard mCloseGuard = CloseGuard.get();
|
||||
private final AtomicBoolean mIsClosed = new AtomicBoolean(false);
|
||||
|
||||
private final SmartspaceSessionId mSessionId;
|
||||
private final ArrayMap<Callback, CallbackWrapper> mRegisteredCallbacks = new ArrayMap<>();
|
||||
private final IBinder mToken = new Binder();
|
||||
|
||||
/**
|
||||
* Creates a new Smartspace ui client.
|
||||
* <p>
|
||||
* The caller should call {@link SmartspaceSession#destroy()} to dispose the client once it
|
||||
* no longer used.
|
||||
*
|
||||
* @param context the {@link Context} of the user of this {@link SmartspaceSession}.
|
||||
* @param smartspaceConfig the Smartspace context.
|
||||
*/
|
||||
// b/177858121 Create weak reference child objects to not leak context.
|
||||
SmartspaceSession(@NonNull Context context, @NonNull SmartspaceConfig smartspaceConfig) {
|
||||
IBinder b = ServiceManager.getService(Context.SMARTSPACE_SERVICE);
|
||||
mInterface = android.app.smartspace.ISmartspaceManager.Stub.asInterface(b);
|
||||
mSessionId = new SmartspaceSessionId(
|
||||
context.getPackageName() + ":" + UUID.randomUUID().toString(), context.getUserId());
|
||||
try {
|
||||
mInterface.createSmartspaceSession(smartspaceConfig, mSessionId, mToken);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to cerate Smartspace session", e);
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
|
||||
mCloseGuard.open("close");
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the Smartspace service of a Smartspace target event.
|
||||
*
|
||||
* @param event The {@link SmartspaceTargetEvent} that represents the Smartspace target event.
|
||||
*/
|
||||
public void notifySmartspaceEvent(@NonNull SmartspaceTargetEvent event) {
|
||||
if (mIsClosed.get()) {
|
||||
throw new IllegalStateException("This client has already been destroyed.");
|
||||
}
|
||||
try {
|
||||
mInterface.notifySmartspaceEvent(mSessionId, event);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to notify event", e);
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the smartspace service for an update.
|
||||
*/
|
||||
public void requestSmartspaceUpdate() {
|
||||
if (mIsClosed.get()) {
|
||||
throw new IllegalStateException("This client has already been destroyed.");
|
||||
}
|
||||
try {
|
||||
mInterface.requestSmartspaceUpdate(mSessionId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to request update.", e);
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the smartspace service provide continuous updates of smartspace cards via the
|
||||
* provided callback, until the given callback is unregistered.
|
||||
*
|
||||
* @param callbackExecutor The callback executor to use when calling the callback.
|
||||
* @param callback The Callback to be called when updates of Smartspace targets are
|
||||
* available.
|
||||
*/
|
||||
public void registerSmartspaceUpdates(@NonNull @CallbackExecutor Executor callbackExecutor,
|
||||
@NonNull Callback callback) {
|
||||
if (mIsClosed.get()) {
|
||||
throw new IllegalStateException("This client has already been destroyed.");
|
||||
}
|
||||
|
||||
if (mRegisteredCallbacks.containsKey(callback)) {
|
||||
// Skip if this callback is already registered
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final CallbackWrapper callbackWrapper = new CallbackWrapper(callbackExecutor,
|
||||
callback::onTargetsAvailable);
|
||||
mRegisteredCallbacks.put(callback, callbackWrapper);
|
||||
mInterface.registerSmartspaceUpdates(mSessionId, callbackWrapper);
|
||||
mInterface.requestSmartspaceUpdate(mSessionId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to register for smartspace updates", e);
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the smartspace service to stop providing continuous updates to the provided
|
||||
* callback until the callback is re-registered.
|
||||
*
|
||||
* @see {@link SmartspaceSession#registerSmartspaceUpdates(Executor, Callback)}.
|
||||
*
|
||||
* @param callback The callback to be unregistered.
|
||||
*/
|
||||
public void unregisterSmartspaceUpdates(@NonNull Callback callback) {
|
||||
if (mIsClosed.get()) {
|
||||
throw new IllegalStateException("This client has already been destroyed.");
|
||||
}
|
||||
|
||||
if (!mRegisteredCallbacks.containsKey(callback)) {
|
||||
// Skip if this callback was never registered
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final CallbackWrapper callbackWrapper = mRegisteredCallbacks.remove(callback);
|
||||
mInterface.unregisterSmartspaceUpdates(mSessionId, callbackWrapper);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to unregister for smartspace updates", e);
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the client and unregisters the callback. Any method on this class after this call
|
||||
* will throw {@link IllegalStateException}.
|
||||
*/
|
||||
public void destroy() {
|
||||
if (!mIsClosed.getAndSet(true)) {
|
||||
mCloseGuard.close();
|
||||
|
||||
// Do destroy;
|
||||
try {
|
||||
mInterface.destroySmartspaceSession(mSessionId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to notify Smartspace target event", e);
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("This client has already been destroyed.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
try {
|
||||
if (mCloseGuard != null) {
|
||||
mCloseGuard.warnIfOpen();
|
||||
}
|
||||
if (!mIsClosed.get()) {
|
||||
destroy();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
super.finalize();
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
finalize();
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for receiving smartspace updates.
|
||||
*/
|
||||
public interface Callback {
|
||||
|
||||
/**
|
||||
* Called when a new set of smartspace targets are available.
|
||||
*
|
||||
* @param targets Sorted list of smartspace targets.
|
||||
*/
|
||||
void onTargetsAvailable(@NonNull List<SmartspaceTarget> targets);
|
||||
}
|
||||
|
||||
static class CallbackWrapper extends Stub {
|
||||
|
||||
private final Consumer<List<SmartspaceTarget>> mCallback;
|
||||
private final Executor mExecutor;
|
||||
|
||||
CallbackWrapper(@NonNull Executor callbackExecutor,
|
||||
@NonNull Consumer<List<SmartspaceTarget>> callback) {
|
||||
mCallback = callback;
|
||||
mExecutor = callbackExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(ParceledListSlice result) {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "CallbackWrapper.onResult result=" + result.getList());
|
||||
}
|
||||
mExecutor.execute(() -> mCallback.accept(result.getList()));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
core/java/android/app/smartspace/SmartspaceSessionId.aidl
Normal file
19
core/java/android/app/smartspace/SmartspaceSessionId.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
parcelable SmartspaceSessionId;
|
||||
114
core/java/android/app/smartspace/SmartspaceSessionId.java
Normal file
114
core/java/android/app/smartspace/SmartspaceSessionId.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The id for an Smartspace session. See {@link SmartspaceSession}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class SmartspaceSessionId implements Parcelable {
|
||||
|
||||
@NonNull
|
||||
private final String mId;
|
||||
|
||||
@NonNull
|
||||
private final int mUserId;
|
||||
|
||||
/**
|
||||
* Creates a new id for a Smartspace session.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public SmartspaceSessionId(@NonNull final String id, @NonNull final int userId) {
|
||||
mId = id;
|
||||
mUserId = userId;
|
||||
}
|
||||
|
||||
private SmartspaceSessionId(Parcel p) {
|
||||
mId = p.readString();
|
||||
mUserId = p.readInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link String} Id of this sessionId.
|
||||
*/
|
||||
@Nullable
|
||||
public String getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the userId associated with this sessionId.
|
||||
*/
|
||||
@NonNull
|
||||
public int getUserId() {
|
||||
return mUserId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (!getClass().equals(o != null ? o.getClass() : null)) return false;
|
||||
|
||||
SmartspaceSessionId other = (SmartspaceSessionId) o;
|
||||
return mId.equals(other.mId) && mUserId == other.mUserId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SmartspaceSessionId{"
|
||||
+ "mId='" + mId + '\''
|
||||
+ ", mUserId=" + mUserId
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mId, mUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(mId);
|
||||
dest.writeInt(mUserId);
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<SmartspaceSessionId> CREATOR =
|
||||
new Creator<SmartspaceSessionId>() {
|
||||
public SmartspaceSessionId createFromParcel(Parcel parcel) {
|
||||
return new SmartspaceSessionId(parcel);
|
||||
}
|
||||
|
||||
public SmartspaceSessionId[] newArray(int size) {
|
||||
return new SmartspaceSessionId[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
19
core/java/android/app/smartspace/SmartspaceTarget.aidl
Normal file
19
core/java/android/app/smartspace/SmartspaceTarget.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
parcelable SmartspaceTarget;
|
||||
660
core/java/android/app/smartspace/SmartspaceTarget.java
Normal file
660
core/java/android/app/smartspace/SmartspaceTarget.java
Normal file
@@ -0,0 +1,660 @@
|
||||
/*
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A {@link SmartspaceTarget} is a data class which holds all properties necessary to inflate a
|
||||
* smartspace card. It contains data and related metadata which is supposed to be utilized by
|
||||
* smartspace clients based on their own UI/UX requirements. Some of the properties have
|
||||
* {@link SmartspaceAction} as their type because they can have associated actions.
|
||||
*
|
||||
* <p><b>NOTE: </b>
|
||||
* If {@link mWidgetId} is set, it should be preferred over all other properties.
|
||||
* Else, if {@link mSliceUri} is set, it should be preferred over all other data properties.
|
||||
* Otherwise, the instance should be treated as a data object.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class SmartspaceTarget implements Parcelable {
|
||||
|
||||
/** A unique Id for an instance of {@link SmartspaceTarget}. */
|
||||
@NonNull
|
||||
private final String mSmartspaceTargetId;
|
||||
|
||||
/** A {@link SmartspaceAction} for the header in the Smartspace card. */
|
||||
@Nullable
|
||||
private final SmartspaceAction mHeaderAction;
|
||||
|
||||
/** A {@link SmartspaceAction} for the base action in the Smartspace card. */
|
||||
@Nullable
|
||||
private final SmartspaceAction mBaseAction;
|
||||
|
||||
/** A timestamp indicating when the card was created. */
|
||||
@NonNull
|
||||
private final long mCreationTimeMillis;
|
||||
|
||||
/**
|
||||
* A timestamp indicating when the card should be removed from view, in case the service
|
||||
* disconnects or restarts.
|
||||
*/
|
||||
@NonNull
|
||||
private final long mExpiryTimeMillis;
|
||||
|
||||
/** A score assigned to a target. */
|
||||
@NonNull
|
||||
private final float mScore;
|
||||
|
||||
/** A {@link List<SmartspaceAction>} containing all action chips. */
|
||||
@NonNull
|
||||
private final List<SmartspaceAction> mActionChips;
|
||||
|
||||
/** A {@link List<SmartspaceAction>} containing all icons for the grid. */
|
||||
@NonNull
|
||||
private final List<SmartspaceAction> mIconGrid;
|
||||
|
||||
/**
|
||||
* {@link FeatureType} indicating the feature type of this card.
|
||||
*
|
||||
* @see FeatureType
|
||||
*/
|
||||
@FeatureType
|
||||
@NonNull
|
||||
private final int mFeatureType;
|
||||
|
||||
/**
|
||||
* Indicates whether the content is sensitive. Certain UI surfaces may choose to skip rendering
|
||||
* real content until the device is unlocked.
|
||||
*/
|
||||
@NonNull
|
||||
private final boolean mSensitive;
|
||||
|
||||
/** Indicating if the UI should show this target in its expanded state. */
|
||||
@NonNull
|
||||
private final boolean mShouldShowExpanded;
|
||||
|
||||
/** A Notification key if the target was generated using a notification. */
|
||||
@Nullable
|
||||
private final String mSourceNotificationKey;
|
||||
|
||||
/** {@link ComponentName} for this target. */
|
||||
@NonNull
|
||||
private final ComponentName mComponentName;
|
||||
|
||||
/** {@link UserHandle} for this target. */
|
||||
@NonNull
|
||||
private final UserHandle mUserHandle;
|
||||
|
||||
/** Target Ids of other {@link SmartspaceTarget}s if they are associated with this target. */
|
||||
@Nullable
|
||||
private final String mAssociatedSmartspaceTargetId;
|
||||
|
||||
/** {@link Uri} Slice Uri if this target is a slice. */
|
||||
@Nullable
|
||||
private final Uri mSliceUri;
|
||||
|
||||
/** {@link AppWidgetProviderInfo} if this target is a widget. */
|
||||
@Nullable
|
||||
private final AppWidgetProviderInfo mWidgetId;
|
||||
|
||||
public static final int FEATURE_UNDEFINED = 0;
|
||||
public static final int FEATURE_WEATHER = 1;
|
||||
public static final int FEATURE_CALENDAR = 2;
|
||||
public static final int FEATURE_COMMUTE_TIME = 3;
|
||||
public static final int FEATURE_FLIGHT = 4;
|
||||
public static final int FEATURE_TIPS = 5;
|
||||
public static final int FEATURE_REMINDER = 6;
|
||||
public static final int FEATURE_ALARM = 7;
|
||||
public static final int FEATURE_ONBOARDING = 8;
|
||||
public static final int FEATURE_SPORTS = 9;
|
||||
public static final int FEATURE_WEATHER_ALERT = 10;
|
||||
public static final int FEATURE_CONSENT = 11;
|
||||
public static final int FEATURE_STOCK_PRICE_CHANGE = 12;
|
||||
public static final int FEATURE_SHOPPING_LIST = 13;
|
||||
public static final int FEATURE_LOYALTY_CARD = 14;
|
||||
public static final int FEATURE_MEDIA = 15;
|
||||
public static final int FEATURE_BEDTIME_ROUTINE = 16;
|
||||
public static final int FEATURE_FITNESS_TRACKING = 17;
|
||||
public static final int FEATURE_ETA_MONITORING = 18;
|
||||
public static final int FEATURE_MISSED_CALL = 19;
|
||||
public static final int FEATURE_PACKAGE_TRACKING = 20;
|
||||
public static final int FEATURE_TIMER = 21;
|
||||
public static final int FEATURE_STOPWATCH = 22;
|
||||
public static final int FEATURE_UPCOMING_ALARM = 23;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = {"FEATURE_"}, value = {
|
||||
FEATURE_UNDEFINED,
|
||||
FEATURE_WEATHER,
|
||||
FEATURE_CALENDAR,
|
||||
FEATURE_COMMUTE_TIME,
|
||||
FEATURE_FLIGHT,
|
||||
FEATURE_TIPS,
|
||||
FEATURE_REMINDER,
|
||||
FEATURE_ALARM,
|
||||
FEATURE_ONBOARDING,
|
||||
FEATURE_SPORTS,
|
||||
FEATURE_WEATHER_ALERT,
|
||||
FEATURE_CONSENT,
|
||||
FEATURE_STOCK_PRICE_CHANGE,
|
||||
FEATURE_SHOPPING_LIST,
|
||||
FEATURE_LOYALTY_CARD,
|
||||
FEATURE_MEDIA,
|
||||
FEATURE_BEDTIME_ROUTINE,
|
||||
FEATURE_FITNESS_TRACKING,
|
||||
FEATURE_ETA_MONITORING,
|
||||
FEATURE_MISSED_CALL,
|
||||
FEATURE_PACKAGE_TRACKING,
|
||||
FEATURE_TIMER,
|
||||
FEATURE_STOPWATCH,
|
||||
FEATURE_UPCOMING_ALARM
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface FeatureType {
|
||||
}
|
||||
|
||||
private SmartspaceTarget(Parcel in) {
|
||||
this.mSmartspaceTargetId = in.readString();
|
||||
this.mHeaderAction = in.readTypedObject(SmartspaceAction.CREATOR);
|
||||
this.mBaseAction = in.readTypedObject(SmartspaceAction.CREATOR);
|
||||
this.mCreationTimeMillis = in.readLong();
|
||||
this.mExpiryTimeMillis = in.readLong();
|
||||
this.mScore = in.readFloat();
|
||||
this.mActionChips = in.createTypedArrayList(SmartspaceAction.CREATOR);
|
||||
this.mIconGrid = in.createTypedArrayList(SmartspaceAction.CREATOR);
|
||||
this.mFeatureType = in.readInt();
|
||||
this.mSensitive = in.readBoolean();
|
||||
this.mShouldShowExpanded = in.readBoolean();
|
||||
this.mSourceNotificationKey = in.readString();
|
||||
this.mComponentName = in.readTypedObject(ComponentName.CREATOR);
|
||||
this.mUserHandle = in.readTypedObject(UserHandle.CREATOR);
|
||||
this.mAssociatedSmartspaceTargetId = in.readString();
|
||||
this.mSliceUri = in.readTypedObject(Uri.CREATOR);
|
||||
this.mWidgetId = in.readTypedObject(AppWidgetProviderInfo.CREATOR);
|
||||
}
|
||||
|
||||
private SmartspaceTarget(String smartspaceTargetId,
|
||||
SmartspaceAction headerAction, SmartspaceAction baseAction, long creationTimeMillis,
|
||||
long expiryTimeMillis, float score,
|
||||
List<SmartspaceAction> actionChips,
|
||||
List<SmartspaceAction> iconGrid, int featureType, boolean sensitive,
|
||||
boolean shouldShowExpanded, String sourceNotificationKey,
|
||||
ComponentName componentName, UserHandle userHandle,
|
||||
String associatedSmartspaceTargetId, Uri sliceUri,
|
||||
AppWidgetProviderInfo widgetId) {
|
||||
mSmartspaceTargetId = smartspaceTargetId;
|
||||
mHeaderAction = headerAction;
|
||||
mBaseAction = baseAction;
|
||||
mCreationTimeMillis = creationTimeMillis;
|
||||
mExpiryTimeMillis = expiryTimeMillis;
|
||||
mScore = score;
|
||||
mActionChips = actionChips;
|
||||
mIconGrid = iconGrid;
|
||||
mFeatureType = featureType;
|
||||
mSensitive = sensitive;
|
||||
mShouldShowExpanded = shouldShowExpanded;
|
||||
mSourceNotificationKey = sourceNotificationKey;
|
||||
mComponentName = componentName;
|
||||
mUserHandle = userHandle;
|
||||
mAssociatedSmartspaceTargetId = associatedSmartspaceTargetId;
|
||||
mSliceUri = sliceUri;
|
||||
mWidgetId = widgetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Id of the target.
|
||||
*/
|
||||
@NonNull
|
||||
public String getSmartspaceTargetId() {
|
||||
return mSmartspaceTargetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the header action of the target.
|
||||
*/
|
||||
@Nullable
|
||||
public SmartspaceAction getHeaderAction() {
|
||||
return mHeaderAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base action of the target.
|
||||
*/
|
||||
@Nullable
|
||||
public SmartspaceAction getBaseAction() {
|
||||
return mBaseAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creation time of the target.
|
||||
*/
|
||||
@NonNull
|
||||
public long getCreationTimeMillis() {
|
||||
return mCreationTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expiry time of the target.
|
||||
*/
|
||||
@NonNull
|
||||
public long getExpiryTimeMillis() {
|
||||
return mExpiryTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the score of the target.
|
||||
*/
|
||||
@NonNull
|
||||
public float getScore() {
|
||||
return mScore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the action chips of the target.
|
||||
*/
|
||||
@NonNull
|
||||
public List<SmartspaceAction> getActionChips() {
|
||||
return mActionChips;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the icons of the target.
|
||||
*/
|
||||
@NonNull
|
||||
public List<SmartspaceAction> getIconGrid() {
|
||||
return mIconGrid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the feature type of the target.
|
||||
*/
|
||||
@NonNull
|
||||
public int getFeatureType() {
|
||||
return mFeatureType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the target is sensitive or not.
|
||||
*/
|
||||
@NonNull
|
||||
public boolean isSensitive() {
|
||||
return mSensitive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the target should be shown in expanded state.
|
||||
*/
|
||||
@NonNull
|
||||
public boolean shouldShowExpanded() {
|
||||
return mShouldShowExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source notification key of the target.
|
||||
*/
|
||||
@Nullable
|
||||
public String getSourceNotificationKey() {
|
||||
return mSourceNotificationKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component name of the target.
|
||||
*/
|
||||
@NonNull
|
||||
public ComponentName getComponentName() {
|
||||
return mComponentName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user handle of the target.
|
||||
*/
|
||||
@NonNull
|
||||
public UserHandle getUserHandle() {
|
||||
return mUserHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of a target associated with this instance.
|
||||
*/
|
||||
@Nullable
|
||||
public String getAssociatedSmartspaceTargetId() {
|
||||
return mAssociatedSmartspaceTargetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the slice uri, if the target is a slice.
|
||||
*/
|
||||
@Nullable
|
||||
public Uri getSliceUri() {
|
||||
return mSliceUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AppWidgetProviderInfo, if the target is a widget.
|
||||
*/
|
||||
@Nullable
|
||||
public AppWidgetProviderInfo getWidgetId() {
|
||||
return mWidgetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Parcelable.Creator
|
||||
*/
|
||||
@NonNull
|
||||
public static final Creator<SmartspaceTarget> CREATOR = new Creator<SmartspaceTarget>() {
|
||||
@Override
|
||||
public SmartspaceTarget createFromParcel(Parcel source) {
|
||||
return new SmartspaceTarget(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmartspaceTarget[] newArray(int size) {
|
||||
return new SmartspaceTarget[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(this.mSmartspaceTargetId);
|
||||
dest.writeTypedObject(this.mHeaderAction, flags);
|
||||
dest.writeTypedObject(this.mBaseAction, flags);
|
||||
dest.writeLong(this.mCreationTimeMillis);
|
||||
dest.writeLong(this.mExpiryTimeMillis);
|
||||
dest.writeFloat(this.mScore);
|
||||
dest.writeTypedList(this.mActionChips);
|
||||
dest.writeTypedList(this.mIconGrid);
|
||||
dest.writeInt(this.mFeatureType);
|
||||
dest.writeBoolean(this.mSensitive);
|
||||
dest.writeBoolean(this.mShouldShowExpanded);
|
||||
dest.writeString(this.mSourceNotificationKey);
|
||||
dest.writeTypedObject(this.mComponentName, flags);
|
||||
dest.writeTypedObject(this.mUserHandle, flags);
|
||||
dest.writeString(this.mAssociatedSmartspaceTargetId);
|
||||
dest.writeTypedObject(this.mSliceUri, flags);
|
||||
dest.writeTypedObject(this.mWidgetId, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SmartspaceTarget{"
|
||||
+ "mSmartspaceTargetId='" + mSmartspaceTargetId + '\''
|
||||
+ ", mHeaderAction=" + mHeaderAction
|
||||
+ ", mBaseAction=" + mBaseAction
|
||||
+ ", mCreationTimeMillis=" + mCreationTimeMillis
|
||||
+ ", mExpiryTimeMillis=" + mExpiryTimeMillis
|
||||
+ ", mScore=" + mScore
|
||||
+ ", mActionChips=" + mActionChips
|
||||
+ ", mIconGrid=" + mIconGrid
|
||||
+ ", mFeatureType=" + mFeatureType
|
||||
+ ", mSensitive=" + mSensitive
|
||||
+ ", mShouldShowExpanded=" + mShouldShowExpanded
|
||||
+ ", mSourceNotificationKey='" + mSourceNotificationKey + '\''
|
||||
+ ", mComponentName=" + mComponentName
|
||||
+ ", mUserHandle=" + mUserHandle
|
||||
+ ", mAssociatedSmartspaceTargetId='" + mAssociatedSmartspaceTargetId + '\''
|
||||
+ ", mSliceUri=" + mSliceUri
|
||||
+ ", mWidgetId=" + mWidgetId
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
SmartspaceTarget that = (SmartspaceTarget) o;
|
||||
return mCreationTimeMillis == that.mCreationTimeMillis
|
||||
&& mExpiryTimeMillis == that.mExpiryTimeMillis
|
||||
&& Float.compare(that.mScore, mScore) == 0
|
||||
&& mFeatureType == that.mFeatureType
|
||||
&& mSensitive == that.mSensitive
|
||||
&& mShouldShowExpanded == that.mShouldShowExpanded
|
||||
&& mSmartspaceTargetId.equals(that.mSmartspaceTargetId)
|
||||
&& Objects.equals(mHeaderAction, that.mHeaderAction)
|
||||
&& Objects.equals(mBaseAction, that.mBaseAction)
|
||||
&& Objects.equals(mActionChips, that.mActionChips)
|
||||
&& Objects.equals(mIconGrid, that.mIconGrid)
|
||||
&& Objects.equals(mSourceNotificationKey, that.mSourceNotificationKey)
|
||||
&& mComponentName.equals(that.mComponentName)
|
||||
&& mUserHandle.equals(that.mUserHandle)
|
||||
&& Objects.equals(mAssociatedSmartspaceTargetId,
|
||||
that.mAssociatedSmartspaceTargetId)
|
||||
&& Objects.equals(mSliceUri, that.mSliceUri)
|
||||
&& Objects.equals(mWidgetId, that.mWidgetId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mSmartspaceTargetId, mHeaderAction, mBaseAction, mCreationTimeMillis,
|
||||
mExpiryTimeMillis, mScore, mActionChips, mIconGrid, mFeatureType, mSensitive,
|
||||
mShouldShowExpanded, mSourceNotificationKey, mComponentName, mUserHandle,
|
||||
mAssociatedSmartspaceTargetId, mSliceUri, mWidgetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link SmartspaceTarget} object.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final class Builder {
|
||||
private final String mSmartspaceTargetId;
|
||||
private SmartspaceAction mHeaderAction;
|
||||
private SmartspaceAction mBaseAction;
|
||||
private long mCreationTimeMillis;
|
||||
private long mExpiryTimeMillis;
|
||||
private float mScore;
|
||||
private List<SmartspaceAction> mActionChips = new ArrayList<>();
|
||||
private List<SmartspaceAction> mIconGrid = new ArrayList<>();
|
||||
private int mFeatureType;
|
||||
private boolean mSensitive;
|
||||
private boolean mShouldShowExpanded;
|
||||
private String mSourceNotificationKey;
|
||||
private final ComponentName mComponentName;
|
||||
private final UserHandle mUserHandle;
|
||||
private String mAssociatedSmartspaceTargetId;
|
||||
private Uri mSliceUri;
|
||||
private AppWidgetProviderInfo mWidgetId;
|
||||
|
||||
/**
|
||||
* A builder for {@link SmartspaceTarget}.
|
||||
*
|
||||
* @param smartspaceTargetId the id of this target
|
||||
* @param componentName the componentName of this target
|
||||
* @param userHandle the userHandle of this target
|
||||
*/
|
||||
public Builder(@NonNull String smartspaceTargetId,
|
||||
@NonNull ComponentName componentName, @NonNull UserHandle userHandle) {
|
||||
this.mSmartspaceTargetId = smartspaceTargetId;
|
||||
this.mComponentName = componentName;
|
||||
this.mUserHandle = userHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the header action.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setHeaderAction(@NonNull SmartspaceAction headerAction) {
|
||||
this.mHeaderAction = headerAction;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base action.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setBaseAction(@NonNull SmartspaceAction baseAction) {
|
||||
this.mBaseAction = baseAction;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the creation time.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCreationTimeMillis(@NonNull long creationTimeMillis) {
|
||||
this.mCreationTimeMillis = creationTimeMillis;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expiration time.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setExpiryTimeMillis(@NonNull long expiryTimeMillis) {
|
||||
this.mExpiryTimeMillis = expiryTimeMillis;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the score.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setScore(@NonNull float score) {
|
||||
this.mScore = score;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action chips.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setActionChips(@NonNull List<SmartspaceAction> actionChips) {
|
||||
this.mActionChips = actionChips;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the icon grid.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setIconGrid(@NonNull List<SmartspaceAction> iconGrid) {
|
||||
this.mIconGrid = iconGrid;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the feature type.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setFeatureType(@NonNull int featureType) {
|
||||
this.mFeatureType = featureType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the contents are sensitive.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSensitive(@NonNull boolean sensitive) {
|
||||
this.mSensitive = sensitive;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to show the card as expanded.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setShouldShowExpanded(@NonNull boolean shouldShowExpanded) {
|
||||
this.mShouldShowExpanded = shouldShowExpanded;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source notification key.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSourceNotificationKey(@NonNull String sourceNotificationKey) {
|
||||
this.mSourceNotificationKey = sourceNotificationKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the associated smartspace target id.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setAssociatedSmartspaceTargetId(
|
||||
@NonNull String associatedSmartspaceTargetId) {
|
||||
this.mAssociatedSmartspaceTargetId = associatedSmartspaceTargetId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the slice uri.
|
||||
*
|
||||
* <p><b>NOTE: </b> If {@link mWidgetId} is also set, {@link mSliceUri} should be ignored.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSliceUri(@NonNull Uri sliceUri) {
|
||||
this.mSliceUri = sliceUri;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the widget id.
|
||||
*
|
||||
* <p><b>NOTE: </b> If {@link mWidgetId} is set, all other @Nullable params should be
|
||||
* ignored.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setWidgetId(@NonNull AppWidgetProviderInfo widgetId) {
|
||||
this.mWidgetId = widgetId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new {@link SmartspaceTarget}.
|
||||
*
|
||||
* @throws IllegalStateException when non null fields are set as null.
|
||||
*/
|
||||
@NonNull
|
||||
public SmartspaceTarget build() {
|
||||
if (mSmartspaceTargetId == null
|
||||
|| mComponentName == null
|
||||
|| mUserHandle == null) {
|
||||
throw new IllegalStateException("Please assign a value to all @NonNull args.");
|
||||
}
|
||||
return new SmartspaceTarget(mSmartspaceTargetId,
|
||||
mHeaderAction, mBaseAction, mCreationTimeMillis, mExpiryTimeMillis, mScore,
|
||||
mActionChips, mIconGrid, mFeatureType, mSensitive, mShouldShowExpanded,
|
||||
mSourceNotificationKey, mComponentName, mUserHandle,
|
||||
mAssociatedSmartspaceTargetId, mSliceUri, mWidgetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
core/java/android/app/smartspace/SmartspaceTargetEvent.aidl
Normal file
19
core/java/android/app/smartspace/SmartspaceTargetEvent.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
parcelable SmartspaceTargetEvent;
|
||||
204
core/java/android/app/smartspace/SmartspaceTargetEvent.java
Normal file
204
core/java/android/app/smartspace/SmartspaceTargetEvent.java
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 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 android.app.smartspace;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* A representation of a smartspace event.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class SmartspaceTargetEvent implements Parcelable {
|
||||
|
||||
/**
|
||||
* User interacted with the target.
|
||||
*/
|
||||
public static final int EVENT_TARGET_INTERACTION = 1;
|
||||
|
||||
/**
|
||||
* Smartspace target was brought into view.
|
||||
*/
|
||||
public static final int EVENT_TARGET_IN_VIEW = 2;
|
||||
/**
|
||||
* Smartspace target went out of view.
|
||||
*/
|
||||
public static final int EVENT_TARGET_OUT_OF_VIEW = 3;
|
||||
/**
|
||||
* A dismiss action was issued by the user.
|
||||
*/
|
||||
public static final int EVENT_TARGET_DISMISS = 4;
|
||||
/**
|
||||
* A block action was issued by the user.
|
||||
*/
|
||||
public static final int EVENT_TARGET_BLOCK = 5;
|
||||
/**
|
||||
* The Ui surface came into view.
|
||||
*/
|
||||
public static final int EVENT_UI_SURFACE_IN_VIEW = 6;
|
||||
/**
|
||||
* The Ui surface went out of view.
|
||||
*/
|
||||
public static final int EVENT_UI_SURFACE_OUT_OF_VIEW = 7;
|
||||
|
||||
/**
|
||||
* @see Parcelable.Creator
|
||||
*/
|
||||
@NonNull
|
||||
public static final Creator<SmartspaceTargetEvent> CREATOR =
|
||||
new Creator<SmartspaceTargetEvent>() {
|
||||
public SmartspaceTargetEvent createFromParcel(Parcel parcel) {
|
||||
return new SmartspaceTargetEvent(parcel);
|
||||
}
|
||||
|
||||
public SmartspaceTargetEvent[] newArray(int size) {
|
||||
return new SmartspaceTargetEvent[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Nullable
|
||||
private final SmartspaceTarget mSmartspaceTarget;
|
||||
|
||||
@Nullable
|
||||
private final String mSmartspaceActionId;
|
||||
|
||||
@EventType
|
||||
private final int mEventType;
|
||||
|
||||
private SmartspaceTargetEvent(@Nullable SmartspaceTarget smartspaceTarget,
|
||||
@Nullable String smartspaceActionId,
|
||||
@EventType int eventType) {
|
||||
mSmartspaceTarget = smartspaceTarget;
|
||||
mSmartspaceActionId = smartspaceActionId;
|
||||
mEventType = eventType;
|
||||
}
|
||||
|
||||
private SmartspaceTargetEvent(Parcel parcel) {
|
||||
mSmartspaceTarget = parcel.readParcelable(null);
|
||||
mSmartspaceActionId = parcel.readString();
|
||||
mEventType = parcel.readInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link SmartspaceTarget} associated with this event.
|
||||
*/
|
||||
@Nullable
|
||||
public SmartspaceTarget getSmartspaceTarget() {
|
||||
return mSmartspaceTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the action id of the Smartspace Action associated with this event.
|
||||
*/
|
||||
@Nullable
|
||||
public String getSmartspaceActionId() {
|
||||
return mSmartspaceActionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link EventType} of this event.
|
||||
*/
|
||||
@NonNull
|
||||
@EventType
|
||||
public int getEventType() {
|
||||
return mEventType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeParcelable(mSmartspaceTarget, flags);
|
||||
dest.writeString(mSmartspaceActionId);
|
||||
dest.writeInt(mEventType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = {"EVENT_"}, value = {
|
||||
EVENT_TARGET_INTERACTION,
|
||||
EVENT_TARGET_IN_VIEW,
|
||||
EVENT_TARGET_OUT_OF_VIEW,
|
||||
EVENT_TARGET_DISMISS,
|
||||
EVENT_TARGET_BLOCK,
|
||||
EVENT_UI_SURFACE_IN_VIEW,
|
||||
EVENT_UI_SURFACE_OUT_OF_VIEW
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface EventType {
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link SmartspaceTargetEvent}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final class Builder {
|
||||
@EventType
|
||||
private final int mEventType;
|
||||
@Nullable
|
||||
private SmartspaceTarget mSmartspaceTarget;
|
||||
@Nullable
|
||||
private String mSmartspaceActionId;
|
||||
|
||||
/**
|
||||
* A builder for {@link SmartspaceTargetEvent}.
|
||||
*/
|
||||
public Builder(@EventType int eventType) {
|
||||
mEventType = eventType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SmartspaceTarget for this event.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSmartspaceTarget(@NonNull SmartspaceTarget smartspaceTarget) {
|
||||
mSmartspaceTarget = smartspaceTarget;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Smartspace action id for this event.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSmartspaceActionId(@NonNull String smartspaceActionId) {
|
||||
mSmartspaceActionId = smartspaceActionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new {@link SmartspaceTargetEvent} instance.
|
||||
*/
|
||||
@NonNull
|
||||
public SmartspaceTargetEvent build() {
|
||||
return new SmartspaceTargetEvent(mSmartspaceTarget, mSmartspaceActionId, mEventType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4614,6 +4614,18 @@ public abstract class Context {
|
||||
@SystemApi
|
||||
public static final String SEARCH_UI_SERVICE = "search_ui";
|
||||
|
||||
/**
|
||||
* Used for getting the smartspace service.
|
||||
*
|
||||
* <p><b>NOTE: </b> this service is optional; callers of
|
||||
* {@code Context.getSystemServiceName(SMARTSPACE_SERVICE)} should check for {@code null}.
|
||||
*
|
||||
* @hide
|
||||
* @see #getSystemService(String)
|
||||
*/
|
||||
@SystemApi
|
||||
public static final String SMARTSPACE_SERVICE = "smartspace";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to access the
|
||||
* {@link com.android.server.voiceinteraction.SoundTriggerService}.
|
||||
|
||||
46
core/java/android/service/smartspace/ISmartspaceService.aidl
Normal file
46
core/java/android/service/smartspace/ISmartspaceService.aidl
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 android.service.smartspace;
|
||||
|
||||
import android.app.smartspace.SmartspaceTarget;
|
||||
import android.app.smartspace.SmartspaceTargetEvent;
|
||||
import android.app.smartspace.SmartspaceSessionId;
|
||||
import android.app.smartspace.SmartspaceConfig;
|
||||
import android.app.smartspace.ISmartspaceCallback;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
|
||||
/**
|
||||
* Interface from the system to Smartspace service.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ISmartspaceService {
|
||||
|
||||
void onCreateSmartspaceSession(in SmartspaceConfig context, in SmartspaceSessionId sessionId);
|
||||
|
||||
void notifySmartspaceEvent(in SmartspaceSessionId sessionId, in SmartspaceTargetEvent event);
|
||||
|
||||
void requestSmartspaceUpdate(in SmartspaceSessionId sessionId);
|
||||
|
||||
void registerSmartspaceUpdates(in SmartspaceSessionId sessionId,
|
||||
in ISmartspaceCallback callback);
|
||||
|
||||
void unregisterSmartspaceUpdates(in SmartspaceSessionId sessionId,
|
||||
in ISmartspaceCallback callback);
|
||||
|
||||
void onDestroySmartspaceSession(in SmartspaceSessionId sessionId);
|
||||
}
|
||||
313
core/java/android/service/smartspace/SmartspaceService.java
Normal file
313
core/java/android/service/smartspace/SmartspaceService.java
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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 android.service.smartspace;
|
||||
|
||||
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
|
||||
|
||||
import android.annotation.CallSuper;
|
||||
import android.annotation.MainThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.Service;
|
||||
import android.app.smartspace.ISmartspaceCallback;
|
||||
import android.app.smartspace.SmartspaceConfig;
|
||||
import android.app.smartspace.SmartspaceSessionId;
|
||||
import android.app.smartspace.SmartspaceTarget;
|
||||
import android.app.smartspace.SmartspaceTargetEvent;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.service.smartspace.ISmartspaceService.Stub;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A service used to share the lifecycle of smartspace UI (open, close, interaction)
|
||||
* and also to return smartspace result on a query.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public abstract class SmartspaceService extends Service {
|
||||
|
||||
/**
|
||||
* The {@link Intent} that must be declared as handled by the service.
|
||||
*
|
||||
* <p>The service must also require the {@link android.permission#MANAGE_SMARTSPACE}
|
||||
* permission.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String SERVICE_INTERFACE =
|
||||
"android.service.smartspace.SmartspaceService";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "SmartspaceService";
|
||||
private final ArrayMap<SmartspaceSessionId, ArrayList<CallbackWrapper>> mSessionCallbacks =
|
||||
new ArrayMap<>();
|
||||
private Handler mHandler;
|
||||
|
||||
private final android.service.smartspace.ISmartspaceService mInterface = new Stub() {
|
||||
|
||||
@Override
|
||||
public void onCreateSmartspaceSession(SmartspaceConfig smartspaceConfig,
|
||||
SmartspaceSessionId sessionId) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(SmartspaceService::doCreateSmartspaceSession,
|
||||
SmartspaceService.this, smartspaceConfig, sessionId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifySmartspaceEvent(SmartspaceSessionId sessionId,
|
||||
SmartspaceTargetEvent event) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(SmartspaceService::notifySmartspaceEvent,
|
||||
SmartspaceService.this, sessionId, event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestSmartspaceUpdate(SmartspaceSessionId sessionId) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(SmartspaceService::doRequestPredictionUpdate,
|
||||
SmartspaceService.this, sessionId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSmartspaceUpdates(SmartspaceSessionId sessionId,
|
||||
ISmartspaceCallback callback) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(SmartspaceService::doRegisterSmartspaceUpdates,
|
||||
SmartspaceService.this, sessionId, callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterSmartspaceUpdates(SmartspaceSessionId sessionId,
|
||||
ISmartspaceCallback callback) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(SmartspaceService::doUnregisterSmartspaceUpdates,
|
||||
SmartspaceService.this, sessionId, callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroySmartspaceSession(SmartspaceSessionId sessionId) {
|
||||
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(SmartspaceService::doDestroy,
|
||||
SmartspaceService.this, sessionId));
|
||||
}
|
||||
};
|
||||
|
||||
@CallSuper
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Log.d(TAG, "onCreate mSessionCallbacks: " + mSessionCallbacks);
|
||||
mHandler = new Handler(Looper.getMainLooper(), null, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public final IBinder onBind(@NonNull Intent intent) {
|
||||
Log.d(TAG, "onBind mSessionCallbacks: " + mSessionCallbacks);
|
||||
if (SERVICE_INTERFACE.equals(intent.getAction())) {
|
||||
return mInterface.asBinder();
|
||||
}
|
||||
Slog.w(TAG, "Tried to bind to wrong intent (should be "
|
||||
+ SERVICE_INTERFACE + ": " + intent);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void doCreateSmartspaceSession(@NonNull SmartspaceConfig config,
|
||||
@NonNull SmartspaceSessionId sessionId) {
|
||||
Log.d(TAG, "doCreateSmartspaceSession mSessionCallbacks: " + mSessionCallbacks);
|
||||
mSessionCallbacks.put(sessionId, new ArrayList<>());
|
||||
onCreateSmartspaceSession(config, sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets called when the client calls <code> SmartspaceManager#createSmartspaceSession </code>.
|
||||
*/
|
||||
public abstract void onCreateSmartspaceSession(@NonNull SmartspaceConfig config,
|
||||
@NonNull SmartspaceSessionId sessionId);
|
||||
|
||||
/**
|
||||
* Gets called when the client calls <code> SmartspaceSession#notifySmartspaceEvent </code>.
|
||||
*/
|
||||
@MainThread
|
||||
public abstract void notifySmartspaceEvent(@NonNull SmartspaceSessionId sessionId,
|
||||
@NonNull SmartspaceTargetEvent event);
|
||||
|
||||
/**
|
||||
* Gets called when the client calls <code> SmartspaceSession#requestSmartspaceUpdate </code>.
|
||||
*/
|
||||
@MainThread
|
||||
public abstract void onRequestSmartspaceUpdate(@NonNull SmartspaceSessionId sessionId);
|
||||
|
||||
private void doRegisterSmartspaceUpdates(@NonNull SmartspaceSessionId sessionId,
|
||||
@NonNull ISmartspaceCallback callback) {
|
||||
Log.d(TAG, "doRegisterSmartspaceUpdates mSessionCallbacks: " + mSessionCallbacks);
|
||||
final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
|
||||
if (callbacks == null) {
|
||||
Slog.e(TAG, "Failed to register for updates for unknown session: " + sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
final CallbackWrapper wrapper = findCallbackWrapper(callbacks, callback);
|
||||
if (wrapper == null) {
|
||||
callbacks.add(new CallbackWrapper(callback,
|
||||
callbackWrapper ->
|
||||
mHandler.post(
|
||||
() -> removeCallbackWrapper(callbacks, callbackWrapper))));
|
||||
}
|
||||
}
|
||||
|
||||
private void doUnregisterSmartspaceUpdates(@NonNull SmartspaceSessionId sessionId,
|
||||
@NonNull ISmartspaceCallback callback) {
|
||||
Log.d(TAG, "doUnregisterSmartspaceUpdates mSessionCallbacks: " + mSessionCallbacks);
|
||||
final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
|
||||
if (callbacks == null) {
|
||||
Slog.e(TAG, "Failed to unregister for updates for unknown session: " + sessionId);
|
||||
return;
|
||||
}
|
||||
|
||||
final CallbackWrapper wrapper = findCallbackWrapper(callbacks, callback);
|
||||
if (wrapper != null) {
|
||||
removeCallbackWrapper(callbacks, wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
private void doRequestPredictionUpdate(@NonNull SmartspaceSessionId sessionId) {
|
||||
Log.d(TAG, "doRequestPredictionUpdate mSessionCallbacks: " + mSessionCallbacks);
|
||||
// Just an optimization, if there are no callbacks, then don't bother notifying the service
|
||||
final ArrayList<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
|
||||
if (callbacks != null && !callbacks.isEmpty()) {
|
||||
onRequestSmartspaceUpdate(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the callback wrapper for the given callback.
|
||||
*/
|
||||
private CallbackWrapper findCallbackWrapper(ArrayList<CallbackWrapper> callbacks,
|
||||
ISmartspaceCallback callback) {
|
||||
for (int i = callbacks.size() - 1; i >= 0; i--) {
|
||||
if (callbacks.get(i).isCallback(callback)) {
|
||||
return callbacks.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void removeCallbackWrapper(
|
||||
ArrayList<CallbackWrapper> callbacks, CallbackWrapper wrapper) {
|
||||
if (callbacks == null) {
|
||||
return;
|
||||
}
|
||||
callbacks.remove(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets called when the client calls <code> SmartspaceManager#destroy() </code>.
|
||||
*/
|
||||
public abstract void onDestroySmartspaceSession(@NonNull SmartspaceSessionId sessionId);
|
||||
|
||||
private void doDestroy(@NonNull SmartspaceSessionId sessionId) {
|
||||
Log.d(TAG, "doDestroy mSessionCallbacks: " + mSessionCallbacks);
|
||||
super.onDestroy();
|
||||
mSessionCallbacks.remove(sessionId);
|
||||
onDestroySmartspaceSession(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the prediction factory to send back results the client app. The can be called
|
||||
* in response to {@link #onRequestSmartspaceUpdate(SmartspaceSessionId)} or proactively as
|
||||
* a result of changes in predictions.
|
||||
*/
|
||||
public final void updateSmartspaceTargets(@NonNull SmartspaceSessionId sessionId,
|
||||
@NonNull List<SmartspaceTarget> targets) {
|
||||
Log.d(TAG, "updateSmartspaceTargets mSessionCallbacks: " + mSessionCallbacks);
|
||||
List<CallbackWrapper> callbacks = mSessionCallbacks.get(sessionId);
|
||||
if (callbacks != null) {
|
||||
for (CallbackWrapper callback : callbacks) {
|
||||
callback.accept(targets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys a smartspace session.
|
||||
*/
|
||||
@MainThread
|
||||
public abstract void onDestroy(@NonNull SmartspaceSessionId sessionId);
|
||||
|
||||
private static final class CallbackWrapper implements Consumer<List<SmartspaceTarget>>,
|
||||
IBinder.DeathRecipient {
|
||||
|
||||
private final Consumer<CallbackWrapper> mOnBinderDied;
|
||||
private ISmartspaceCallback mCallback;
|
||||
|
||||
CallbackWrapper(ISmartspaceCallback callback,
|
||||
@Nullable Consumer<CallbackWrapper> onBinderDied) {
|
||||
mCallback = callback;
|
||||
mOnBinderDied = onBinderDied;
|
||||
try {
|
||||
mCallback.asBinder().linkToDeath(this, 0);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to link to death: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCallback(@NonNull ISmartspaceCallback callback) {
|
||||
if (mCallback == null) {
|
||||
Slog.e(TAG, "Callback is null, likely the binder has died.");
|
||||
return false;
|
||||
}
|
||||
return mCallback.equals(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(List<SmartspaceTarget> smartspaceTargets) {
|
||||
try {
|
||||
if (mCallback != null) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,
|
||||
"CallbackWrapper.accept smartspaceTargets=" + smartspaceTargets);
|
||||
}
|
||||
mCallback.onResult(new ParceledListSlice(smartspaceTargets));
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Error sending result:" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
mCallback.asBinder().unlinkToDeath(this, 0);
|
||||
mCallback = null;
|
||||
if (mOnBinderDied != null) {
|
||||
mOnBinderDied.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5168,6 +5168,11 @@
|
||||
<permission android:name="android.permission.MANAGE_SEARCH_UI"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- @SystemApi Allows an application to manage the smartspace service.
|
||||
@hide <p>Not for use by third-party applications.</p> -->
|
||||
<permission android:name="android.permission.MANAGE_SMARTSPACE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Allows an app to set the theme overlay in /vendor/overlay
|
||||
being used.
|
||||
@hide <p>Not for use by third-party applications.</p> -->
|
||||
|
||||
@@ -3800,6 +3800,15 @@
|
||||
-->
|
||||
<string name="config_defaultSearchUiService" translatable="false"></string>
|
||||
|
||||
<!-- The package name for the system's smartspace service.
|
||||
This service returns smartspace results.
|
||||
|
||||
This service must be trusted, as it can be activated without explicit consent of the user.
|
||||
If no service with the specified name exists on the device, smartspace will be disabled.
|
||||
Example: "com.android.intelligence/.SmartspaceService"
|
||||
-->
|
||||
<string name="config_defaultSmartspaceService" translatable="false"></string>
|
||||
|
||||
<!-- The package name for the system's speech recognition service.
|
||||
This service must be trusted, as it can be activated without explicit consent of the user.
|
||||
Example: "com.android.speech/.RecognitionService"
|
||||
|
||||
@@ -3498,6 +3498,7 @@
|
||||
<java-symbol type="string" name="config_defaultAppPredictionService" />
|
||||
<java-symbol type="string" name="config_defaultContentSuggestionsService" />
|
||||
<java-symbol type="string" name="config_defaultSearchUiService" />
|
||||
<java-symbol type="string" name="config_defaultSmartspaceService" />
|
||||
<java-symbol type="string" name="config_defaultMusicRecognitionService" />
|
||||
<java-symbol type="string" name="config_defaultAttentionService" />
|
||||
<java-symbol type="string" name="config_defaultRotationResolverService" />
|
||||
|
||||
@@ -28,6 +28,7 @@ filegroup {
|
||||
":services.profcollect-sources",
|
||||
":services.restrictions-sources",
|
||||
":services.searchui-sources",
|
||||
":services.smartspace-sources",
|
||||
":services.speech-sources",
|
||||
":services.startop.iorap-sources",
|
||||
":services.systemcaptions-sources",
|
||||
@@ -76,6 +77,7 @@ java_library {
|
||||
"services.profcollect",
|
||||
"services.restrictions",
|
||||
"services.searchui",
|
||||
"services.smartspace",
|
||||
"services.speech",
|
||||
"services.startop",
|
||||
"services.systemcaptions",
|
||||
|
||||
@@ -341,6 +341,8 @@ public final class SystemServer implements Dumpable {
|
||||
"com.android.server.contentsuggestions.ContentSuggestionsManagerService";
|
||||
private static final String SEARCH_UI_MANAGER_SERVICE_CLASS =
|
||||
"com.android.server.searchui.SearchUiManagerService";
|
||||
private static final String SMARTSPACE_MANAGER_SERVICE_CLASS =
|
||||
"com.android.server.smartspace.SmartspaceManagerService";
|
||||
private static final String DEVICE_IDLE_CONTROLLER_CLASS =
|
||||
"com.android.server.DeviceIdleController";
|
||||
private static final String BLOB_STORE_MANAGER_SERVICE_CLASS =
|
||||
@@ -1670,6 +1672,12 @@ public final class SystemServer implements Dumpable {
|
||||
mSystemServiceManager.startService(SEARCH_UI_MANAGER_SERVICE_CLASS);
|
||||
t.traceEnd();
|
||||
|
||||
// Smartspace manager service
|
||||
// TODO: add deviceHasConfigString(context, R.string.config_defaultSmartspaceService)
|
||||
t.traceBegin("StartSmartspaceService");
|
||||
mSystemServiceManager.startService(SMARTSPACE_MANAGER_SERVICE_CLASS);
|
||||
t.traceEnd();
|
||||
|
||||
t.traceBegin("InitConnectivityModuleConnector");
|
||||
try {
|
||||
ConnectivityModuleConnector.getInstance().init(context);
|
||||
|
||||
13
services/smartspace/Android.bp
Normal file
13
services/smartspace/Android.bp
Normal file
@@ -0,0 +1,13 @@
|
||||
filegroup {
|
||||
name: "services.smartspace-sources",
|
||||
srcs: ["java/**/*.java"],
|
||||
path: "java",
|
||||
visibility: ["//frameworks/base/services"],
|
||||
}
|
||||
|
||||
java_library_static {
|
||||
name: "services.smartspace",
|
||||
defaults: ["platform_service_defaults"],
|
||||
srcs: [":services.smartspace-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.server.smartspace;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.service.smartspace.ISmartspaceService;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
|
||||
|
||||
|
||||
/**
|
||||
* Proxy to the {@link android.service.smartspace.SmartspaceService} implementation in another
|
||||
* process.
|
||||
*/
|
||||
public class RemoteSmartspaceService extends
|
||||
AbstractMultiplePendingRequestsRemoteService<RemoteSmartspaceService,
|
||||
ISmartspaceService> {
|
||||
|
||||
private static final String TAG = "RemoteSmartspaceService";
|
||||
|
||||
private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
|
||||
|
||||
private final RemoteSmartspaceServiceCallbacks mCallback;
|
||||
|
||||
public RemoteSmartspaceService(Context context, String serviceInterface,
|
||||
ComponentName componentName, int userId,
|
||||
RemoteSmartspaceServiceCallbacks callback, boolean bindInstantServiceAllowed,
|
||||
boolean verbose) {
|
||||
super(context, serviceInterface, componentName, userId, callback,
|
||||
context.getMainThreadHandler(),
|
||||
bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0,
|
||||
verbose, /* initialCapacity= */ 1);
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ISmartspaceService getServiceInterface(IBinder service) {
|
||||
return ISmartspaceService.Stub.asInterface(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getTimeoutIdleBindMillis() {
|
||||
return PERMANENT_BOUND_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getRemoteRequestMillis() {
|
||||
return TIMEOUT_REMOTE_REQUEST_MILLIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a request to bind to the remote service.
|
||||
*/
|
||||
public void reconnect() {
|
||||
super.scheduleBind();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule async request on remote service.
|
||||
*/
|
||||
public void scheduleOnResolvedService(@NonNull AsyncRequest<ISmartspaceService> request) {
|
||||
scheduleAsyncRequest(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute async request on remote service immediately instead of sending it to Handler queue.
|
||||
*/
|
||||
public void executeOnResolvedService(@NonNull AsyncRequest<ISmartspaceService> request) {
|
||||
executeAsyncRequest(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Failure callback
|
||||
*/
|
||||
public interface RemoteSmartspaceServiceCallbacks
|
||||
extends VultureCallback<RemoteSmartspaceService> {
|
||||
|
||||
/**
|
||||
* Notifies a the failure or timeout of a remote call.
|
||||
*/
|
||||
void onFailureOrTimeout(boolean timedOut);
|
||||
|
||||
/**
|
||||
* Notifies change in connected state of the remote service.
|
||||
*/
|
||||
void onConnectedStateChanged(boolean connected);
|
||||
}
|
||||
|
||||
@Override // from AbstractRemoteService
|
||||
protected void handleOnConnectedStateChanged(boolean connected) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onConnectedStateChanged(connected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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.server.smartspace;
|
||||
|
||||
import static android.Manifest.permission.MANAGE_SMARTSPACE;
|
||||
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
|
||||
import static android.content.Context.SMARTSPACE_SERVICE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.smartspace.ISmartspaceCallback;
|
||||
import android.app.smartspace.ISmartspaceManager;
|
||||
import android.app.smartspace.SmartspaceConfig;
|
||||
import android.app.smartspace.SmartspaceSessionId;
|
||||
import android.app.smartspace.SmartspaceTargetEvent;
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.infra.AbstractMasterSystemService;
|
||||
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
|
||||
import com.android.server.wm.ActivityTaskManagerInternal;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A service used to return smartspace targets given a query.
|
||||
*/
|
||||
public class SmartspaceManagerService extends
|
||||
AbstractMasterSystemService<SmartspaceManagerService, SmartspacePerUserService> {
|
||||
|
||||
private static final String TAG = SmartspaceManagerService.class.getSimpleName();
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
|
||||
|
||||
private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
|
||||
|
||||
public SmartspaceManagerService(Context context) {
|
||||
super(context, new FrameworkResourcesServiceNameResolver(context,
|
||||
com.android.internal.R.string.config_defaultSmartspaceService), null,
|
||||
PACKAGE_UPDATE_POLICY_NO_REFRESH | PACKAGE_RESTART_POLICY_NO_REFRESH);
|
||||
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SmartspacePerUserService newServiceLocked(int resolvedUserId, boolean disabled) {
|
||||
return new SmartspacePerUserService(this, mLock, resolvedUserId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
publishBinderService(SMARTSPACE_SERVICE, new SmartspaceManagerStub());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enforceCallingPermissionForManagement() {
|
||||
getContext().enforceCallingPermission(MANAGE_SMARTSPACE, TAG);
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
|
||||
final SmartspacePerUserService service = peekServiceForUserLocked(userId);
|
||||
if (service != null) {
|
||||
service.onPackageUpdatedLocked();
|
||||
}
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
|
||||
final SmartspacePerUserService service = peekServiceForUserLocked(userId);
|
||||
if (service != null) {
|
||||
service.onPackageRestartedLocked();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaximumTemporaryServiceDurationMs() {
|
||||
return MAX_TEMP_SERVICE_DURATION_MS;
|
||||
}
|
||||
|
||||
private class SmartspaceManagerStub extends ISmartspaceManager.Stub {
|
||||
|
||||
@Override
|
||||
public void createSmartspaceSession(@NonNull SmartspaceConfig smartspaceConfig,
|
||||
@NonNull SmartspaceSessionId sessionId, @NonNull IBinder token) {
|
||||
runForUserLocked("createSmartspaceSession", sessionId, (service) ->
|
||||
service.onCreateSmartspaceSessionLocked(smartspaceConfig, sessionId, token));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifySmartspaceEvent(SmartspaceSessionId sessionId,
|
||||
SmartspaceTargetEvent event) {
|
||||
runForUserLocked("notifySmartspaceEvent", sessionId,
|
||||
(service) -> service.notifySmartspaceEventLocked(sessionId, event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestSmartspaceUpdate(SmartspaceSessionId sessionId) {
|
||||
runForUserLocked("requestSmartspaceUpdate", sessionId,
|
||||
(service) -> service.requestSmartspaceUpdateLocked(sessionId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSmartspaceUpdates(@NonNull SmartspaceSessionId sessionId,
|
||||
@NonNull ISmartspaceCallback callback) {
|
||||
runForUserLocked("registerSmartspaceUpdates", sessionId,
|
||||
(service) -> service.registerSmartspaceUpdatesLocked(sessionId, callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterSmartspaceUpdates(SmartspaceSessionId sessionId,
|
||||
ISmartspaceCallback callback) {
|
||||
runForUserLocked("unregisterSmartspaceUpdates", sessionId,
|
||||
(service) -> service.unregisterSmartspaceUpdatesLocked(sessionId, callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroySmartspaceSession(@NonNull SmartspaceSessionId sessionId) {
|
||||
runForUserLocked("destroySmartspaceSession", sessionId,
|
||||
(service) -> service.onDestroyLocked(sessionId));
|
||||
}
|
||||
|
||||
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
|
||||
@Nullable FileDescriptor err,
|
||||
@NonNull String[] args, @Nullable ShellCallback callback,
|
||||
@NonNull ResultReceiver resultReceiver) {
|
||||
new SmartspaceManagerServiceShellCommand(SmartspaceManagerService.this)
|
||||
.exec(this, in, out, err, args, callback, resultReceiver);
|
||||
}
|
||||
|
||||
private void runForUserLocked(@NonNull final String func,
|
||||
@NonNull final SmartspaceSessionId sessionId,
|
||||
@NonNull final Consumer<SmartspacePerUserService> c) {
|
||||
ActivityManagerInternal am = LocalServices.getService(ActivityManagerInternal.class);
|
||||
final int userId = am.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
|
||||
sessionId.getUserId(), false, ALLOW_NON_FULL, null, null);
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "runForUserLocked:" + func + " from pid=" + Binder.getCallingPid()
|
||||
+ ", uid=" + Binder.getCallingUid());
|
||||
}
|
||||
if (!(mServiceNameResolver.isTemporary(userId)
|
||||
|| mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()))) {
|
||||
|
||||
String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
|
||||
+ ", uid=" + Binder.getCallingUid();
|
||||
Slog.w(TAG, msg);
|
||||
throw new SecurityException(msg);
|
||||
}
|
||||
|
||||
final long origId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
final SmartspacePerUserService service = getServiceForUserLocked(userId);
|
||||
c.accept(service);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.server.smartspace;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.ShellCommand;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* The shell command implementation for the SmartspaceManagerService.
|
||||
*/
|
||||
public class SmartspaceManagerServiceShellCommand extends ShellCommand {
|
||||
|
||||
private static final String TAG =
|
||||
SmartspaceManagerServiceShellCommand.class.getSimpleName();
|
||||
|
||||
private final SmartspaceManagerService mService;
|
||||
|
||||
public SmartspaceManagerServiceShellCommand(@NonNull SmartspaceManagerService service) {
|
||||
mService = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onCommand(String cmd) {
|
||||
if (cmd == null) {
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
switch (cmd) {
|
||||
case "set": {
|
||||
final String what = getNextArgRequired();
|
||||
switch (what) {
|
||||
case "temporary-service": {
|
||||
final int userId = Integer.parseInt(getNextArgRequired());
|
||||
String serviceName = getNextArg();
|
||||
if (serviceName == null) {
|
||||
mService.resetTemporaryService(userId);
|
||||
pw.println("SmartspaceService temporarily reset. ");
|
||||
return 0;
|
||||
}
|
||||
final int duration = Integer.parseInt(getNextArgRequired());
|
||||
mService.setTemporaryService(userId, serviceName, duration);
|
||||
pw.println("SmartspaceService temporarily set to " + serviceName
|
||||
+ " for " + duration + "ms");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHelp() {
|
||||
try (PrintWriter pw = getOutPrintWriter()) {
|
||||
pw.println("SmartspaceManagerService commands:");
|
||||
pw.println(" help");
|
||||
pw.println(" Prints this help text.");
|
||||
pw.println("");
|
||||
pw.println(" set temporary-service USER_ID [COMPONENT_NAME DURATION]");
|
||||
pw.println(" Temporarily (for DURATION ms) changes the service implemtation.");
|
||||
pw.println(" To reset, call with just the USER_ID argument.");
|
||||
pw.println("");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* 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.server.smartspace;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.smartspace.ISmartspaceCallback;
|
||||
import android.app.smartspace.SmartspaceConfig;
|
||||
import android.app.smartspace.SmartspaceSessionId;
|
||||
import android.app.smartspace.SmartspaceTargetEvent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.service.smartspace.ISmartspaceService;
|
||||
import android.service.smartspace.SmartspaceService;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.infra.AbstractRemoteService;
|
||||
import com.android.server.infra.AbstractPerUserSystemService;
|
||||
|
||||
/**
|
||||
* Per-user instance of {@link SmartspaceManagerService}.
|
||||
*/
|
||||
public class SmartspacePerUserService extends
|
||||
AbstractPerUserSystemService<SmartspacePerUserService, SmartspaceManagerService>
|
||||
implements RemoteSmartspaceService.RemoteSmartspaceServiceCallbacks {
|
||||
|
||||
private static final String TAG = SmartspacePerUserService.class.getSimpleName();
|
||||
@GuardedBy("mLock")
|
||||
private final ArrayMap<SmartspaceSessionId, SmartspaceSessionInfo> mSessionInfos =
|
||||
new ArrayMap<>();
|
||||
@Nullable
|
||||
@GuardedBy("mLock")
|
||||
private RemoteSmartspaceService mRemoteService;
|
||||
/**
|
||||
* When {@code true}, remote service died but service state is kept so it's restored after
|
||||
* the system re-binds to it.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private boolean mZombie;
|
||||
|
||||
protected SmartspacePerUserService(SmartspaceManagerService master,
|
||||
Object lock, int userId) {
|
||||
super(master, lock, userId);
|
||||
}
|
||||
|
||||
@Override // from PerUserSystemService
|
||||
protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
|
||||
throws NameNotFoundException {
|
||||
|
||||
ServiceInfo si;
|
||||
try {
|
||||
si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
|
||||
PackageManager.GET_META_DATA, mUserId);
|
||||
} catch (RemoteException e) {
|
||||
throw new NameNotFoundException("Could not get service for " + serviceComponent);
|
||||
}
|
||||
// TODO(b/177858728): must check that either the service is from a system component,
|
||||
// or it matches a service set by shell cmd (so it can be used on CTS tests and when
|
||||
// OEMs are implementing the real service and also verify the proper permissions
|
||||
return si;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Override // from PerUserSystemService
|
||||
protected boolean updateLocked(boolean disabled) {
|
||||
final boolean enabledChanged = super.updateLocked(disabled);
|
||||
if (enabledChanged) {
|
||||
if (!isEnabledLocked()) {
|
||||
// Clear the remote service for the next call
|
||||
updateRemoteServiceLocked();
|
||||
}
|
||||
}
|
||||
return enabledChanged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the service of a new smartspace session.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
public void onCreateSmartspaceSessionLocked(@NonNull SmartspaceConfig smartspaceConfig,
|
||||
@NonNull SmartspaceSessionId sessionId, @NonNull IBinder token) {
|
||||
final boolean serviceExists = resolveService(sessionId,
|
||||
s -> s.onCreateSmartspaceSession(smartspaceConfig, sessionId));
|
||||
|
||||
if (serviceExists && !mSessionInfos.containsKey(sessionId)) {
|
||||
final SmartspaceSessionInfo sessionInfo = new SmartspaceSessionInfo(
|
||||
sessionId, smartspaceConfig, token, () -> {
|
||||
synchronized (mLock) {
|
||||
onDestroyLocked(sessionId);
|
||||
}
|
||||
});
|
||||
if (sessionInfo.linkToDeath()) {
|
||||
mSessionInfos.put(sessionId, sessionInfo);
|
||||
} else {
|
||||
// destroy the session if calling process is already dead
|
||||
onDestroyLocked(sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records an smartspace event to the service.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
public void notifySmartspaceEventLocked(@NonNull SmartspaceSessionId sessionId,
|
||||
@NonNull SmartspaceTargetEvent event) {
|
||||
final SmartspaceSessionInfo sessionInfo = mSessionInfos.get(sessionId);
|
||||
if (sessionInfo == null) return;
|
||||
resolveService(sessionId, s -> s.notifySmartspaceEvent(sessionId, event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the service to return smartspace results of an input query.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
public void requestSmartspaceUpdateLocked(@NonNull SmartspaceSessionId sessionId) {
|
||||
final SmartspaceSessionInfo sessionInfo = mSessionInfos.get(sessionId);
|
||||
if (sessionInfo == null) return;
|
||||
resolveService(sessionId,
|
||||
s -> s.requestSmartspaceUpdate(sessionId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback for continuous updates of predicted apps or shortcuts.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
public void registerSmartspaceUpdatesLocked(@NonNull SmartspaceSessionId sessionId,
|
||||
@NonNull ISmartspaceCallback callback) {
|
||||
final SmartspaceSessionInfo sessionInfo = mSessionInfos.get(sessionId);
|
||||
if (sessionInfo == null) return;
|
||||
final boolean serviceExists = resolveService(sessionId,
|
||||
s -> s.registerSmartspaceUpdates(sessionId, callback));
|
||||
if (serviceExists) {
|
||||
sessionInfo.addCallbackLocked(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a callback for continuous updates of predicted apps or shortcuts.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
public void unregisterSmartspaceUpdatesLocked(@NonNull SmartspaceSessionId sessionId,
|
||||
@NonNull ISmartspaceCallback callback) {
|
||||
final SmartspaceSessionInfo sessionInfo = mSessionInfos.get(sessionId);
|
||||
if (sessionInfo == null) return;
|
||||
final boolean serviceExists = resolveService(sessionId,
|
||||
s -> s.unregisterSmartspaceUpdates(sessionId, callback));
|
||||
if (serviceExists) {
|
||||
sessionInfo.removeCallbackLocked(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the service of the end of an existing smartspace session.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
public void onDestroyLocked(@NonNull SmartspaceSessionId sessionId) {
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "onDestroyLocked(): sessionId=" + sessionId);
|
||||
}
|
||||
final SmartspaceSessionInfo sessionInfo = mSessionInfos.remove(sessionId);
|
||||
if (sessionInfo == null) return;
|
||||
resolveService(sessionId, s -> s.onDestroySmartspaceSession(sessionId));
|
||||
sessionInfo.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailureOrTimeout(boolean timedOut) {
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "onFailureOrTimeout(): timed out=" + timedOut);
|
||||
}
|
||||
// Do nothing, we are just proxying to the smartspace ui service
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectedStateChanged(boolean connected) {
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "onConnectedStateChanged(): connected=" + connected);
|
||||
}
|
||||
if (connected) {
|
||||
synchronized (mLock) {
|
||||
if (mZombie) {
|
||||
// Validation check - shouldn't happen
|
||||
if (mRemoteService == null) {
|
||||
Slog.w(TAG, "Cannot resurrect sessions because remote service is null");
|
||||
return;
|
||||
}
|
||||
mZombie = false;
|
||||
resurrectSessionsLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDied(RemoteSmartspaceService service) {
|
||||
if (isDebug()) {
|
||||
Slog.w(TAG, "onServiceDied(): service=" + service);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
mZombie = true;
|
||||
}
|
||||
updateRemoteServiceLocked();
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void updateRemoteServiceLocked() {
|
||||
if (mRemoteService != null) {
|
||||
mRemoteService.destroy();
|
||||
mRemoteService = null;
|
||||
}
|
||||
}
|
||||
|
||||
void onPackageUpdatedLocked() {
|
||||
if (isDebug()) {
|
||||
Slog.v(TAG, "onPackageUpdatedLocked()");
|
||||
}
|
||||
destroyAndRebindRemoteService();
|
||||
}
|
||||
|
||||
void onPackageRestartedLocked() {
|
||||
if (isDebug()) {
|
||||
Slog.v(TAG, "onPackageRestartedLocked()");
|
||||
}
|
||||
destroyAndRebindRemoteService();
|
||||
}
|
||||
|
||||
private void destroyAndRebindRemoteService() {
|
||||
if (mRemoteService == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "Destroying the old remote service.");
|
||||
}
|
||||
mRemoteService.destroy();
|
||||
mRemoteService = null;
|
||||
|
||||
synchronized (mLock) {
|
||||
mZombie = true;
|
||||
}
|
||||
mRemoteService = getRemoteServiceLocked();
|
||||
if (mRemoteService != null) {
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "Rebinding to the new remote service.");
|
||||
}
|
||||
mRemoteService.reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the remote service connected, it's used to restore state from a 'zombie'
|
||||
* service (i.e., after it died).
|
||||
*/
|
||||
private void resurrectSessionsLocked() {
|
||||
final int numSessions = mSessionInfos.size();
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "Resurrecting remote service (" + mRemoteService + ") on "
|
||||
+ numSessions + " sessions.");
|
||||
}
|
||||
|
||||
for (SmartspaceSessionInfo sessionInfo : mSessionInfos.values()) {
|
||||
sessionInfo.resurrectSessionLocked(this, sessionInfo.mToken);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
protected boolean resolveService(
|
||||
@NonNull final SmartspaceSessionId sessionId,
|
||||
@NonNull final AbstractRemoteService.AsyncRequest<ISmartspaceService> cb) {
|
||||
|
||||
final RemoteSmartspaceService service = getRemoteServiceLocked();
|
||||
if (service != null) {
|
||||
service.executeOnResolvedService(cb);
|
||||
}
|
||||
return service != null;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
private RemoteSmartspaceService getRemoteServiceLocked() {
|
||||
if (mRemoteService == null) {
|
||||
final String serviceName = getComponentNameLocked();
|
||||
if (serviceName == null) {
|
||||
if (mMaster.verbose) {
|
||||
Slog.v(TAG, "getRemoteServiceLocked(): not set");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
|
||||
|
||||
mRemoteService = new RemoteSmartspaceService(getContext(),
|
||||
SmartspaceService.SERVICE_INTERFACE, serviceComponent, mUserId, this,
|
||||
mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
|
||||
}
|
||||
|
||||
return mRemoteService;
|
||||
}
|
||||
|
||||
private static final class SmartspaceSessionInfo {
|
||||
private static final boolean DEBUG = false; // Do not submit with true
|
||||
@NonNull
|
||||
final IBinder mToken;
|
||||
@NonNull
|
||||
final IBinder.DeathRecipient mDeathRecipient;
|
||||
@NonNull
|
||||
private final SmartspaceSessionId mSessionId;
|
||||
@NonNull
|
||||
private final SmartspaceConfig mSmartspaceConfig;
|
||||
private final RemoteCallbackList<ISmartspaceCallback> mCallbacks =
|
||||
new RemoteCallbackList<ISmartspaceCallback>() {
|
||||
@Override
|
||||
public void onCallbackDied(ISmartspaceCallback callback) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Binder died for session Id=" + mSessionId
|
||||
+ " and callback=" + callback.asBinder());
|
||||
}
|
||||
if (mCallbacks.getRegisteredCallbackCount() == 0) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SmartspaceSessionInfo(
|
||||
@NonNull final SmartspaceSessionId id,
|
||||
@NonNull final SmartspaceConfig context,
|
||||
@NonNull final IBinder token,
|
||||
@NonNull final IBinder.DeathRecipient deathRecipient) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Creating SmartspaceSessionInfo for session Id=" + id);
|
||||
}
|
||||
mSessionId = id;
|
||||
mSmartspaceConfig = context;
|
||||
mToken = token;
|
||||
mDeathRecipient = deathRecipient;
|
||||
}
|
||||
|
||||
void addCallbackLocked(ISmartspaceCallback callback) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Storing callback for session Id=" + mSessionId
|
||||
+ " and callback=" + callback.asBinder());
|
||||
}
|
||||
mCallbacks.register(callback);
|
||||
}
|
||||
|
||||
void removeCallbackLocked(ISmartspaceCallback callback) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Removing callback for session Id=" + mSessionId
|
||||
+ " and callback=" + callback.asBinder());
|
||||
}
|
||||
mCallbacks.unregister(callback);
|
||||
}
|
||||
|
||||
boolean linkToDeath() {
|
||||
try {
|
||||
mToken.linkToDeath(mDeathRecipient, 0);
|
||||
} catch (RemoteException e) {
|
||||
if (DEBUG) {
|
||||
Slog.w(TAG, "Caller is dead before session can be started, sessionId: "
|
||||
+ mSessionId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Removing all callbacks for session Id=" + mSessionId
|
||||
+ " and " + mCallbacks.getRegisteredCallbackCount() + " callbacks.");
|
||||
}
|
||||
if (mToken != null) {
|
||||
mToken.unlinkToDeath(mDeathRecipient, 0);
|
||||
}
|
||||
mCallbacks.kill();
|
||||
}
|
||||
|
||||
void resurrectSessionLocked(SmartspacePerUserService service, IBinder token) {
|
||||
int callbackCount = mCallbacks.getRegisteredCallbackCount();
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Resurrecting remote service (" + service.getRemoteServiceLocked()
|
||||
+ ") for session Id=" + mSessionId + " and "
|
||||
+ callbackCount + " callbacks.");
|
||||
}
|
||||
service.onCreateSmartspaceSessionLocked(mSmartspaceConfig, mSessionId, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user