Twórz własne kafelki Szybkich ustawień dla swojej aplikacji

Szybkie ustawienia to kafelki wyświetlane w panelu Szybkie ustawienia, przedstawiające działania, które użytkownicy mogą kliknąć, aby szybko ukończyć zadania cykliczne. Aplikacja może udostępnić użytkownikom niestandardowy kafelek za pomocą klasy TileService i używać obiektu Tile do śledzenia stanu kafelka. Możesz na przykład utworzyć kafelek umożliwiający użytkownikom włączanie lub wyłączanie sieci VPN udostępnianej przez Twoją aplikację.

Panel Szybkie ustawienia z włączonym i wyłączonym kafelkiem VPN
Rysunek 1. Panel Szybkich ustawień z włączonym i wyłączonym kafelkiem VPN.

Zdecyduj, kiedy utworzyć kafelek

Zalecamy tworzenie kafelków dla określonych funkcji, do których użytkownicy powinni mieć dostęp często lub do których wymagają szybkiego dostępu (albo i jedno i drugie). Najskuteczniejsze kafelki to te, które spełniają obie te cechy, dając szybki dostęp do często wykonywanych działań.

Możesz na przykład utworzyć kafelek z aplikacją do fitnessu, który pozwoli użytkownikom szybko rozpocząć sesję treningową. Nie zalecamy jednak tworzenia dla tej samej aplikacji kafelka, który umożliwiłby użytkownikom przeglądanie całej historii treningów.

Przypadki użycia kafelka aplikacji Fitness
Rysunek 2. Przykłady zalecanych i niezalecanych kart w przypadku aplikacji do fitnessu.

Aby zwiększyć wykrywalność i łatwość obsługi kafelka, zalecamy unikanie niektórych praktyk:

  • Unikaj uruchamiania aplikacji kafelkami. Zamiast tego użyj skrótu aplikacji lub standardowego programu uruchamiającego.

  • Unikaj używania kafelków do jednorazowych działań użytkownika. Zamiast tego użyj skrótu do aplikacji lub powiadomienia.

  • Unikaj tworzenia zbyt wielu kafelków. Zalecamy maksymalnie po 2 na aplikację. Zamiast tego użyj skrótu do aplikacji.

  • Unikaj używania kafelków, które wyświetlają informacje, ale nie są interaktywne dla użytkowników. Zamiast nich używaj powiadomienia lub widżetu.

Utwórz kafelek

Aby utworzyć kafelek, musisz najpierw utworzyć odpowiednią ikonę kafelka, a następnie utworzyć i zadeklarować TileService w pliku manifestu aplikacji.

Przykład Szybkich ustawień zawiera przykład tworzenia kafelka i zarządzania nim.

Utwórz ikonę niestandardową

Będziesz potrzebować ikony niestandardowej, która będzie wyświetlana na kafelku w panelu Szybkich ustawień. Ikona ta zostanie dodana podczas deklarowania właściwości TileService, jak opisano w następnej sekcji. Ikona musi być biała i mieć przezroczyste tło. Ma wymiary 24 x 24 dp i może mieć postać VectorDrawable.

Przykład obiektu rysowalnego wektorowego
Rysunek 3. Przykład rysowanego wektora.

Utwórz ikonę, która będzie wizualnie sygnalizować przeznaczenie kafelka. Dzięki temu użytkownicy mogą z łatwością określić, czy Twój kafelek odpowiada ich potrzebom. Możesz na przykład utworzyć ikonę stopera dla kafelka aplikacji do fitnessu, który umożliwia użytkownikom rozpoczęcie sesji treningowej.

Tworzenie i zadeklarowanie usługi TileService

Utwórz dla kafelka usługę, która rozszerza klasę TileService.

Kotlin

class MyQSTileService: TileService() {

  // Called when the user adds your tile.
  override fun onTileAdded() {
    super.onTileAdded()
  }
  // Called when your app can update your tile.
  override fun onStartListening() {
    super.onStartListening()
  }

  // Called when your app can no longer update your tile.
  override fun onStopListening() {
    super.onStopListening()
  }

  // Called when the user taps on your tile in an active or inactive state.
  override fun onClick() {
    super.onClick()
  }
  // Called when the user removes your tile.
  override fun onTileRemoved() {
    super.onTileRemoved()
  }
}

Java

public class MyQSTileService extends TileService {

  // Called when the user adds your tile.
  @Override
  public void onTileAdded() {
    super.onTileAdded();
  }

  // Called when your app can update your tile.
  @Override
  public void onStartListening() {
    super.onStartListening();
  }

  // Called when your app can no longer update your tile.
  @Override
  public void onStopListening() {
    super.onStopListening();
  }

  // Called when the user taps on your tile in an active or inactive state.
  @Override
  public void onClick() {
    super.onClick();
  }

  // Called when the user removes your tile.
  @Override
  public void onTileRemoved() {
    super.onTileRemoved();
  }
}

Zadeklaruj TileService w pliku manifestu aplikacji. Dodaj nazwę i etykietę elementu TileService, ikonę niestandardową utworzoną w poprzedniej sekcji oraz odpowiednie uprawnienie.

 <service
     android:name=".MyQSTileService"
     android:exported="true"
     android:label="@string/my_default_tile_label"  // 18-character limit.
     android:icon="@drawable/my_default_icon_label"
     android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
     <intent-filter>
         <action android:name="android.service.quicksettings.action.QS_TILE" />
     </intent-filter>
 </service>

Zarządzanie usługą TileService

Gdy utworzysz i zadeklarujesz TileService w manifeście aplikacji, musisz zarządzać jego stanem.

TileService jest usługą powiązaną. TileService jest ograniczony, gdy żąda tego aplikacja lub system musi się z nią skomunikować. Typowy cykl życia powiązanej usługi obejmuje 4 metody wywołania zwrotnego: onCreate(), onBind(), onUnbind() i onDestroy(). Te metody są wywoływane przez system za każdym razem, gdy usługa wchodzi w nowy etap cyklu życia.

Omówienie cyklu życia TileService

Oprócz wywołań zwrotnych, które kontrolują cykl życia powiązanej usługi, musisz wdrożyć inne metody specyficzne dla cyklu życia TileService. Te metody mogą być wywoływane poza obiektami onCreate() i onDestroy(), ponieważ metody cyklu życia Service i metody cyklu życia TileService są wywoływane w 2 osobnych wątkach asynchronicznych.

Cykl życia TileService obejmuje te metody, które są wywoływane przez system za każdym razem, gdy obiekt TileService wchodzi w nową fazę cyklu życia:

  • onTileAdded(): ta metoda jest wywoływana tylko wtedy, gdy użytkownik po raz pierwszy doda Twój kafelek, a następnie usunie go i doda ponownie. To najlepszy moment na każdą jednorazową inicjalizację. Może to jednak nie spełniać wszystkich wymagań związanych z inicjowaniem.

  • onStartListening() i onStopListening(): te metody są często wywoływane przy każdej aktualizacji kafelka przez aplikację. TileService pozostaje wiązany między onStartListening() a onStopListening(), dzięki czemu aplikacja może modyfikować kafelek i przekazywać aktualizacje.

  • onTileRemoved(): ta metoda jest wywoływana tylko wtedy, gdy użytkownik usunie Twój kafelek.

Wybierz tryb słuchania

Urządzenie TileService nasłuchuje w trybie aktywnym lub nieaktywnym. Zalecamy korzystanie z trybu aktywnego, który musisz zadeklarować w pliku manifestu aplikacji. W przeciwnym razie TileService to tryb standardowy i nie trzeba go deklarować.

Nie zakładaj, że Twoje urządzenie TileService będzie działać poza parami metod onStartListening() i onStopListening().

Użyj trybu aktywnego w przypadku instancji TileService, która w swoim procesie nasłuchuje i monitoruje swój stan. TileService w trybie aktywnym jest przypisany do zdarzeń onTileAdded(), onTileRemoved() i kliknięć oraz na żądanie przez proces aplikacji.

Zalecamy tryb aktywny, jeśli urządzenie TileService otrzymuje powiadomienie, gdy stan kafelka powinien zostać zaktualizowany przez własny proces. Aktywne kafelki ograniczają obciążenie systemu, ponieważ nie muszą być powiązane za każdym razem, gdy panel Szybkich ustawień staje się widoczny dla użytkownika.

Statyczną metodę TileService.requestListeningState() można wywołać, aby zażądać rozpoczęcia stanu nasłuchiwania i otrzymać wywołanie zwrotne do onStartListening().

Tryb aktywny możesz zadeklarować, dodając META_DATA_ACTIVE_TILE do pliku manifestu aplikacji.

<service ...>
    <meta-data android:name="android.service.quicksettings.ACTIVE_TILE"
         android:value="true" />
    ...
</service>

Tryb nieaktywny

Tryb nieaktywny to tryb standardowy. Element TileService jest w trybie nieaktywnym, jeśli jest powiązany zawsze, gdy Twój kafelek jest widoczny dla użytkownika. Oznacza to, że Twój TileService może zostać utworzony i powiązany ponownie w przypadku, gdy nie ma na niego wpływu. Może też być niepowiązany i zniszczony, gdy użytkownik nie wyświetla kafelka.

Gdy użytkownik otworzy panel Szybkich ustawień, aplikacja otrzyma wywołanie zwrotne do onStartListening(). Obiekt Tile możesz aktualizować dowolną liczbę razy między onStartListening() a onStopListening().

Nie musisz deklarować trybu nieaktywnego – po prostu nie dodawaj META_DATA_ACTIVE_TILE do pliku manifestu aplikacji.

Omówienie stanów kafelków

Gdy użytkownik doda Twój kafelek, zawsze będzie on istniał w jednym z następujących stanów.

  • STATE_ACTIVE: oznacza, że urządzenie jest włączone lub włączone. W tym stanie użytkownik może wchodzić w interakcje z Twoim kafelkiem.

    Na przykład w przypadku kafelka aplikacji do fitnessu, który pozwala użytkownikom rozpocząć sesję treningu czasowego, STATE_ACTIVE oznacza, że użytkownik rozpoczął sesję treningową i minutnik jest aktywny.

  • STATE_INACTIVE – oznacza, że urządzenie jest wyłączone lub wstrzymane. W tym stanie użytkownik może wchodzić w interakcje z Twoim kafelkiem.

    Aby ponownie użyć przykładowego kafelka aplikacji fitness, kafelek w STATE_INACTIVE oznacza, że użytkownik nie rozpoczął sesji treningowej, ale może to zrobić.

  • STATE_UNAVAILABLE: wskazuje stan tymczasowo niedostępny. W tym stanie użytkownik nie może korzystać z Twojego kafelka.

    Na przykład kafelek w języku STATE_UNAVAILABLE oznacza, że z jakiegoś powodu nie jest on obecnie dostępny dla użytkownika.

System ustawia tylko początkowy stan obiektu Tile. Ustawiasz stan obiektu Tile przez pozostałą część jego cyklu życia.

System może zabarwić ikonę kafelka i tło, aby odzwierciedlić stan obiektu Tile. Obiekty Tile ustawione na STATE_ACTIVE są najciemniejsze, przy czym STATE_INACTIVE i STATE_UNAVAILABLE są coraz jaśniejsze. Odcień zależy od producenta i wersji.

Kafelek VPN podświetlony w celu odzwierciedlenia stanu obiektu
Rysunek 4. Przykłady kafelka, który ma zabarwiony kolor odzwierciedlający stan kafelka (odpowiednio aktywny, nieaktywny lub niedostępny).

Zaktualizuj kafelek

Możesz zaktualizować kafelek, gdy zadzwoni do Ciebie onStartListening(). W zależności od trybu kafelka może on zostać zaktualizowany co najmniej raz do momentu odebrania połączenia zwrotnego pod numer onStopListening().

W trybie aktywnym możesz zaktualizować kafelek dokładnie raz, zanim otrzymasz wywołanie zwrotne pod numer onStopListening(). W trybie nieaktywnym możesz aktualizować kafelek dowolną liczbę razy między onStartListening() a onStopListening().

Możesz pobrać obiekt Tile, wywołując metodę getQsTile(). Aby zaktualizować określone pola obiektu Tile, wywołaj te metody:

Po ustawieniu pól obiektu Tile na prawidłowe wartości musisz wywołać metodę updateTile(), aby zaktualizować kafelek. System przeanalizuje zaktualizowane dane kafelków i zaktualizuje interfejs.

Kotlin

data class StateModel(val enabled: Boolean, val label: String, val icon: Icon)

override fun onStartListening() {
  super.onStartListening()
  val state = getStateFromService()
  qsTile.label = state.label
  qsTile.contentDescription = tile.label
  qsTile.state = if (state.enabled) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
  qsTile.icon = state.icon
  qsTile.updateTile()
}

Java

public class StateModel {
  final boolean enabled;
  final String label;
  final Icon icon;

  public StateModel(boolean e, String l, Icon i) {
    enabled = e;
    label = l;
    icon = i;
  }
}

@Override
public void onStartListening() {
  super.onStartListening();
  StateModel state = getStateFromService();
  Tile tile = getQsTile();
  tile.setLabel(state.label);
  tile.setContentDescription(state.label);
  tile.setState(state.enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
  tile.setIcon(state.icon);
  tile.updateTile();
}

Dotknij uchwytu

Użytkownicy mogą kliknąć Twój kafelek, aby wywołać działanie, jeśli jest on w regionie STATE_ACTIVE lub STATE_INACTIVE. Następnie system wywołuje wywołanie zwrotne onClick() aplikacji.

Gdy aplikacja otrzyma wywołanie zwrotne do onClick(), może uruchomić okno lub działanie, aktywować pracę w tle albo zmienić stan kafelka.

Kotlin

var clicks = 0
override fun onClick() {
  super.onClick()
  counter++
  qsTile.state = if (counter % 2 == 0) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
  qsTile.label = "Clicked $counter times"
  qsTile.contentDescription = qsTile.label
  qsTile.updateTile()
}

Java

int clicks = 0;

@Override
public void onClick() {
  super.onClick();
  counter++;
  Tile tile = getQsTile();
  tile.setState((counter % 2 == 0) ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
  tile.setLabel("Clicked " + counter + " times");
  tile.setContentDescription(tile.getLabel());
  tile.updateTile();
}

Otwórz okno

showDialog() zwija panel Szybkie ustawienia i wyświetla okno. Jeśli działanie wymaga podania dodatkowych danych lub uzyskania zgody użytkownika, możesz dodać do niego kontekst, korzystając z okna.

Uruchamianie aktywności

startActivityAndCollapse() rozpoczyna aktywność podczas zwijania panelu. Aktywności przydają się, gdy chcesz wyświetlić bardziej szczegółowe informacje niż w oknie lub gdy działanie jest bardzo interaktywne.

Jeśli aplikacja wymaga istotnej interakcji z użytkownikiem, powinna uruchamiać działanie tylko w ostateczności. Zamiast tego spróbuj użyć okna lub przełącznika.

Przytrzymanie kafelka powoduje wyświetlenie ekranu Informacje o aplikacji. Aby zastąpić to działanie i zamiast tego uruchomić aktywność związaną z ustawieniami, dodaj <intent-filter> do jednego z aktywności przy użyciu funkcji ACTION_QS_TILE_PREFERENCES.

Od wersji Android API 28 PendingIntent musi zawierać Intent.FLAG_ACTIVITY_NEW_TASK:

if (Build.VERSION.SDK_INT >= 28) {
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}

Możesz też dodać flagę w AndroidManifest.xml w sekcji konkretnej Activity.

Oznacz kafelek jako z możliwością przełączania

Zalecamy oznaczenie kafelka jako przełączania, jeśli działa głównie jako przełącznik dwustanowy (co jest najczęstszym zachowaniem kafelków). Pomaga to przekazywać informacje o działaniu kafelka w systemie operacyjnym i zwiększać ogólną dostępność.

Ustaw metadane TOGGLEABLE_TILE na true, aby oznaczyć kafelek jako możliwy do przełączania.

<service ...>
  <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE"
    android:value="true" />
</service>

Wykonuj działania tylko na bezpiecznie zablokowanych urządzeniach

Na zablokowanych urządzeniach kafelek może się wyświetlać u góry ekranu blokady. Jeśli kafelek zawiera informacje poufne, sprawdź wartość isSecure(), aby określić, czy urządzenie jest w stanie zabezpieczeń, a TileService powinien odpowiednio zmienić swoje działanie.

Jeśli czynność na kafelku można bezpiecznie wykonać po zablokowaniu, użyj startActivity(), aby uruchomić aktywność u góry ekranu blokady.

Jeśli czynność dotycząca kafelka jest niebezpieczna, użyj unlockAndRun(), aby poprosić użytkownika o odblokowanie urządzenia. Jeśli operacja się uda, system uruchomi obiekt Runnable, który przekażesz do tej metody.

Poproś użytkownika o dodanie Twojego kafelka

Aby ręcznie dodać kafelek, użytkownicy muszą wykonać kilka czynności:

  1. Przesuń palcem w dół, aby otworzyć panel Szybkie ustawienia.
  2. Kliknij przycisk edycji.
  3. Przewijać wszystkie kafelki na urządzeniu, aż znajdą Twój kafelek.
  4. Przytrzymaj kafelek i przeciągnij go na listę aktywnych kafelków.

Użytkownik może też w dowolnym momencie przenieść lub usunąć Twój kafelek.

Począwszy od Androida 13 możesz używać metody requestAddTileService(), aby znacznie ułatwić użytkownikom dodawanie kafelka do urządzenia. Ta metoda wyświetla użytkownikom prośbę o szybkie dodanie Twojego kafelka bezpośrednio do panelu Szybkich ustawień. Prompt zawiera nazwę aplikacji, podaną etykietę i ikonę.

Prompt API Szybkich ustawień Miejsc docelowych
Rysunek 5. Prompt interfejsu Quick Settings Placement API.
public void requestAddTileService (
  ComponentName tileServiceComponentName,
  CharSequence tileLabel,
  Icon icon,
  Executor resultExecutor,
  Consumer<Integer> resultCallback
)

Wywołanie zwrotne zawiera informacje o tym, czy kafelek został dodany, a nie dodany, czy był już dostępny, a także czy wystąpił jakiś błąd.

Decyzję o tym, kiedy i jak często prosić użytkowników o zgodę na wykorzystanie danych, należy wedle własnego uznania. Zalecamy wywoływanie funkcji requestAddTileService() tylko w kontekście, na przykład wtedy, gdy użytkownik po raz pierwszy wejdzie w interakcję z funkcją obsługiwaną przez Twój kafelek.

System może przerwać przetwarzanie żądań dotyczących danego obiektu ComponentName, jeśli użytkownik został wcześniej odrzucony przez użytkownika tyle razy. Użytkownik jest określany na podstawie Context użytego do pobrania tej usługi – musi być zgodny z bieżącym użytkownikiem.