org.uiautomation.ios.utils.SimulatorSettings.java Source code

Java tutorial

Introduction

Here is the source code for org.uiautomation.ios.utils.SimulatorSettings.java

Source

/*
 * Copyright 2012 ios-driver committers.
 * 
 * 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 org.uiautomation.ios.utils;

import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.openqa.selenium.WebDriverException;
import org.uiautomation.ios.communication.device.DeviceType;
import org.uiautomation.ios.communication.device.DeviceVariation;
import org.uiautomation.ios.server.command.uiautomation.NewSessionNHandler;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

public class SimulatorSettings {

    private final String sdkVersion;
    private final File contentAndSettingsFolder;
    private final File globalPreferencePlist;
    private static final String PLUTIL = "/usr/bin/plutil";
    private static final String TEMPLATE = "/globalPlist.json";

    public SimulatorSettings(String sdkVersion) {
        this.sdkVersion = sdkVersion;
        this.contentAndSettingsFolder = getContentAndSettingsFolder();
        this.globalPreferencePlist = getGlobalPreferenceFile();
    }

    public void setLocationPreference(boolean authorized, String bundleId) {
        File f = new File(contentAndSettingsFolder + "/Library/Caches/locationd/", "clients.plist");

        try {
            JSONObject clients = new JSONObject();
            JSONObject options = new JSONObject();
            options.put("Whitelisted", false);
            options.put("BundleId", bundleId);
            options.put("Authorized", authorized);
            clients.put(bundleId, options);
            writeOnDisk(clients, f);
        } catch (Exception e) {
            throw new WebDriverException("cannot set location in " + f.getAbsolutePath());
        }
    }

    /**
     * the default keyboard options aren't good for automation. For instance it automatically
     * capitalize the first letter of sentences etc. Getting rid of all that to have the keyboard
     * execute requests without changing them.
     */
    public void setKeyboardOptions() {
        File folder = new File(contentAndSettingsFolder + "/Library/Preferences/");
        File preferenceFile = new File(folder, "com.apple.Preferences.plist");

        try {
            JSONObject preferences = new JSONObject();
            preferences.put("KeyboardAutocapitalization", false);
            preferences.put("KeyboardAutocorrection", false);
            preferences.put("KeyboardCapsLock", false);
            preferences.put("KeyboardCheckSpelling", false);
            writeOnDisk(preferences, preferenceFile);
        } catch (Exception e) {
            throw new WebDriverException("cannot set options in " + preferenceFile.getAbsolutePath());
        }
    }

    public void setMobileSafariOptions() {
        File folder = new File(contentAndSettingsFolder + "/Library/Preferences/");
        File preferenceFile = new File(folder, "com.apple.mobilesafari.plist");

        try {
            JSONObject preferences = new JSONObject();
            preferences.put("WarnAboutFraudulentWebsites", false);
            writeOnDisk(preferences, preferenceFile);
        } catch (Exception e) {
            throw new WebDriverException("cannot set options in " + preferenceFile.getAbsolutePath());
        }
    }

    /**
     * set the emulator to the given locale.Required a clean context (can only be done after "reset
     * content and settings" )
     *
     * @param locale   fr_FR
     * @param language fr
     */
    public void setL10N(String locale, String language) {
        try {
            JSONObject plistJSON = getPreferenceFile(locale, language);
            writeOnDisk(plistJSON, globalPreferencePlist);
        } catch (Exception e) {
            throw new WebDriverException("cannot configure simulator", e);
        }
    }

    /**
     * update the preference to have the simulator start in the correct more ( ie retina vs normal,
     * iphone screen size ).
     */
    public void setVariation(DeviceType device, DeviceVariation variation) {
        String value = getSimulateDeviceValue(device, variation);
        setDefaultSimulatorPreference("SimulateDevice", value);
    }

    /**
     * update the preference of the simulator. Similar to using the IOS Simulator menu > Hardware >
     * [DeviceType | Version ]
     */
    private void setDefaultSimulatorPreference(String key, String value) {
        List<String> com = new ArrayList<String>();
        com.add("defaults");
        com.add("write");
        com.add("com.apple.iphonesimulator");
        com.add(key);
        com.add(value);

        Command updatePreference = new Command(com, true);
        updatePreference.executeAndWait();
    }

    /**
     * Does what IOS Simulator - Reset content and settings menu does, by deleting the files on disk.
     * The simulator shouldn't be running when that is done.
     */
    public void resetContentAndSettings() {
        if (hasContentAndSettingsFolder()) {
            boolean ok = deleteRecursive(getContentAndSettingsFolder());
            if (!ok) {
                System.err.println("cannot delete content and settings folder " + contentAndSettingsFolder);
            }
        }
        boolean ok = contentAndSettingsFolder.mkdir();
        if (!ok) {
            System.err.println("couldn't re-create" + contentAndSettingsFolder);
        }
    }

    private File getContentAndSettingsFolder() {
        String home = System.getProperty("user.home");
        String s = String.format("%s/Library/Application Support/iPhone Simulator/%s", home, sdkVersion);
        File f = new File(s);
        if (!f.exists()) {
            f.mkdirs();
        }
        return f;
    }

    private boolean deleteRecursive(File folder) {
        if (folder.isDirectory()) {
            String[] children = folder.list();
            for (int i = 0; i < children.length; i++) {
                File delMe = new File(folder, children[i]);
                boolean success = deleteRecursive(delMe);
                if (!success) {
                    System.err.println("cannot delete " + delMe);
                }
            }
        }
        return folder.delete();
    }

    private boolean hasContentAndSettingsFolder() {
        File f = getContentAndSettingsFolder();
        return f.exists();
    }

    private String getSimulateDeviceValue(DeviceType device, DeviceVariation variation) {
        switch (device) {
        case iphone:
            return getIphoneString(variation);
        case ipad:
            return getIpadString(variation);
        default:
            throw new WebDriverException(device + " - " + variation + " doesn't map to a supported apple device.");
        }
    }

    private String getIpadString(DeviceVariation variation) {
        switch (variation) {
        case Regular:
            return "iPad";
        case Retina:
            return "\"iPad (Retina)\"";
        default:
            throw new WebDriverException(variation + " isn't supported for ipad.");
        }
    }

    private JSONObject loadGlobalPreferencesTemplate() throws JSONException, IOException {
        InputStream is = NewSessionNHandler.class.getResourceAsStream(TEMPLATE);
        StringWriter writer = new StringWriter();
        IOUtils.copy(is, writer, "UTF-8");
        String content = writer.toString();
        JSONObject config = new JSONObject(content);
        return config;
    }

    private JSONObject getPreferenceFile(String locale, String language) throws JSONException, IOException {
        JSONObject res = loadGlobalPreferencesTemplate();
        JSONArray languages = new JSONArray();
        languages.put(language);
        res.put("AppleLanguages", languages);
        res.put("AppleLocale", locale);
        return res;

    }

    private String getIphoneString(DeviceVariation variation) {
        switch (variation) {
        case Regular:
            return "iPhone";
        case Retina35:
            return "\"iPhone (Retina 3.5-inch)\"";
        case Retina4:
            return "\"iPhone (Retina 4-inch)\"";
        default:
            throw new WebDriverException(variation + " isn't supported for ipad.");
        }
    }

    private File getGlobalPreferenceFile() {
        File folder = new File(contentAndSettingsFolder + "/Library/Preferences/");
        File global = new File(folder, ".GlobalPreferences.plist");
        return global;
    }

    // TODO use plist utils.
    private void writeOnDisk(JSONObject plistJSON, File destination) throws IOException, JSONException {
        if (destination.exists()) {
            // to be on the safe side. If the emulator already runs, it won't work
            // anyway.
            throw new WebDriverException(globalPreferencePlist + "already exists.Cannot create it.");
        }

        // make sure the folder is ready for the plist file
        destination.getParentFile().mkdirs();

        checkPlUtil();

        File from = createTmpFile(plistJSON);

        List<String> command = new ArrayList<String>();
        command.add(PLUTIL);
        command.add("-convert");
        command.add("binary1");
        command.add("-o");
        command.add(destination.getAbsolutePath());
        command.add(from.getAbsolutePath());

        ProcessBuilder b = new ProcessBuilder(command);
        int i = -1;
        try {
            Process p = b.start();
            i = p.waitFor();
        } catch (Exception e) {
            throw new WebDriverException("failed to run " + command.toString(), e);
        }
        if (i != 0) {
            throw new WebDriverException("convertion to binary pfile failed.exitCode=" + i);
        }

    }

    private File createTmpFile(JSONObject content) throws IOException, JSONException {
        File res = File.createTempFile("global", ".json");
        BufferedWriter out = new BufferedWriter(new FileWriter(res));
        out.write(content.toString(2));
        out.close();
        return res;
    }

    private void checkPlUtil() {
        File f = new File(PLUTIL);
        if (!f.exists() || !f.canExecute()) {
            throw new WebDriverException("Cannot access " + PLUTIL);
        }

    }
}