당연한 말이지만 이를 위해서는 java 코드를 주로 수정해야 한다. Settings 관련 코드는 다음에 위치한다.
packages/apps/Setting/
화면 처리와 관련된 내용을 수정한다고 가정하고 Display Setting을 보면 되는데 일단 가속도계의 입력에 따른 회전을 관리하는 Orientation을 찾아 보자. 이미 안드로이드 어플리케이션을 만들어 본 경우라면 당연한 이해하겠지만 기본적으로 3개의 파일이 관련되어 있다.
packages/apps/Setting/res/values/strings.xml
packages/apps/Setting/res/xml/sound_and_display_settings.xml
src/com/android/settings/SoundAndDisplaySettings.java
순서대로 보면 다음과 같다.
Sound & Display Setting 화면에서 Orientation에 대한 것은 on/off 만을 설정하도록 checkbox 형태로 구현되어 있다. 실제 화면을 보면 "Orientation" 이란 타이틀 문자열과, 타이틀 문자열 아래에서 현재 상태에 따라 나타나는 "Switch orientation automatically when rotating phone"에 대한 문자열이 필요하다.
<!-- Sound & display settings screen, accelerometer-based rotation check box label -->
<string name="accelerometer_title">Orientation</string>
<!-- Sound & display settings screen, accelerometer-based rotation summary text when check box is selected -->
<string name="accelerometer_summary_on">Switch orientation automatically when rotating phone</string>
<!-- Sound & display settings screen, accelerometer-based rotation summary text when check box is clear -->
<string name="accelerometer_summary_off">Switch orientation automatically when rotating phone</string>
<string name="accelerometer_title">Orientation</string>
<!-- Sound & display settings screen, accelerometer-based rotation summary text when check box is selected -->
<string name="accelerometer_summary_on">Switch orientation automatically when rotating phone</string>
<!-- Sound & display settings screen, accelerometer-based rotation summary text when check box is clear -->
<string name="accelerometer_summary_off">Switch orientation automatically when rotating phone</string>
실제 코드를 보면 accelerometer_title과 accelerometer_summary_on, accelerometer_summary_off 를 정의하고 있다. 여기서 뒤에 2개는 같은 내용으로 되어 있는데 상태에 따라 다른 내용을 보여주고 싶으면 다르게 정의하면 된다.
일단 문자열을 정의하면 checkbox 형태를 사용하므로 이에 대한 내용을 sound_and_display_settings.xml에 정의한다.
<PreferenceCategory
android:title="@string/display_settings">
<CheckBoxPreference
android:key="accelerometer"
android:title="@string/accelerometer_title"
android:summaryOn="@string/accelerometer_summary_on"
android:summaryOff="@string/accelerometer_summary_off"/>
<ListPreference
android:key="animations"
android:title="@string/animations_title"
android:persistent="false"
android:entries="@array/animations_entries"
android:entryValues="@array/animations_values" />
android:title="@string/display_settings">
<CheckBoxPreference
android:key="accelerometer"
android:title="@string/accelerometer_title"
android:summaryOn="@string/accelerometer_summary_on"
android:summaryOff="@string/accelerometer_summary_off"/>
<ListPreference
android:key="animations"
android:title="@string/animations_title"
android:persistent="false"
android:entries="@array/animations_entries"
android:entryValues="@array/animations_values" />
CheckBox를 위한 key 이름을 정의하고 와 title, summayOn, summeryOff에 사용할 문자열을 strings.xml에 정의한 내용으로 정의(연결)해 둔다.
실제 코드 구현은 SoundAndDisplaySettings.java에 구현되어 있다.
먼저 사용할 KEY 문자열을 정의한다. sound_and_display_settings.xml에 정의한 key 문자열과 같은 값으로 한다. 여기에서 final은 JAVA에서 주로 사용하는 것으로 문자열이 수정하지 않는 고정된 값임을 나타낸다.
private static final String KEY_ACCELEROMETER = "accelerometer";
실제 화면 구성에서 사용할 CheckBoxPreference 클래스의 accelerometer 인스턴스를 선언한다.
private CheckBoxPreference mVibrate;
private CheckBoxPreference mDtmfTone;
private CheckBoxPreference mSoundEffects;
private CheckBoxPreference mHapticFeedback;
private ListPreference mAnimations;
private CheckBoxPreference mAccelerometer;
private CheckBoxPreference mDtmfTone;
private CheckBoxPreference mSoundEffects;
private CheckBoxPreference mHapticFeedback;
private ListPreference mAnimations;
private CheckBoxPreference mAccelerometer;
Settings 어플 화면에서 관련 설정을 보여주고, 동작하도록 하기 위해서는 OnCreate(), updateState(), OnPreferenceTreeClick() 메소드를 수정하면 된다.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAnimations = (ListPreference) findPreference(KEY_ANIMATIONS);
mAnimations.setOnPreferenceChangeListener(this);
mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);
mAccelerometer.setPersistent(false);
......
}
super.onCreate(savedInstanceState);
mAnimations = (ListPreference) findPreference(KEY_ANIMATIONS);
mAnimations.setOnPreferenceChangeListener(this);
mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER);
mAccelerometer.setPersistent(false);
......
}
당연한 얘기지만 key 값을 통해서 xml 파일로부터 필요한 리소스 정보를 참조할 수 있다.
private void updateState(boolean force) {
......
mAnimations.setValueIndex(idx);
updateAnimationsSummary(mAnimations.getValue());
mAccelerometer.setChecked(Settings.System.getInt(
getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) != 0);
......
}
......
mAnimations.setValueIndex(idx);
updateAnimationsSummary(mAnimations.getValue());
mAccelerometer.setChecked(Settings.System.getInt(
getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) != 0);
......
}
위의 내용을 보면 화면에 해당 값을 보여줘야 할 경우에 Settings.System.ACCELEROMETER_ROTATION 의 값을 얻어서 현재 mAccelerometer의 값을 어떤 상태로 설정할지를 결정한다.
실제 사용자가 항목을 클릭했을 때의 동작을 정의하는 것은 OnPreferenceTreeClick() 메소드에 정의한다.
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mSilent || preference == mVibrate) {
setRingerMode(mSilent.isChecked(), mVibrate.isChecked());
if (preference == mSilent) updateState(false);
} else if (preference == mPlayMediaNotificationSounds) {
......
} else if (preference == mAccelerometer) {
Settings.System.putInt(getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION,
mAccelerometer.isChecked() ? 1 : 0);
}else if (preference == mNotificationPulse) {
......
}
if (preference == mSilent || preference == mVibrate) {
setRingerMode(mSilent.isChecked(), mVibrate.isChecked());
if (preference == mSilent) updateState(false);
} else if (preference == mPlayMediaNotificationSounds) {
......
} else if (preference == mAccelerometer) {
Settings.System.putInt(getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION,
mAccelerometer.isChecked() ? 1 : 0);
}else if (preference == mNotificationPulse) {
......
}
여기는 반대로 현재의 상태를 확인하여 Settings.System.ACCELEROMETER_ROTATION 의 값을 변경하고 있다.
여기까지가 사용자의 입력을 받아서 화면상의 처리를 위한 코드이다.
실제 사용자의 입력은 어떻게 관리될까? 이를 위한 코드는 framework 코드를 참조해야 한다.
위에서 정의한 ACCELEROMETER_ROTATION은 다음 파일에서 정의한다.
frameworks/base/core/java/android/provider/Settings.java
/**
* Control whether the accelerometer will be used to change screen
* orientation. If 0, it will not be used unless explicitly requested
* by the application; if 1, it will be used by default unless explicitly
* disabled by the application.
*/
public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
* Control whether the accelerometer will be used to change screen
* orientation. If 0, it will not be used unless explicitly requested
* by the application; if 1, it will be used by default unless explicitly
* disabled by the application.
*/
public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
정의된 값은 백업을 위해서 SETTINGS_TO_BACKUP 배열에 등록해 둔다. 실제 0과 1의 값이 어떤 의미인지를 설명하고 문자열로 정의해둔다.
실제 이렇게 정의된 값을 이용하는 것은 ACCELEROMETER_ROTATION은 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java에서 값을 로드해 두는데 사용한다.
설정 값에 따라 응용 방법은 다양하게 변경될 수 있다.
다른 예로 ADB를 들 수 있다. ADB의 경우에는 ADB_ENABLED 설정을 위와 유사하게 구현할 수 있다. 실제 ADB_ENABLED가 활성화되어도 동작 시점은 USB 케이블이 연결되어 있는 경우에만 동작하여야 한다. 이를 위해서 위와는 다른 코드 구현이 필요하다.
frameworks/base/service/java/com/android/server/SystemServer.java
여기에서는 ADB를 위하여 AdbSettingsObserver 클래스를 정의해 두고 ADB_ENABLED가 설정되면 persist.service.adb.enable 이라는 SystemProperties를 설정하도록 하고 있다.
private class AdbSettingsObserver extends ContentObserver {
public AdbSettingsObserver() {
super(null);
}
@Override
public void onChange(boolean selfChange) {
boolean enableAdb = (Settings.Secure.getInt(mContentResolver,
Settings.Secure.ADB_ENABLED, 0) > 0);
// setting this secure property will start or stop adbd
SystemProperties.set("persist.service.adb.enable", enableAdb ? "1" : "0"); }
}
public AdbSettingsObserver() {
super(null);
}
@Override
public void onChange(boolean selfChange) {
boolean enableAdb = (Settings.Secure.getInt(mContentResolver,
Settings.Secure.ADB_ENABLED, 0) > 0);
// setting this secure property will start or stop adbd
SystemProperties.set("persist.service.adb.enable", enableAdb ? "1" : "0"); }
}
AdbSettingsObserver 클래스의 인스턴스 run() 메소드에서 생성된다.
// register observer to listen for settings changes
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
false, new AdbSettingsObserver());
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
false, new AdbSettingsObserver());
이 코드는 Setting 어플에서의 설정 변화를 감시하고 있다가, 설정이 바뀌면 바로 persist.service.adb.enable를 바꾸도록 하고 있다.
감사합니다. 많은 도움이 되었습니다.
답글삭제감사합니다. 도움이 많이 되었습니다.
답글삭제