- Allow the updater to open and install zip files
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index efd1694..00d8112 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2,8 +2,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="com.fairphone.updater"
-    android:versionCode="18"
-    android:versionName="18 (FP 1.8.3)" >
+    android:versionCode="19"
+    android:versionName="19 (FP 1.8.3)" >
 
     <uses-sdk
         android:minSdkVersion="17"
@@ -75,6 +75,11 @@
 
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:mimeType="application/zip"/>
+            </intent-filter>
         </activity>
         <activity
             android:name=".BetaEnabler"
diff --git a/res/layout/fragment_download_fairphone_install.xml b/res/layout/fragment_download_fairphone_install.xml
index c6efefb..beb7252 100644
--- a/res/layout/fragment_download_fairphone_install.xml
+++ b/res/layout/fragment_download_fairphone_install.xml
@@ -10,6 +10,7 @@
         android:visibility="visible" >
 
         <TextView
+            android:id="@+id/download_complete_label"
             style="@style/TextBold16White"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/src/com/fairphone/updater/FairphoneUpdater.java b/src/com/fairphone/updater/FairphoneUpdater.java
index 99cf36b..1a4763c 100644
--- a/src/com/fairphone/updater/FairphoneUpdater.java
+++ b/src/com/fairphone/updater/FairphoneUpdater.java
@@ -3,6 +3,7 @@
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
+import android.net.Uri;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.support.v4.app.Fragment;
@@ -65,11 +66,12 @@
     public static final String PREFERENCE_OTA_DOWNLOAD_URL = "OtaDownloadUrl";
     
     private static final String TAG_FIRST_FRAGMENT = "FIRST_FRAGMENT";
+    private String mZipPath;
 
 
     public static enum UpdaterState
     {
-        NORMAL, DOWNLOAD, PREINSTALL
+        NORMAL, DOWNLOAD, PREINSTALL, ZIP_INSTALL
     }
 
     private Version mDeviceVersion;
@@ -112,6 +114,8 @@
     protected void onCreate(Bundle savedInstanceState)
     {
         super.onCreate(savedInstanceState);
+        mSharedPreferences = getSharedPreferences(FAIRPHONE_UPDATER_PREFERENCES, MODE_PRIVATE);
+
         onNewIntent(getIntent());
         
         setContentView(R.layout.activity_updater);
@@ -125,8 +129,6 @@
         DEV_MODE_ENABLED = false;
         mIsDevModeCounter = 10;
 
-        mSharedPreferences = getSharedPreferences(FAIRPHONE_UPDATER_PREFERENCES, MODE_PRIVATE);
-
         // update first times
         mIsFirstTimeAndroid = mSharedPreferences.getBoolean(PREFERENCE_FIRST_TIME_ANDROID, true);
 
@@ -306,7 +308,8 @@
         {
             ((DownloadAndRestartFragment) fragment).abortUpdateProcess("");
         }
-        else if (fragment != null && TAG_FIRST_FRAGMENT.equals(fragment.getTag()))
+
+        if (fragment != null && TAG_FIRST_FRAGMENT.equals(fragment.getTag()))
         {
             clearSelectedItems();
             finish();
@@ -530,6 +533,9 @@
                     firstFragment = new MainFragment();
                 }
                 break;
+            case ZIP_INSTALL:
+                firstFragment = new DownloadAndRestartFragment(true);
+                break;
             default:
                 firstFragment = new MainFragment();
                 break;
@@ -643,7 +649,10 @@
         String itemName = "";
         if (version != null)
         {
-            itemName = version.getImageTypeDescription(getResources()) + " " + version.getName() + " " + version.getBuildNumber();
+            if(mCurrentState != UpdaterState.ZIP_INSTALL) {
+                itemName = version.getImageTypeDescription(getResources()) + " ";
+            }
+            itemName += version.getName() + " " + version.getBuildNumber();
         }
         return itemName;
     }
@@ -777,19 +786,40 @@
     {
         super.onNewIntent(intent);
         setIntent(intent);
-        
         mLaunchGapps = false;
 
-        if (checkStartGappsInstall(intent))
-        {
-            mLaunchGapps = true;
-        }
-        else
-        {
-            Intent parentIntent = getParentActivityIntent();
-            if (checkStartGappsInstall(parentIntent))
+        if(intent != null) {
+            String action = intent.getAction();
+            switch (action)
             {
-                mLaunchGapps = true;
+                case GappsInstallerHelper.EXTRA_START_GAPPS_INSTALL:
+                    if (checkStartGappsInstall(intent)) {
+                        mLaunchGapps = true;
+                    } else {
+                        Intent parentIntent = getParentActivityIntent();
+                        if (checkStartGappsInstall(parentIntent)) {
+                            mLaunchGapps = true;
+                        }
+                    }
+                    break;
+                case Intent.ACTION_VIEW:
+                    Uri data = intent.getData();
+                    if(data != null)
+                    {
+                        String zipPath = data.getPath();
+                        if(!TextUtils.isEmpty(zipPath)) {
+                            mZipPath = zipPath;
+                            updateStatePreference(UpdaterState.ZIP_INSTALL);
+                        }
+                        else
+                        {
+                            mZipPath = "";
+                        }
+                    }
+                    break;
+                default:
+                    //no action
+                    break;
             }
         }
     }
@@ -806,6 +836,10 @@
 
         // check current state
         mCurrentState = getCurrentUpdaterState();
+        if(mCurrentState == UpdaterState.ZIP_INSTALL)
+        {
+            mCurrentState = TextUtils.isEmpty(mZipPath) ? UpdaterState.NORMAL : UpdaterState.ZIP_INSTALL;
+        }
 
         startService();
 
@@ -897,4 +931,9 @@
     {
         savePreference(UpdaterService.PREFERENCE_LAST_CONFIG_DOWNLOAD_ID, 0L);
     }
+
+    public String getZipFilePath()
+    {
+        return mZipPath;
+    }
 }
diff --git a/src/com/fairphone/updater/data/Version.java b/src/com/fairphone/updater/data/Version.java
index efa06b2..29ba80a 100644
--- a/src/com/fairphone/updater/data/Version.java
+++ b/src/com/fairphone/updater/data/Version.java
@@ -45,6 +45,8 @@
 
     private final List<Integer> mDependencies;
 
+    public static final int ZIP_INSTALL_VERSION = 999;
+
     public Version()
     {
         super();
diff --git a/src/com/fairphone/updater/fragments/DownloadAndRestartFragment.java b/src/com/fairphone/updater/fragments/DownloadAndRestartFragment.java
index 9a4f084..586da9a 100644
--- a/src/com/fairphone/updater/fragments/DownloadAndRestartFragment.java
+++ b/src/com/fairphone/updater/fragments/DownloadAndRestartFragment.java
@@ -39,6 +39,7 @@
 import com.fairphone.updater.UpdaterService;
 import com.fairphone.updater.data.DownloadableItem;
 import com.fairphone.updater.data.Store;
+import com.fairphone.updater.data.UpdaterData;
 import com.fairphone.updater.data.Version;
 import com.fairphone.updater.data.VersionParserHelper;
 import com.fairphone.updater.tools.PrivilegeChecker;
@@ -55,6 +56,7 @@
 
     private static final String TAG = DownloadAndRestartFragment.class.getSimpleName();
     private static final int GET_LATEST_DOWNLOAD_ID_RETRIES = 12;
+    private boolean mIsZipInstall;
 
     private TextView mDownloadVersionName;
     private LinearLayout mVersionDownloadingGroup;
@@ -74,6 +76,7 @@
     private BroadcastReceiver mNetworkStateReceiver;
 
     private long mLatestUpdateDownloadId;
+    private TextView mDownloadCompleteLabel;
 
     public DownloadAndRestartFragment(boolean isVersion)
     {
@@ -86,10 +89,11 @@
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
     {
         // Inflate the layout for this fragment
+        mIsZipInstall = UpdaterState.ZIP_INSTALL == mainActivity.getCurrentUpdaterState();
         View view;
         if (mIsVersion)
         {
-            mSelectedVersion = mainActivity.getSelectedVersion();
+            mSelectedVersion = getSelectedVersion();
             view = inflateViewByImageType(inflater, container);
             mSelectedStore = null;
         }
@@ -105,6 +109,29 @@
         return view;
     }
 
+    private Version getSelectedVersion() {
+        Version version;
+        if(mIsZipInstall) {
+            Resources resources = mainActivity.getResources();
+
+            //Get the zip file name
+            String[] zipPath = getDownloadPath(null).split("/");
+            String zipName = "";
+            if (zipPath != null && zipPath.length > 0) {
+                zipName = zipPath[zipPath.length - 1];
+            }
+
+            version = new Version();
+            version.setName(resources.getString(R.string.install) + " " + zipName);
+            version.setNumber(Version.ZIP_INSTALL_VERSION);
+        }
+        else
+        {
+            version = mainActivity.getSelectedVersion();
+        }
+        return version;
+    }
+
     private View inflateViewByImageType(LayoutInflater inflater, ViewGroup container)
     {
         View view = inflater.inflate(R.layout.fragment_download_fairphone, container, false);
@@ -141,6 +168,7 @@
                 break;
 
             case PREINSTALL:
+            case ZIP_INSTALL:
                 setupPreInstallState();
 
                 mVersionDownloadingGroup.setVisibility(View.GONE);
@@ -179,6 +207,10 @@
             public void onClick(View v)
             {
                 abortUpdateProcess("");
+                if(Utils.hasUnifiedPartition(mainActivity.getResources()))
+                {
+                    Utils.clearCache();
+                }
                 mainActivity.onBackPressed();
             }
         });
@@ -335,6 +367,7 @@
     private void setupLayout(View view)
     {
         mDownloadVersionName = (TextView) view.findViewById(R.id.download_version_name_text);
+        mDownloadCompleteLabel = (TextView) view.findViewById(R.id.download_complete_label);
 
         // download in progress group
         mVersionDownloadingGroup = (LinearLayout) view.findViewById(R.id.version_downloading_group);
@@ -363,6 +396,14 @@
         if (item != null)
         {
             mDownloadVersionName.setText(mainActivity.getItemName(item, mIsVersion));
+            if(mIsZipInstall)
+            {
+                mDownloadCompleteLabel.setVisibility(View.GONE);
+            }
+            else
+            {
+                mDownloadCompleteLabel.setVisibility(View.VISIBLE);
+            }
         }
 
         toggleDownloadProgressAndRestart();
@@ -514,7 +555,7 @@
 
             if (file.exists())
             {
-                if (Utils.checkMD5(item.getMd5Sum(), file))
+                if (Utils.checkMD5(item.getMd5Sum(), file) || mIsZipInstall)
                 {
                     copyUpdateToCache(file);
                 }
@@ -817,8 +858,17 @@
 
     private String getDownloadPath(DownloadableItem item)
     {
-        Resources resources = mainActivity.getResources();
-        return Environment.getExternalStorageDirectory() + resources.getString(R.string.updaterFolder) + Utils.getFilenameFromDownloadableItem(item, mIsVersion);
+        String path;
+        if(mIsZipInstall)
+        {
+           path = mainActivity.getZipFilePath();
+        }
+        else
+        {
+            Resources resources = mainActivity.getResources();
+            path = Environment.getExternalStorageDirectory() + resources.getString(R.string.updaterFolder) + Utils.getFilenameFromDownloadableItem(item, mIsVersion);
+        }
+        return path;
     }
 
     public void abortUpdateProcess(final String reason)