aboutsummaryrefslogtreecommitdiffstats
path: root/sdkstats/src
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:16 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:16 -0800
commit82ea7a177797b844b252effea5c7c7c5d63ea4ac (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /sdkstats/src
parentc9432be76d50a527da232d518f633add2f76242b (diff)
downloadsdk-82ea7a177797b844b252effea5c7c7c5d63ea4ac.zip
sdk-82ea7a177797b844b252effea5c7c7c5d63ea4ac.tar.gz
sdk-82ea7a177797b844b252effea5c7c7c5d63ea4ac.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'sdkstats/src')
-rw-r--r--sdkstats/src/Android.mk15
-rw-r--r--sdkstats/src/com/android/sdkstats/SdkStatsService.java416
2 files changed, 0 insertions, 431 deletions
diff --git a/sdkstats/src/Android.mk b/sdkstats/src/Android.mk
deleted file mode 100644
index bff43f3..0000000
--- a/sdkstats/src/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2007 The Android Open Source Project
-#
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_JAVA_LIBRARIES := \
- androidprefs \
- swt \
- org.eclipse.jface_3.2.0.I20060605-1400 \
- org.eclipse.equinox.common_3.2.0.v20060603 \
- org.eclipse.core.commands_3.2.0.I20060605-1400
-LOCAL_MODULE := sdkstats
-
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/sdkstats/src/com/android/sdkstats/SdkStatsService.java b/sdkstats/src/com/android/sdkstats/SdkStatsService.java
deleted file mode 100644
index 0b3d41b..0000000
--- a/sdkstats/src/com/android/sdkstats/SdkStatsService.java
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (C) 2007 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.sdkstats;
-
-import com.android.prefs.AndroidLocation;
-import com.android.prefs.AndroidLocation.AndroidLocationException;
-
-import org.eclipse.jface.preference.PreferenceStore;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.Font;
-import org.eclipse.swt.graphics.FontData;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.program.Program;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Link;
-import org.eclipse.swt.widgets.Shell;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.util.Random;
-
-/** Utility class to send "ping" usage reports to the server. */
-public class SdkStatsService {
-
- /** Minimum interval between ping, in milliseconds. */
- private static final long PING_INTERVAL_MSEC = 86400 * 1000; // 1 day
-
- /* Text strings displayed in the opt-out dialog. */
- private static final String WINDOW_TITLE_TEXT =
- "Android SDK";
-
- private static final String HEADER_TEXT =
- "Thanks for using the Android SDK!";
-
- private static final String NOTICE_TEXT =
- "We know you just want to get started but please read this first.";
-
- /** Used in the preference pane (PrefsDialog) as well. */
- public static final String BODY_TEXT =
- "By choosing to send certain usage statistics to Google, you can " +
- "help us improve the Android SDK. These usage statistics let us " +
- "measure things like active usage of the SDK and let us know things " +
- "like which versions of the SDK are in use and which tools are the " +
- "most popular with developers. This limited data is not associated " +
- "with personal information about you, is examined on an aggregate " +
- "basis, and is maintained in accordance with the " +
- "<a href=\"http://www.google.com/intl/en/privacy.html\">Google " +
- "Privacy Policy</a>.";
-
- /** Used in the preference pane (PrefsDialog) as well. */
- public static final String CHECKBOX_TEXT =
- "Send usage statistics to Google.";
-
- private static final String FOOTER_TEXT =
- "If you later decide to change this setting, you can do so in the " +
- "\"ddms\" tool under \"File\" > \"Preferences\" > \"Usage Stats\".";
-
- private static final String BUTTON_TEXT =
- " Proceed ";
-
- /** List of Linux browser commands to try, in order (see openUrl). */
- private static final String[] LINUX_BROWSERS = new String[] {
- "firefox -remote openurl(%URL%,new-window)", // $NON-NLS-1$ running FF
- "mozilla -remote openurl(%URL%,new-window)", // $NON-NLS-1$ running Moz
- "firefox %URL%", // $NON-NLS-1$ new FF
- "mozilla %URL%", // $NON-NLS-1$ new Moz
- "kfmclient openURL %URL%", // $NON-NLS-1$ Konqueror
- "opera -newwindow %URL%", // $NON-NLS-1$ Opera
- };
-
- public final static String PING_OPT_IN = "pingOptIn"; //$NON-NLS-1$
- public final static String PING_TIME = "pingTime"; //$NON-NLS-1$
- public final static String PING_ID = "pingId"; //$NON-NLS-1$
-
-
- private static PreferenceStore sPrefStore;
-
- /**
- * Send a "ping" to the Google toolbar server, if enough time has
- * elapsed since the last ping, and if the user has not opted out.
- * If this is the first time, notify the user and offer an opt-out.
- * Note: UI operations (if any) are synchronous, but the actual ping
- * (if any) is sent in a <i>non-daemon</i> background thread.
- *
- * @param app name to report in the ping
- * @param version to report in the ping
- */
- public static void ping(final String app, final String version) {
- // Validate the application and version input.
- final String normalVersion = normalizeVersion(app, version);
-
- // Unique, randomly assigned ID for this installation.
- PreferenceStore prefs = getPreferenceStore();
- if (prefs != null) {
- if (!prefs.contains(PING_ID)) {
- // First time: make up a new ID. TODO: Use something more random?
- prefs.setValue(PING_ID, new Random().nextLong());
-
- // Also give them a chance to opt out.
- prefs.setValue(PING_OPT_IN, getUserPermission());
- try {
- prefs.save();
- }
- catch (IOException ioe) {
- }
- }
-
- // If the user has not opted in, do nothing and quietly return.
- if (!prefs.getBoolean(PING_OPT_IN)) {
- // user opted out.
- return;
- }
-
- // If the last ping *for this app* was too recent, do nothing.
- String timePref = PING_TIME + "." + app; // $NON-NLS-1$
- long now = System.currentTimeMillis();
- long then = prefs.getLong(timePref);
- if (now - then < PING_INTERVAL_MSEC) {
- // too soon after a ping.
- return;
- }
-
- // Record the time of the attempt, whether or not it succeeds.
- prefs.setValue(timePref, now);
- try {
- prefs.save();
- }
- catch (IOException ioe) {
- }
-
- // Send the ping itself in the background (don't block if the
- // network is down or slow or confused).
- final long id = prefs.getLong(PING_ID);
- new Thread() {
- @Override
- public void run() {
- try {
- actuallySendPing(app, normalVersion, id);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }.start();
- }
- }
-
- /**
- * Returns the DDMS {@link PreferenceStore}.
- */
- public static synchronized PreferenceStore getPreferenceStore() {
- if (sPrefStore == null) {
- // get the location of the preferences
- String homeDir = null;
- try {
- homeDir = AndroidLocation.getFolder();
- } catch (AndroidLocationException e1) {
- // pass, we'll do a dummy store since homeDir is null
- }
-
- if (homeDir != null) {
- String rcFileName = homeDir + "ddms.cfg"; //$NON-NLS-1$
-
- // also look for an old pref file in the previous location
- String oldPrefPath = System.getProperty("user.home") //$NON-NLS-1$
- + File.separator + ".ddmsrc"; //$NON-NLS-1$
- File oldPrefFile = new File(oldPrefPath);
- if (oldPrefFile.isFile()) {
- try {
- PreferenceStore oldStore = new PreferenceStore(oldPrefPath);
- oldStore.load();
-
- oldStore.save(new FileOutputStream(rcFileName), "");
- oldPrefFile.delete();
-
- PreferenceStore newStore = new PreferenceStore(rcFileName);
- newStore.load();
- sPrefStore = newStore;
- } catch (IOException e) {
- // create a new empty store.
- sPrefStore = new PreferenceStore(rcFileName);
- }
- } else {
- sPrefStore = new PreferenceStore(rcFileName);
-
- try {
- sPrefStore.load();
- } catch (IOException e) {
- System.err.println("Error Loading Preferences");
- }
- }
- } else {
- sPrefStore = new PreferenceStore();
- }
- }
-
- return sPrefStore;
- }
-
- /**
- * Unconditionally send a "ping" request to the Google toolbar server.
- *
- * @param app name to report in the ping
- * @param version to report in the ping (dotted numbers, no more than four)
- * @param id of the local installation
- * @throws IOException if the ping failed
- */
- @SuppressWarnings("deprecation")
- private static void actuallySendPing(String app, String version, long id)
- throws IOException {
- // Detect and report the host OS.
- String os = System.getProperty("os.name"); // $NON-NLS-1$
- if (os.startsWith("Mac OS")) { // $NON-NLS-1$
- os = "mac"; // $NON-NLS-1$
- } else if (os.startsWith("Windows")) { // $NON-NLS-1$
- os = "win"; // $NON-NLS-1$
- } else if (os.startsWith("Linux")) { // $NON-NLS-1$
- os = "linux"; // $NON-NLS-1$
- } else {
- // Unknown -- surprising -- send it verbatim so we can see it.
- os = URLEncoder.encode(os);
- }
-
- // Include the application's name as part of the as= value.
- // Share the user ID for all apps, to allow unified activity reports.
-
- URL url = new URL(
- "http", // $NON-NLS-1$
- "tools.google.com", // $NON-NLS-1$
- "/service/update?as=androidsdk_" + app + // $NON-NLS-1$
- "&id=" + Long.toHexString(id) + // $NON-NLS-1$
- "&version=" + version + // $NON-NLS-1$
- "&os=" + os); // $NON-NLS-1$
-
- // Discard the actual response, but make sure it reads OK
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-
- // Believe it or not, a 404 response indicates success:
- // the ping was logged, but no update is configured.
- if (conn.getResponseCode() != HttpURLConnection.HTTP_OK &&
- conn.getResponseCode() != HttpURLConnection.HTTP_NOT_FOUND) {
- throw new IOException(
- conn.getResponseMessage() + ": " + url); // $NON-NLS-1$
- }
- }
-
- /**
- * Prompt the user for whether they want to opt out of reporting.
- * @return whether the user allows reporting (they do not opt out).
- */
- private static boolean getUserPermission() {
- // Use dialog trim for the shell, but without a close button.
- final Display display = new Display();
- final Shell shell = new Shell(display, SWT.TITLE | SWT.BORDER);
- shell.setText(WINDOW_TITLE_TEXT);
- shell.setLayout(new GridLayout(1, false)); // 1 column
-
- // Take the default font and scale it up for the title.
- final Label title = new Label(shell, SWT.CENTER | SWT.WRAP);
- final FontData[] fontdata = title.getFont().getFontData();
- for (int i = 0; i < fontdata.length; i++) {
- fontdata[i].setHeight(fontdata[i].getHeight() * 4 / 3);
- }
- title.setFont(new Font(display, fontdata));
- title.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
- title.setText(HEADER_TEXT);
-
- final Label notice = new Label(shell, SWT.WRAP);
- notice.setFont(title.getFont());
- notice.setForeground(new Color(display, 255, 0, 0));
- notice.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
- notice.setText(NOTICE_TEXT);
-
- final Link text = new Link(shell, SWT.WRAP);
- text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
- text.setText(BODY_TEXT);
- text.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent event) {
- openUrl(event.text);
- }
- });
-
- final Button checkbox = new Button(shell, SWT.CHECK);
- checkbox.setSelection(true); // Opt-in by default.
- checkbox.setText(CHECKBOX_TEXT);
-
- final Link footer = new Link(shell, SWT.WRAP);
- footer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
- footer.setText(FOOTER_TEXT);
-
- // Whether the user gave permission (size-1 array for writing to).
- // Initialize to false, set when the user clicks the button.
- final boolean[] permission = new boolean[] { false };
-
- final Button button = new Button(shell, SWT.PUSH);
- button.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER));
- button.setText(BUTTON_TEXT);
- button.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent event) {
- permission[0] = checkbox.getSelection();
- shell.close();
- }
- });
-
- // Size the window to a fixed width, as high as necessary, centered.
- final Point size = shell.computeSize(450, SWT.DEFAULT, true);
- final Rectangle screen = display.getClientArea();
- shell.setBounds(
- screen.x + screen.width / 2 - size.x / 2,
- screen.y + screen.height / 2 - size.y / 2,
- size.x, size.y);
-
- shell.open();
- while (!shell.isDisposed()) {
- if (!display.readAndDispatch())
- display.sleep();
- }
-
- display.dispose(); // Otherwise ddms' own Display can't be created
- return permission[0];
- }
-
- /**
- * Open a URL in an external browser.
- * @param url to open - MUST be sanitized and properly formed!
- */
- public static void openUrl(final String url) {
- // TODO: consider using something like BrowserLauncher2
- // (http://browserlaunch2.sourceforge.net/) instead of these hacks.
-
- // SWT's Program.launch() should work on Mac, Windows, and GNOME
- // (because the OS shell knows how to launch a default browser).
- if (!Program.launch(url)) {
- // Must be Linux non-GNOME (or something else broke).
- // Try a few Linux browser commands in the background.
- new Thread() {
- @Override
- public void run() {
- for (String cmd : LINUX_BROWSERS) {
- cmd = cmd.replaceAll("%URL%", url); // $NON-NLS-1$
- try {
- Process proc = Runtime.getRuntime().exec(cmd);
- if (proc.waitFor() == 0) break; // Success!
- } catch (InterruptedException e) {
- // Should never happen!
- throw new RuntimeException(e);
- } catch (IOException e) {
- // Swallow the exception and try the next browser.
- }
- }
-
- // TODO: Pop up some sort of error here?
- // (We're in a new thread; can't use the existing Display.)
- }
- }.start();
- }
- }
-
- /**
- * Validate the supplied application version, and normalize the version.
- * @param app to report
- * @param version supplied by caller
- * @return normalized dotted quad version
- */
- private static String normalizeVersion(String app, String version) {
- // Application name must contain only word characters (no punctuaation)
- if (!app.matches("\\w+")) {
- throw new IllegalArgumentException("Bad app name: " + app);
- }
-
- // Version must be between 1 and 4 dotted numbers
- String[] numbers = version.split("\\.");
- if (numbers.length > 4) {
- throw new IllegalArgumentException("Bad version: " + version);
- }
- for (String part: numbers) {
- if (!part.matches("\\d+")) {
- throw new IllegalArgumentException("Bad version: " + version);
- }
- }
-
- // Always output 4 numbers, even if fewer were supplied (pad with .0)
- StringBuffer normal = new StringBuffer(numbers[0]);
- for (int i = 1; i < 4; i++) {
- normal.append(".").append(i < numbers.length ? numbers[i] : "0");
- }
- return normal.toString();
- }
-}