<commit_before>package com.mapswithme.maps;

import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.location.Location;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;

import com.mapswithme.maps.base.MapsWithMeBaseListActivity;
import com.mapswithme.maps.location.LocationService;
import com.mapswithme.maps.search.SearchController;
import com.mapswithme.util.InputUtils;
import com.mapswithme.util.Language;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.Utils;
import com.mapswithme.util.statistics.Statistics;


public class SearchActivity extends MapsWithMeBaseListActivity implements LocationService.Listener
{
  private static String TAG = "SearchActivity";
  public static final String SEARCH_RESULT = "search_result";

  public static final String EXTRA_SCOPE = "search_scope";
  public static final String EXTRA_QUERY = "search_query";

  public static void startForSearch(Context context, String query, int scope)
  {
    final Intent i = new Intent(context, SearchActivity.class);
    i.putExtra(EXTRA_SCOPE, scope).putExtra(EXTRA_QUERY, query);
    context.startActivity(i);
  }

  public static void startForSearch(Context context, String query)
  {
    final Intent i = new Intent(context, SearchActivity.class);
    i.putExtra(EXTRA_QUERY, query);
    context.startActivity(i);
  }

  private static class SearchAdapter extends BaseAdapter
  {
    private final SearchActivity m_context;
    private final LayoutInflater m_inflater;


    private final Resources m_resource;
    private final String m_packageName;

    private static final String m_categories[] = {
      "food",
      "shop",
      "hotel",
      "tourism",
      "entertainment",
      "atm",
      "bank",
      "transport",
      "fuel",
      "parking",
      "pharmacy",
      "hospital",
      "toilet",
      "post",
      "police"
    };

    private int m_count = -1;
    private int m_resultID = 0;

    public SearchAdapter(SearchActivity context)
    {
      m_context = context;
      m_inflater = (LayoutInflater) m_context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

      m_resource = m_context.getResources();
      m_packageName = m_context.getApplicationContext().getPackageName();
    }

    private static final int CATEGORY_TYPE = 0;
    private static final int RESULT_TYPE = 1;
    private static final int MESSAGE_TYPE = 2;


    private boolean isShowCategories()
    {
      return m_context.isShowCategories();
    }

    private String getWarningForEmptyResults()
    {
      // First try to show warning if no country downloaded for viewport.
      if (m_context.m_searchMode != AROUND_POSITION)
      {
        final String name = m_context.getViewportCountryNameIfAbsent();
        if (name != null)
          return String.format(m_context.getString(R.string.download_viewport_country_to_search), name);
      }

      // If now position detected or no country downloaded for position.
      if (m_context.m_searchMode != IN_VIEWPORT)
      {
        final Location loc = m_context.m_location.getLastKnown();
        if (loc == null)
        {
          return m_context.getString(R.string.unknown_current_position);
        }
        else
        {
          final String name = m_context.getCountryNameIfAbsent(loc.getLatitude(), loc.getLongitude());
          if (name != null)
            return String.format(m_context.getString(R.string.download_location_country), name);
        }
      }

      return null;
    }

    @Override
    public boolean isEnabled(int position)
    {
      return (isShowCategories() || m_count > 0);
    }

    @Override
    public int getItemViewType(int position)
    {
      if (isShowCategories())
        return CATEGORY_TYPE;
      else
        return (m_count == 0 ? MESSAGE_TYPE : RESULT_TYPE);
    }

    @Override
    public int getViewTypeCount()
    {
      return 3;
    }

    @Override
    public int getCount()
    {
      if (isShowCategories())
        return m_categories.length;
      else if (m_count < 0)
        return 0;
      else
        return (m_count == 0 ? 1 : m_count + 1); // first additional item is "Show all result for"
    }

    @Override
    public Object getItem(int position)
    {
      return position;
    }

    @Override
    public long getItemId(int position)
    {
      return position;
    }

    private static class ViewHolder
    {
      public TextView m_name = null;
      public TextView m_country = null;
      public TextView m_distance = null;
      public TextView m_amenity = null;
      public ArrowImage m_flag = null;

      void initFromView(View v, int type)
      {
        m_name = (TextView) v.findViewById(R.id.name);

        if (type != MESSAGE_TYPE)
          m_flag = (ArrowImage) v.findViewById(R.id.country_flag);

        if (type != CATEGORY_TYPE)
          m_country = (TextView) v.findViewById(R.id.country);

        if (type == RESULT_TYPE)
        {
          m_distance = (TextView) v.findViewById(R.id.distance);
          m_amenity = (TextView) v.findViewById(R.id.amenity);
        }
      }
    }

    /// Created from native code.
    public static class SearchResult
    {
      public String m_name;
      public String m_country;
      public String m_amenity;

      public String m_flag;
      public String m_distance;
      public double m_azimut;

      /// 0 - suggestion result
      /// 1 - feature result
      public int m_type;

      // Called from native code
      @SuppressWarnings("unused")
      public SearchResult(String suggestion)
      {
        m_name = suggestion;
        m_type = 0;
      }

      // Called from native code
      @SuppressWarnings("unused")
      public SearchResult(String name, String country, String amenity,
                          String flag, String distance, double azimut)
      {
        m_name = name;
        m_country = country;
        m_amenity = amenity;

        m_flag = flag;
        m_distance = distance;
        m_azimut = azimut;

        m_type = 1;
      }
    }

    private String getCategoryName(String strID)
    {
      final int id = m_resource.getIdentifier(strID, "string", m_packageName);
      if (id > 0)
      {
        return m_context.getString(id);
      }
      else
      {
        Log.e(TAG, "Failed to get resource id from: " + strID);
        return null;
      }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
      ViewHolder holder = null;

      if (convertView == null)
      {
        holder = new ViewHolder();

        switch (getItemViewType(position))
        {
        case CATEGORY_TYPE:
          convertView = m_inflater.inflate(R.layout.search_category_item, null);
          holder.initFromView(convertView, CATEGORY_TYPE);
          break;

        case RESULT_TYPE:
          convertView = m_inflater.inflate(R.layout.search_item, null);
          holder.initFromView(convertView, RESULT_TYPE);
          break;

        case MESSAGE_TYPE:
          convertView = m_inflater.inflate(R.layout.search_message_item, null);
          holder.initFromView(convertView, MESSAGE_TYPE);
          break;
        }

        convertView.setTag(holder);
      }
      else
      {
        holder = (ViewHolder) convertView.getTag();
      }

      if (isShowCategories())
      {
        // Show categories list.

        final String strID = m_categories[position];

        holder.m_name.setText(getCategoryName(strID));
        holder.m_flag.setFlag(m_resource, m_packageName, strID);
      }
      else if (m_count == 0)
      {
        // Show warning message.

        holder.m_name.setText(m_context.getString(R.string.no_search_results_found));

        final String msg = getWarningForEmptyResults();
        if (msg != null)
        {
          holder.m_country.setVisibility(View.VISIBLE);
          holder.m_country.setText(msg);
        }
        else
          holder.m_country.setVisibility(View.GONE);
      }
      else
      {
        // title item with "Show all" text
        if (position == 0)
        {
          holder.m_name.setText(m_context.getString(R.string.search_show_on_map));
          holder.m_country.setText(null);
          holder.m_amenity.setText(null);
          holder.m_distance.setText(null);
          holder.m_flag.clear();

          return convertView;
        }
        // 0 index is for multiple result
        // so real result are from 1
        --position;

        // Show search results.

        final SearchResult r = m_context.getResult(position, m_resultID);
        if (r != null)
        {
          holder.m_name.setText(r.m_name);
          holder.m_country.setText(r.m_country);
          holder.m_amenity.setText(r.m_amenity);
          holder.m_distance.setText(r.m_distance);

          if (r.m_type == 1)
          {
            if (r.m_flag != null && r.m_flag.length() > 0 && r.m_azimut < 0.0)
              holder.m_flag.setFlag(m_resource, m_packageName, r.m_flag);
            else
              holder.m_flag.setAzimut(r.m_azimut);
          }
          else
            holder.m_flag.clear();
        }
      }

      return convertView;
    }

    /// Update list data.
    public void updateData(int count, int resultID)
    {
      m_count = count;
      m_resultID = resultID;

      notifyDataSetChanged();
    }

    public void updateData()
    {
      notifyDataSetChanged();
    }

    public void updateCategories()
    {
      m_count = -1;
      updateData();
    }

    /// Show tapped country or get suggestion or get category to search.
    /// @return Suggestion string with space in the end (for full match purpose).
    public String onItemClick(int position)
    {
      if (isShowCategories())
      {

        final String category = getCategoryName(m_categories[position]);
        Statistics.INSTANCE.trackSearchCategoryClicked(m_context, category);

        return category + ' ';
      }
      else
      {
        if (m_count > 0)
        {
          // Show all items was clicked
          if (position == 0)
          {
            SearchActivity.nativeShowAllSearchResults();
            return null;
          }

          // Specific result was clicked
          final int resIndex = position - 1;
          final SearchResult r = m_context.getResult(resIndex, m_resultID);
          if (r != null)
          {
            if (r.m_type == 1)
            {
              // show country and close activity
              SearchActivity.nativeShowItem(resIndex);
              return null;
            }
            else
            {
              // advise suggestion
              return r.m_name + ' ';
            }
          }
        }
      }


      // close activity in case of any error
      return null;
    }
  }

  private String getSearchString()
  {
    return mSearchBox.getText().toString();
  }

  private boolean isShowCategories()
  {
    return (getSearchString().length() == 0);
  }

  private LocationService m_location;
  // Search views
  private EditText mSearchBox;
  private ProgressBar mSearchProgress;
  private View mClearQueryBtn;
  private View mVoiceInput;
  private View mSearchIcon;
  //

  private RadioGroup mSearchScopeGroup;

  @SuppressLint("NewApi")
  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);

    if (Utils.apiEqualOrGreaterThan(11))
    {
      final ActionBar actionBar = getActionBar();
      if (actionBar != null)
        actionBar.hide();
    }

    m_location = ((MWMApplication) getApplication()).getLocationService();

    setContentView(R.layout.search_list_view);
    setUpView();
    // Create search list view adapter.
    setListAdapter(new SearchAdapter(this));

    nativeConnect();

    //checking search intent
    final Intent intent = getIntent();
    if (intent != null && intent.hasExtra(EXTRA_QUERY))
    {
      mSearchBox.setText(intent.getStringExtra(EXTRA_QUERY));
      if (intent.hasExtra(EXTRA_SCOPE))
        setSearchGroupSelectionByMode(intent.getIntExtra(EXTRA_SCOPE, 0));
      runSearch();
    }
  }

  private void setSearchGroupSelectionByMode(final int savedSearchMode)
  {
    switch (savedSearchMode)
    {
      case ALL:         mSearchScopeGroup.check(R.id.search_scope_everywhere); break;
      case IN_VIEWPORT: mSearchScopeGroup.check(R.id.search_scope_on_screen);  break;
      default:          mSearchScopeGroup.check(R.id.search_scope_near);       break;
    }
  }

  @Override
  protected void onDestroy()
  {
    nativeDisconnect();
    super.onDestroy();
  }

  private void setUpView()
  {
    mVoiceInput = findViewById(R.id.search_voice_input);
    mSearchIcon = findViewById(R.id.search_icon);
    mSearchProgress = (ProgressBar) findViewById(R.id.search_progress);
    mClearQueryBtn = findViewById(R.id.search_image_clear);
    mClearQueryBtn.setOnClickListener(new OnClickListener()
    {
      @Override
      public void onClick(View v)
      {
        mSearchBox.getText().clear();
      }
    });

    // Initialize search edit box processor.
    mSearchBox = (EditText) findViewById(R.id.search_text_query);
    mSearchBox.addTextChangedListener(new TextWatcher()
    {
      @Override
      public void afterTextChanged(Editable s)
      {
        if (runSearch() == QUERY_EMPTY)
          showCategories();

        if (s.length() == 0) // enable voice input
        {
          UiUtils.invisible(mClearQueryBtn);
          UiUtils.hideIf(!InputUtils.isVoiceInputSupported(SearchActivity.this), mVoiceInput);
        }
        else // show clear cross
        {
          UiUtils.show(mClearQueryBtn);
          UiUtils.invisible(mVoiceInput);
        }
      }

      @Override
      public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
      {
      }

      @Override
      public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3)
      {
      }
    });

    setUpSearchModes();

    mVoiceInput.setOnClickListener(new OnClickListener()
    {
      @Override
      public void onClick(View v)
      {
        final Intent vrIntent = InputUtils.createIntentForVoiceRecognition(getResources().getString(R.string.search_map));
        startActivityForResult(vrIntent, RC_VOICE_RECOGNITIN);
      }
    });

    getListView().setOnScrollListener(new OnScrollListener()
    {
      @Override
      public void onScrollStateChanged(AbsListView view, int scrollState)
      {
        // Hide keyboard when user starts scroll
        InputUtils.hideKeyboard(mSearchBox);

        // Hacky way to remove focus from only edittext at activity
        mSearchBox.setFocusableInTouchMode(false);
        mSearchBox.setFocusable(false);
        mSearchBox.setFocusableInTouchMode(true);
        mSearchBox.setFocusable(true);
      }

      @Override
      public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
      {}
    });
  }

  private void setUpSearchModes()
  {
    // Initialize search modes group
    mSearchScopeGroup = (RadioGroup)findViewById(R.id.search_scope);
    // Default mode is AROUND_POSITION
    setSearchGroupSelectionByMode(MWMApplication.get().nativeGetInt(SEARCH_MODE_SETTING, AROUND_POSITION));
    mSearchScopeGroup.setOnCheckedChangeListener(new OnCheckedChangeListener()
    {
      @Override
      public void onCheckedChanged(RadioGroup group, int checkedId)
      {
        int mode;

        if (R.id.search_scope_everywhere == checkedId)
          mode = ALL;
        else if (R.id.search_scope_near == checkedId)
          mode = AROUND_POSITION;
        else if (R.id.search_scope_on_screen == checkedId)
          mode = IN_VIEWPORT;
        else
          throw new IllegalArgumentException("Unknown Id: " + checkedId);

        getMwmApplication().nativeSetInt(SEARCH_MODE_SETTING, mode);
        runSearch(mode);
      }
    });
  }

  @Override
  protected void onResume()
  {
    super.onResume();

    // Reset current mode flag - start first search.
    m_flags = 0;
    m_north = -1.0;

    m_location.startUpdate(this);

    // do the search immediately after resume
    Utils.setStringAndCursorToEnd(mSearchBox, getLastQuery());
    mSearchBox.requestFocus();
  }

  @Override
  protected void onPause()
  {
    m_location.stopUpdate(this);

    super.onPause();
  }

  private SearchAdapter getSA()
  {
    return (SearchAdapter) getListView().getAdapter();
  }

  @Override
  protected void onListItemClick(ListView l, View v, int position, long id)
  {
    super.onListItemClick(l, v, position, id);
    final String suggestion = getSA().onItemClick(position);
    if (suggestion == null)
    {
      presentResult(v, position);
    }
    else
    {
      // set suggestion string and run search (this call invokes runSearch)
      runSearch(suggestion);
    }
  }

  private void presentResult(View v, int position)
  {
    if (MWMApplication.get().isProVersion())
    {
      finish();

      final SearchAdapter.ViewHolder vh = (SearchAdapter.ViewHolder) v.getTag();

      final String queryTitle = vh.m_name.getText().toString().trim();
      final String showOnMapTitle = getString(R.string.search_show_on_map).trim();

      if (showOnMapTitle.equalsIgnoreCase(queryTitle))
        SearchController.get().setQuery(mSearchBox.getText().toString());
      else
        SearchController.get().setQuery(queryTitle);

      MWMActivity.startWithSearchResult(this, position != 0);
    }
    else
    {
      // Should we add something more attractive?
      Utils.toastShortcut(this, R.string.search_available_in_pro_version);
    }
  }

  @Override
  public void onBackPressed()
  {
    if (!isShowCategories())
    {
      // invokes runSearch with empty string - adapter will show categories
      mSearchBox.setText("");
    }
    else
    {
      super.onBackPressed();
      SearchController.get().cancel();
    }
  }

  /// Current position.
  private double m_lat;
  private double m_lon;
  private double m_north = -1.0;

  /// @name These constants should be equal with
  /// Java_com_mapswithme_maps_SearchActivity_nativeRunSearch routine.
  //@{
  private static final int NOT_FIRST_QUERY = 1;
  private static final int HAS_POSITION = 2;
  //@}
  private int m_flags = 0;

  private void updateDistance()
  {
    getSA().updateData();
  }

  private void showCategories()
  {<commit_msg>Close search screen in 2 backs.<commit_after>package com.mapswithme.maps;

import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.location.Location;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;

import com.mapswithme.maps.base.MapsWithMeBaseListActivity;
import com.mapswithme.maps.location.LocationService;
import com.mapswithme.maps.search.SearchController;
import com.mapswithme.util.InputUtils;
import com.mapswithme.util.Language;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.Utils;
import com.mapswithme.util.statistics.Statistics;


public class SearchActivity extends MapsWithMeBaseListActivity implements LocationService.Listener
{
  private static String TAG = "SearchActivity";
  public static final String SEARCH_RESULT = "search_result";

  public static final String EXTRA_SCOPE = "search_scope";
  public static final String EXTRA_QUERY = "search_query";

  public static void startForSearch(Context context, String query, int scope)
  {
    final Intent i = new Intent(context, SearchActivity.class);
    i.putExtra(EXTRA_SCOPE, scope).putExtra(EXTRA_QUERY, query);
    context.startActivity(i);
  }

  public static void startForSearch(Context context, String query)
  {
    final Intent i = new Intent(context, SearchActivity.class);
    i.putExtra(EXTRA_QUERY, query);
    context.startActivity(i);
  }

  private static class SearchAdapter extends BaseAdapter
  {
    private final SearchActivity m_context;
    private final LayoutInflater m_inflater;


    private final Resources m_resource;
    private final String m_packageName;

    private static final String m_categories[] = {
      "food",
      "shop",
      "hotel",
      "tourism",
      "entertainment",
      "atm",
      "bank",
      "transport",
      "fuel",
      "parking",
      "pharmacy",
      "hospital",
      "toilet",
      "post",
      "police"
    };

    private int m_count = -1;
    private int m_resultID = 0;

    public SearchAdapter(SearchActivity context)
    {
      m_context = context;
      m_inflater = (LayoutInflater) m_context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

      m_resource = m_context.getResources();
      m_packageName = m_context.getApplicationContext().getPackageName();
    }

    private static final int CATEGORY_TYPE = 0;
    private static final int RESULT_TYPE = 1;
    private static final int MESSAGE_TYPE = 2;


    private boolean isShowCategories()
    {
      return m_context.isShowCategories();
    }

    private String getWarningForEmptyResults()
    {
      // First try to show warning if no country downloaded for viewport.
      if (m_context.m_searchMode != AROUND_POSITION)
      {
        final String name = m_context.getViewportCountryNameIfAbsent();
        if (name != null)
          return String.format(m_context.getString(R.string.download_viewport_country_to_search), name);
      }

      // If now position detected or no country downloaded for position.
      if (m_context.m_searchMode != IN_VIEWPORT)
      {
        final Location loc = m_context.m_location.getLastKnown();
        if (loc == null)
        {
          return m_context.getString(R.string.unknown_current_position);
        }
        else
        {
          final String name = m_context.getCountryNameIfAbsent(loc.getLatitude(), loc.getLongitude());
          if (name != null)
            return String.format(m_context.getString(R.string.download_location_country), name);
        }
      }

      return null;
    }

    @Override
    public boolean isEnabled(int position)
    {
      return (isShowCategories() || m_count > 0);
    }

    @Override
    public int getItemViewType(int position)
    {
      if (isShowCategories())
        return CATEGORY_TYPE;
      else
        return (m_count == 0 ? MESSAGE_TYPE : RESULT_TYPE);
    }

    @Override
    public int getViewTypeCount()
    {
      return 3;
    }

    @Override
    public int getCount()
    {
      if (isShowCategories())
        return m_categories.length;
      else if (m_count < 0)
        return 0;
      else
        return (m_count == 0 ? 1 : m_count + 1); // first additional item is "Show all result for"
    }

    @Override
    public Object getItem(int position)
    {
      return position;
    }

    @Override
    public long getItemId(int position)
    {
      return position;
    }

    private static class ViewHolder
    {
      public TextView m_name = null;
      public TextView m_country = null;
      public TextView m_distance = null;
      public TextView m_amenity = null;
      public ArrowImage m_flag = null;

      void initFromView(View v, int type)
      {
        m_name = (TextView) v.findViewById(R.id.name);

        if (type != MESSAGE_TYPE)
          m_flag = (ArrowImage) v.findViewById(R.id.country_flag);

        if (type != CATEGORY_TYPE)
          m_country = (TextView) v.findViewById(R.id.country);

        if (type == RESULT_TYPE)
        {
          m_distance = (TextView) v.findViewById(R.id.distance);
          m_amenity = (TextView) v.findViewById(R.id.amenity);
        }
      }
    }

    /// Created from native code.
    public static class SearchResult
    {
      public String m_name;
      public String m_country;
      public String m_amenity;

      public String m_flag;
      public String m_distance;
      public double m_azimut;

      /// 0 - suggestion result
      /// 1 - feature result
      public int m_type;

      // Called from native code
      @SuppressWarnings("unused")
      public SearchResult(String suggestion)
      {
        m_name = suggestion;
        m_type = 0;
      }

      // Called from native code
      @SuppressWarnings("unused")
      public SearchResult(String name, String country, String amenity,
                          String flag, String distance, double azimut)
      {
        m_name = name;
        m_country = country;
        m_amenity = amenity;

        m_flag = flag;
        m_distance = distance;
        m_azimut = azimut;

        m_type = 1;
      }
    }

    private String getCategoryName(String strID)
    {
      final int id = m_resource.getIdentifier(strID, "string", m_packageName);
      if (id > 0)
      {
        return m_context.getString(id);
      }
      else
      {
        Log.e(TAG, "Failed to get resource id from: " + strID);
        return null;
      }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
      ViewHolder holder = null;

      if (convertView == null)
      {
        holder = new ViewHolder();

        switch (getItemViewType(position))
        {
        case CATEGORY_TYPE:
          convertView = m_inflater.inflate(R.layout.search_category_item, null);
          holder.initFromView(convertView, CATEGORY_TYPE);
          break;

        case RESULT_TYPE:
          convertView = m_inflater.inflate(R.layout.search_item, null);
          holder.initFromView(convertView, RESULT_TYPE);
          break;

        case MESSAGE_TYPE:
          convertView = m_inflater.inflate(R.layout.search_message_item, null);
          holder.initFromView(convertView, MESSAGE_TYPE);
          break;
        }

        convertView.setTag(holder);
      }
      else
      {
        holder = (ViewHolder) convertView.getTag();
      }

      if (isShowCategories())
      {
        // Show categories list.

        final String strID = m_categories[position];

        holder.m_name.setText(getCategoryName(strID));
        holder.m_flag.setFlag(m_resource, m_packageName, strID);
      }
      else if (m_count == 0)
      {
        // Show warning message.

        holder.m_name.setText(m_context.getString(R.string.no_search_results_found));

        final String msg = getWarningForEmptyResults();
        if (msg != null)
        {
          holder.m_country.setVisibility(View.VISIBLE);
          holder.m_country.setText(msg);
        }
        else
          holder.m_country.setVisibility(View.GONE);
      }
      else
      {
        // title item with "Show all" text
        if (position == 0)
        {
          holder.m_name.setText(m_context.getString(R.string.search_show_on_map));
          holder.m_country.setText(null);
          holder.m_amenity.setText(null);
          holder.m_distance.setText(null);
          holder.m_flag.clear();

          return convertView;
        }
        // 0 index is for multiple result
        // so real result are from 1
        --position;

        // Show search results.

        final SearchResult r = m_context.getResult(position, m_resultID);
        if (r != null)
        {
          holder.m_name.setText(r.m_name);
          holder.m_country.setText(r.m_country);
          holder.m_amenity.setText(r.m_amenity);
          holder.m_distance.setText(r.m_distance);

          if (r.m_type == 1)
          {
            if (r.m_flag != null && r.m_flag.length() > 0 && r.m_azimut < 0.0)
              holder.m_flag.setFlag(m_resource, m_packageName, r.m_flag);
            else
              holder.m_flag.setAzimut(r.m_azimut);
          }
          else
            holder.m_flag.clear();
        }
      }

      return convertView;
    }

    /// Update list data.
    public void updateData(int count, int resultID)
    {
      m_count = count;
      m_resultID = resultID;

      notifyDataSetChanged();
    }

    public void updateData()
    {
      notifyDataSetChanged();
    }

    public void updateCategories()
    {
      m_count = -1;
      updateData();
    }

    /// Show tapped country or get suggestion or get category to search.
    /// @return Suggestion string with space in the end (for full match purpose).
    public String onItemClick(int position)
    {
      if (isShowCategories())
      {

        final String category = getCategoryName(m_categories[position]);
        Statistics.INSTANCE.trackSearchCategoryClicked(m_context, category);

        return category + ' ';
      }
      else
      {
        if (m_count > 0)
        {
          // Show all items was clicked
          if (position == 0)
          {
            SearchActivity.nativeShowAllSearchResults();
            return null;
          }

          // Specific result was clicked
          final int resIndex = position - 1;
          final SearchResult r = m_context.getResult(resIndex, m_resultID);
          if (r != null)
          {
            if (r.m_type == 1)
            {
              // show country and close activity
              SearchActivity.nativeShowItem(resIndex);
              return null;
            }
            else
            {
              // advise suggestion
              return r.m_name + ' ';
            }
          }
        }
      }


      // close activity in case of any error
      return null;
    }
  }

  private String getSearchString()
  {
    return mSearchBox.getText().toString();
  }

  private boolean isShowCategories()
  {
    return (getSearchString().length() == 0);
  }

  private LocationService m_location;
  // Search views
  private EditText mSearchBox;
  private ProgressBar mSearchProgress;
  private View mClearQueryBtn;
  private View mVoiceInput;
  private View mSearchIcon;
  //

  private RadioGroup mSearchScopeGroup;

  @SuppressLint("NewApi")
  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);

    if (Utils.apiEqualOrGreaterThan(11))
    {
      final ActionBar actionBar = getActionBar();
      if (actionBar != null)
        actionBar.hide();
    }

    m_location = ((MWMApplication) getApplication()).getLocationService();

    setContentView(R.layout.search_list_view);
    setUpView();
    // Create search list view adapter.
    setListAdapter(new SearchAdapter(this));

    nativeConnect();

    //checking search intent
    final Intent intent = getIntent();
    if (intent != null && intent.hasExtra(EXTRA_QUERY))
    {
      mSearchBox.setText(intent.getStringExtra(EXTRA_QUERY));
      if (intent.hasExtra(EXTRA_SCOPE))
        setSearchGroupSelectionByMode(intent.getIntExtra(EXTRA_SCOPE, 0));
      runSearch();
    }
  }

  private void setSearchGroupSelectionByMode(final int savedSearchMode)
  {
    switch (savedSearchMode)
    {
      case ALL:         mSearchScopeGroup.check(R.id.search_scope_everywhere); break;
      case IN_VIEWPORT: mSearchScopeGroup.check(R.id.search_scope_on_screen);  break;
      default:          mSearchScopeGroup.check(R.id.search_scope_near);       break;
    }
  }

  @Override
  protected void onDestroy()
  {
    nativeDisconnect();
    super.onDestroy();
  }

  private void setUpView()
  {
    mVoiceInput = findViewById(R.id.search_voice_input);
    mSearchIcon = findViewById(R.id.search_icon);
    mSearchProgress = (ProgressBar) findViewById(R.id.search_progress);
    mClearQueryBtn = findViewById(R.id.search_image_clear);
    mClearQueryBtn.setOnClickListener(new OnClickListener()
    {
      @Override
      public void onClick(View v)
      {
        mSearchBox.getText().clear();
      }
    });

    // Initialize search edit box processor.
    mSearchBox = (EditText) findViewById(R.id.search_text_query);
    mSearchBox.addTextChangedListener(new TextWatcher()
    {
      @Override
      public void afterTextChanged(Editable s)
      {
        if (runSearch() == QUERY_EMPTY)
          showCategories();

        if (s.length() == 0) // enable voice input
        {
          UiUtils.invisible(mClearQueryBtn);
          UiUtils.hideIf(!InputUtils.isVoiceInputSupported(SearchActivity.this), mVoiceInput);
        }
        else // show clear cross
        {
          UiUtils.show(mClearQueryBtn);
          UiUtils.invisible(mVoiceInput);
        }
      }

      @Override
      public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
      {
      }

      @Override
      public void onTextChanged(CharSequence s, int arg1, int arg2, int arg3)
      {
      }
    });

    setUpSearchModes();

    mVoiceInput.setOnClickListener(new OnClickListener()
    {
      @Override
      public void onClick(View v)
      {
        final Intent vrIntent = InputUtils.createIntentForVoiceRecognition(getResources().getString(R.string.search_map));
        startActivityForResult(vrIntent, RC_VOICE_RECOGNITIN);
      }
    });

    getListView().setOnScrollListener(new OnScrollListener()
    {
      @Override
      public void onScrollStateChanged(AbsListView view, int scrollState)
      {
        // Hide keyboard when user starts scroll
        InputUtils.hideKeyboard(mSearchBox);

        // Hacky way to remove focus from only edittext at activity
        mSearchBox.setFocusableInTouchMode(false);
        mSearchBox.setFocusable(false);
        mSearchBox.setFocusableInTouchMode(true);
        mSearchBox.setFocusable(true);
      }

      @Override
      public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
      {}
    });
  }

  private void setUpSearchModes()
  {
    // Initialize search modes group
    mSearchScopeGroup = (RadioGroup)findViewById(R.id.search_scope);
    // Default mode is AROUND_POSITION
    setSearchGroupSelectionByMode(MWMApplication.get().nativeGetInt(SEARCH_MODE_SETTING, AROUND_POSITION));
    mSearchScopeGroup.setOnCheckedChangeListener(new OnCheckedChangeListener()
    {
      @Override
      public void onCheckedChanged(RadioGroup group, int checkedId)
      {
        int mode;

        if (R.id.search_scope_everywhere == checkedId)
          mode = ALL;
        else if (R.id.search_scope_near == checkedId)
          mode = AROUND_POSITION;
        else if (R.id.search_scope_on_screen == checkedId)
          mode = IN_VIEWPORT;
        else
          throw new IllegalArgumentException("Unknown Id: " + checkedId);

        getMwmApplication().nativeSetInt(SEARCH_MODE_SETTING, mode);
        runSearch(mode);
      }
    });
  }

  @Override
  protected void onResume()
  {
    super.onResume();

    // Reset current mode flag - start first search.
    m_flags = 0;
    m_north = -1.0;

    m_location.startUpdate(this);

    // do the search immediately after resume
    Utils.setStringAndCursorToEnd(mSearchBox, getLastQuery());
    mSearchBox.requestFocus();
  }

  @Override
  protected void onPause()
  {
    m_location.stopUpdate(this);

    super.onPause();
  }

  private SearchAdapter getSA()
  {
    return (SearchAdapter) getListView().getAdapter();
  }

  @Override
  protected void onListItemClick(ListView l, View v, int position, long id)
  {
    super.onListItemClick(l, v, position, id);
    final String suggestion = getSA().onItemClick(position);
    if (suggestion == null)
    {
      presentResult(v, position);
    }
    else
    {
      // set suggestion string and run search (this call invokes runSearch)
      runSearch(suggestion);
    }
  }

  private void presentResult(View v, int position)
  {
    if (MWMApplication.get().isProVersion())
    {
      finish();

      final SearchAdapter.ViewHolder vh = (SearchAdapter.ViewHolder) v.getTag();

      final String queryTitle = vh.m_name.getText().toString().trim();
      final String showOnMapTitle = getString(R.string.search_show_on_map).trim();

      if (showOnMapTitle.equalsIgnoreCase(queryTitle))
        SearchController.get().setQuery(mSearchBox.getText().toString());
      else
        SearchController.get().setQuery(queryTitle);

      MWMActivity.startWithSearchResult(this, position != 0);
    }
    else
    {
      // Should we add something more attractive?
      Utils.toastShortcut(this, R.string.search_available_in_pro_version);
    }
  }

  @Override
  public void onBackPressed()
  {
    super.onBackPressed();
    SearchController.get().cancel();
  }

  /// Current position.
  private double m_lat;
  private double m_lon;
  private double m_north = -1.0;

  /// @name These constants should be equal with
  /// Java_com_mapswithme_maps_SearchActivity_nativeRunSearch routine.
  //@{
  private static final int NOT_FIRST_QUERY = 1;
  private static final int HAS_POSITION = 2;
  //@}
  private int m_flags = 0;

  private void updateDistance()
  {
    getSA().updateData();
  }

  private void showCategories()
  {
{'fraction_non_alphanumeric': 0.09443067348768525, 'fraction_numerical': 0.0027688413058382997, 'mean_word_length': 2.4696248856358647, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3012824', 'n_tokens_mistral': 11392, 'n_tokens_neox': 10928, 'n_words': 2466}