title: how to extract zip file content into sd card?
body: <p>i want to extract my .obb file contents which contain zip file for .zim file and want to extract these files into my sd card. how can I do that I tried the following way with java helperclass?
  Is that correct?</p>
  
  <pre><code>   public class MainActivity extends Activity implements IDownloaderClient {
      private static final String LOG_TAG = "LVLDownloader";
      private ProgressBar mPB;
  
      private TextView mStatusText;
      private TextView mProgressFraction;
      private TextView mProgressPercent;
      private TextView mAverageSpeed;
      private TextView mTimeRemaining;
  
      private View mDashboard;
      private View mCellMessage;
  
      private Button mPauseButton;
      private Button mWiFiSettingsButton;
  
      private boolean mStatePaused;
      private int mState;
  
      private IDownloaderService mRemoteService;
  
      private IStub mDownloaderClientStub;
  
      private void setState(int newState) {
          if (mState != newState) {
              mState = newState;
              mStatusText.setText(Helpers.getDownloaderStringResourceIDFromState(newState));
          }
      }
  
      private void setButtonPausedState(boolean paused) {
          mStatePaused = paused;
          int stringResourceID = paused ? R.string.text_button_resume :
                  R.string.text_button_pause;
          mPauseButton.setText(stringResourceID);
      }
  
      /**
       * This is a little helper class that demonstrates simple testing of an
       * Expansion APK file delivered by Market. You may not wish to hard-code
       * things such as file lengths into your executable... and you may wish to
       * turn this code off during application development.
       */
      private static class XAPKFile {
          public final boolean mIsMain;
          public final int mFileVersion;
          public final long mFileSize;
  
          XAPKFile(boolean isMain, int fileVersion, long fileSize) {
              mIsMain = isMain;
              mFileVersion = fileVersion;
              mFileSize = fileSize;
          }
      }
  
      /**
       * Here is where you place the data that the validator will use to determine
       * if the file was delivered correctly. This is encoded in the source code
       * so the application can easily determine whether the file has been
       * properly delivered without having to talk to the server. If the
       * application is using LVL for licensing, it may make sense to eliminate
       * these checks and to just rely on the server.
       */
      private static final XAPKFile[] xAPKS = {
              new XAPKFile(
                      true, // true signifies a main file
                      4, // the version of the APK that the file was uploaded
                         // against
                      240000L // the length of the file in bytes
              ),
              new XAPKFile(
                      true, // false signifies a patch file
                      3, // the version of the APK that the patch file was uploaded
                         // against
                      24000L // the length of the patch file in bytes
              )            
      };
  
      /**
       * Go through each of the APK Expansion files defined in the structure above
       * and determine if the files are present and match the required size. Free
       * applications should definitely consider doing this, as this allows the
       * application to be launched for the first time without having a network
       * connection present. Paid applications that use LVL should probably do at
       * least one LVL check that requires the network to be present, so this is
       * not as necessary.
       * 
       * @return true if they are present.
       */
      boolean expansionFilesDelivered() {
          for (XAPKFile xf : xAPKS) {
              String fileName = Helpers.getExpansionAPKFileName(this, xf.mIsMain, xf.mFileVersion);
              if (!Helpers.doesFileExist(this, fileName, xf.mFileSize, false))
                  return false;
          }
          return true;
      }
  
      /**
       * Calculating a moving average for the validation speed so we don't get
       * jumpy calculations for time etc.
       */
      static private final float SMOOTHING_FACTOR = 0.005f;
  
      /**
       * Used by the async task
       */
      private boolean mCancelValidation;
  
      /**
       * Go through each of the Expansion APK files and open each as a zip file.
       * Calculate the CRC for each file and return false if any fail to match.
       * 
       * @return true if XAPKZipFile is successful
       */
      void validateXAPKZipFiles() {
          AsyncTask&lt;Object, DownloadProgressInfo, Boolean&gt; validationTask = new AsyncTask&lt;Object, DownloadProgressInfo, Boolean&gt;() {
  
              @Override
              protected void onPreExecute() {
                  mDashboard.setVisibility(View.VISIBLE);
                  mCellMessage.setVisibility(View.GONE);
                  mStatusText.setText(R.string.text_verifying_download);
                  mPauseButton.setOnClickListener(new View.OnClickListener() {
                      @Override
                      public void onClick(View view) {
                          mCancelValidation = true;
                      }
                  });
                  mPauseButton.setText(R.string.text_button_cancel_verify);
                  super.onPreExecute();
              }
  
              @Override
              protected Boolean doInBackground(Object... params) {
                  for (XAPKFile xf : xAPKS) {
                      String fileName = Helpers.getExpansionAPKFileName(
                              MainActivity.this,
                              xf.mIsMain, xf.mFileVersion);
                      if (!Helpers.doesFileExist(MainActivity.this, fileName,
                              xf.mFileSize, false))
                          return false;
                      fileName = Helpers
                              .generateSaveFileName(MainActivity.this, fileName);
                      ZipResourceFile zrf;
                      byte[] buf = new byte[1024 * 256];
                      try {
                          zrf = new ZipResourceFile(fileName);
                          ZipEntryRO[] entries = zrf.getAllEntries();
                          /**
                           * First calculate the total compressed length
                           */
                          long totalCompressedLength = 0;
                          for (ZipEntryRO entry : entries) {
                              totalCompressedLength += entry.mCompressedLength;
                          }
                          float averageVerifySpeed = 0;
                          long totalBytesRemaining = totalCompressedLength;
                          long timeRemaining;
                          /**
                           * Then calculate a CRC for every file in the Zip file,
                           * comparing it to what is stored in the Zip directory.
                           * Note that for compressed Zip files we must extract
                           * the contents to do this comparison.
                           */
                          for (ZipEntryRO entry : entries) {
                              if (-1 != entry.mCRC32) {
                                  long length = entry.mUncompressedLength;
                                  CRC32 crc = new CRC32();
                                  DataInputStream dis = null;
                                  try {
                                      dis = new DataInputStream(
                                              zrf.getInputStream(entry.mFileName));
  
                                      long startTime = SystemClock.uptimeMillis();
                                      while (length &gt; 0) {
                                          int seek = (int) (length &gt; buf.length ? buf.length
                                                  : length);
                                          dis.readFully(buf, 0, seek);
                                          crc.update(buf, 0, seek);
                                          length -= seek;
                                          long currentTime = SystemClock.uptimeMillis();
                                          long timePassed = currentTime - startTime;
                                          if (timePassed &gt; 0) {
                                              float currentSpeedSample = (float) seek
                                                      / (float) timePassed;
                                              if (0 != averageVerifySpeed) {
                                                  averageVerifySpeed = SMOOTHING_FACTOR
                                                          * currentSpeedSample
                                                          + (1 - SMOOTHING_FACTOR)
                                                          * averageVerifySpeed;
                                              } else {
                                                  averageVerifySpeed = currentSpeedSample;
                                              }
                                              totalBytesRemaining -= seek;
                                              timeRemaining = (long) (totalBytesRemaining / averageVerifySpeed);
                                              this.publishProgress(
                                                      new DownloadProgressInfo(
                                                              totalCompressedLength,
                                                              totalCompressedLength
                                                                      - totalBytesRemaining,
                                                              timeRemaining,
                                                              averageVerifySpeed)
                                                      );
                                          }
                                          startTime = currentTime;
                                          if (mCancelValidation)
                                              return true;
                                      }
                                      if (crc.getValue() != entry.mCRC32) {
                                          Log.e(Constants.TAG,
                                                  "CRC does not match for entry: "
                                                          + entry.mFileName);
                                          Log.e(Constants.TAG,
                                                  "In file: " + entry.getZipFileName());
                                          return false;
                                      }
                                  } finally {
                                      if (null != dis) {
                                          dis.close();
                                      }
                                  }
                              }
                          }
                      } catch (IOException e) {
                          e.printStackTrace();
                          return false;
                      }
                  }
                  return true;
              }
  
              @Override
              protected void onProgressUpdate(DownloadProgressInfo... values) {
                  onDownloadProgress(values[0]);
                  super.onProgressUpdate(values);
              }
  
              @Override
              protected void onPostExecute(Boolean result) {
                  if (result) {
                      mDashboard.setVisibility(View.VISIBLE);
                      mCellMessage.setVisibility(View.GONE);
                      mStatusText.setText(R.string.text_validation_complete);
                      mPauseButton.setOnClickListener(new View.OnClickListener() {
                          @Override
                          public void onClick(View view) {
                              finish();
                          }
                      });
                      mPauseButton.setText(android.R.string.ok);
                  } else {
                      mDashboard.setVisibility(View.VISIBLE);
                      mCellMessage.setVisibility(View.GONE);
                      mStatusText.setText(R.string.text_validation_failed);
                      mPauseButton.setOnClickListener(new View.OnClickListener() {
                          @Override
                          public void onClick(View view) {
                              finish();
                          }
                      });
                      mPauseButton.setText(android.R.string.cancel);
                  }
                  super.onPostExecute(result);
              }
  
          };
          validationTask.execute(new Object());
      }
  
      /**
       * If the download isn't present, we initialize the download UI. This ties
       * all of the controls into the remote service calls.
       */
      private void initializeDownloadUI() {
          mDownloaderClientStub = DownloaderClientMarshaller.CreateStub
                  (this, ExpansionFileDownloaderService.class);
          setContentView(R.layout.activity_main);
  
          mPB = (ProgressBar) findViewById(R.id.progressBar);
          mStatusText = (TextView) findViewById(R.id.statusText);
          mProgressFraction = (TextView) findViewById(R.id.progressAsFraction);
          mProgressPercent = (TextView) findViewById(R.id.progressAsPercentage);
          mAverageSpeed = (TextView) findViewById(R.id.progressAverageSpeed);
          mTimeRemaining = (TextView) findViewById(R.id.progressTimeRemaining);
          mDashboard = findViewById(R.id.downloaderDashboard);
          mCellMessage = findViewById(R.id.approveCellular);
          mPauseButton = (Button) findViewById(R.id.pauseButton);
          mWiFiSettingsButton = (Button) findViewById(R.id.wifiSettingsButton);
  
          mPauseButton.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  if (mStatePaused) {
                      mRemoteService.requestContinueDownload();
                  } else {
                      mRemoteService.requestPauseDownload();
                  }
                  setButtonPausedState(!mStatePaused);
              }
          });
  
          mWiFiSettingsButton.setOnClickListener(new View.OnClickListener() {
  
              @Override
              public void onClick(View v) {
                  startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS));
              }
          });
  
          Button resumeOnCell = (Button) findViewById(R.id.resumeOverCellular);
          resumeOnCell.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  mRemoteService.setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR);
                  mRemoteService.requestContinueDownload();
                  mCellMessage.setVisibility(View.GONE);
              }
          });
  
      }
  
      /**
       * Called when the activity is first create; we wouldn't create a layout in
       * the case where we have the file and are moving to another activity
       * without downloading.
       */
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
  
          /**
           * Both downloading and validation make use of the "download" UI
           */
          initializeDownloadUI();
  
          /**
           * Before we do anything, are the files we expect already here and
           * delivered (presumably by Market) For free titles, this is probably
           * worth doing. (so no Market request is necessary)
           */
          if (!expansionFilesDelivered()) {
  
              try {
                  Intent launchIntent = MainActivity.this
                          .getIntent();
                  Intent intentToLaunchThisActivityFromNotification = new Intent(
                          MainActivity
                          .this, MainActivity.this.getClass());
                  intentToLaunchThisActivityFromNotification.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                          Intent.FLAG_ACTIVITY_CLEAR_TOP);
                  intentToLaunchThisActivityFromNotification.setAction(launchIntent.getAction());
  
                  if (launchIntent.getCategories() != null) {
                      for (String category : launchIntent.getCategories()) {
                          intentToLaunchThisActivityFromNotification.addCategory(category);
                      }
                  }
  
                  // Build PendingIntent used to open this activity from
                  // Notification
                  PendingIntent pendingIntent = PendingIntent.getActivity(
                          MainActivity.this,
                          0, intentToLaunchThisActivityFromNotification,
                          PendingIntent.FLAG_UPDATE_CURRENT);
                  // Request to start the download
                  int startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(this,
                          pendingIntent, ExpansionFileDownloaderService.class);
  
                  if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
                      // The DownloaderService has started downloading the files,
                      // show progress
                      initializeDownloadUI();
                      return;
                  } // otherwise, download not needed so we fall through to
                    // starting the movie
              } catch (NameNotFoundException e) {
                  Log.e(LOG_TAG, "Cannot find own package! MAYDAY!");
                  e.printStackTrace();
              }
  
          } else {
              validateXAPKZipFiles();
          }
  
      }
  
      /**
       * Connect the stub to our service on start.
       */
      @Override
      protected void onStart() {
          if (null != mDownloaderClientStub) {
              mDownloaderClientStub.connect(this);
          }
          super.onStart();
      }
  
      /**
       * Disconnect the stub from our service on stop
       */
      @Override
      protected void onStop() {
          if (null != mDownloaderClientStub) {
              mDownloaderClientStub.disconnect(this);
          }
          super.onStop();
      }
  
      /**
       * Critical implementation detail. In onServiceConnected we create the
       * remote service and marshaler. This is how we pass the client information
       * back to the service so the client can be properly notified of changes. We
       * must do this every time we reconnect to the service.
       */
      @Override
      public void onServiceConnected(Messenger m) {
          mRemoteService = DownloaderServiceMarshaller.CreateProxy(m);
          mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger());
      }
  
      /**
       * The download state should trigger changes in the UI --- it may be useful
       * to show the state as being indeterminate at times. This sample can be
       * considered a guideline.
       */
      @Override
      public void onDownloadStateChanged(int newState) {
          setState(newState);
          boolean showDashboard = true;
          boolean showCellMessage = false;
          boolean paused;
          boolean indeterminate;
          switch (newState) {
              case IDownloaderClient.STATE_IDLE:
                  // STATE_IDLE means the service is listening, so it's
                  // safe to start making calls via mRemoteService.
                  paused = false;
                  indeterminate = true;
                  break;
              case IDownloaderClient.STATE_CONNECTING:
              case IDownloaderClient.STATE_FETCHING_URL:
                  showDashboard = true;
                  paused = false;
                  indeterminate = true;
                  break;
              case IDownloaderClient.STATE_DOWNLOADING:
                  paused = false;
                  showDashboard = true;
                  indeterminate = false;
                  break;
  
              case IDownloaderClient.STATE_FAILED_CANCELED:
              case IDownloaderClient.STATE_FAILED:
              case IDownloaderClient.STATE_FAILED_FETCHING_URL:
              case IDownloaderClient.STATE_FAILED_UNLICENSED:
                  paused = true;
                  showDashboard = false;
                  indeterminate = false;
                  break;
              case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION:
              case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION:
                  showDashboard = false;
                  paused = true;
                  indeterminate = false;
                  showCellMessage = true;
                  break;
  
              case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
                  paused = true;
                  indeterminate = false;
                  break;
              case IDownloaderClient.STATE_PAUSED_ROAMING:
              case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE:
                  paused = true;
                  indeterminate = false;
                  break;
              case IDownloaderClient.STATE_COMPLETED:
                  showDashboard = false;
                  paused = false;
                  indeterminate = false;
                  validateXAPKZipFiles();
                  return;
              default:
                  paused = true;
                  indeterminate = true;
                  showDashboard = true;
          }
          int newDashboardVisibility = showDashboard ? View.VISIBLE : View.GONE;
          if (mDashboard.getVisibility() != newDashboardVisibility) {
              mDashboard.setVisibility(newDashboardVisibility);
          }
          int cellMessageVisibility = showCellMessage ? View.VISIBLE : View.GONE;
          if (mCellMessage.getVisibility() != cellMessageVisibility) {
              mCellMessage.setVisibility(cellMessageVisibility);
          }
  
          mPB.setIndeterminate(indeterminate);
          setButtonPausedState(paused);
      }
  
      /**
       * Sets the state of the various controls based on the progressinfo object
       * sent from the downloader service.
       */
      @Override
      public void onDownloadProgress(DownloadProgressInfo progress) {
          mAverageSpeed.setText(getString(R.string.kilobytes_per_second,
                  Helpers.getSpeedString(progress.mCurrentSpeed)));
          mTimeRemaining.setText(getString(R.string.time_remaining,
                  Helpers.getTimeRemaining(progress.mTimeRemaining)));
  
          progress.mOverallTotal = progress.mOverallTotal;
          mPB.setMax((int) (progress.mOverallTotal &gt;&gt; 8));
          mPB.setProgress((int) (progress.mOverallProgress &gt;&gt; 8));
          mProgressPercent.setText(Long.toString(progress.mOverallProgress
                  * 100 /
                  progress.mOverallTotal) + "%");
          mProgressFraction.setText(Helpers.getDownloadProgressString
                  (progress.mOverallProgress,
                          progress.mOverallTotal));
  
      try {
          ZipResourceFile expansionFile = APKExpansionSupport
                  .getAPKExpansionZipFile(this, 4, 0);
  
          ZipEntryRO[] zip = expansionFile.getAllEntries();
          Log.e("", "zip[0].isUncompressed() : " + zip[0].isUncompressed());
          Log.e("",
                  "mFile.getAbsolutePath() : "
                          + zip[0].mFile.getAbsolutePath());
          Log.e("", "mFileName : " + zip[0].mFileName);
          Log.e("", "mZipFileName : " + zip[0].mZipFileName);
          Log.e("", "mCompressedLength : " + zip[0].mCompressedLength);
  
          File file = new File(Environment.getExternalStorageDirectory()
                  .getAbsolutePath() + "");
          ZipHelper.unzip(zip[0].mZipFileName, file);
  
          if (file.exists()) {
              Log.e("", "unzipped : " + file.getAbsolutePath());
          }
  
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
  
      @Override
      protected void onDestroy() {
          this.mCancelValidation = true;
          super.onDestroy();
      }
  
  }
  </code></pre>