Merge pull request #1016 from abarth/clean_icons

Remove unused icons from the material design icons package
diff --git a/examples/fitness/apk/AndroidManifest.xml b/examples/fitness/apk/AndroidManifest.xml
index 7ddc4d3..83967b2 100644
--- a/examples/fitness/apk/AndroidManifest.xml
+++ b/examples/fitness/apk/AndroidManifest.xml
@@ -15,5 +15,9 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <service
+            android:name="org.domokit.sky.shell.UpdateService"
+            android:exported="false"
+            android:process=":remote"/>
     </application>
- </manifest>
\ No newline at end of file
+ </manifest>
diff --git a/sky/build/sky_app.gni b/sky/build/sky_app.gni
index ce66f6b..612edb6 100644
--- a/sky/build/sky_app.gni
+++ b/sky/build/sky_app.gni
@@ -47,8 +47,11 @@
 
       sources = [
         "$root_build_dir/icudtl.dat",
-        "$target_gen_dir/app.skyx",
+        "$target_gen_dir/app.skyx"
       ]
+      if (defined(invoker.manifest)) {
+        sources += [ invoker.manifest ]
+      }
       deps = [
         ":$skyx_target_name",
         ":gen_${bundle_prefix}_bundle",
diff --git a/sky/packages/material_design_icons/pubspec.yaml b/sky/packages/material_design_icons/pubspec.yaml
index 89681db..0748c5c 100644
--- a/sky/packages/material_design_icons/pubspec.yaml
+++ b/sky/packages/material_design_icons/pubspec.yaml
@@ -1,5 +1,5 @@
 name: material_design_icons
-version: 0.0.2
+version: 0.0.3
 author: Chromium Authors <sky-dev@googlegroups.com>
 description: Material Design Icons
 homepage: https://github.com/domokit/sky_engine
diff --git a/sky/shell/BUILD.gn b/sky/shell/BUILD.gn
index 6df0f3b..4b8c350 100644
--- a/sky/shell/BUILD.gn
+++ b/sky/shell/BUILD.gn
@@ -90,6 +90,7 @@
       "android/org/domokit/sky/shell/PlatformViewAndroid.java",
       "android/org/domokit/sky/shell/SkyMain.java",
       "android/org/domokit/sky/shell/TracingController.java",
+      "android/org/domokit/sky/shell/UpdateService.java",
     ]
     jni_package = "sky/shell"
   }
@@ -105,6 +106,7 @@
       "android/sky_main.h",
       "android/tracing_controller.cc",
       "android/tracing_controller.h",
+      "android/update_service_android.cc",
     ]
 
     deps = common_deps + [
@@ -131,6 +133,7 @@
       "android/org/domokit/sky/shell/SkyApplication.java",
       "android/org/domokit/sky/shell/SkyMain.java",
       "android/org/domokit/sky/shell/TracingController.java",
+      "android/org/domokit/sky/shell/UpdateService.java",
     ]
 
     deps = [
diff --git a/sky/shell/android/AndroidManifest.xml b/sky/shell/android/AndroidManifest.xml
index a3df5dc..ca7c185 100644
--- a/sky/shell/android/AndroidManifest.xml
+++ b/sky/shell/android/AndroidManifest.xml
@@ -21,5 +21,9 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <service
+            android:name="UpdateService"
+            android:exported="false"
+            android:process=":remote"/>
     </application>
  </manifest>
diff --git a/sky/shell/android/library_loader.cc b/sky/shell/android/library_loader.cc
index 5cb62e3..35e1605 100644
--- a/sky/shell/android/library_loader.cc
+++ b/sky/shell/android/library_loader.cc
@@ -15,6 +15,7 @@
 #include "sky/shell/android/platform_view_android.h"
 #include "sky/shell/android/sky_main.h"
 #include "sky/shell/android/tracing_controller.h"
+#include "sky/shell/android/update_service_android.h"
 
 namespace {
 
@@ -25,6 +26,7 @@
     {"PlatformViewAndroid", sky::shell::PlatformViewAndroid::Register},
     {"SkyMain", sky::shell::RegisterSkyMain},
     {"TracingController", sky::shell::RegisterTracingController},
+    {"UpdateService", sky::shell::RegisterUpdateService},
 };
 
 bool RegisterJNI(JNIEnv* env) {
diff --git a/sky/shell/android/org/domokit/sky/shell/SkyApplication.java b/sky/shell/android/org/domokit/sky/shell/SkyApplication.java
index ca27b16..27f0abf 100644
--- a/sky/shell/android/org/domokit/sky/shell/SkyApplication.java
+++ b/sky/shell/android/org/domokit/sky/shell/SkyApplication.java
@@ -34,10 +34,11 @@
 public class SkyApplication extends BaseChromiumApplication {
     static final String SNAPSHOT = "snapshot_blob.bin";
     static final String APP_BUNDLE = "app.skyx";
+    static final String MANIFEST = "sky.yaml";
 
     private static final String TAG = "SkyApplication";
     private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "sky_shell";
-    private static final String[] SKY_RESOURCES = {"icudtl.dat", SNAPSHOT, APP_BUNDLE};
+    private static final String[] SKY_RESOURCES = {"icudtl.dat", SNAPSHOT, APP_BUNDLE, MANIFEST};
 
     private ResourceExtractor mResourceExtractor;
 
@@ -51,6 +52,7 @@
         initJavaUtils();
         initResources();
         initNative();
+        UpdateService.init(getApplicationContext());
         onServiceRegistryAvailable(ServiceRegistry.SHARED);
     }
 
diff --git a/sky/shell/android/org/domokit/sky/shell/UpdateService.java b/sky/shell/android/org/domokit/sky/shell/UpdateService.java
new file mode 100644
index 0000000..93cec09
--- /dev/null
+++ b/sky/shell/android/org/domokit/sky/shell/UpdateService.java
@@ -0,0 +1,86 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.domokit.sky.shell;
+
+import android.app.AlarmManager;
+import android.app.Service;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+import java.io.File;
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.base.PathUtils;
+
+/**
+ * A class that schedules and runs periodic autoupdate checks.
+ */
+@JNINamespace("sky::shell")
+public class UpdateService extends Service {
+    private static final String TAG = "UpdateService";
+    private static final int REQUEST_CODE = 0;  // Not sure why this is needed.
+    private static final boolean ENABLED = false;
+
+    private long mNativePtr = 0;
+
+    public static void init(Context context) {
+        if (ENABLED)
+            maybeScheduleUpdateCheck(context);
+    }
+
+    private static void maybeScheduleUpdateCheck(Context context) {
+        Intent alarm = new Intent(context, UpdateService.class);
+        PendingIntent existingIntent = PendingIntent.getService(
+                context, REQUEST_CODE, alarm, PendingIntent.FLAG_NO_CREATE);
+        if (existingIntent != null) {
+          Log.i(TAG, "Update alarm exists: " + PathUtils.getDataDirectory(context));
+          return;
+        }
+
+        PendingIntent pendingIntent = PendingIntent.getService(
+                context, REQUEST_CODE, alarm, PendingIntent.FLAG_UPDATE_CURRENT);
+        AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        manager.setInexactRepeating(AlarmManager.RTC, System.currentTimeMillis(),
+                AlarmManager.INTERVAL_DAY, pendingIntent);
+
+        Log.i(TAG, "Update scheduled: " + PathUtils.getDataDirectory(context));
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        SkyMain.ensureInitialized(getApplicationContext(), null);
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mNativePtr != 0)
+            nativeDetach(mNativePtr);
+        mNativePtr = 0;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        final File dataDir = new File(PathUtils.getDataDirectory(this));
+        mNativePtr = nativeCheckForUpdates(dataDir.getPath());
+        return START_NOT_STICKY;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+      return null;
+    }
+
+    @SuppressWarnings("unused")
+    @CalledByNative
+    public void onUpdateFinished() {
+        stopSelf();
+    }
+
+    private native long nativeCheckForUpdates(String dataDir);
+    private native void nativeDetach(long nativeUpdateTask);
+}
diff --git a/sky/shell/android/update_service_android.cc b/sky/shell/android/update_service_android.cc
new file mode 100644
index 0000000..f3f2911
--- /dev/null
+++ b/sky/shell/android/update_service_android.cc
@@ -0,0 +1,118 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sky/shell/android/update_service_android.h"
+
+#include "base/android/jni_string.h"
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/threading/worker_pool.h"
+#include "jni/UpdateService_jni.h"
+#include "mojo/data_pipe_utils/data_pipe_utils.h"
+#include "mojo/public/cpp/application/connect.h"
+#include "mojo/public/interfaces/application/service_provider.mojom.h"
+#include "mojo/services/network/public/interfaces/network_service.mojom.h"
+#include "sky/shell/shell.h"
+
+namespace sky {
+namespace shell {
+
+namespace {
+
+// TODO(mpcomplete): make this a utility method?
+static mojo::URLLoaderPtr FetchURL(
+    mojo::NetworkService* network_service,
+    const std::string& url,
+    base::Callback<void(mojo::URLResponsePtr)> callback) {
+  mojo::URLLoaderPtr loader;
+  network_service->CreateURLLoader(GetProxy(&loader));
+
+  mojo::URLRequestPtr request = mojo::URLRequest::New();
+  request->url = url;
+  request->auto_follow_redirects = true;
+  loader->Start(request.Pass(), callback);
+
+  return loader.Pass();
+}
+
+}  // namespace
+
+static jlong CheckForUpdates(JNIEnv* env, jobject jcaller, jstring j_data_dir) {
+  std::string data_dir = base::android::ConvertJavaStringToUTF8(env, j_data_dir);
+  scoped_ptr<UpdateTask> task(new UpdateTask(env, jcaller, data_dir));
+
+  // TODO(mpcomplete): download a manifest and check the version.
+  task->DownloadAppBundle("file://" + data_dir + "/app.skyx");
+
+  return reinterpret_cast<jlong>(task.release());
+}
+
+bool RegisterUpdateService(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+UpdateTask::UpdateTask(JNIEnv* env, jobject update_service, std::string data_dir)
+    : final_path_(base::FilePath(data_dir).AppendASCII("app.skyx")) {
+  update_service_.Reset(env, update_service);
+
+  mojo::ServiceProviderPtr service_provider =
+      CreateServiceProvider(Shell::Shared().service_provider_context());
+  mojo::ConnectToService(service_provider.get(), &network_service_);
+}
+
+void UpdateTask::DownloadAppBundle(const std::string& url) {
+  LOG(INFO) << "Update downloading " << url << " to: " << final_path_.value();
+  if (!base::CreateTemporaryFile(&temp_path_)) {
+    CallOnFinished();
+    return;
+  }
+
+  url_loader_ =
+      FetchURL(network_service_.get(), url,
+               base::Bind(&UpdateTask::OnResponse, base::Unretained(this)));
+}
+
+void UpdateTask::Detach(JNIEnv* env, jobject jcaller) {
+  delete this;
+}
+
+void UpdateTask::OnResponse(mojo::URLResponsePtr response) {
+  mojo::ScopedDataPipeConsumerHandle data;
+  if (response->status_code == 200)
+    data = response->body.Pass();
+  if (!data.is_valid()) {
+    LOG(ERROR) << "Update failed: Server responded " << response->status_code;
+    CallOnFinished();
+    return;
+  }
+
+  scoped_refptr<base::TaskRunner> worker_runner =
+      base::WorkerPool::GetTaskRunner(true);
+  mojo::common::CopyToFile(
+      data.Pass(), temp_path_, worker_runner.get(),
+      base::Bind(&UpdateTask::OnCopied, base::Unretained(this)));
+}
+
+void UpdateTask::OnCopied(bool success) {
+  int64 size = 0;
+  GetFileSize(temp_path_, &size);
+
+  // This assumes temp files are created on the same volume as the data_dir.
+  // TODO(mpcomplete): only replace on next startup. Otherwise, a currently
+  // running version of the app will get confused.
+  bool rv = base::ReplaceFile(temp_path_, final_path_, nullptr);
+  LOG(INFO) << "Update finished: " << rv << " filesize(" << final_path_.value() << ")=" << size;
+
+  CallOnFinished();
+}
+
+void UpdateTask::CallOnFinished() {
+  // The Java side is responsible for deleting the UpdateTask when finished.
+  Java_UpdateService_onUpdateFinished(base::android::AttachCurrentThread(),
+                                      update_service_.obj());
+}
+
+}  // namespace shell
+}  // namespace sky
diff --git a/sky/shell/android/update_service_android.h b/sky/shell/android/update_service_android.h
new file mode 100644
index 0000000..e6498c2
--- /dev/null
+++ b/sky/shell/android/update_service_android.h
@@ -0,0 +1,41 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SKY_SHELL_UPDATE_SERVICE_H_
+#define SKY_SHELL_UPDATE_SERVICE_H_
+
+#include <jni.h>
+
+#include "base/android/jni_string.h"
+#include "base/files/file_path.h"
+#include "mojo/services/network/public/interfaces/network_service.mojom.h"
+
+namespace sky {
+namespace shell {
+
+class UpdateTask {
+ public:
+  UpdateTask(JNIEnv* env, jobject update_service, std::string data_dir);
+
+  void DownloadAppBundle(const std::string& url);
+  void Detach(JNIEnv* env, jobject jcaller);
+
+ private:
+  void OnResponse(mojo::URLResponsePtr response);
+  void OnCopied(bool success);
+  void CallOnFinished();
+
+  base::android::ScopedJavaGlobalRef<jobject> update_service_;
+  mojo::NetworkServicePtr network_service_;
+  base::FilePath temp_path_;
+  base::FilePath final_path_;
+  mojo::URLLoaderPtr url_loader_;
+};
+
+bool RegisterUpdateService(JNIEnv* env);
+
+}  // namespace shell
+}  // namespace sky
+
+#endif  // SKY_SHELL_UPDATE_SERVICE_H_