aboutsummaryrefslogtreecommitdiff
path: root/SlicesApp/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'SlicesApp/src/com')
-rw-r--r--SlicesApp/src/com/android/experimental/slicesapp/SlicesActivity.java132
-rw-r--r--SlicesApp/src/com/android/experimental/slicesapp/SlicesBroadcastReceiver.java29
-rw-r--r--SlicesApp/src/com/android/experimental/slicesapp/SlicesProvider.java380
3 files changed, 541 insertions, 0 deletions
diff --git a/SlicesApp/src/com/android/experimental/slicesapp/SlicesActivity.java b/SlicesApp/src/com/android/experimental/slicesapp/SlicesActivity.java
new file mode 100644
index 0000000..9dc4049
--- /dev/null
+++ b/SlicesApp/src/com/android/experimental/slicesapp/SlicesActivity.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 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.experimental.slicesapp;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.Spinner;
+import android.widget.TextView;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SlicesActivity extends Activity {
+
+ private static final String TAG = "SlicesActivity";
+
+ private int mState;
+ private ViewGroup mSlicePreviewFrame;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ SharedPreferences state = getSharedPreferences("slice", 0);
+ mState = 0;
+ if (state != null) {
+ mState = Integer.parseInt(state.getString(getUri().toString(), "0"));
+ }
+ setContentView(R.layout.activity_layout);
+ mSlicePreviewFrame = (ViewGroup) findViewById(R.id.slice_preview);
+ findViewById(R.id.subtract).setOnClickListener(v -> {
+ mState--;
+ state.edit().putString(getUri().toString(), String.valueOf(mState)).commit();
+ updateState();
+ getContentResolver().notifyChange(getUri(), null);
+ });
+ findViewById(R.id.add).setOnClickListener(v -> {
+ mState++;
+ state.edit().putString(getUri().toString(), String.valueOf(mState)).commit();
+ updateState();
+ getContentResolver().notifyChange(getUri(), null);
+ });
+ findViewById(R.id.auth).setOnClickListener(v -> {
+ List<ApplicationInfo> packages = getPackageManager().getInstalledApplications(0);
+ packages.forEach(info -> grantUriPermission(info.packageName, getUri(),
+ Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION));
+ });
+
+ Spinner spinner = findViewById(R.id.spinner);
+ List<String> list = new ArrayList<>();
+ list.add("Default");
+ list.add("Single-line");
+ list.add("Single-line action");
+ list.add("Two-line");
+ list.add("Two-line action");
+ list.add("Weather");
+ list.add("Messaging");
+ list.add("Keep actions");
+ list.add("Maps multi");
+ list.add("Settings");
+ list.add("Settings content");
+ ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_spinner_item, list);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(adapter);
+ spinner.setSelection(list.indexOf(state.getString("slice_type", "Default")));
+ spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ state.edit().putString("slice_type", list.get(position)).commit();
+ getContentResolver().notifyChange(getUri(), null);
+ updateSlice(getUri());
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ bindCheckbox(R.id.header, state, "show_header");
+ bindCheckbox(R.id.sub_header, state, "show_sub_header");
+ bindCheckbox(R.id.show_action_row, state, "show_action_row");
+
+ updateState();
+ }
+
+ private void bindCheckbox(int id, SharedPreferences state, String key) {
+ CheckBox checkbox = findViewById(id);
+ checkbox.setChecked(state.getBoolean(key, false));
+ checkbox.setOnCheckedChangeListener((v, isChecked) -> {
+ state.edit().putBoolean(key, isChecked).commit();
+ getContentResolver().notifyChange(getUri(), null);
+ updateSlice(getUri());
+ });
+ }
+
+ private void updateState() {
+ ((TextView) findViewById(R.id.summary)).setText(String.valueOf(mState));
+ }
+
+ public Uri getUri() {
+ return new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(getPackageName())
+ .appendPath("main").build();
+ }
+
+ private void updateSlice(Uri uri) {
+ }
+}
diff --git a/SlicesApp/src/com/android/experimental/slicesapp/SlicesBroadcastReceiver.java b/SlicesApp/src/com/android/experimental/slicesapp/SlicesBroadcastReceiver.java
new file mode 100644
index 0000000..26adaa7
--- /dev/null
+++ b/SlicesApp/src/com/android/experimental/slicesapp/SlicesBroadcastReceiver.java
@@ -0,0 +1,29 @@
+package com.android.experimental.slicesapp;
+
+import android.app.slice.Slice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Toast;
+
+public class SlicesBroadcastReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (SlicesProvider.SLICE_ACTION.equals(action)) {
+ // A slice was clicked and we've got an action to handle
+ Bundle bundle = intent.getExtras();
+ String message = "";
+ boolean newState = false;
+ if (bundle != null) {
+ message = bundle.getString(SlicesProvider.INTENT_ACTION_EXTRA);
+ newState = bundle.getBoolean(Slice.EXTRA_TOGGLE_STATE);
+ }
+ String text = message + " new state: " + newState;
+ Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
+ }
+ }
+}
diff --git a/SlicesApp/src/com/android/experimental/slicesapp/SlicesProvider.java b/SlicesApp/src/com/android/experimental/slicesapp/SlicesProvider.java
new file mode 100644
index 0000000..125bbb7
--- /dev/null
+++ b/SlicesApp/src/com/android/experimental/slicesapp/SlicesProvider.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2017 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.experimental.slicesapp;
+
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.app.slice.Slice;
+import android.app.slice.Slice.Builder;
+import android.app.slice.SliceProvider;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import java.util.function.Consumer;
+
+
+public class SlicesProvider extends SliceProvider {
+
+ private static final String TAG = "SliceProvider";
+ public static final String SLICE_INTENT = "android.intent.action.EXAMPLE_SLICE_INTENT";
+ public static final String SLICE_ACTION = "android.intent.action.EXAMPLE_SLICE_ACTION";
+ public static final String INTENT_ACTION_EXTRA = "android.intent.slicesapp.INTENT_ACTION_EXTRA";
+
+ private final int NUM_LIST_ITEMS = 10;
+
+ private SharedPreferences mSharedPrefs;
+
+ @Override
+ public boolean onCreate() {
+ mSharedPrefs = getContext().getSharedPreferences("slice", 0);
+ return true;
+ }
+
+ private Uri getIntentUri() {
+ return new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(getContext().getPackageName())
+ .appendPath("main").appendPath("intent")
+ .build();
+ }
+
+ //@Override
+ public Uri onMapIntentToUri(Intent intent) {
+ if (intent.getAction().equals(SLICE_INTENT)) {
+ return getIntentUri();
+ }
+ return null;//super.onMapIntentToUri(intent);
+ }
+
+ /**
+ * Overriding onBindSlice will generate one Slice for all modes.
+ * @param sliceUri
+ */
+ @Override
+ public Slice onBindSlice(Uri sliceUri) {
+ Log.w(TAG, "onBindSlice uri: " + sliceUri);
+ String type = mSharedPrefs.getString("slice_type", "Default");
+ if ("Default".equals(type)) {
+ return null;
+ }
+ Slice.Builder b = new Builder(sliceUri);
+ if (mSharedPrefs.getBoolean("show_header", false)) {
+ b.addText("Header", null, Slice.HINT_TITLE);
+ if (mSharedPrefs.getBoolean("show_sub_header", false)) {
+ b.addText("Sub-header", null);
+ }
+ }
+ if (sliceUri.equals(getIntentUri())) {
+ type = "Intent";
+ }
+ switch (type) {
+ case "Shortcut":
+ b.addColor(Color.CYAN, null).addIcon(
+ Icon.createWithResource(getContext(), R.drawable.mady),
+ null,
+ Slice.HINT_LARGE);
+ break;
+ case "Single-line":
+ b.addSubSlice(makeList(new Slice.Builder(b), this::makeSingleLine,
+ this::addIcon));
+ addPrimaryAction(b);
+ break;
+ case "Single-line action":
+ b.addSubSlice(makeList(new Slice.Builder(b), this::makeSingleLine,
+ this::addAltActions));
+ addPrimaryAction(b);
+ break;
+ case "Two-line":
+ b.addSubSlice(makeList(new Slice.Builder(b), this::makeTwoLine,
+ this::addIcon));
+ addPrimaryAction(b);
+ break;
+ case "Two-line action":
+ b.addSubSlice(makeList(new Slice.Builder(b), this::makeTwoLine,
+ this::addAltActions));
+ addPrimaryAction(b);
+ break;
+ case "Weather":
+ b.addSubSlice(createWeather(new Slice.Builder(b).addHints(Slice.HINT_HORIZONTAL)));
+ break;
+ case "Messaging":
+ createConversation(b);
+ break;
+ case "Keep actions":
+ b.addSubSlice(createKeepNote(new Slice.Builder(b)));
+ break;
+ case "Maps multi":
+ b.addSubSlice(createMapsMulti(new Slice.Builder(b)
+ .addHints(Slice.HINT_HORIZONTAL)));
+ break;
+ case "Intent":
+ b.addSubSlice(createIntentSlice(new Slice.Builder(b)
+ .addHints(Slice.HINT_HORIZONTAL)));
+ break;
+ case "Settings":
+ createSettingsSlice(b);
+ break;
+ case "Settings content":
+ createSettingsContentSlice(b);
+ break;
+ }
+ if (mSharedPrefs.getBoolean("show_action_row", false)) {
+ Intent intent = new Intent(getContext(), SlicesActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 0, intent, 0);
+ b.addSubSlice(new Slice.Builder(b).addHints(Slice.HINT_ACTIONS)
+ .addAction(pendingIntent, new Slice.Builder(b)
+ .addText("Action1", null)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_add),
+ null)
+ .build())
+ .addAction(pendingIntent, new Slice.Builder(b)
+ .addText("Action2", null)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_remove),
+ null)
+ .build())
+ .addAction(pendingIntent, new Slice.Builder(b)
+ .addText("Action3", null)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_add),
+ null)
+ .build())
+ .build());
+ }
+ return b.build();
+ }
+
+ private Slice createWeather(Builder grid) {
+ grid.addSubSlice(new Slice.Builder(grid)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.weather_1),
+ Slice.HINT_LARGE)
+ .addText("MON", null)
+ .addText("69\u00B0", null, Slice.HINT_LARGE).build());
+ grid.addSubSlice(new Slice.Builder(grid)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.weather_2),
+ Slice.HINT_LARGE)
+ .addText("TUE", null)
+ .addText("71\u00B0", null, Slice.HINT_LARGE).build());
+ grid.addSubSlice(new Slice.Builder(grid)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.weather_3),
+ Slice.HINT_LARGE)
+ .addText("WED", null)
+ .addText("76\u00B0", null, Slice.HINT_LARGE).build());
+ grid.addSubSlice(new Slice.Builder(grid)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.weather_4),
+ Slice.HINT_LARGE)
+ .addText("THU", null)
+ .addText("69\u00B0", null, Slice.HINT_LARGE).build());
+ grid.addSubSlice(new Slice.Builder(grid)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.weather_2),
+ Slice.HINT_LARGE)
+ .addText("FRI", null)
+ .addText("71\u00B0", null, Slice.HINT_LARGE).build());
+ return grid.build();
+ }
+
+ private Slice createConversation(Builder b2) {
+ b2.addHints(Slice.HINT_LIST);
+ b2.addSubSlice(new Slice.Builder(b2)
+ .addText("yo home \uD83C\uDF55, I emailed you the info", null)
+ .addTimestamp(System.currentTimeMillis() - 20 * DateUtils.MINUTE_IN_MILLIS, null)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.mady),
+ Slice.SUBTYPE_SOURCE,
+ Slice.HINT_TITLE, Slice.HINT_LARGE)
+ .build(), Slice.SUBTYPE_MESSAGE);
+ b2.addSubSlice(new Builder(b2)
+ .addText("just bought my tickets", null)
+ .addTimestamp(System.currentTimeMillis() - 10 * DateUtils.MINUTE_IN_MILLIS, null)
+ .build(), Slice.SUBTYPE_MESSAGE);
+ b2.addSubSlice(new Builder(b2)
+ .addText("yay! can't wait for getContext() weekend!\n"
+ + "\uD83D\uDE00", null)
+ .addTimestamp(System.currentTimeMillis() - 5 * DateUtils.MINUTE_IN_MILLIS, null)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.mady),
+ Slice.SUBTYPE_SOURCE,
+ Slice.HINT_LARGE)
+ .build(), Slice.SUBTYPE_MESSAGE);
+ RemoteInput ri = new RemoteInput.Builder("someKey").setLabel("someLabel")
+ .setAllowFreeFormInput(true).build();
+ b2.addRemoteInput(ri, null);
+ return b2.build();
+ }
+
+ private Slice addIcon(Builder b) {
+ b.addIcon(Icon.createWithResource(getContext(), R.drawable.ic_add), null);
+ return b.build();
+ }
+
+ private void addAltActions(Builder builder) {
+ Intent intent = new Intent(getContext(), SlicesActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 0, intent, 0);
+ builder.addSubSlice(new Slice.Builder(builder).addHints(Slice.HINT_ACTIONS)
+ .addAction(pendingIntent, new Slice.Builder(builder)
+ .addText("Alt1", null)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_add), null)
+ .build())
+ .addAction(pendingIntent, new Slice.Builder(builder)
+ .addText("Alt2", null)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_remove), null)
+ .build())
+ .build());
+ }
+
+ private void makeSingleLine(Builder b) {
+ b.addText("Single-line list item text", null, Slice.HINT_TITLE);
+ }
+
+ private void makeTwoLine(Builder b) {
+ b.addText("Two-line list item text", null, Slice.HINT_TITLE);
+ b.addText("Secondary text", null);
+ }
+
+ private void addPrimaryAction(Builder b) {
+ Intent intent = new Intent(getContext(), SlicesActivity.class);
+ PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
+ b.addSubSlice(new Slice.Builder(b).addAction(pi,
+ new Slice.Builder(b).addColor(0xFFFF5722, null)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_slice),
+ Slice.HINT_TITLE)
+ .addText("Slice App", null, Slice.HINT_TITLE)
+ .build()).addHints(Slice.HINT_HIDDEN, Slice.HINT_TITLE).build());
+ }
+
+ private Slice makeList(Builder list, Consumer<Builder> lineCreator,
+ Consumer<Builder> lineHandler) {
+ list.addHints(Slice.HINT_LIST);
+ for (int i = 0; i < NUM_LIST_ITEMS; i++) {
+ Builder b = new Builder(list);
+ lineCreator.accept(b);
+ lineHandler.accept(b);
+ list.addSubSlice(b.build());
+ }
+ return list.build();
+ }
+
+ private Slice createKeepNote(Builder b) {
+ Intent intent = new Intent(getContext(), SlicesActivity.class);
+ PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
+ RemoteInput ri = new RemoteInput.Builder("someKey").setLabel("someLabel")
+ .setAllowFreeFormInput(true).build();
+ return b.addText("Create new note", null, Slice.HINT_TITLE).addText("with keep", null)
+ .addColor(0xffffc107, null)
+ .addAction(pi, new Slice.Builder(b)
+ .addText("List", null)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_list), null)
+ .build())
+ .addAction(pi, new Slice.Builder(b)
+ .addText("Voice note", null)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_voice), null)
+ .build())
+ .addAction(pi, new Slice.Builder(b)
+ .addText("Camera", null)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_camera), null)
+ .build())
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_create), null)
+ .addRemoteInput(ri, null)
+ .build();
+ }
+
+ private Slice createMapsMulti(Builder b) {
+ Intent intent = new Intent(getContext(), SlicesActivity.class);
+ PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
+ b.addHints(Slice.HINT_HORIZONTAL, Slice.HINT_LIST);
+
+ b.addSubSlice(new Slice.Builder(b)
+ .addAction(pi, new Slice.Builder(b)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_home), null)
+ .build())
+ .addText("Home", null, Slice.HINT_LARGE)
+ .addText("25 min", null).build());
+ b.addSubSlice(new Slice.Builder(b)
+ .addAction(pi, new Slice.Builder(b)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_work), null)
+ .build())
+ .addText("Work", null, Slice.HINT_LARGE)
+ .addText("1 hour 23 min", null).build());
+ b.addSubSlice(new Slice.Builder(b)
+ .addAction(pi, new Slice.Builder(b)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_car), null)
+ .build())
+ .addText("Mom's", null, Slice.HINT_LARGE)
+ .addText("37 min", null).build());
+ b.addColor(0xff0B8043, null);
+ return b.build();
+ }
+
+ private Slice createIntentSlice(Builder b) {
+ Intent intent = new Intent(getContext(), SlicesActivity.class);
+
+ PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
+
+ b.addHints(Slice.HINT_LIST).addColor(0xff0B8043, null);
+ b.addSubSlice(new Slice.Builder(b)
+ .addAction(pi, new Slice.Builder(b)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_next), null)
+ .build())
+ .addText("Next", null, Slice.HINT_LARGE).build());
+ b.addSubSlice(new Slice.Builder(b)
+ .addAction(pi, new Slice.Builder(b)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_play), null)
+ .build())
+ .addText("Play", null, Slice.HINT_LARGE).build());
+ b.addSubSlice(new Slice.Builder(b)
+ .addAction(pi, new Slice.Builder(b)
+ .addIcon(Icon.createWithResource(getContext(), R.drawable.ic_prev), null)
+ .build())
+ .addText("Previous", null, Slice.HINT_LARGE).build());
+ return b.build();
+ }
+
+ private Slice.Builder createSettingsSlice(Builder b) {
+ b.addSubSlice(new Slice.Builder(b)
+ .addAction(getIntent("toggled"), new Slice.Builder(b)
+ .addText("Wi-fi", null)
+ .addText("GoogleGuest", null)
+ .addHints(Slice.HINT_TOGGLE, Slice.HINT_SELECTED)
+ .build())
+ .build());
+ return b;
+ }
+
+ private Slice.Builder createSettingsContentSlice(Builder b) {
+ b.addSubSlice(new Slice.Builder(b)
+ .addAction(getIntent("main content"),
+ new Slice.Builder(b)
+ .addText("Wi-fi", null)
+ .addText("GoogleGuest", null)
+ .build())
+ .addAction(getIntent("toggled"),
+ new Slice.Builder(b)
+ .addHints(Slice.HINT_TOGGLE, Slice.HINT_SELECTED)
+ .build())
+ .build());
+ return b;
+ }
+
+ private PendingIntent getIntent(String message) {
+ Intent intent = new Intent(SLICE_ACTION);
+ intent.setClass(getContext(), SlicesBroadcastReceiver.class);
+ intent.putExtra(INTENT_ACTION_EXTRA, message);
+ PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ return pi;
+ }
+}