Попытка UNINSTALL_SHORTCUT, но ярлык не исчезнет - PullRequest
8 голосов
/ 13 августа 2010

Я создал тестовое действие, которое устанавливает ярлык самого себя на главном экране Android. Когда вы нажимаете кнопку, действие должно удалить тот же ярлык, который он только что создал. Однако ничто из того, что я делаю, не удаляет ярлык.

Вот код Java (ShortcutTest.java):

import java.net.URISyntaxException;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class ShortcutTest extends Activity {
    String shortcutUri;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        addShortcut(getBaseContext());

        Button button = (Button)findViewById(R.id.Button01);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                removeShortcut(getBaseContext());
                finish();
            }
        });
    }

    public void addShortcut(Context context) {
        Intent shortcutIntent = new Intent();
        shortcutIntent.setClassName("com.telespree.android.client", "com.telespree.android.client.ShortcutTest");
        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

        Intent intent = new Intent();
        intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
        intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "ShortcutTest");
        intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(context, R.drawable.icon));
        intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
        shortcutUri = intent.toUri(MODE_WORLD_WRITEABLE);
        context.sendBroadcast(intent);
    }

    public void removeShortcut(Context context) {
        Intent intent = null;
        try {
            intent = Intent.parseUri(shortcutUri, 0);
        } catch (URISyntaxException e) {
        }
        intent.setAction("com.android.launcher.permission.UNINSTALL_SHORTCUT");
        context.sendBroadcast(intent);
    }
}

Вот Манифест:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.telespree.android.client"
      android:versionCode="1"
      android:versionName="1.0">

      <permission
        android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
        android:protectionLevel="normal"
        />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".ShortcutTest"
                  android:label="@string/app_name" android:theme="@android:style/Theme.Translucent">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
    <!-- 
    <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"/>
     -->

    <uses-sdk android:minSdkVersion="7" />

</manifest> 

Я почти уверен, что есть какая-то проблема с разрешениями, хотя я видел другие посты в Интернете, которые указывают, что это возможно.

Любой совет с благодарностью.

Спасибо.

Ответы [ 5 ]

20 голосов
/ 03 марта 2014

DEPRECATED; ХРАНИТСЯ ТОЛЬКО ДЛЯ ИСТОРИЧЕСКИХ ЦЕЛЕЙ

Этот ответ был опубликован в 2014 году, когда описанный метод основывался на функциональности, существовавшей в большинстве устройств Android. Однако, как упомянул Adrian-Costin Țundrea , эта функция была удалена пару лет назад из Launcher3, который является средством запуска AOSP, на котором Google Now Launcher основан 1 . Сообщение коммита говорит:

Снятие опоры из-за ее ворсистой конструкции. Удаление ярлыка вызывает полную перезагрузку. Также у нас нет никакой концепции владельца, поэтому любое приложение может удалить любой ярлык.

По состоянию на март 2017 года эта программа запуска тоже постепенно прекращается в пользу «Служб Google Search Launcher», что означает, что производители могут вместо этого интегрировать определенную библиотеку Google в свои собственные собственные программы запуска полагаться на стандартный лаунчер, предоставленный Google.

Учитывая, что каждый производитель может свободно внедрять свои средства запуска, в зависимости от того, что они хотят, и предполагая, что некоторые из них основаны на Launcher3, трудно сказать, на каких устройствах будет работать метод, описанный ниже, поскольку Launcher3 был запущен даже на некоторых Android 4.1 устройства, которые являются одними из старейших устройств, все еще используемых .


Привет!

Я только что столкнулся с той же самой проблемой и хотел бы поделиться своим опытом после успешного ее решения. tl; dr - перейти к разделу «В заключение» ниже.

Некоторый фон:

Во время работы над «следующей версией» приложения возникла необходимость изменить точку входа по умолчанию (т.е. переименовать «Основное действие»). Это нахмурилось , потому что пользователи, которые будут обновляться со старой версии, все равно будут иметь старый ярлык, указывающий на неправильное место. Чтобы максимально избежать проблем, при первом запуске, без их ведома, старый ярлык должен был быть заменен новым.

Шаг 1: Настройка новой точки входа

Это самая простая часть. Чтобы объявить точку входа , единственное существенное, что нужно сделать , - это вставить следующий тег <action ...> в соответствующее объявление активности в вашем манифесте:

<activity
    android:name="YOUR_PACKAGE_NAME.YOUR_ACTIVITY_NAME"
    android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
    </intent-filter>
</activity>

Что делает точку входа значением по умолчанию в некотором смысле, это то, что ярлык на панели запуска указывает на нее. Вот почему разработчики обычно также включают это в <intent-filter>:

<category android:name="android.intent.category.LAUNCHER"/>

Следует отметить, что каждое действие, которое имеет это в <intent-filter> , будет создавать элемент в вашем ящике приложения - вот почему в большинстве случаев 1 экземпляр - это все, что вам нужно.

Шаг 2: выяснить, как работает старый ярлык

Имея рутированное устройство, я мог получить доступ к таблице базы данных, в которой хранятся элементы запуска / домашнего экрана / рабочего стола (см. Изображение того, как выглядят записи SQLite) , в котором находится:

/data/data/com.android.launcher/databases/launcher.db -> SELECT * FROM favorites`

Вот более читаемая версия выделенной записи с картинки:

#Intent;
    action=android.intent.action.MAIN;
    category=android.intent.category.LAUNCHER;
    launchFlags=0x10200000;
    package=gidutz.soft.bluecard;
    component=gidutz.soft.bluecard/.LoadingScreen;
 end

Обратите внимание на 0x10200000 - это объясняется в Шаг 4 - Попытка 1 ниже.

Шаг 3: Выяснение того, что ожидает программа удаления ярлыков

Строки 38-42 в UninstallShortcutReceiver.java говорят нам, что:

Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
boolean duplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true);

if (intent != null && name != null) { ... }

Это означает, что «намерение удаления» должно иметь и Intent.EXTRA_SHORTCUT_INTENT и Intent.EXTRA_SHORTCUT_NAME, иначе оно даже не будет рассматривать выполнение.

Шаг 4: Поиск правильного синтаксиса

Это пробная ошибка со счастливым концом.

Попытка 1: восстановление намерения

Intent oldShortcutIntent = new Intent();
oldShortcutIntent.setAction(Intent.ACTION_MAIN);
oldShortcutIntent.addCategory(Intent.CATEGORY_LAUNCHER);
oldShortcutIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED +
                           Intent.FLAG_ACTIVITY_NEW_TASK);
oldShortcutIntent.setPackage("gidutz.soft.bluecard");
oldShortcutIntent.setComponent(new ComponentName("gidutz.soft.bluecard",
                                                     ".LoadingScreen"));
//  The above line is equivalent to:
Intent oldShortcutIntent = new Intent(getApplicationContext(),LoadingScreen.class);
Intent uninstaller = new Intent();
uninstaller.putExtra(Intent.EXTRA_SHORTCUT_INTENT, oldShortcutIntent);
uninstaller.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Blue Card");
uninstaller.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
getApplicationContext().sendBroadcast(uninstaller);

Результат: Значок не удален. 0x10200000 - это фактически сумма двух аргументов, как объяснено здесь .

Попытка 2: использование кода как есть от viralpatel

Intent shortcutIntent = new Intent(getApplicationContext(),LoadingScreen.class);
shortcutIntent.setAction(Intent.ACTION_MAIN);

Intent addIntent = new Intent();
addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Blue Card");

addIntent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
getApplicationContext().sendBroadcast(addIntent);

Результат: Значок не удален.

Попытка 3: "Грубая сила"

Попытка скопировать и вставить намерение в точности так, как оно отображается в launcher.db:

Intent intent = new Intent();
String oldShortcutUri = "#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;package=gidutz.soft.bluecard;component=gidutz.soft.bluecard/.LoadingScreen;end";
try {
    Intent altShortcutIntent  = Intent.parseUri(oldShortcutUri,0);
    intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, altShortcutIntent);
    intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Blue Card");
} catch (URISyntaxException e) {
}
intent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
getApplicationContext().sendBroadcast(intent);

Результат: Значок удален !!

В заключение

  1. Убедитесь, что ваше намерение «Удаление значков» использует тот же URI, который использовался для создания значка, который вы пытаетесь удалить, либо сохраняя URI, использованный для его создания, либо получая его из launcher.db.
  2. Подождите примерно 2-3 секунды, пока не появится тост "Значок удален".

Источники

1) Это руководство на viralpatel.net

2) Реализация Google UninstallShortcutReceiver.java

3) Эта тема на xdadevelopers

приписка

Чтобы смоделировать и отладить обновление Google Play (которое сохраняет старый ярлык), я сделал следующее:

  1. Установил старую версию приложения из магазина - на моем экране автоматически появилась иконка со «старым ярлыком».
  2. Создайте резервную копию моего launcher.db с помощью Total Commander.
  3. Установил новую версию через мою IDE (вы также можете использовать .apk для этого) - теперь "старый ярлык" исчез.
  4. Открыл Total Commander и свернул его (чтобы ярлык был доступен в меню «ALT-TAB»).
  5. Зашел в Настройки устройства >> Приложения >> ВСЕ, нашел мой лаунчер (для меня это был "Требушет", так как я на CM11) и Force остановил it.
  6. ALT-TAB в Total Commander и восстановил БД.
  7. Нажал аппаратную кнопку «домой», чтобы перезапустить модуль запуска.
  8. Viola! Старый ярлык теперь восстановлен.

Примечание 1. В ретроспективе, возможно, было бы проще создать старый ярлык вручную, используя URI, полученный из базы данных, вместо того, чтобы проходить через все операции резервного копирования и принудительного останова.

Примечание 2: Я не пробовал удалять значки, принадлежащие другим приложениям, используя этот метод, но он может быть достаточно сумасшедшим, чтобы работать.

10 голосов
/ 16 ноября 2015

В то время как оба решения от Dev-iL и Funt работают, им советуют делать это до Зефира.В Android 6.0 (на котором установлен Launcher v3) Google удалил UninstallShortcutReceiver из-за проблем с безопасностью (вероятно, потому, что стало очевидно здесь ).Так что не ожидайте, что он будет работать с Android 6.0.Надеюсь, что в будущем выпуске он будет читаться в той или иной форме.

PS: Обычно это должен быть комментарий, но я не могу комментировать из-за репутации ...

4 голосов
/ 11 февраля 2011

Вам нужно установить действие для shortcutIntent как:

shortcutIntent.setAction(Intent.ACTION_MAIN);
3 голосов
/ 18 сентября 2011

Попробуйте использовать

public void removeShortcut(Context context) {
        Intent intent = new Intent();

        intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "ShortcutTest");

        try {
            Intent shortcutIntent = Intent.parseUri(shortcutUri, 0);
            intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
        } catch (URISyntaxException e) {
        }
        intent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
        context.sendBroadcast(intent);
    }

Примечание. Вам не нужно сохранять shortcutUri, чтобы удалить ярлык.Вместо этого вы можете использовать

Intent shortcutIntent = new Intent();
shortcutIntent.setClassName("com.telespree.android.client",
        "com.telespree.android.client.ShortcutTest");
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

Intent intent = new Intent();
try {
    intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT,
            Intent.parseUri(shortcutIntent.toUri(0), 0));
} catch (URISyntaxException e) {
    e.printStackTrace();
}
...
intent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
context.sendBroadcast(intent);

Если вы хотите использовать intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); вместо

intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT,
                Intent.parseUri(shortcutIntent.toUri(0), 0));

, тогда вам нужно каждый раз устанавливать действие на shortcutIntent, то есть при установкенапример, при удалении, например Intent shortcutIntent = new Intent(Intent.ACTION_MAIN);

0 голосов
/ 17 марта 2014

Мне потребовалось около часа на отладку и проверку каждого примера на стеке, но решение было очень простым.В вашем коде есть опечатка: вам нужно использовать com.android.launcher. action .UNINSTALL_SHORTCUT (в отличие от разрешения, как в Манифесте)

intent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");

Edit:исправленный ответ

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...