Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 501eec92 authored by -b master's avatar -b master
Browse files

Revert "hand rolled out 220f4d63 due to...

Revert "hand rolled out 220f4d63 due to interface changes on master, the change will need to be made again"

This reverts commit f8e3ba5b.
parent 1d6ec76f
Loading
Loading
Loading
Loading
+71 −0
Original line number Diff line number Diff line
@@ -1353,6 +1353,49 @@ public final class Settings {
         */
        public static final String SHOW_WEB_SUGGESTIONS = "show_web_suggestions";

        /**
         * Settings to backup. This is here so that it's in the same place as the settings
         * keys and easy to update.
         * @hide
         */
        public static final String[] SETTINGS_TO_BACKUP = {
            STAY_ON_WHILE_PLUGGED_IN,
            END_BUTTON_BEHAVIOR,
            WIFI_SLEEP_POLICY,
            WIFI_USE_STATIC_IP,
            WIFI_STATIC_IP,
            WIFI_STATIC_GATEWAY,
            WIFI_STATIC_NETMASK,
            WIFI_STATIC_DNS1,
            WIFI_STATIC_DNS2,
            BLUETOOTH_DISCOVERABILITY,
            BLUETOOTH_DISCOVERABILITY_TIMEOUT,
            DIM_SCREEN,
            SCREEN_OFF_TIMEOUT,
            SCREEN_BRIGHTNESS,
            VIBRATE_ON,
            NOTIFICATIONS_USE_RING_VOLUME,
            RINGTONE,
            NOTIFICATION_SOUND,
            TEXT_AUTO_REPLACE,
            TEXT_AUTO_CAPS,
            TEXT_AUTO_PUNCTUATE,
            TEXT_SHOW_PASSWORD,
            AUTO_TIME,
            TIME_12_24,
            DATE_FORMAT,
            ACCELEROMETER_ROTATION,
            DTMF_TONE_WHEN_DIALING,
            DTMF_TONE_TYPE_WHEN_DIALING,
            EMERGENCY_TONE,
            CALL_AUTO_RETRY,
            HEARING_AID,
            TTY_MODE,
            SOUND_EFFECTS_ENABLED,
            HAPTIC_FEEDBACK_ENABLED,
            SHOW_WEB_SUGGESTIONS
        };

        // Settings moved to Settings.Secure

        /**
@@ -2267,6 +2310,34 @@ public final class Settings {
         */
        public static final String LAST_SETUP_SHOWN = "last_setup_shown";

        /**
         * @hide
         */
        public static final String[] SETTINGS_TO_BACKUP = {
            INSTALL_NON_MARKET_APPS,
            PARENTAL_CONTROL_ENABLED,
            PARENTAL_CONTROL_REDIRECT_URL,
            USB_MASS_STORAGE_ENABLED,
            ACCESSIBILITY_ENABLED,
            ENABLED_ACCESSIBILITY_SERVICES,
            TTS_USE_DEFAULTS,
            TTS_DEFAULT_RATE,
            TTS_DEFAULT_PITCH,
            TTS_DEFAULT_SYNTH,
            TTS_DEFAULT_LANG,
            TTS_DEFAULT_COUNTRY,
            WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
            WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
            WIFI_NUM_ALLOWED_CHANNELS,
            WIFI_NUM_OPEN_NETWORKS_KEPT,
            BACKGROUND_DATA,
            PREFERRED_NETWORK_MODE,
            PREFERRED_TTY_MODE,
            CDMA_CELL_BROADCAST_SMS,
            PREFERRED_CDMA_SUBSCRIPTION,
            ENHANCED_VOICE_PRIVACY_ENABLED
        };

        /**
         * Helper method for determining if a location provider is enabled.
         * @param cr the content resolver to use
+1 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@

    <application android:allowClearUserData="false"
                 android:label="@string/app_label"
                 android:backupAgent="SettingsBackupAgent"
                 android:icon="@drawable/ic_launcher_settings">

        <provider android:name="SettingsProvider" android:authorities="settings"
+320 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.providers.settings;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;

import android.backup.BackupDataInput;
import android.backup.BackupDataOutput;
import android.backup.BackupHelperAgent;
import android.bluetooth.BluetoothDevice;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.media.AudioManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;

/**
 * Performs backup and restore of the System and Secure settings.
 * List of settings that are backed up are stored in the Settings.java file
 */
public class SettingsBackupAgent extends BackupHelperAgent {

    private static final String KEY_SYSTEM = "system";
    private static final String KEY_SECURE = "secure";
    private static final String KEY_SYNC = "sync_providers";

    private static String[] sortedSystemKeys = null;
    private static String[] sortedSecureKeys = null;

    private static final byte[] EMPTY_DATA = new byte[0];

    private static final String TAG = "SettingsBackupAgent";

    private static final int COLUMN_ID = 0;
    private static final int COLUMN_NAME = 1;
    private static final int COLUMN_VALUE = 2;

    private static final String[] PROJECTION = {
        Settings.NameValueTable._ID,
        Settings.NameValueTable.NAME,
        Settings.NameValueTable.VALUE
    };

    private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
    private static final String FILE_BT_ROOT = "/data/misc/hcid/";

    private SettingsHelper mSettingsHelper;

    public void onCreate() {
        mSettingsHelper = new SettingsHelper(this);
        super.onCreate();
    }

    @Override
    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
            ParcelFileDescriptor newState) throws IOException {

        byte[] systemSettingsData = getSystemSettings();
        byte[] secureSettingsData = getSecureSettings();
        byte[] syncProviders = mSettingsHelper.getSyncProviders();
        
        data.writeEntityHeader(KEY_SYSTEM, systemSettingsData.length);
        data.writeEntityData(systemSettingsData, systemSettingsData.length);

        data.writeEntityHeader(KEY_SECURE, secureSettingsData.length);
        data.writeEntityData(secureSettingsData, secureSettingsData.length);

        data.writeEntityHeader(KEY_SYNC, syncProviders.length);
        data.writeEntityData(syncProviders, syncProviders.length);
        
        //TODO: Permissions problem : backupFile(FILE_WIFI_SUPPLICANT, data);
    }

    @Override
    public void onRestore(BackupDataInput data, int appVersionCode,
            ParcelFileDescriptor newState) throws IOException {

        enableWifi(false);
        enableBluetooth(false);

        while (data.readNextHeader()) {
            final String key = data.getKey();
            if (KEY_SYSTEM.equals(key)) {
                restoreSettings(data, Settings.System.CONTENT_URI);
            } else if (KEY_SECURE.equals(key)) {
                restoreSettings(data, Settings.Secure.CONTENT_URI);
            } else if (FILE_WIFI_SUPPLICANT.equals(key)) {
                restoreFile(FILE_WIFI_SUPPLICANT, data);
            } else if (KEY_SYNC.equals(key)) {
                mSettingsHelper.setSyncProviders(data);
            } else {
                data.skipEntityData();
            }
        }
    }

    private byte[] getSystemSettings() {
        Cursor sortedCursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION,
                null, null, Settings.NameValueTable.NAME);
        // Copy and sort the array
        if (sortedSystemKeys == null) {
            sortedSystemKeys = copyAndSort(Settings.System.SETTINGS_TO_BACKUP);
        }
        byte[] result = extractRelevantValues(sortedCursor, sortedSystemKeys);
        sortedCursor.close();
        return result;
    }

    private byte[] getSecureSettings() {
        Cursor sortedCursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION,
                null, null, Settings.NameValueTable.NAME);
        // Copy and sort the array
        if (sortedSecureKeys == null) {
            sortedSecureKeys = copyAndSort(Settings.Secure.SETTINGS_TO_BACKUP);
        }
        byte[] result = extractRelevantValues(sortedCursor, sortedSecureKeys);
        sortedCursor.close();
        return result;
    }

    private void restoreSettings(BackupDataInput data, Uri contentUri) {
        ContentValues cv = new ContentValues(2);
        byte[] settings = new byte[data.getDataSize()];
        try {
            data.readEntityData(settings, 0, settings.length);
        } catch (IOException ioe) {
            Log.e(TAG, "Couldn't read entity data");
            return;
        }
        int pos = 0;
        while (pos < settings.length) {
            int length = readInt(settings, pos);
            pos += 4;
            String settingName = length > 0? new String(settings, pos, length) : null;
            pos += length;
            length = readInt(settings, pos);
            pos += 4;
            String settingValue = length > 0? new String(settings, pos, length) : null;
            pos += length;
            if (!TextUtils.isEmpty(settingName) && !TextUtils.isEmpty(settingValue)) {
                //Log.i(TAG, "Restore " + settingName + " = " + settingValue);
                cv.clear();
                cv.put(Settings.NameValueTable.NAME, settingName);
                cv.put(Settings.NameValueTable.VALUE, settingValue);
                getContentResolver().insert(contentUri, cv);
                mSettingsHelper.restoreValue(settingName, settingValue);
            }
        }
    }

    private String[] copyAndSort(String[] keys) {
        String[] sortedKeys = new String[keys.length];
        System.arraycopy(keys, 0, sortedKeys, 0, keys.length);
        Arrays.sort(sortedKeys);
        return sortedKeys;
    }

    /**
     * Given a cursor sorted by key name and a set of keys sorted by name, 
     * extract the required keys and values and write them to a byte array.
     * @param sortedCursor
     * @param sortedKeys
     * @return
     */
    byte[] extractRelevantValues(Cursor sortedCursor, String[] sortedKeys) {
        byte[][] values = new byte[sortedKeys.length * 2][]; // keys and values
        if (!sortedCursor.moveToFirst()) {
            Log.e(TAG, "Couldn't read from the cursor");
            return new byte[0];
        }
        int keyIndex = 0;
        int totalSize = 0;
        while (!sortedCursor.isAfterLast()) {
            String name = sortedCursor.getString(COLUMN_NAME);
            while (sortedKeys[keyIndex].compareTo(name.toString()) < 0) {
                keyIndex++;
                if (keyIndex == sortedKeys.length) break;
            }
            if (keyIndex < sortedKeys.length && name.equals(sortedKeys[keyIndex])) {
                String value = sortedCursor.getString(COLUMN_VALUE);
                byte[] nameBytes = name.toString().getBytes();
                totalSize += 4 + nameBytes.length;
                values[keyIndex * 2] = nameBytes;
                byte[] valueBytes;
                if (TextUtils.isEmpty(value)) {
                    valueBytes = null;
                    totalSize += 4;
                } else {
                    valueBytes = value.toString().getBytes();
                    totalSize += 4 + valueBytes.length;
                    //Log.i(TAG, "Backing up " + name + " = " + value);
                }
                values[keyIndex * 2 + 1] = valueBytes;
                keyIndex++;
            }
            if (keyIndex == sortedKeys.length || !sortedCursor.moveToNext()) {
                break;
            }
        }

        byte[] result = new byte[totalSize];
        int pos = 0;
        for (int i = 0; i < sortedKeys.length * 2; i++) {
            if (values[i] != null) {
                pos = writeInt(result, pos, values[i].length);
                pos = writeBytes(result, pos, values[i]);
            }
        }
        return result;
    }

    private void backupFile(String filename, BackupDataOutput data) {
        try {
            File file = new File(filename);
            if (file.exists()) {
                byte[] bytes = new byte[(int) file.length()];
                FileInputStream fis = new FileInputStream(file);
                int offset = 0;
                int got = 0;
                do {
                    got = fis.read(bytes, offset, bytes.length - offset);
                    if (got > 0) offset += got;
                } while (offset < bytes.length && got > 0);
                data.writeEntityHeader(filename, bytes.length);
                data.writeEntityData(bytes, bytes.length);
            } else {
                data.writeEntityHeader(filename, 0);
                data.writeEntityData(EMPTY_DATA, 0);
            }
        } catch (IOException ioe) {
            Log.w(TAG, "Couldn't backup " + filename);
        }
    }

    private void restoreFile(String filename, BackupDataInput data) {
        byte[] bytes = new byte[data.getDataSize()];
        if (bytes.length <= 0) return;
        try {
            data.readEntityData(bytes, 0, bytes.length);
            FileOutputStream fos = new FileOutputStream(filename);
            fos.write(bytes);
        } catch (IOException ioe) {
            Log.w(TAG, "Couldn't restore " + filename);
        }
    }

    /**
     * Write an int in BigEndian into the byte array.
     * @param out byte array
     * @param pos current pos in array
     * @param value integer to write
     * @return the index after adding the size of an int (4)
     */
    private int writeInt(byte[] out, int pos, int value) {
        out[pos + 0] = (byte) ((value >> 24) & 0xFF);
        out[pos + 1] = (byte) ((value >> 16) & 0xFF);
        out[pos + 2] = (byte) ((value >>  8) & 0xFF);
        out[pos + 3] = (byte) ((value >>  0) & 0xFF);
        return pos + 4;
    }

    private int writeBytes(byte[] out, int pos, byte[] value) {
        System.arraycopy(value, 0, out, pos, value.length);
        return pos + value.length;
    }

    private int readInt(byte[] in, int pos) {
        int result =
                ((in[pos    ] & 0xFF) << 24) |
                ((in[pos + 1] & 0xFF) << 16) |
                ((in[pos + 2] & 0xFF) <<  8) |
                ((in[pos + 3] & 0xFF) <<  0);
        return result;
    }

    private void enableWifi(boolean enable) {
        WifiManager wfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        if (wfm != null) {
            wfm.setWifiEnabled(enable);
        }
    }

    private void enableBluetooth(boolean enable) {
        BluetoothDevice bt = (BluetoothDevice) getSystemService(Context.BLUETOOTH_SERVICE);
        if (bt != null) {
            if (!enable) {
                bt.disable();
            } else {
                bt.enable();
            }
        }
    }
}
+110 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.providers.settings;

import android.backup.BackupDataInput;
import android.content.ContentResolver;
import android.content.Context;
import android.media.AudioManager;
import android.os.IHardwareService;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.content.IContentService;
import android.util.Log;

public class SettingsHelper {
    private static final String TAG = "SettingsHelper";

    private Context mContext;
    private AudioManager mAudioManager;
    private IContentService mContentService;
    private static final String SYNC_AUTO = "auto_sync";
    private static final String SYNC_MAIL = "gmail-ls_sync";
    private static final String SYNC_CALENDAR = "calendar_sync";
    private static final String SYNC_CONTACTS = "contacts_sync";

    public SettingsHelper(Context context) {
        mContext = context;
        mAudioManager = (AudioManager) context
                .getSystemService(Context.AUDIO_SERVICE);
        mContentService = ContentResolver.getContentService();
    }

    public void restoreValue(String name, String value) {
        if (Settings.System.SCREEN_BRIGHTNESS.equals(name)) {
            setBrightness(Integer.parseInt(value));
        } else if (Settings.System.SOUND_EFFECTS_ENABLED.equals(name)) {
            if (Integer.parseInt(value) == 1) {
                mAudioManager.loadSoundEffects();
            } else {
                mAudioManager.unloadSoundEffects();
            }
        }
    }

    private void setBrightness(int brightness) {
        try {
            IHardwareService hardware = IHardwareService.Stub
                    .asInterface(ServiceManager.getService("hardware"));
            if (hardware != null) {
                hardware.setBacklights(brightness);
            }
        } catch (RemoteException doe) {

        }
    }

    static final String[] PROVIDERS = { "gmail-ls", "calendar", "contacts" };
    
    byte[] getSyncProviders() {
        byte[] sync = new byte[1 + PROVIDERS.length];
        // TODO: Sync backup needs to be moved to SystemBackupAgent
        /*
        try {
            sync[0] = (byte) (mContentService.getListenForNetworkTickles() ? 1 : 0);
            for (int i = 0; i < PROVIDERS.length; i++) {
                sync[i + 1] = (byte) 
                        (mContentService.getSyncAutomatically(PROVIDERS[i]) ? 1 : 0);
            }
        } catch (RemoteException re) {
            Log.w(TAG, "Unable to backup sync providers");
            return sync;
        }
        */
        return sync;
    }
    
    void setSyncProviders(BackupDataInput backup) {
        byte[] sync = new byte[backup.getDataSize()];

        try {
            backup.readEntityData(sync, 0, sync.length);
            // TODO: Sync backup needs to be moved to SystemBackupAgent
            /*
            mContentService.setListenForNetworkTickles(sync[0] == 1);
            for (int i = 0; i < PROVIDERS.length; i++) {
                mContentService.setSyncProviderAutomatically(PROVIDERS[i], sync[i + 1] > 0);
            }
        } catch (RemoteException re) {
            Log.w(TAG, "Unable to restore sync providers");
            */
        } catch (java.io.IOException ioe) {
            Log.w(TAG, "Unable to read sync settings");
        }
    }
}
+15 −2
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.providers.settings;

import java.io.FileNotFoundException;

import android.backup.IBackupManager;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -27,6 +30,7 @@ import android.database.sqlite.SQLiteQueryBuilder;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.DrmStore;
import android.provider.MediaStore;
@@ -34,8 +38,6 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;

import java.io.FileNotFoundException;

public class SettingsProvider extends ContentProvider {
    private static final String TAG = "SettingsProvider";
    private static final boolean LOCAL_LOGV = false;
@@ -137,6 +139,17 @@ public class SettingsProvider extends ContentProvider {
            SystemProperties.set(property, Long.toString(version));
        }

        // Inform the backup manager about a data change
        IBackupManager ibm = IBackupManager.Stub.asInterface(
                ServiceManager.getService(Context.BACKUP_SERVICE));
        if (ibm != null) {
            try {
                ibm.dataChanged(getContext().getPackageName());
            } catch (Exception e) {
                // Try again later
            }
        }

        // Now send the notification through the content framework.

        String notify = uri.getQueryParameter("notify");