суббота, 13 апреля 2013 г.

Как создать свой плагин поиска данных


Общие требования

Плагин для SCleaner Pro (далее SCP) – это самое обычное приложение, которое способно обмениваться с SCP различного рода данными.
SCP общается с плагином посредством broadcast-ов, передавая или получая с их помощью необходимую информацию.

Критерии создания плагина поиска данных:
1.    у плагина должно быть уникальное имя пакета, но начинаться это имя должно с ru.scleaner.plugin.searchdata.
Например:

ru.scleaner.plugin.searchdata.examplesearchplugin

2.    в манифесте плагина обязательно должен быть прописан Receiver, который будет принимать broadcast-ы от SCP.
Например:

<receiver
android:name="ru.scleaner.plugin.searchdata.standart.Receiver"
              android:enabled="true"
       android:exported="true" >
<intent-filter>
   <action android:name="ru.scleaner.plugin.searchdata.examplesearchplugin " />
</intent-filter>
          </receiver>
3. для того, чтобы SCP мог показывать пользователю информацию о плагине, в его файле strings.xml должны присутствовать следующие строки:
         app_name – имя плагина;
         autor – автор плагина;
         web – ссылка на какой-либо ресурс в интернете или Маркете;
         “transcription”краткое описание.


 Принцип взаимодействия SCP с плагином
* При работе с broadcast сообщениями используются константы класса PluginsConstants который входит в состав библиотеки SCleaner Libs



 Этап 1.
При каждом запуске SCP рассылает всем плагинам поиска сообщение об обновлении своих данных:

Intent intent = new Intent();
intent.setAction([имя пакета плагина]);
intent.putExtra(PluginsConstants.REQUEST_TYPE, PluginsConstants.UPDATE_WORKSPACE);
sendBroadcast(intent);

Ваш receiver должен (или не должен) получить это сообщение, а что делать, получив это сообщение – решаете Вы. Это сделано для того, чтобы плагин мог подготовить (или обновить) какую-либо нужную информацию для себя перед началом работы.
Пример получения сообщения Ваши receiver-ом:

public class Receiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        if (intent != null)
        {
            if (intent.getAction().equals("ru.scleaner.plugin.searchdata.examplesearchplugin "))
            {
                String cmd = intent.getStringExtra(PluginsConstants.REQUEST_TYPE);
                if (cmd != null && cmd.length() != 0)
                {
                    if (cmd.equals(PluginsConstants.UPDATE_WORKSPACE))
                    {
                        ///
                        /// Здесь вы делаете то, что Вам нужно, если это необходимо
                        ///
                    }
                }
            }
        }
    }
}

Этот пример описывает принцип отправки-получения сообщения SCP для плагина.

Этап 2.
На этом этапе SCP рассылает активным плагинам (именно активным, т.е. тем, которые включены в настройках) сообщение о том, что необходимо начать поиск:

Intent intent = new Intent();
intent.setAction([имя пакета плагина]);
intent.putExtra(PluginsConstants.REQUEST_TYPE, PluginsConstants.SEARCH_START);
sendBroadcast(intent);

Соответственно, Ваш receiver должен получить это сообщение и выполнить какое-либо действие для начала поиска необходимых данных. Например, добавив к выше описанному классу еще одно условие:

else if (cmd.equals(PluginsConstants.SEARCH_START))
{
     ///
     /// Здесь необходимо начать поиск
     ///
}

Этап 3.
После того, как был начат поиск, SCP переходим в режим получения данных от плагинов. В этот период Ваш плагин должен отправлять найденные данные, а SCP будет получать их и отображать пользователю.
Для того, чтобы не было ситуаций бесконечного поиска, каждому плагину отведено 5 минут «молчания». Под «молчанием» имеется ввиду период времени, когда от плагина не поступало никаких данных. Такой плагин SCP считает либо зависшим, либо не запущенным вовсе, и как только период «молчания» достигает 5 минут этот плагин считается остановленным. Помимо этого, пользователь может самостоятельно отменить поиск, при этом SCP отправит работающим плагинам следующее сообщение:

Intent intent = new Intent();
intent.setAction([имя пакета]+".SEARCH");
intent.putExtra(PluginsConstants.FLAG_SEARCH_MESSAGE_TYPE, PluginsConstants.SEARCH_STOPED);
sendBroadcast(intent);

Обратите внимание, что здесь уже сообщение отправляется с другим action:

intent.setAction([имя пакета]+".SEARCH");

В процессе поиска все сообщения будут отправляться именно с таким action, чтобы показать, что эти сообщения относятся только к процессу поиска, поэтому здесь Вы решайте сами где и как обрабатывать эти сообщения – либо в начале поиска динамически регистрируйте новый receiver и в нем обрабатывайте все приходящие во время поиска сообщения, либо создавайте отдельный receiver и прописывайте его в манифесте. Лично я в стандартном плагине в самом начале поиска динамически регистрировал новый receiver. Это можно сделать к примеру так (на примере стандартного плагина поиска данных):

registerReceiver(receiverPluginsMessages, new IntentFilter("ru.scleaner.plugin.searchdata.standart.SEARCH"));
private BroadcastReceiver receiverPluginsMessages = new BroadcastReceiver()
{
        @Override
        public void onReceive(Context context, Intent intent)
        {
                  if (intent != null)
                  {
                        String cmd = intent.getStringExtra(PluginsConstants.FLAG_SEARCH_MESSAGE_TYPE);
                        if (cmd != null)
                        {
                                   ///
                                   /// Обрабатываем полученные сообщения
                                   ///
                       }
                  }
        }
};

После того, как Ваш плагин завершил свою работу и передал все необходимые данные (об этом чуть ниже) он должен послать сообщение SCP о том, что он завершил свою работу. Сделать это просто:

Intent intent = new Intent();
intent.setAction(PluginsConstants.ACTION_SEARCH);
intent.putExtra(PluginsConstants.PACKAGE_NAME, "[имя пакета плагина]");
intent.putExtra(PluginsConstants.FLAG_SEARCH_MESSAGE_TYPE, PluginsConstants.SEARCH_FINISHED);
sendBroadcast(intent);

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

Как передать найденные данные программе SCP.
Теперь самое интересное. То, для чего и нужен плагин поиска. В процессе того как Ваш плагин находит данные он должен передавать их SCP. Делать это можно периодически или один раз при завершении поиска. Необходимо лишь учесть тот факт, что посылая сообщения слишком часто Android может просто проигнорировать некоторые из них и тогда эти данные не будут получены программой SCP. Еще может быть так, что Вы попытаетесь передать слишком много данных одним разом, а так как отправка и получение broadcast сообщений являются асинхронными вещами, то программа может не успеть получить все данные из сообщения и завершить поиск. Какое именно количество считается большим – сказать сложно, оно познается только при непосредственном тесте.
Каждый найденный файл или папка должны представлять из себя объект SCleanerItemInfo – это класс библиотеки SCleaner Libs, который описывает найденный объект. По его методам Вы легко сможете догадаться что там нужно указать, если это нужно. К примеру, если Вы создаете этот объект для файла /mnt/sdcard/test.txt:

File cfi = new File(“/mnt/sdcard/test.txt”);
SCleanerItemInfo i_i = new SCleanerItemInfo(cfi.getPath(),cfi.getName(),SCleanerItemInfo.TYPE_FILE);
i_i.setSize(cfi.getSize());
i_i.setInfo(“Test file”);

Как видно из примера – ничего сложного в создании такого объекта нет. SCP умеет обрабатывать объекты только такого типа. Но передать этот объект SCP именно так не получится, т.к. для этого необходимо, чтобы все найденные объекты были внутри специального класса-контейнера ConteinerOfSCleanerItems. Только после этого можно передавать данные программе SCP. Пример создания контейнера и добавления в него найденных данных:

///Создаем список для хранения найденных данных (т.к. контейнер принимает данные только в списке)
ArrayList<SCleanerItemInfo> found_items = new ArrayList<SCleanerItemInfo>();
found_items.add(i_i);
/// Создаем контейнер и добавляем найденные данные
ConteinerOfSCleanerItems conteiner = new ConteinerOfSCleanerItems();
conteiner.setData(found_items);

Теперь передаем этот контейнер программе SCP:

Intent intent = new Intent();
intent.setAction(PluginsConstants.ACTION_SEARCH);
intent.putExtra(PluginsConstants.PACKAGE_NAME, "[имя пакета]");
intent.putExtra(PluginsConstants.FLAG_SEARCH_MESSAGE_TYPE, PluginsConstants.SEARCH_FOUND_DATA_CONTEINER);
intent.putExtra(PluginsConstants.SEARCH_FOUND_DATA_CONTEINER, conteiner);
sendBroadcast(intent);

Теперь SCP получит эти данные и отобразит это пользователю. Как и было описано ранее – как часто и когда именно посылать эти данные в процессе поиска – дело Ваше.
Каждый раз, когда SCP получает от плагина какие-либо данные, счетчик периода «молчания» этого плагина сбрасывается. Поэтому не стоит посылать данные реже, чем раз в 5 минут.

Какие еще данные можно передать во время поиска.
В процессе поиска Ваш плагин может посылать простую информацию о ходе выполнения поиска данных Вашим плагином, чтобы программа SCP смогла отобразить это в окне поиска и пользователь мог видеть, что Ваш плагин активен и работает.
Можно отправлять 3 вида информации:
1.    Строку описания хода поиска (отображается под прогрессбаром):
     Intent intent = new Intent();
   intent.setAction(PluginsConstants.ACTION_SEARCH);
   intent.putExtra(PluginsConstants.PACKAGE_NAME, "[имя пакета плагина]");
   intent.putExtra(PluginsConstants.FLAG_SEARCH_MESSAGE_TYPE, PluginsConstants.SEARCH_MESSAGE_PROGRESS_INFO);
   intent.putExtra(PluginsConstants.SEARCH_MESSAGE_PROGRESS_INFO, “текст описания текущего действия ...”);
   sendBroadcast(intent);
2.    Данные о количестве найденных файлов, папок и их размер:
     Intent intent = new Intent();
   intent.setAction(PluginsConstants.ACTION_SEARCH);
   intent.putExtra(PluginsConstants.PACKAGE_NAME, "[имя пакета плагина]");
   intent.putExtra(PluginsConstants.FLAG_SEARCH_MESSAGE_TYPE, PluginsConstants.SEARCH_MESSAGE_FOUND_DATA_INFO);
   intent.putExtra(PluginsConstants.SEARCH_MESSAGE_FOUND_DATA_INFO_FILES_COUNT, [int]);
   intent.putExtra(PluginsConstants.SEARCH_MESSAGE_FOUND_DATA_INFO_FOLDERS_COUNT, [int]);
   intent.putExtra(PluginsConstants.SEARCH_MESSAGE_FOUND_DATA_INFO_SIZE, [long]);
   sendBroadcast(intent);
3.    Значение для прогрессбара:
     Intent intent = new Intent();
   intent.setAction(PluginsConstants.ACTION_SEARCH);
   intent.addFlags(0x00000020);
   intent.putExtra(PluginsConstants.PACKAGE_NAME, "[имя пакета плагина]");
   intent.putExtra(PluginsConstants.FLAG_SEARCH_MESSAGE_TYPE, PluginsConstants.SEARCH_MESSAGE_PROGRESS_VALUE);
   intent.putExtra(PluginsConstants.SEARCH_MESSAGE_PROGRESS_VALUE_MAX, [int]);
   intent.putExtra(PluginsConstants.SEARCH_MESSAGE_PROGRESS_VALUE_PROGRESS, [int]);
   sendBroadcast(intent);

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


Ресурсы
дополнительная библиотека SCP libshttp://4pda.ru/forum/index.php?showtopic=430366&view=findpost&p=21234927

Комментариев нет:

Отправить комментарий