1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.quicksearchbox;
18
19
20import com.android.quicksearchbox.util.Util;
21
22import android.content.Context;
23import android.content.Intent;
24import android.graphics.drawable.Drawable;
25import android.net.Uri;
26import android.os.Bundle;
27import android.util.Log;
28import android.util.Patterns;
29import android.webkit.URLUtil;
30
31import java.util.ArrayList;
32import java.util.List;
33import java.util.concurrent.Executor;
34
35/**
36 * The web search source.
37 */
38public class WebCorpus extends MultiSourceCorpus {
39    private static final String TAG = "QSB.WebCorpus";
40    private static final boolean DBG = false;
41
42    private static final String WEB_CORPUS_NAME = "web";
43
44    private final SearchSettings mSettings;
45
46    private Source mWebSearchSource;
47
48    private final Source mBrowserSource;
49
50    public WebCorpus(Context context, Config config, SearchSettings settings, Executor executor,
51            Source webSearchSource, Source browserSource) {
52        super(context, config, executor, webSearchSource, browserSource);
53        if (DBG) {
54            Log.d(TAG, "init webSource=" + webSearchSource + "; browser source = " + browserSource);
55        }
56        mSettings = settings;
57        mWebSearchSource = webSearchSource;
58        mBrowserSource = browserSource;
59    }
60
61    protected SearchSettings getSettings() {
62        return mSettings;
63    }
64
65    public void setWebSource(Source web) {
66        if (DBG) Log.d(TAG, "setWebSource(" + web + ")");
67        mWebSearchSource = web;
68    }
69
70    public CharSequence getLabel() {
71        return getContext().getText(R.string.corpus_label_web);
72    }
73
74    public CharSequence getHint() {
75        // The web corpus uses a drawable hint instead
76        return null;
77    }
78
79    private boolean isUrl(String query) {
80       return Patterns.WEB_URL.matcher(query).matches();
81    }
82
83    public Intent createSearchIntent(String query, Bundle appData) {
84        if (isUrl(query)) {
85            return createBrowseIntent(query);
86        } else if (mWebSearchSource != null){
87            return mWebSearchSource.createSearchIntent(query, appData);
88        } else {
89            return null;
90        }
91    }
92
93    private Intent createBrowseIntent(String query) {
94        Intent intent = new Intent(Intent.ACTION_VIEW);
95        intent.addCategory(Intent.CATEGORY_BROWSABLE);
96        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
97        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
98        String url = URLUtil.guessUrl(query);
99        intent.setData(Uri.parse(url));
100        return intent;
101    }
102
103    public Intent createVoiceSearchIntent(Bundle appData) {
104        // TODO in 2-pane mode, mWebSearchSource may be NULL
105        // this functionality should be moved elsewhere.
106        if (mWebSearchSource != null){
107            return mWebSearchSource.createVoiceSearchIntent(appData);
108        } else {
109            return null;
110        }
111    }
112
113    private int getCorpusIconResource() {
114        return R.drawable.corpus_icon_web;
115    }
116
117    public Drawable getCorpusIcon() {
118        return getContext().getResources().getDrawable(getCorpusIconResource());
119    }
120
121    public Uri getCorpusIconUri() {
122        return Util.getResourceUri(getContext(), getCorpusIconResource());
123    }
124
125    public String getName() {
126        return WEB_CORPUS_NAME;
127    }
128
129    @Override
130    public int getQueryThreshold() {
131        return 0;
132    }
133
134    @Override
135    public boolean queryAfterZeroResults() {
136        return true;
137    }
138
139    @Override
140    public boolean voiceSearchEnabled() {
141        return true;
142    }
143
144    public boolean isWebCorpus() {
145        return true;
146    }
147
148    public CharSequence getSettingsDescription() {
149        return getContext().getText(R.string.corpus_description_web);
150    }
151
152    @Override
153    protected List<Source> getSourcesToQuery(String query, boolean onlyCorpus) {
154        ArrayList<Source> sourcesToQuery = new ArrayList<Source>(2);
155        if (mWebSearchSource != null) sourcesToQuery.add(mWebSearchSource);
156        if (mBrowserSource != null && query.length() > 0) {
157            sourcesToQuery.add(mBrowserSource);
158        }
159        if (DBG) Log.d(TAG, "getSourcesToQuery sourcesToQuery=" + sourcesToQuery);
160        return sourcesToQuery;
161    }
162
163    @Override
164    protected Result createResult(String query, ArrayList<SourceResult> results, int latency) {
165        return new WebResult(query, results, latency);
166    }
167
168    protected class WebResult extends Result {
169
170        public WebResult(String query, ArrayList<SourceResult> results, int latency) {
171            super(query, results, latency);
172        }
173
174        @Override
175        public void fill() {
176            SourceResult webSearchResult = null;
177            SourceResult browserResult = null;
178            for (SourceResult result : getResults()) {
179                if (result.getSource().equals(mWebSearchSource)) {
180                    webSearchResult = result;
181                } else {
182                    browserResult = result;
183                }
184            }
185            if (browserResult != null && browserResult.getCount() > 0) {
186                add(new SuggestionPosition(browserResult, 0));
187            }
188            if (webSearchResult != null) {
189                int count = webSearchResult.getCount();
190                for (int i = 0; i < count; i++) {
191                    add(new SuggestionPosition(webSearchResult, i));
192                }
193            }
194        }
195
196    }
197}
198