diff options
Diffstat (limited to 'SliceBrowser')
-rw-r--r-- | SliceBrowser/Android.mk | 34 | ||||
-rw-r--r-- | SliceBrowser/AndroidManifest.xml | 39 | ||||
-rw-r--r-- | SliceBrowser/res/drawable/ic_large.xml | 28 | ||||
-rw-r--r-- | SliceBrowser/res/drawable/ic_shortcut.xml | 34 | ||||
-rw-r--r-- | SliceBrowser/res/drawable/ic_small.xml | 27 | ||||
-rw-r--r-- | SliceBrowser/res/layout/activity_layout.xml | 75 | ||||
-rw-r--r-- | SliceBrowser/res/values/strings.xml | 21 | ||||
-rw-r--r-- | SliceBrowser/src/com/android/experimental/slicepresenter/SlicePresenter.java | 222 |
8 files changed, 480 insertions, 0 deletions
diff --git a/SliceBrowser/Android.mk b/SliceBrowser/Android.mk new file mode 100644 index 0000000..578f7b1 --- /dev/null +++ b/SliceBrowser/Android.mk @@ -0,0 +1,34 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_USE_AAPT2 := true + +LOCAL_PACKAGE_NAME := SlicePresenter +LOCAL_SRC_FILES := $(call all-java-files-under, src) \ + $(call all-Iaidl-files-under, src) + +LOCAL_STATIC_ANDROID_LIBRARIES := \ + android-support-v7-cardview + +LOCAL_CERTIFICATE := platform + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) diff --git a/SliceBrowser/AndroidManifest.xml b/SliceBrowser/AndroidManifest.xml new file mode 100644 index 0000000..0e15bfd --- /dev/null +++ b/SliceBrowser/AndroidManifest.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.experimental.slicepresenter"> + + <uses-sdk + android:minSdkVersion="26" /> + + <uses-permission android:name="android.permission.BIND_SLICE" /> + + <application android:label="@string/app_label"> + <activity android:name=".SlicePresenter" + android:theme="@android:style/Theme.DeviceDefault.Light.NoActionBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> + +</manifest> + diff --git a/SliceBrowser/res/drawable/ic_large.xml b/SliceBrowser/res/drawable/ic_large.xml new file mode 100644 index 0000000..b8042a8 --- /dev/null +++ b/SliceBrowser/res/drawable/ic_large.xml @@ -0,0 +1,28 @@ +<!-- +Copyright (C) 2014 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48.0dp" + android:height="48.0dp" + android:viewportWidth="48.0" + android:viewportHeight="48.0"> + <path + android:fillColor="#FF000000" + android:pathData="M34.0,2.02L14.0,2.0c-2.21,0.0 -4.0,1.79 -4.0,4.0l0.0,36.0c0.0,2.21 1.79,4.0 4.0,4.0l20.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L38.0,6.0c0.0,-2.21 -1.79,-3.98 -4.0,-3.98zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0l0.0,28.0z"/> + <path + android:strokeColor="#FF000000" + android:strokeWidth="2" + android:pathData="M16,18 l16,0 l0,10 l-16,0z"/> +</vector> diff --git a/SliceBrowser/res/drawable/ic_shortcut.xml b/SliceBrowser/res/drawable/ic_shortcut.xml new file mode 100644 index 0000000..4b5485d --- /dev/null +++ b/SliceBrowser/res/drawable/ic_shortcut.xml @@ -0,0 +1,34 @@ +<!-- +Copyright (C) 2014 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="48.0dp" + android:viewportHeight="48.0" + android:viewportWidth="48.0" + android:width="48.0dp"> + <path + android:fillColor="#e2e2e2" + android:pathData="M24.0,24.0m-19.0,0.0a19.0,19.0 0.0,1.0 1.0,38.0 0.0a19.0,19.0 0.0,1.0 1.0,-38.0 0.0"/> + <group + android:scaleX=".7" + android:scaleY=".7" + android:translateX="7.2" + android:translateY="7.2"> + + <path + android:fillColor="#ff000000" + android:pathData="M12.0,36.0c0.0,1.0 0.9,2.0 2.0,2.0l2.0,0.0l0.0,7.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0l0.0,-7.0l4.0,0.0l0.0,7.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0l0.0,-7.0l2.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L36.0,16.0L12.0,16.0l0.0,20.0zM7.0,16.0c-1.66,0.0 -3.0,1.34 -3.0,3.0l0.0,14.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0L10.0,19.0c0.0,-1.66 -1.34,-3.0 -3.0,-3.0zm34.0,0.0c-1.66,0.0 -3.0,1.34 -3.0,3.0l0.0,14.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0L44.0,19.0c0.0,-1.66 -1.34,-3.0 -3.0,-3.0zM31.06,4.32l2.61,-2.61c0.39,-0.3 0.39,-1.02 0.0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0.0L29.3,3.25C27.7,2.46 25.91,2.0 24.0,2.0c-1.92,0.0 -3.7,0.46 -5.33,1.26L15.0,0.29c-0.39,-0.39 -1.02,-0.39 -1.41,0.0 -0.3,0.39 -0.39,1.02 0.0,1.41l2.62,2.62C13.94,6.51 12.0,10.03 12.0,14.0l24.0,0.0c0.0,-3.98 -1.95,-7.5 -4.94,-9.68zM20.0,10.0l-2.0,0.0L18.0,8.0l2.0,0.0l0.0,2.0zm10.0,0.0l-2.0,0.0L28.0,8.0l2.0,0.0l0.0,2.0z"/> + </group> +</vector> diff --git a/SliceBrowser/res/drawable/ic_small.xml b/SliceBrowser/res/drawable/ic_small.xml new file mode 100644 index 0000000..b35e1c1 --- /dev/null +++ b/SliceBrowser/res/drawable/ic_small.xml @@ -0,0 +1,27 @@ +<!-- +Copyright (C) 2014 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48.0dp" + android:height="48.0dp" + android:viewportWidth="48.0" + android:viewportHeight="48.0"> + <path + android:fillColor="#FF000000" + android:pathData="M34.0,2.02L14.0,2.0c-2.21,0.0 -4.0,1.79 -4.0,4.0l0.0,36.0c0.0,2.21 1.79,4.0 4.0,4.0l20.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L38.0,6.0c0.0,-2.21 -1.79,-3.98 -4.0,-3.98zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0l0.0,28.0z"/> + <path + android:fillColor="#FF000000" + android:pathData="M16,18 l16,0 l0,4 l-16,0z"/> +</vector> diff --git a/SliceBrowser/res/layout/activity_layout.xml b/SliceBrowser/res/layout/activity_layout.xml new file mode 100644 index 0000000..833414c --- /dev/null +++ b/SliceBrowser/res/layout/activity_layout.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="top" + android:orientation="vertical" > + + <FrameLayout + android:id="@+id/search_bar_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="#f2f2f2"> + <android.support.v7.widget.CardView + android:id="@+id/search_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="8dp" + app:cardCornerRadius="2dp" + app:cardBackgroundColor="?android:attr/colorBackground" + app:cardElevation="2dp"> + <Toolbar + android:id="@+id/search_toolbar" + android:layout_width="match_parent" + android:layout_height="48dp" + android:background="?android:attr/selectableItemBackground" + android:contentInsetStart="0dp" + android:contentInsetStartWithNavigation="0dp" + android:theme="?android:attr/actionBarTheme"> + <SearchView + android:id="@+id/search_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:iconifiedByDefault="false" + android:imeOptions="actionSearch|flagNoExtractUi" + android:queryHint="content://..." + android:searchIcon="@null"/> + </Toolbar> + </android.support.v7.widget.CardView> + </FrameLayout> + + + <ScrollView + android:id="@+id/container" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" > + + <FrameLayout + android:id="@+id/slice_preview" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:orientation="vertical" + android:background="?android:attr/colorBackground" + android:elevation="10dp" /> + </ScrollView> + +</LinearLayout> diff --git a/SliceBrowser/res/values/strings.xml b/SliceBrowser/res/values/strings.xml new file mode 100644 index 0000000..3b5c795 --- /dev/null +++ b/SliceBrowser/res/values/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="app_label">Slice Browser</string> + + <string name="intent_button">Use Intent Slice</string> + <string name="uri_button">Use URI Slice</string> +</resources> diff --git a/SliceBrowser/src/com/android/experimental/slicepresenter/SlicePresenter.java b/SliceBrowser/src/com/android/experimental/slicepresenter/SlicePresenter.java new file mode 100644 index 0000000..6b8a90e --- /dev/null +++ b/SliceBrowser/src/com/android/experimental/slicepresenter/SlicePresenter.java @@ -0,0 +1,222 @@ +/* + * 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.slicepresenter; + +import android.app.Activity; +import android.app.slice.Slice; +import android.app.slice.widget.SliceView; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.BaseColumns; +import android.util.ArrayMap; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.SubMenu; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.CursorAdapter; +import android.widget.LinearLayout; +import android.widget.SearchView; +import android.widget.SearchView.OnSuggestionListener; +import android.widget.SimpleCursorAdapter; +import android.widget.Spinner; +import android.widget.Toolbar; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public class SlicePresenter extends Activity { + + private static final String TAG = "SlicePresenter"; + + private static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI"; + + private ArrayList<Uri> mSliceUris = new ArrayList<Uri>(); + private String mSelectedMode; + private ViewGroup mContainer; + private boolean mShowingIntentSlice; + private SearchView mSearchView; + private SimpleCursorAdapter mAdapter; + private SubMenu mTypeMenu; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_layout); + + Toolbar toolbar = findViewById(R.id.search_toolbar); + setActionBar(toolbar); + + // Shows the slice + mContainer = findViewById(R.id.slice_preview); + mSearchView = findViewById(R.id.search_view); + + final String[] from = new String[]{"uri"}; + final int[] to = new int[]{android.R.id.text1}; + mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, + null, from, to, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); + mSearchView.setSuggestionsAdapter(mAdapter); + mSearchView.setIconifiedByDefault(false); + mSearchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() { + @Override + public boolean onSuggestionClick(int position) { + mSearchView.setQuery(((Cursor) mAdapter.getItem(position)).getString(1), true); + return true; + } + + @Override + public boolean onSuggestionSelect(int position) { + mSearchView.setQuery(((Cursor) mAdapter.getItem(position)).getString(1), true); + return true; + } + }); + mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + addSlice(Uri.parse(s)); + mSearchView.clearFocus(); + return false; + } + + @Override + public boolean onQueryTextChange(String s) { + populateAdapter(s); + return false; + } + }); + + mSelectedMode = (savedInstanceState != null) + ? savedInstanceState.getString("SELECTED_MODE", SliceView.MODE_SHORTCUT) + : SliceView.MODE_SHORTCUT; + if (savedInstanceState != null) { + mSearchView.setQuery(savedInstanceState.getString("SELECTED_QUERY"), true); + } + + // TODO: Listen for changes. + updateAvailableSlices(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + mTypeMenu = menu.addSubMenu("Type"); + mTypeMenu.setIcon(R.drawable.ic_shortcut); + mTypeMenu.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + mTypeMenu.add("Shortcut"); + mTypeMenu.add("Small"); + mTypeMenu.add("Large"); + super.onCreateOptionsMenu(menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getTitle().toString()) { + case "Shortcut": + mTypeMenu.setIcon(R.drawable.ic_shortcut); + mSelectedMode = SliceView.MODE_SHORTCUT; + updateSliceModes(); + return true; + case "Small": + mTypeMenu.setIcon(R.drawable.ic_small); + mSelectedMode = SliceView.MODE_SMALL; + updateSliceModes(); + return true; + case "Large": + mTypeMenu.setIcon(R.drawable.ic_large); + mSelectedMode = SliceView.MODE_LARGE; + updateSliceModes(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + outState.putString("SELECTED_MODE", mSelectedMode); + outState.putString("SELECTED_QUERY", mSearchView.getQuery().toString()); + } + + private void updateAvailableSlices() { + mSliceUris.clear(); + List<PackageInfo> packageInfos = getPackageManager() + .getInstalledPackages(PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA); + for (PackageInfo pi : packageInfos) { + ActivityInfo[] activityInfos = pi.activities; + if (activityInfos != null) { + for (ActivityInfo ai : activityInfos) { + if (ai.metaData != null) { + String sliceUri = ai.metaData.getString(SLICE_METADATA_KEY); + if (sliceUri != null) { + mSliceUris.add(Uri.parse(sliceUri)); + } + } + } + } + } + populateAdapter(String.valueOf(mSearchView.getQuery())); + } + + private void addSlice(Uri uri) { + if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { + SliceView v = new SliceView(getApplicationContext()); + v.setTag(uri); + mContainer.removeAllViews(); + mContainer.addView(v); + v.setMode(mSelectedMode); + v.setSlice(uri); + } else { + Log.w(TAG, "Invalid uri, skipping slice: " + uri); + } + } + + private void updateSliceModes() { + final int count = mContainer.getChildCount(); + for (int i = 0; i < count; i++) { + ((SliceView) mContainer.getChildAt(i)).setMode(mSelectedMode); + } + } + + private void populateAdapter(String query) { + final MatrixCursor c = new MatrixCursor(new String[]{BaseColumns._ID, "uri"}); + ArrayMap<String, Integer> ranking = new ArrayMap<>(); + ArrayList<String> suggestions = new ArrayList(); + mSliceUris.forEach(uri -> { + String uriString = uri.toString(); + if (uriString.contains(query)) { + ranking.put(uriString, uriString.indexOf(query)); + suggestions.add(uriString); + } + }); + suggestions.sort(Comparator.comparingInt(ranking::get)); + for (int i = 0; i < suggestions.size(); i++) { + c.addRow(new Object[]{i, suggestions.get(i)}); + } + mAdapter.changeCursor(c); + } +} |