정보 아키텍처

Android 8.0에는 설정 앱을 통해 설정 구성 방식을 간소화하고 사용자가 빠르게 설정을 찾아 Android 기기를 맞춤설정할 수 있도록 하기 위한 새로운 정보 아키텍처가 도입되었습니다. Android 9에는 추가적인 설정 기능과 간편한 구현을 위한 몇 가지 개선사항이 도입되었습니다.

예시 및 소스

설정의 페이지 대부분은 현재 새 프레임워크를 사용하여 구현되어 있습니다. DisplaySettings가 좋은 예입니다. packages/apps/Settings/src/com/android/settings/DisplaySettings.java

중요한 구성요소의 파일 경로는 다음과 같습니다.

  • CategoryKey: packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
  • DashboardFragmentRegistry: packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
  • DashboardFragment: packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragment.java
  • AbstractPreferenceController: frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
  • BasePreferenceController(Android 9에 도입됨): packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java

구현

기기 제조업체는 필요에 따라 기존 설정 정보 아키텍처를 조정하고 추가 설정 페이지를 삽입하여 파트너 관련 기능을 수용하는 것이 좋습니다. 환경설정을 레거시 페이지(SettingsPreferencePage로 구현됨)에서 새 페이지(DashboardFragment를 사용하여 구현됨)로 옮기는 과정은 복잡할 수 있습니다. 레거시 페이지의 환경설정은 PreferenceController로 구현되지 않을 가능성이 높습니다.

따라서 환경설정을 레거시 페이지에서 새 페이지로 옮길 때에는 새 DashboardFragment에서 인스턴스화하기 전에 PreferenceController를 생성하고 코드를 컨트롤러로 옮겨야 합니다. PreferenceController에 요구되는 API는 이름에 설명되어 있으며 Javadoc에도 문서화되어 있습니다.

PreferenceController에 단위 테스트를 추가하는 것이 좋습니다. 변경사항이 AOSP에 제출된 후에는 단위 테스트가 필요합니다. Robolectric 기반 테스트를 작성하는 자세한 방법은 readme 파일 packages/apps/Settings/tests/robotests/README.md를 참조하세요.

플러그인 형식 정보 아키텍처

각 설정 항목은 환경설정으로 구현됩니다. 환경설정은 한 페이지에서 다른 페이지로 쉽게 옮길 수 있습니다.

여러 설정을 쉽게 옮길 수 있도록 Android 8.0에는 설정 항목이 포함된 플러그인 형식 호스트 프래그먼트가 도입되었습니다. 설정 항목은 플러그인 형식 컨트롤러로 모델링됩니다. 따라서 설정 페이지는 단일 호스트 프래그먼트와 여러 설정 컨트롤러에 의해 구성됩니다.

DashboardFragment

DashboardFragment는 플러그인 형식의 환경설정 컨트롤러 호스트입니다. 프래그먼트는 PreferenceFragment에서 상속되며 정적 환경설정 목록과 동적 환경설정 목록을 둘 다 확장하고 업데이트하기 위한 후크를 포함하고 있습니다.

정적 환경설정

정적 환경설정 목록은 <Preference> 태그를 사용하여 XML에 정의됩니다. DashboardFragment 구현은 getPreferenceScreenResId() 메서드를 사용하여 표시할 정적 환경설정 목록을 어떤 XML 파일에 포함할지 정의합니다.

동적 환경설정

동적 항목은 인텐트가 포함된 타일을 나타내며, 외부 또는 내부 활동으로 연결됩니다. 일반적으로 인텐트는 다른 설정 페이지로 연결됩니다. 예를 들어 설정 홈페이지의 'Google' 설정 항목은 동적 항목입니다. 동적 항목은 AndroidManifest(아래 설명 참조)에서 정의되며, FeatureProvider( DashboardFeatureProvider로 정의됨)를 통해 로드됩니다.

동적 설정은 정적으로 구성된 설정보다 무겁습니다. 따라서 일반적인 경우에는 개발자가 설정을 정적으로 구현해야 합니다. 하지만 동적 설정은 아래에 해당하는 경우에 유용할 수 있습니다.

  • 설정이 설정 앱에서 직접적으로 구현되지 않음(예: OEM/이동통신사 앱에 의해 구현된 설정을 삽입하는 경우)
  • 설정이 설정 홈페이지에 표시되어야 함
  • 이미 설정에 관한 활동이 있으며 추가적인 정적 구성을 구현하고 싶지 않음

활동을 동적 설정으로 구성하려면 다음을 수행합니다.

  • 활동에 인텐트 필터를 추가하여 활동을 동적 설정으로 표시합니다.
  • 설정 앱이 어떤 카테고리에 속하는지 해당 앱에 알립니다. 카테고리는 CategoryKey에 정의된 상수입니다.
  • 선택사항: 설정이 표시될 때 요약 텍스트를 추가합니다.

다음은 DisplaySettings의 설정 앱에서 가져온 예시입니다.

<activity android:name="Settings$DisplaySettingsActivity"
                   android:label="@string/display_settings"
                   android:icon="@drawable/ic_settings_display">
             <!-- Mark the activity as a dynamic setting -->
              <intent-filter>
                     <action android:name="com.android.settings.action.IA_SETTINGS" />
              </intent-filter>
             <!-- Tell Settings app which category it belongs to -->
              <meta-data android:name="com.android.settings.category"
                     android:value="com.android.settings.category.ia.homepage" />
             <!-- Add a summary text when the setting is displayed -->
              <meta-data android:name="com.android.settings.summary"
                     android:resource="@string/display_dashboard_summary"/>
             </activity>

렌더링 시 프래그먼트에서 AndroidManifest에 정의된 정적 XML 및 동적 설정의 환경설정 목록을 요청합니다. PreferenceController가 자바 코드 또는 XML 중 어디에 정의되었든, DashboardFragmentPreferenceController(아래 설명 참조)를 통해 각 설정의 논리를 관리하고 처리합니다. 그러면 목록이 UI에 혼합 목록으로 표시됩니다.

PreferenceController

이 섹션에 설명된 것처럼 PreferenceController 구현 방식은 Android 9 및 Android 8.x 간에 차이가 있습니다.

Android 9 버전의 PreferenceController

PreferenceController에는 표시, 업데이트, 검색 색인 생성 등의 환경설정과 상호작용하기 위한 모든 논리가 포함됩니다.

PreferenceController의 인터페이스는 BasePreferenceController로 정의됩니다. 예를 들면 packages/apps/Settings/src/com/android/settings/core/ BasePreferenceController.java의 코드를 참조해 보세요.

BasePreferenceController에는 여러 개의 하위 클래스가 있으며, 각 하위 클래스는 설정 앱에서 기본적으로 지원하는 구체적인 UI 스타일에 매핑됩니다. 예를 들어 TogglePreferenceController에는 사용자가 전환 기반 환경설정 UI와 어떻게 상호작용해야 하는지에 대해 매핑되는 API가 있습니다.

BasePreferenceController에는 getAvailabilityStatus(), displayPreference(), handlePreferenceTreeClicked(), 등의 API가 있습니다. 각 API에 관한 상세 문서는 인터페이스 클래스에서 찾을 수 있습니다.

BasePreferenceController(및 TogglePreferenceController 등의 하위 클래스) 구현의 제한사항은 구성자 서명이 다음 중 하나와 일치해야 한다는 것입니다.

  • public MyController(Context context, String key) {}
  • public MyController(Context context) {}

환경설정을 프래그먼트에 설치하는 동안 대시보드에서는 표시 시간 전에 PreferenceController 연결을 위한 메서드를 제공합니다. 설치 시점에는 앞으로의 모든 관련 이벤트가 컨트롤러로 전송되도록 컨트롤러가 프래그먼트에 연결됩니다.

DashboardFragment는 화면에서 PreferenceController 목록을 유지합니다. 프래그먼트의 onCreate()에서는 모든 컨트롤러가 getAvailabilityStatus() 메서드에 대해 호출되며, true를 반환하는 경우 displayPreference()가 호출되어 표시 논리를 처리합니다. getAvailabilityStatus() 역시 중요한 이유는 검색 도중 어떤 항목을 사용할 수 있는지 설정 프레임워크에 알리기 때문입니다.

Android 8.x 버전의 PreferenceController

PreferenceController에는 표시, 업데이트, 검색 색인 생성 등의 환경설정과 상호작용하기 위한 모든 논리가 포함됩니다.

환경설정 상호작용과 마찬가지로 PreferenceController 인터페이스에는 API isAvailable(), displayPreference(), handlePreferenceTreeClicked() 등이 있습니다. 각 API에 관한 상세 문서는 인터페이스 클래스에서 찾을 수 있습니다.

환경설정을 프래그먼트에 설치하는 동안 대시보드에서는 표시 시간 전에 PreferenceController 연결을 위한 메서드를 제공합니다. 설치 시점에는 앞으로의 모든 관련 이벤트가 컨트롤러로 전송되도록 컨트롤러가 프래그먼트에 연결됩니다.

DashboardFragment는 화면에서 PreferenceControllers 목록을 유지합니다. 프래그먼트의 onCreate()에서는 모든 컨트롤러가 isAvailable() 메서드에 대해 호출되며, true를 반환하는 경우 displayPreference()가 호출되어 표시 논리를 처리합니다.

DashboardFragment 사용

환경설정을 A 페이지에서 B 페이지로 이동

환경설정이 원본 페이지의 환경설정 XML 파일에 정적으로 나열된 경우 아래의 Android 버전에 맞는 정적 이동 절차를 따르세요. 아니면 본인의 Android 버전에 맞는 동적 이동 절차를 따르세요.

Android 9에서의 정적 이동

  1. 원본 페이지 및 도착 페이지의 환경설정 XML 파일을 찾습니다. 이 정보는 페이지의 getPreferenceScreenResId() 메서드에서 찾을 수 있습니다.
  2. 원본 페이지의 XML에서 환경설정을 제거합니다.
  3. 도착 페이지의 XML에 환경설정을 추가합니다.
  4. 원본 페이지의 자바 구현에서 이 환경설정의 PreferenceController를 제거합니다. 보통 createPreferenceControllers()에 위치합니다. 컨트롤러는 XML에서 직접 선언될 수도 있습니다.

    참고: 환경설정에 PreferenceController가 없을 수도 있습니다.

  5. 도착 페이지의 createPreferenceControllers()에서 PreferenceController를 인스턴스화합니다. PreferenceController가 기존 페이지의 XML에 정의된 경우 새 페이지에 대해서도 XML에 정의합니다.

Android 9에서의 동적 이동

  1. 원본 및 도착 페이지에서 어떤 카테고리를 호스팅하는지 찾습니다. 이 정보는 DashboardFragmentRegistry에서 찾을 수 있습니다.
  2. 이동하려는 설정이 포함된 AndroidManifest.xml 파일을 열고 이 설정을 나타내는 활동 항목을 찾습니다.
  3. com.android.settings.category에 관한 활동의 메타데이터 값을 새 페이지의 카테고리 키에 설정합니다.

Android 8.x 버전에서의 정적 이동

  1. 원본 페이지 및 도착 페이지의 환경설정 XML 파일을 찾습니다.
  2. 이 정보는 페이지의 getPreferenceScreenResId() 메서드에서 찾을 수 있습니다.
  3. 원본 페이지의 XML에서 환경설정을 제거합니다.
  4. 환경설정을 도착 페이지의 XML에 추가합니다.
  5. 원본 페이지의 자바 구현에서 이 환경설정의 PreferenceController를 제거합니다. 보통 getPreferenceControllers()에 위치합니다.
  6. 참고: 환경설정에 PreferenceController가 없을 수도 있습니다.

  7. 도착 페이지의 getPreferenceControllers()에서 PreferenceController를 인스턴스화합니다.

Android 8.x 버전에서의 동적 이동

  1. 원본 및 도착 페이지에서 어떤 카테고리를 호스팅하는지 찾습니다. 이 정보는 DashboardFragmentRegistry에서 찾을 수 있습니다.
  2. 이동하려는 설정이 포함된 AndroidManifest.xml 파일을 열고 이 설정을 나타내는 활동 항목을 찾습니다.
  3. com.android.settings.category 관련 활동의 메타데이터 값을 변경하고 값을 새 페이지의 카테고리 키에 설정합니다.

페이지에서 새 환경설정 생성

환경설정이 원본 페이지의 환경설정 XML 파일에 정적으로 나열된 경우 아래의 절차를 따르세요. 아니면 동적 절차를 따르세요.

정적 환경설정 생성

  1. 페이지의 환경설정 XML 파일을 찾습니다. 이 정보는 페이지의 getPreferenceScreenResId() 메서드에서 찾을 수 있습니다.
  2. XML에서 새 환경설정 항목을 추가합니다. 고유한 android:key가 있는지 확인합니다.
  3. 페이지의 getPreferenceControllers() 메서드에서 이 환경설정의 PreferenceController를 정의합니다.
    • Android 8.x의 경우 페이지의 createPreferenceControllers() 메서드에서 이 환경설정의 PreferenceController를 인스턴스화합니다(Android 9의 경우 선택사항).

      이 환경설정이 이미 다른 장소에 존재하는 경우 이미 PreferenceController가 있을 가능성이 있습니다. 이 경우 컨트롤러를 새로 생성할 필요없이 PreferenceController를 재사용할 수 있습니다.

    • Android 9부터는 XML에서 환경설정 옆에 PreferenceController를 선언할 수 있습니다(선택사항). 예:
      <Preference
              android:key="reset_dashboard"
              android:title="@string/reset_dashboard_title"
              settings:controller="com.android.settings.system.ResetPreferenceController"/>

동적 환경설정 생성

  1. 원본 및 도착 페이지에서 어떤 카테고리를 호스팅하는지 찾습니다. 이 정보는 DashboardFragmentRegistry에서 찾을 수 있습니다.
  2. AndroidManifest에서 새 활동 생성
  3. 새 활동에 필요한 메타데이터를 추가하여 설정을 정의합니다. com.android.settings.category의 메타데이터 값을 1단계에서 정의된 동일한 값으로 설정합니다.

새 페이지 만들기

  1. DashboardFragment에서 상속되는 새 프래그먼트를 생성합니다.
  2. DashboardFragmentRegistry에 관련 카테고리를 정의합니다.

    참고: 이 단계는 선택사항입니다. 이 페이지에 동적 환경설정이 필요하지 않은 경우에는 카테고리 키를 제공할 필요가 없습니다.

  3. 단계에 따라 페이지에 필요한 설정을 추가하세요. 자세한 내용은 구현 섹션을 참조하세요.

유효성 검사

  • 설정에서 robolectric 테스트를 실행합니다. 모든 기존 테스트와 신규 테스트가 통과되어야 합니다.
  • 설정을 구성하고 설치한 다음 수정 중인 페이지를 직접 엽니다. 페이지가 즉시 업데이트됩니다.