19f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li/*
2f04335f899f2cce69f843692a3cb9cec229683c2tturney * Copyright (C) 2017 The Android Open Source Project
39f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
4f04335f899f2cce69f843692a3cb9cec229683c2tturney * Licensed under the Apache License, Version 2.0 (the "License");
5f04335f899f2cce69f843692a3cb9cec229683c2tturney * you may not use this file except in compliance with the License.
6f04335f899f2cce69f843692a3cb9cec229683c2tturney * You may obtain a copy of the License at
79f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
8f04335f899f2cce69f843692a3cb9cec229683c2tturney *      http://www.apache.org/licenses/LICENSE-2.0
99f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Unless required by applicable law or agreed to in writing, software
11f04335f899f2cce69f843692a3cb9cec229683c2tturney * distributed under the License is distributed on an "AS IS" BASIS,
12f04335f899f2cce69f843692a3cb9cec229683c2tturney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f04335f899f2cce69f843692a3cb9cec229683c2tturney * See the License for the specific language governing permissions and
14f04335f899f2cce69f843692a3cb9cec229683c2tturney * limitations under the License.
159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li */
169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipackage com.googlecode.android_scripting;
189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.app.AlertDialog;
209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.app.ProgressDialog;
219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.content.Context;
229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.content.DialogInterface;
239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.content.DialogInterface.OnCancelListener;
249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.os.AsyncTask;
259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.exception.Sl4aException;
279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.future.FutureResult;
289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.io.File;
309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.io.FileNotFoundException;
319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.io.FileOutputStream;
329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.io.IOException;
339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.Enumeration;
349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.zip.ZipEntry;
359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.zip.ZipFile;
369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li/**
389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * AsyncTask for extracting ZIP files.
399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li */
419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipublic class ZipExtractorTask extends AsyncTask<Void, Integer, Long> {
429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private static enum Replace {
449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    YES, NO, YESTOALL, SKIPALL
459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  }
469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private final File mInput;
489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private final File mOutput;
499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private final ProgressDialog mDialog;
509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private Throwable mException;
519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private int mProgress = 0;
529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private final Context mContext;
539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private boolean mReplaceAll;
549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private final class ProgressReportingOutputStream extends FileOutputStream {
569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private ProgressReportingOutputStream(File f) throws FileNotFoundException {
579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      super(f);
589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Override
619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public void write(byte[] buffer, int offset, int count) throws IOException {
629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      super.write(buffer, offset, count);
639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mProgress += count;
649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      publishProgress(mProgress);
659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  }
679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  public ZipExtractorTask(String in, String out, Context context, boolean replaceAll)
699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      throws Sl4aException {
709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    super();
719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    mInput = new File(in);
729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    mOutput = new File(out);
739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    if (!mOutput.exists()) {
749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      if (!mOutput.mkdirs()) {
759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        throw new Sl4aException("Failed to make directories: " + mOutput.getAbsolutePath());
769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      }
779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    if (context != null) {
799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mDialog = new ProgressDialog(context);
809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    } else {
819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mDialog = null;
829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    mContext = context;
859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    mReplaceAll = replaceAll;
869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  }
889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  @Override
909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  protected void onPreExecute() {
919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    Log.v("Extracting " + mInput.getAbsolutePath() + " to " + mOutput.getAbsolutePath());
929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    if (mDialog != null) {
939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mDialog.setTitle("Extracting");
949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mDialog.setMessage(mInput.getName());
959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mDialog.setOnCancelListener(new OnCancelListener() {
979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        @Override
989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public void onCancel(DialogInterface dialog) {
999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          cancel(true);
1009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      });
1029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mDialog.show();
1039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  }
1059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  @Override
1079f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  protected Long doInBackground(Void... params) {
1089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    try {
1099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      return unzip();
1109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    } catch (Exception e) {
1119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      if (mInput.exists()) {
1129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        // Clean up bad zip file.
1139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mInput.delete();
1149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      }
1159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mException = e;
1169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      return null;
1179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  }
1199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  @Override
1219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  protected void onProgressUpdate(Integer... progress) {
1229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    if (mDialog == null) {
1239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      return;
1249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    if (progress.length > 1) {
1269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      int max = progress[1];
1279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mDialog.setMax(max);
1289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    } else {
1299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mDialog.setProgress(progress[0].intValue());
1309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  }
1329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  @Override
1349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  protected void onPostExecute(Long result) {
1359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    if (mDialog != null && mDialog.isShowing()) {
1369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mDialog.dismiss();
1379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    if (isCancelled()) {
1399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      return;
1409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    if (mException != null) {
1429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      Log.e("Zip extraction failed.", mException);
1439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  }
1459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  @Override
1479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  protected void onCancelled() {
1489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    if (mDialog != null) {
1499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      mDialog.setTitle("Extraction cancelled.");
1509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  }
1529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private long unzip() throws Exception {
1549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    long extractedSize = 0l;
1559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    Enumeration<? extends ZipEntry> entries;
1569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    ZipFile zip = new ZipFile(mInput);
1579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    long uncompressedSize = getOriginalSize(zip);
1589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    publishProgress(0, (int) uncompressedSize);
1609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    entries = zip.entries();
1629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    try {
1649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      while (entries.hasMoreElements()) {
1659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        ZipEntry entry = entries.nextElement();
1669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (entry.isDirectory()) {
1679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          // Not all zip files actually include separate directory entries.
1689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          // We'll just ignore them
1699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          // and create them as necessary for each actual entry.
1709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          continue;
1719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        File destination = new File(mOutput, entry.getName());
1739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (!destination.getParentFile().exists()) {
1749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          destination.getParentFile().mkdirs();
1759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (destination.exists() && mContext != null && !mReplaceAll) {
1779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          Replace answer = showDialog(entry.getName());
1789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          switch (answer) {
1799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          case YES:
1809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            break;
1819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          case NO:
1829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            continue;
1839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          case YESTOALL:
1849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mReplaceAll = true;
1859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            break;
1869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          default:
1879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return extractedSize;
1889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          }
1899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        ProgressReportingOutputStream outStream = new ProgressReportingOutputStream(destination);
1919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        extractedSize += IoUtils.copy(zip.getInputStream(entry), outStream);
1929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        outStream.close();
1939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      }
1949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    } finally {
1959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      try {
1969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        zip.close();
1979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      } catch (Exception e) {
1989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        // swallow this exception, we are only interested in the original one
1999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      }
2009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    Log.v("Extraction is complete.");
2029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    return extractedSize;
2039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  }
2049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private long getOriginalSize(ZipFile file) {
2069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    Enumeration<? extends ZipEntry> entries = file.entries();
2079f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    long originalSize = 0l;
2089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    while (entries.hasMoreElements()) {
2099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      ZipEntry entry = entries.nextElement();
2109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      if (entry.getSize() >= 0) {
2119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        originalSize += entry.getSize();
2129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      }
2139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    return originalSize;
2159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  }
2169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  private Replace showDialog(final String name) {
2189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    final FutureResult<Replace> mResult = new FutureResult<Replace>();
2199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    MainThread.run(mContext, new Runnable() {
2219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      @Override
2229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      public void run() {
2239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
2249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        builder.setTitle(String.format("Script \"%s\" already exist.", name));
2259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        builder.setMessage(String.format("Do you want to replace script \"%s\" ?", name));
2269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        DialogInterface.OnClickListener buttonListener = new DialogInterface.OnClickListener() {
2289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          @Override
2299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          public void onClick(DialogInterface dialog, int which) {
2309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            Replace result = Replace.SKIPALL;
2319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            switch (which) {
2329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            case DialogInterface.BUTTON_POSITIVE:
2339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li              result = Replace.YES;
2349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li              break;
2359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            case DialogInterface.BUTTON_NEGATIVE:
2369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li              result = Replace.NO;
2379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li              break;
2389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            case DialogInterface.BUTTON_NEUTRAL:
2399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li              result = Replace.YESTOALL;
2409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li              break;
2419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
2429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mResult.set(result);
2439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            dialog.dismiss();
2449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          }
2459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        };
2469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        builder.setNegativeButton("Skip", buttonListener);
2479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        builder.setPositiveButton("Replace", buttonListener);
2489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        builder.setNeutralButton("Replace All", buttonListener);
2499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
2519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          @Override
2529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          public void onCancel(DialogInterface dialog) {
2539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mResult.set(Replace.SKIPALL);
2549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            dialog.dismiss();
2559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li          }
2569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        });
2579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        builder.show();
2589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      }
2599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    });
2609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    try {
2629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      return mResult.get();
2639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    } catch (InterruptedException e) {
2649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li      Log.e(e);
2659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    return null;
2679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li  }
2689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li}
269