ShortcutManager sample application.
This is slightly more practical than ShortuctDemo. This app allows the user to publish shortcuts to websites. Bug 30259354 Change-Id: I0e7358aadf016c75c4926595abbe6ce117d69c2d
This commit is contained in:
34
samples/ShortcutSample/Android.mk
Normal file
34
samples/ShortcutSample/Android.mk
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2016 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
# We build two apps from the same source
|
||||||
|
|
||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_PACKAGE_NAME := ShortcutSample
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := samples tests
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||||
|
|
||||||
|
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
|
||||||
|
|
||||||
|
# TODO Change to 25
|
||||||
|
LOCAL_SDK_VERSION := current
|
||||||
|
|
||||||
|
include $(BUILD_PACKAGE)
|
||||||
41
samples/ShortcutSample/AndroidManifest.xml
Normal file
41
samples/ShortcutSample/AndroidManifest.xml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2016 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.example.android.shortcutsample">
|
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="25" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:icon="@drawable/app"
|
||||||
|
android:resizeableActivity="true">
|
||||||
|
|
||||||
|
<activity android:name="Main">
|
||||||
|
<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>
|
||||||
|
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/>
|
||||||
|
</activity>
|
||||||
|
<receiver android:name="MyReceiver">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.LOCALE_CHANGED" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
BIN
samples/ShortcutSample/res/drawable-nodpi/add.png
Normal file
BIN
samples/ShortcutSample/res/drawable-nodpi/add.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
samples/ShortcutSample/res/drawable-nodpi/app.png
Normal file
BIN
samples/ShortcutSample/res/drawable-nodpi/app.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
samples/ShortcutSample/res/drawable-nodpi/link.png
Normal file
BIN
samples/ShortcutSample/res/drawable-nodpi/link.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
62
samples/ShortcutSample/res/layout/list_item.xml
Normal file
62
samples/ShortcutSample/res/layout/list_item.xml
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2016 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"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
>
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="8dip"
|
||||||
|
>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/line1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="#000000"
|
||||||
|
android:textSize="16sp"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/line2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="#444444"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
<Button
|
||||||
|
android:id="@+id/remove"
|
||||||
|
android:text="@string/remove_shortcut"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="visible"
|
||||||
|
style="@android:style/Widget.Material.Button.Borderless"/>
|
||||||
|
<Button
|
||||||
|
android:id="@+id/disable"
|
||||||
|
android:text="@string/disable_shortcut"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="visible"
|
||||||
|
style="@android:style/Widget.Material.Button.Borderless"/>
|
||||||
|
</LinearLayout>
|
||||||
41
samples/ShortcutSample/res/layout/main.xml
Normal file
41
samples/ShortcutSample/res/layout/main.xml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2016 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"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
<Button
|
||||||
|
android:id="@+id/add"
|
||||||
|
android:text="@string/add_new_website"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:onClick="onAddPressed"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="#444444"
|
||||||
|
android:text="@string/existing_shortcuts"
|
||||||
|
/>
|
||||||
|
<ListView
|
||||||
|
android:id="@android:id/list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dip"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:enabled="true"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
25
samples/ShortcutSample/res/values-ja/strings.xml
Normal file
25
samples/ShortcutSample/res/values-ja/strings.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2016 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_name">ショートカットサンプル</string>
|
||||||
|
<string name="add_new_website">ウェブサイト追加</string>
|
||||||
|
<string name="add_new_website_short">追加</string>
|
||||||
|
<string name="existing_shortcuts">既存のショートカット:</string>
|
||||||
|
<string name="remove_shortcut">削除</string>
|
||||||
|
<string name="disable_shortcut">無効</string>
|
||||||
|
<string name="enable_shortcut">有効</string>
|
||||||
|
</resources>
|
||||||
25
samples/ShortcutSample/res/values/strings.xml
Normal file
25
samples/ShortcutSample/res/values/strings.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2016 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_name">Shortcut Sample</string>
|
||||||
|
<string name="add_new_website">Add New Website</string>
|
||||||
|
<string name="add_new_website_short">Add Website</string>
|
||||||
|
<string name="existing_shortcuts">Existing shortcuts:</string>
|
||||||
|
<string name="remove_shortcut">Remove</string>
|
||||||
|
<string name="disable_shortcut">Disable</string>
|
||||||
|
<string name="enable_shortcut">Enable</string>
|
||||||
|
</resources>
|
||||||
29
samples/ShortcutSample/res/xml/shortcuts.xml
Normal file
29
samples/ShortcutSample/res/xml/shortcuts.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2016 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.
|
||||||
|
-->
|
||||||
|
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
<shortcut
|
||||||
|
android:shortcutId="add_website"
|
||||||
|
android:icon="@drawable/add"
|
||||||
|
android:shortcutShortLabel="@string/add_new_website_short"
|
||||||
|
android:shortcutLongLabel="@string/add_new_website"
|
||||||
|
>
|
||||||
|
<intent
|
||||||
|
android:action="com.example.android.shortcutsample.ADD_WEBSITE"
|
||||||
|
android:targetPackage="com.example.android.shortcutsample"
|
||||||
|
android:targetClass="com.example.android.shortcutsample.Main"
|
||||||
|
/>
|
||||||
|
</shortcut>
|
||||||
|
</shortcuts>
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.example.android.shortcutsample;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.ListActivity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ShortcutInfo;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Main extends ListActivity implements OnClickListener {
|
||||||
|
static final String TAG = "ShortcutSample";
|
||||||
|
|
||||||
|
private static final String ID_ADD_WEBSITE = "add_website";
|
||||||
|
|
||||||
|
private static final String ACTION_ADD_WEBSITE =
|
||||||
|
"com.example.android.shortcutsample.ADD_WEBSITE";
|
||||||
|
|
||||||
|
private MyAdapter mAdapter;
|
||||||
|
|
||||||
|
private ShortcutHelper mHelper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.main);
|
||||||
|
|
||||||
|
mHelper = new ShortcutHelper(this);
|
||||||
|
|
||||||
|
mHelper.maybeRestoreAllDynamicShortcuts();
|
||||||
|
|
||||||
|
mHelper.refreshShortcuts(/*force=*/ false);
|
||||||
|
|
||||||
|
if (ACTION_ADD_WEBSITE.equals(getIntent().getAction())) {
|
||||||
|
// Invoked via the manifest shortcut.
|
||||||
|
addWebSite();
|
||||||
|
}
|
||||||
|
|
||||||
|
mAdapter = new MyAdapter(this.getApplicationContext());
|
||||||
|
setListAdapter(mAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
refreshList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the add button.
|
||||||
|
*/
|
||||||
|
public void onAddPressed(View v) {
|
||||||
|
addWebSite();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addWebSite() {
|
||||||
|
Log.i(TAG, "addWebSite");
|
||||||
|
|
||||||
|
// This is important. This allows the launcher to build a prediction model.
|
||||||
|
mHelper.reportShortcutUsed(ID_ADD_WEBSITE);
|
||||||
|
|
||||||
|
final EditText editUri = new EditText(this);
|
||||||
|
|
||||||
|
editUri.setHint("http://www.android.com/");
|
||||||
|
editUri.setInputType(EditorInfo.TYPE_TEXT_VARIATION_URI);
|
||||||
|
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle("Add new website")
|
||||||
|
.setMessage("Type URL of a website")
|
||||||
|
.setView(editUri)
|
||||||
|
.setPositiveButton("Add", (dialog, whichButton) -> {
|
||||||
|
final String url = editUri.getText().toString().trim();
|
||||||
|
if (url.length() > 0) {
|
||||||
|
mHelper.addWebSiteShortcut(url);
|
||||||
|
refreshList();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshList() {
|
||||||
|
mAdapter.setShortcuts(mHelper.getShortcuts());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
final ShortcutInfo shortcut = (ShortcutInfo) ((View) v.getParent()).getTag();
|
||||||
|
|
||||||
|
switch (v.getId()) {
|
||||||
|
case R.id.disable:
|
||||||
|
if (shortcut.isEnabled()) {
|
||||||
|
mHelper.disableShortcut(shortcut);
|
||||||
|
} else {
|
||||||
|
mHelper.enableShortcut(shortcut);
|
||||||
|
}
|
||||||
|
refreshList();
|
||||||
|
break;
|
||||||
|
case R.id.remove:
|
||||||
|
mHelper.removeShortcut(shortcut);
|
||||||
|
refreshList();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final List<ShortcutInfo> EMPTY_LIST = new ArrayList<>();
|
||||||
|
|
||||||
|
private String getType(ShortcutInfo shortcut) {
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
String sep = "";
|
||||||
|
if (shortcut.isDynamic()) {
|
||||||
|
sb.append(sep);
|
||||||
|
sb.append("Dynamic");
|
||||||
|
sep = ", ";
|
||||||
|
}
|
||||||
|
if (shortcut.isPinned()) {
|
||||||
|
sb.append(sep);
|
||||||
|
sb.append("Pinned");
|
||||||
|
sep = ", ";
|
||||||
|
}
|
||||||
|
if (!shortcut.isEnabled()) {
|
||||||
|
sb.append(sep);
|
||||||
|
sb.append("Disabled");
|
||||||
|
sep = ", ";
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyAdapter extends BaseAdapter {
|
||||||
|
private final Context mContext;
|
||||||
|
private final LayoutInflater mInflater;
|
||||||
|
private List<ShortcutInfo> mList = EMPTY_LIST;
|
||||||
|
|
||||||
|
public MyAdapter(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
mInflater = mContext.getSystemService(LayoutInflater.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return mList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int position) {
|
||||||
|
return mList.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasStableIds() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areAllItemsEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled(int position) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShortcuts(List<ShortcutInfo> list) {
|
||||||
|
mList = list;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
final View view;
|
||||||
|
if (convertView != null) {
|
||||||
|
view = convertView;
|
||||||
|
} else {
|
||||||
|
view = mInflater.inflate(R.layout.list_item, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
bindView(view, position, mList.get(position));
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindView(View view, int position, ShortcutInfo shortcut) {
|
||||||
|
view.setTag(shortcut);
|
||||||
|
|
||||||
|
final TextView line1 = (TextView) view.findViewById(R.id.line1);
|
||||||
|
final TextView line2 = (TextView) view.findViewById(R.id.line2);
|
||||||
|
|
||||||
|
line1.setText(shortcut.getLongLabel());
|
||||||
|
|
||||||
|
line2.setText(getType(shortcut));
|
||||||
|
|
||||||
|
final Button remove = (Button) view.findViewById(R.id.remove);
|
||||||
|
final Button disable = (Button) view.findViewById(R.id.disable);
|
||||||
|
|
||||||
|
disable.setText(
|
||||||
|
shortcut.isEnabled() ? R.string.disable_shortcut : R.string.enable_shortcut);
|
||||||
|
|
||||||
|
remove.setOnClickListener(Main.this);
|
||||||
|
disable.setOnClickListener(Main.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.example.android.shortcutsample;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class MyReceiver extends BroadcastReceiver {
|
||||||
|
private static final String TAG = Main.TAG;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
Log.i(TAG, "onReceive: " + intent);
|
||||||
|
if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
|
||||||
|
// Refresh all shortcut to update the labels.
|
||||||
|
// (Right now shortcut labels don't contain localized strings though.)
|
||||||
|
new ShortcutHelper(context).refreshShortcuts(/*force=*/ true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.example.android.shortcutsample;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ShortcutInfo;
|
||||||
|
import android.content.pm.ShortcutManager;
|
||||||
|
import android.graphics.drawable.Icon;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.PersistableBundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
public class ShortcutHelper {
|
||||||
|
private static final String TAG = Main.TAG;
|
||||||
|
|
||||||
|
private static final String EXTRA_LAST_REFRESH =
|
||||||
|
"com.example.android.shortcutsample.EXTRA_LAST_REFRESH";
|
||||||
|
|
||||||
|
private static final long REFRESH_INTERVAL_MS = 60 * 60 * 1000;
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
private final ShortcutManager mShortcutManager;
|
||||||
|
|
||||||
|
public ShortcutHelper(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
mShortcutManager = mContext.getSystemService(ShortcutManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void maybeRestoreAllDynamicShortcuts() {
|
||||||
|
if (mShortcutManager.getDynamicShortcuts().size() == 0) {
|
||||||
|
// NOTE: If this application is always supposed to have dynamic shortcuts, then publish
|
||||||
|
// them here.
|
||||||
|
// Note when an application is "restored" on a new device, all dynamic shortcuts
|
||||||
|
// will *not* be restored but the pinned shortcuts *will*.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reportShortcutUsed(String id) {
|
||||||
|
mShortcutManager.reportShortcutUsed(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this when interacting with ShortcutManager to show consistent error messages.
|
||||||
|
*/
|
||||||
|
private void callShortcutManager(BooleanSupplier r) {
|
||||||
|
try {
|
||||||
|
if (!r.getAsBoolean()) {
|
||||||
|
Utils.showToast(mContext, "Call to ShortcutManager is rate-limited");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Caught Exception", e);
|
||||||
|
Utils.showToast(mContext, "Error while calling ShortcutManager: " + e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all mutable shortcuts from this app self.
|
||||||
|
*/
|
||||||
|
public List<ShortcutInfo> getShortcuts() {
|
||||||
|
// Load mutable dynamic shortcuts and pinned shortcuts and put them into a single list
|
||||||
|
// removing duplicates.
|
||||||
|
|
||||||
|
final List<ShortcutInfo> ret = new ArrayList<>();
|
||||||
|
final HashSet<String> seenKeys = new HashSet<>();
|
||||||
|
|
||||||
|
// Check existing shortcuts shortcuts
|
||||||
|
for (ShortcutInfo shortcut : mShortcutManager.getDynamicShortcuts()) {
|
||||||
|
if (!shortcut.isImmutable()) {
|
||||||
|
ret.add(shortcut);
|
||||||
|
seenKeys.add(shortcut.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ShortcutInfo shortcut : mShortcutManager.getPinnedShortcuts()) {
|
||||||
|
if (!shortcut.isImmutable() && !seenKeys.contains(shortcut.getId())) {
|
||||||
|
ret.add(shortcut);
|
||||||
|
seenKeys.add(shortcut.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the activity starts. Looks for shortcuts that have been pushed and refreshes
|
||||||
|
* them (but the refresh part isn't implemented yet...).
|
||||||
|
*/
|
||||||
|
public void refreshShortcuts(boolean force) {
|
||||||
|
new AsyncTask<Void, Void, Void>() {
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
Log.i(TAG, "refreshingShortcuts...");
|
||||||
|
|
||||||
|
final long now = System.currentTimeMillis();
|
||||||
|
final long staleThreshold = force ? now : now - REFRESH_INTERVAL_MS;
|
||||||
|
|
||||||
|
// Check all existing dynamic and pinned shortcut, and if their last refresh
|
||||||
|
// time is older than a certain threshold, update them.
|
||||||
|
|
||||||
|
final List<ShortcutInfo> updateList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (ShortcutInfo shortcut : getShortcuts()) {
|
||||||
|
if (shortcut.isImmutable()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PersistableBundle extras = shortcut.getExtras();
|
||||||
|
if (extras != null && extras.getLong(EXTRA_LAST_REFRESH) >= staleThreshold) {
|
||||||
|
// Shortcut still fresh.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Log.i(TAG, "Refreshing shortcut: " + shortcut.getId());
|
||||||
|
|
||||||
|
final ShortcutInfo.Builder b = new ShortcutInfo.Builder(
|
||||||
|
mContext, shortcut.getId());
|
||||||
|
|
||||||
|
setSiteInformation(b, shortcut.getIntent().getData());
|
||||||
|
setExtras(b);
|
||||||
|
|
||||||
|
updateList.add(b.build());
|
||||||
|
}
|
||||||
|
// Call update.
|
||||||
|
if (updateList.size() > 0) {
|
||||||
|
callShortcutManager(() -> mShortcutManager.updateShortcuts(updateList));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShortcutInfo createShortcutForUrl(String urlAsString) {
|
||||||
|
Log.i(TAG, "createShortcutForUrl: " + urlAsString);
|
||||||
|
|
||||||
|
final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mContext, urlAsString);
|
||||||
|
|
||||||
|
final Uri uri = Uri.parse(urlAsString);
|
||||||
|
b.setIntent(new Intent(Intent.ACTION_VIEW, uri));
|
||||||
|
|
||||||
|
setSiteInformation(b, uri);
|
||||||
|
setExtras(b);
|
||||||
|
|
||||||
|
return b.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShortcutInfo.Builder setSiteInformation(ShortcutInfo.Builder b, Uri uri) {
|
||||||
|
// TODO Get the actual site <title> and use it.
|
||||||
|
// TODO Set the current locale to accept-language to get localized title.
|
||||||
|
b.setShortLabel(uri.getHost());
|
||||||
|
b.setLongLabel(uri.toString());
|
||||||
|
|
||||||
|
// TODO Fetch the favicon from the URI and sets to the icon.
|
||||||
|
b.setIcon(Icon.createWithResource(mContext, R.drawable.link));
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShortcutInfo.Builder setExtras(ShortcutInfo.Builder b) {
|
||||||
|
final PersistableBundle extras = new PersistableBundle();
|
||||||
|
extras.putLong(EXTRA_LAST_REFRESH, System.currentTimeMillis());
|
||||||
|
b.setExtras(extras);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeUrl(String urlAsString) {
|
||||||
|
if (urlAsString.startsWith("http://") || urlAsString.startsWith("https://")) {
|
||||||
|
return urlAsString;
|
||||||
|
} else {
|
||||||
|
return "http://" + urlAsString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addWebSiteShortcut(String urlAsString) {
|
||||||
|
final String uriFinal = urlAsString;
|
||||||
|
callShortcutManager(() -> {
|
||||||
|
final ShortcutInfo shortcut = createShortcutForUrl(normalizeUrl(uriFinal));
|
||||||
|
return mShortcutManager.addDynamicShortcuts(Arrays.asList(shortcut));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeShortcut(ShortcutInfo shortcut) {
|
||||||
|
mShortcutManager.removeDynamicShortcuts(Arrays.asList(shortcut.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disableShortcut(ShortcutInfo shortcut) {
|
||||||
|
mShortcutManager.disableShortcuts(Arrays.asList(shortcut.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enableShortcut(ShortcutInfo shortcut) {
|
||||||
|
mShortcutManager.enableShortcuts(Arrays.asList(shortcut.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.example.android.shortcutsample;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ShortcutInfo;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.PersistableBundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
private Utils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showToast(Context context, String message) {
|
||||||
|
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user