/**
   * Get the file list of the input path
   *
   * @param fileName the name of the file waiting to be parsed
   * @param walkType the type of walk routine, application can use CD_CHILD and CD_PARENT.
   * @return
   * @throws Exception Invalid input file name
   */
  public void parseDLNAFile(String fileName, boolean walkType) throws Exception {

    cancelNotify();

    if (walkType == CD_CHILD) {

      if (fileName == null || fileName.equals(mRoot)) {
        if (localLOGV) NetLog.d(TAG, "[parseDLNAFile][root][fileName]:" + fileName);
        parseRootDirectory();
        return;
      }

      REQUEST_MATCH_NUM = 0;
      if (isDevice(fileName) == true) {
        // device
        if (localLOGV) NetLog.d(TAG, "[parseDLNAFile][device][fileName]:" + fileName);
        parseDevice(fileName);
        return;

      } else {
        // content
        if (localLOGV) NetLog.d(TAG, "[parseDLNAFile][content][fileName]:" + fileName);
        parseContent(fileName);
        return;
      }
    } else {
      try {
        if (mTraceFile.empty() == false) {
          DLNATempFile dlnaFile = mTraceFile.pop();
          constructCurPath(dlnaFile.getName(), false);
          if (dlnaFile.getType() == DLNATempFile.TYPE_DEVICE) {
            if (localLOGV) NetLog.d(TAG, "[parseParent] pop device, next parse root");
            mCurPath = mRoot;
            // player.stop();

            parseRootDirectory();
            return;
          } else {
            dlnaFile = mTraceFile.peek();
            String name = dlnaFile.getName();
            if (dlnaFile.getType() == DLNATempFile.TYPE_DEVICE) {
              constructCurPath(dlnaFile.getName(), false);
              mTraceFile.pop();
              parseDevice(name);

            } else {
              parseContent(name);
            }
          }
        } else {
          if (localLOGV) NetLog.d(TAG, "[parseParent] stack is empty, next parse root");
          // player.stop();
          parseRootDirectory();
        }
      } catch (Exception e) {
        throw new Exception(e);
      }
    }
  }
  private boolean isDevice(String fileName) {
    if (fileName == null) return false;

    int total = mListDLNADeviceName.size();
    if (localLOGV) NetLog.d(TAG, "---mListDLNADeviceName total:" + total);
    for (int i = 0; i < total; i++) {
      if (mListDLNADeviceName.get(i).getName().equals(fileName)) {
        if (localLOGV) NetLog.d(TAG, "device name: " + mListDLNADeviceName.get(i).getName());
        return true;
      }
    }

    return false;
  }
  /**
   * Call back function, implement for com.mediatek.dlna.jar. Application should not use this API.
   *
   * @return.
   */
  public void notifyDeviceFound(FoundDeviceEvent event) {
    if (localLOGV) NetLog.d(TAG, "notifyDeviceFound");
    DLNADevice device = event.getDevice();
    String name = device.getName();

    DLNAFile devicefile = new DLNAFile(device, mRoot, mRoot);

    if (localLOGV) NetLog.d(TAG, "add device to device list");
    mListDLNADeviceName.add(devicefile);

    mNameDeviceTable.put(name, device);
    if (listener != null) {
      listener.onFileFound(new FileEvent(event, mListDLNADeviceName));
    }
  }
  /**
   * Print the scan result list which filter the same ssid by common logic. Applications used for
   * debug.
   */
  public void printAccessPointsList() {
    if (WifiConst.DummyMode) {
      return;
    }
    List<WifiAccessPoint> list;
    list = mAccessPoints;
    // null!!!
    if (list != null && list.size() >= 0) {
      NetLog.d(TAG, "Filtered by common logic,  getScanAccessPoints total ---- > " + list.size());
      for (int i = 0; i < list.size(); i++) {

        NetLog.d(TAG, "number[" + i + "] " + list.get(i).ssid);
      }
    }
    return;
  }
  /**
   * Enable the scan access point which has no security. This may result in the asynchronous
   * delivery of state change events. Applications should register the
   * 'SUPPLICANT_STATE_CHANGED_ACTION' and 'NETWORK_STATE_CHANGED_ACTION' receiver to receive the
   * state change events.
   *
   * @param One of the access point which want to link.
   * @return Return true if the operation succeed, false otherwise.
   */
  public boolean enableNetworkLink(ScanResult result) {
    if (WifiConst.DummyMode) {
      return false;
    }

    int networkId = -1;
    if (result == null) {
      return false;
    }

    if (isConfigured(result)) {
      if (localLOGV)
        NetLog.d(
            TAG, "[WifiAvailableAp][EnableNetworkLink]: " + result.SSID + " has been configured.");
      networkId = getNetworkId(result);
    } else {
      if (localLOGV)
        NetLog.d(
            TAG,
            "[WifiAvailableAp][EnableNetworkLink]: " + result.SSID + " has not been configured.");
      WifiConfiguration config = new WifiConfiguration();

      config.SSID = WifiUtil.convertToQuotedString(result.SSID);
      config.allowedKeyManagement.set(KeyMgmt.NONE);
      config.status = WifiConfiguration.Status.ENABLED;
      networkId = mWifiManager.addNetwork(config);
      mWifiManager.updateNetwork(config);
    }

    if (networkId == -1) {
      return false;
    }

    if (mWifiManager.enableNetwork(networkId, true)) {
      mWifiManager.reconnect();

      if (localLOGV)
        NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: enable network link success.");
      return true;
    }

    return false;
  }
  private void parseRootDirectory() {
    if (!isStartOnce) {
      mCurPath = mRoot;

      mListDLNADeviceName.clear();
      mNameDeviceTable.clear();
      if (localLOGV) NetLog.d(TAG, "start call DigitalMediaPlayer.getInstance()");
      player = DigitalMediaPlayer.getInstance();
      if (localLOGV) NetLog.d(TAG, "end call DigitalMediaPlayer.getInstance()");
      player.setDeviceEventListener(mDLNAManager);

      // player.stop();
      player.start();
      new Exception().printStackTrace();
      isStartOnce = true;
    } else {
      notifyDirect();
    }
    return;
  }
  /** Print the scan result list. Applications used for debug. */
  public void printScanList() {
    if (WifiConst.DummyMode) {
      return;
    }
    List<ScanResult> list;

    list = mWifiscanResultList;

    if (list == null) {
      return;
    }

    NetLog.d(TAG, "In common logic,  getScanResults total ---- > " + list.size());
    for (int i = 0; i < list.size(); i++) {

      //			Log.d(TAG, "number[" + i + "] "+ list.get(i).SSID + " " + list.get(i).toString());
      NetLog.d(TAG, "number[" + i + "] " + list.get(i).SSID);
    }

    return;
  }
  /**
   * Request a scan for access points. Return immediately. The availability of the results is made
   * known later by means of an asynchronous event sent on completion of the scan. Applications
   * should register the 'SCAN_READY' receiver to receive the scan ready message. If application
   * first time to use this function, it need to make sure the supplicant is ready. To check the
   * supplicant's status, application must call 'pingSupplicant' of WifiDongleControl class.
   *
   * @return Return true if the operation succeeded, else return false.
   */
  public boolean startScan() {
    if (WifiConst.DummyMode) {
      return false;
    }

    if (mScanReceiver == null || !getWifiStatus()) {
      if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][StartScan]: Wifi dongle status wrong.");
      return false;
    }

    pingSupplicantThread thread = new pingSupplicantThread();
    thread.start();

    return true;
  }
  /** Destroy options. */
  public void stopDlna() {
    if (localLOGV) NetLog.d(TAG, "destroy dlna Manager structure.");
    mListDLNADeviceName.clear();
    mNameDeviceTable.clear();
    mListContentName.clear();
    mTraceFile.clear();
    if (player != null) {
      new Exception().printStackTrace();
      player.stop();
    }

    isStartOnce = false;
    mDLNAManager = null;
    mCurPath = "/";
    listener = null;
  }
  /**
   * Call back function, implement for com.mediatek.dlna.jar. Application should not use this API.
   *
   * @return.
   */
  public void notifyDeviceLeft(LeftDeviceEvent event) {
    if (localLOGV) NetLog.d(TAG, "notifyDeviceLeft");
    String name = event.getDevice().getName();
    DLNADevice device = event.getDevice();

    int number = mListDLNADeviceName.size();
    for (int i = 0; i < number; i++) {
      DLNAFile tempDevice = mListDLNADeviceName.get(i);
      if (device.equals(tempDevice.getDevice())) {
        mListDLNADeviceName.remove(tempDevice);
        break;
      }
    }

    mNameDeviceTable.remove(name);
    if (listener != null) {
      listener.onFileLeft(new FileEvent(event, mListDLNADeviceName));
    }
  }
  private void parseContent(String fileName) throws Exception {
    int contentType = checkContent(fileName);
    Content content = null;
    if (contentType == CONTENT_UNKNOW) {
      if (localLOGV) NetLog.d(TAG, "Invalid parsing file name: " + fileName);
      throw new Exception();
    } else if (contentType == CONTENT_CHILD) {
      constructCurPath(fileName, true);
      content = mNameContentTable.get(fileName);
      DLNATempFile fileins = new DLNATempFile(content);
      mTraceFile.push(fileins);
    } else {
      content = mTraceFile.peek().getContent();
    }

    mListContentName.clear();

    // mNameContentTable.clear();
    server = content.getServer();
    server.setActionEventListener(mDLNAManager);

    if (localLOGV) NetLog.v(TAG, "start 2 browse : " + System.currentTimeMillis());

    REQUEST_MATCH_NUM = 0;
    currentID = content.getObjectId();
    mBrowseHandle =
        server.browse(
            content.getObjectId(),
            MediaServer.BrowseFlag.BrowseDirectChildren,
            REQUEST_MATCH_NUM,
            BROWSE_REQUEST,
            MediaServer.FILTER_BASIC_INFO,
            MediaServer.SORT_ASCENDING_CRITERIA_TITLE);

    if (localLOGV) NetLog.v(TAG, "end 2 browse : " + System.currentTimeMillis());
    return;
  }
 /**
  * Call back function, implement for com.mediatek.dlna.jar. Application should not use this API.
  *
  * @return.
  */
 public void notifyContentFailed(FailedContentEvent event) {
   if (localLOGV) NetLog.d(TAG, "notifyContentFailed");
   if (listener != null) {
     listener.onFileFailed(new FileEvent(event));
   }
 }
  /**
   * Enable the scan access point which has security. This may result in the asynchronous delivery
   * of state change events. Applications should register the 'SUPPLICANT_STATE_CHANGED_ACTION' and
   * 'NETWORK_STATE_CHANGED_ACTION' receiver to receive the state change events.
   *
   * @param One of the access point which want to link.
   * @return Return true if the operation succeed, false otherwise.
   */
  public boolean enableNetworkLink(ScanResult result, String sectretKey) {
    if (WifiConst.DummyMode) {
      return false;
    }

    int networkId = -1;
    int keyLength = sectretKey.length();
    WifiConfiguration config = new WifiConfiguration();
    if (localLOGV)
      NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: Enable Access Point with Password.");
    if (result == null || sectretKey == null) {
      return false;
    }

    WifiUtil.clearConfiguration(config);
    config.status = WifiConfiguration.Status.ENABLED;

    config.SSID = WifiUtil.convertToQuotedString(result.SSID);

    int encrypt = WifiUtil.getEncrypt(result);

    if (encrypt == WifiConst.W_ENCRYPT_WEP) {
      if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: WEP encrypt.");
      if ((keyLength == 5 || keyLength == 10 || keyLength == 13 || keyLength == 26)
          && sectretKey.matches("[0-9A-Fa-f]*")) {
        config.wepKeys[0] = sectretKey;
      } else {
        config.wepKeys[0] = '"' + sectretKey + '"';
      }
    } else {
      if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: other encrypt.");
      if (sectretKey.matches("[0-9A-Fa-f]{64}")) {
        config.preSharedKey = sectretKey;
      } else {
        config.preSharedKey = "\"" + sectretKey + "\"";
      }
    }

    int ConfirmType = WifiUtil.getConfirmType(result);
    switch (ConfirmType) {
      case WifiConst.W_CONFIRM_OPEN:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_CONFIRM_OPEN");
        config.allowedKeyManagement.set(KeyMgmt.NONE);
        config.allowedAuthAlgorithms.clear();
        config.allowedPairwiseCiphers.set(PairwiseCipher.NONE);
        config.allowedGroupCiphers.clear();
        config.allowedProtocols.clear();
        break;

      case WifiConst.W_CONFIRM_WEP:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_CONFIRM_WEP");
        config.allowedKeyManagement.set(KeyMgmt.NONE);
        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
        config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
        config.allowedPairwiseCiphers.set(PairwiseCipher.NONE);

        if (keyLength == 5 || keyLength == 10) {
          config.allowedGroupCiphers.set(GroupCipher.WEP40);
        } else {
          config.allowedGroupCiphers.set(GroupCipher.WEP104);
        }

        config.allowedProtocols.clear();
        break;

      case WifiConst.W_CONFIRM_WPA_PSK:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_CONFIRM_WPA_PSK");
        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
        config.allowedProtocols.set(Protocol.WPA);
        config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
        break;

      case WifiConst.W_CONFIRM_WPA2_PSK:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_CONFIRM_WPA2_PSK");
        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
        config.allowedProtocols.set(Protocol.RSN);
        config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
        break;

      case WifiConst.W_CONFIRM_PSK_AUTO:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_CONFIRM_PSK_AUTO");
        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
        config.allowedProtocols.set(Protocol.RSN);
        config.allowedProtocols.set(Protocol.WPA);
        config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
        break;

      case WifiConst.W_CONFIRM_WPA_EAP:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_CONFIRM_WPA_EAP");
        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
        config.allowedProtocols.set(Protocol.WPA);
        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
        break;

      case WifiConst.W_CONFIRM_WPA2_EAP:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_CONFIRM_WPA2_EAP");
        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
        config.allowedProtocols.set(Protocol.RSN);
        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
        break;

      case WifiConst.W_CONFIRM_EAP_AUTO:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_CONFIRM_EAP_AUTO");
        config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
        config.allowedProtocols.set(Protocol.RSN);
        config.allowedProtocols.set(Protocol.WPA);
        config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
        break;

      default:
        break;
    }

    switch (encrypt) {
      case WifiConst.W_ENCRYPT_WEP:
        break;

      case WifiConst.W_ENCRYPT_TKIP:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_ENCRYPT_TKIP");
        config.allowedGroupCiphers.set(GroupCipher.TKIP);
        config.allowedPairwiseCiphers.set(PairwiseCipher.TKIP);
        break;

      case WifiConst.W_ENCRYPT_AES:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_ENCRYPT_AES");
        config.allowedGroupCiphers.set(GroupCipher.CCMP);
        config.allowedPairwiseCiphers.set(PairwiseCipher.CCMP);
        break;

      case WifiConst.W_ENCRYPT_TKIP_AES:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_ENCRYPT_TKIP_AES");
        config.allowedGroupCiphers.set(GroupCipher.TKIP);
        config.allowedGroupCiphers.set(GroupCipher.CCMP);
        config.allowedPairwiseCiphers.set(PairwiseCipher.TKIP);
        config.allowedPairwiseCiphers.set(PairwiseCipher.CCMP);
        break;

      default:
        if (localLOGV) NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: W_ENCRYPT default.");
        break;
    }

    networkId = mWifiManager.addNetwork(config);
    if (localLOGV)
      NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: 398  networkId -> " + networkId);
    mWifiManager.updateNetwork(config);

    if (networkId == -1) {
      return false;
    }

    if (mWifiManager.enableNetwork(networkId, true)) {
      if (localLOGV)
        NetLog.d(TAG, "[WifiAvailableAp][EnableNetworkLink]: Enable network link SUCCESS.");

      mWifiManager.reconnect();

      return true;
    }

    return false;
  }