Home | History | Annotate | Download | only in browser
      1 /*
      2  * Copyright (C) 2009 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 
     17 package com.android.browser;
     18 
     19 import android.content.Context;
     20 import android.database.DataSetObserver;
     21 import android.graphics.Color;
     22 import android.util.AttributeSet;
     23 import android.view.LayoutInflater;
     24 import android.view.View;
     25 import android.view.ViewGroup;
     26 import android.view.View.OnClickListener;
     27 import android.webkit.ConsoleMessage;
     28 import android.webkit.WebView;
     29 import android.widget.Button;
     30 import android.widget.EditText;
     31 import android.widget.LinearLayout;
     32 import android.widget.ListView;
     33 import android.widget.TextView;
     34 import android.widget.TwoLineListItem;
     35 
     36 import java.util.Vector;
     37 
     38 /* package */ class ErrorConsoleView extends LinearLayout {
     39 
     40     /**
     41      * Define some constants to describe the visibility of the error console.
     42      */
     43     public static final int SHOW_MINIMIZED = 0;
     44     public static final int SHOW_MAXIMIZED = 1;
     45     public static final int SHOW_NONE      = 2;
     46 
     47     private TextView mConsoleHeader;
     48     private ErrorConsoleListView mErrorList;
     49     private LinearLayout mEvalJsViewGroup;
     50     private EditText mEvalEditText;
     51     private Button mEvalButton;
     52     private WebView mWebView;
     53     private int mCurrentShowState = SHOW_NONE;
     54 
     55     private boolean mSetupComplete = false;
     56 
     57     // Before we've been asked to display the console, cache any messages that should
     58     // be added to the console. Then when we do display the console, add them to the view
     59     // then.
     60     private Vector<ConsoleMessage> mErrorMessageCache;
     61 
     62     public ErrorConsoleView(Context context) {
     63         super(context);
     64     }
     65 
     66     public ErrorConsoleView(Context context, AttributeSet attributes) {
     67         super(context, attributes);
     68     }
     69 
     70     private void commonSetupIfNeeded() {
     71         if (mSetupComplete) {
     72             return;
     73         }
     74 
     75         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
     76                 Context.LAYOUT_INFLATER_SERVICE);
     77         inflater.inflate(R.layout.error_console, this);
     78 
     79         // Get references to each ui element.
     80         mConsoleHeader = (TextView) findViewById(R.id.error_console_header_id);
     81         mErrorList = (ErrorConsoleListView) findViewById(R.id.error_console_list_id);
     82         mEvalJsViewGroup = (LinearLayout) findViewById(R.id.error_console_eval_view_group_id);
     83         mEvalEditText = (EditText) findViewById(R.id.error_console_eval_text_id);
     84         mEvalButton = (Button) findViewById(R.id.error_console_eval_button_id);
     85 
     86         mEvalButton.setOnClickListener(new OnClickListener() {
     87             public void onClick(View v) {
     88                 // Send the javascript to be evaluated to webkit as a javascript: url
     89                 // TODO: Can we expose access to webkit's JS interpreter here and evaluate it that
     90                 // way? Note that this is called on the UI thread so we will need to post a message
     91                 // to the WebCore thread to implement this.
     92                 if (mWebView != null) {
     93                     mWebView.loadUrl("javascript:" + mEvalEditText.getText());
     94                 }
     95 
     96                 mEvalEditText.setText("");
     97             }
     98         });
     99 
    100         // Make clicking on the console title bar min/maximse it.
    101         mConsoleHeader.setOnClickListener(new OnClickListener() {
    102             public void onClick(View v) {
    103                 if (mCurrentShowState == SHOW_MINIMIZED) {
    104                     showConsole(SHOW_MAXIMIZED);
    105                 } else {
    106                     showConsole(SHOW_MINIMIZED);
    107                 }
    108             }
    109         });
    110 
    111         // Add any cached messages to the list now that we've assembled the view.
    112         if (mErrorMessageCache != null) {
    113             for (ConsoleMessage msg : mErrorMessageCache) {
    114                 mErrorList.addErrorMessage(msg);
    115             }
    116             mErrorMessageCache.clear();
    117         }
    118 
    119         mSetupComplete = true;
    120     }
    121 
    122     /**
    123      * Adds a message to the set of messages the console uses.
    124      */
    125     public void addErrorMessage(ConsoleMessage consoleMessage) {
    126         if (mSetupComplete) {
    127             mErrorList.addErrorMessage(consoleMessage);
    128         } else {
    129             if (mErrorMessageCache == null) {
    130                 mErrorMessageCache = new Vector<ConsoleMessage>();
    131             }
    132             mErrorMessageCache.add(consoleMessage);
    133         }
    134     }
    135 
    136     /**
    137      * Removes all error messages from the console.
    138      */
    139     public void clearErrorMessages() {
    140         if (mSetupComplete) {
    141             mErrorList.clearErrorMessages();
    142         } else if (mErrorMessageCache != null) {
    143             mErrorMessageCache.clear();
    144         }
    145     }
    146 
    147     /**
    148      * Returns the current number of errors displayed in the console.
    149      */
    150     public int numberOfErrors() {
    151         if (mSetupComplete) {
    152             return mErrorList.getCount();
    153         } else {
    154             return (mErrorMessageCache == null) ? 0 : mErrorMessageCache.size();
    155         }
    156     }
    157 
    158     /**
    159      * Sets the webview that this console is associated with. Currently this is used so
    160      * we can call into webkit to evaluate JS expressions in the console.
    161      */
    162     public void setWebView(WebView webview) {
    163         mWebView = webview;
    164     }
    165 
    166     /**
    167      * Sets the visibility state of the console.
    168      */
    169     public void showConsole(int show_state) {
    170         commonSetupIfNeeded();
    171         switch (show_state) {
    172             case SHOW_MINIMIZED:
    173                 mConsoleHeader.setVisibility(View.VISIBLE);
    174                 mConsoleHeader.setText(R.string.error_console_header_text_minimized);
    175                 mErrorList.setVisibility(View.GONE);
    176                 mEvalJsViewGroup.setVisibility(View.GONE);
    177                 break;
    178 
    179             case SHOW_MAXIMIZED:
    180                 mConsoleHeader.setVisibility(View.VISIBLE);
    181                 mConsoleHeader.setText(R.string.error_console_header_text_maximized);
    182                 mErrorList.setVisibility(View.VISIBLE);
    183                 mEvalJsViewGroup.setVisibility(View.VISIBLE);
    184                 break;
    185 
    186             case SHOW_NONE:
    187                 mConsoleHeader.setVisibility(View.GONE);
    188                 mErrorList.setVisibility(View.GONE);
    189                 mEvalJsViewGroup.setVisibility(View.GONE);
    190                 break;
    191         }
    192         mCurrentShowState = show_state;
    193     }
    194 
    195     /**
    196      * Returns the current visibility state of the console.
    197      */
    198     public int getShowState() {
    199         if (mSetupComplete) {
    200             return mCurrentShowState;
    201         } else {
    202             return SHOW_NONE;
    203         }
    204     }
    205 
    206     /**
    207      * This class extends ListView to implement the View that will actually display the set of
    208      * errors encountered on the current page.
    209      */
    210     private static class ErrorConsoleListView extends ListView {
    211         // An adapter for this View that contains a list of error messages.
    212         private ErrorConsoleMessageList mConsoleMessages;
    213 
    214         public ErrorConsoleListView(Context context, AttributeSet attributes) {
    215             super(context, attributes);
    216             mConsoleMessages = new ErrorConsoleMessageList(context);
    217             setAdapter(mConsoleMessages);
    218         }
    219 
    220         public void addErrorMessage(ConsoleMessage consoleMessage) {
    221             mConsoleMessages.add(consoleMessage);
    222             setSelection(mConsoleMessages.getCount());
    223         }
    224 
    225         public void clearErrorMessages() {
    226             mConsoleMessages.clear();
    227         }
    228 
    229         /**
    230          * This class is an adapter for ErrorConsoleListView that contains the error console
    231          * message data.
    232          */
    233         private static class ErrorConsoleMessageList extends android.widget.BaseAdapter
    234                 implements android.widget.ListAdapter {
    235 
    236             private Vector<ConsoleMessage> mMessages;
    237             private LayoutInflater mInflater;
    238 
    239             public ErrorConsoleMessageList(Context context) {
    240                 mMessages = new Vector<ConsoleMessage>();
    241                 mInflater = (LayoutInflater)context.getSystemService(
    242                         Context.LAYOUT_INFLATER_SERVICE);
    243             }
    244 
    245             /**
    246              * Add a new message to the list and update the View.
    247              */
    248             public void add(ConsoleMessage consoleMessage) {
    249                 mMessages.add(consoleMessage);
    250                 notifyDataSetChanged();
    251             }
    252 
    253             /**
    254              * Remove all messages from the list and update the view.
    255              */
    256             public void clear() {
    257                 mMessages.clear();
    258                 notifyDataSetChanged();
    259             }
    260 
    261             @Override
    262             public boolean areAllItemsEnabled() {
    263                 return false;
    264             }
    265 
    266             @Override
    267             public boolean isEnabled(int position) {
    268                 return false;
    269             }
    270 
    271             public long getItemId(int position) {
    272                 return position;
    273             }
    274 
    275             public Object getItem(int position) {
    276                 return mMessages.get(position);
    277             }
    278 
    279             public int getCount() {
    280                 return mMessages.size();
    281             }
    282 
    283             @Override
    284             public boolean hasStableIds() {
    285                 return true;
    286             }
    287 
    288             /**
    289              * Constructs a TwoLineListItem for the error at position.
    290              */
    291             public View getView(int position, View convertView, ViewGroup parent) {
    292                 View view;
    293                 ConsoleMessage error = mMessages.get(position);
    294 
    295                 if (error == null) {
    296                     return null;
    297                 }
    298 
    299                 if (convertView == null) {
    300                     view = mInflater.inflate(android.R.layout.two_line_list_item, parent, false);
    301                 } else {
    302                     view = convertView;
    303                 }
    304 
    305                 TextView headline = (TextView) view.findViewById(android.R.id.text1);
    306                 TextView subText = (TextView) view.findViewById(android.R.id.text2);
    307                 headline.setText(error.sourceId() + ":" + error.lineNumber());
    308                 subText.setText(error.message());
    309                 switch (error.messageLevel()) {
    310                     case ERROR:
    311                         subText.setTextColor(Color.RED);
    312                         break;
    313                     case WARNING:
    314                         // Orange
    315                         subText.setTextColor(Color.rgb(255,192,0));
    316                         break;
    317                     case TIP:
    318                         subText.setTextColor(Color.BLUE);
    319                         break;
    320                     default:
    321                         subText.setTextColor(Color.LTGRAY);
    322                         break;
    323                 }
    324                 return view;
    325             }
    326 
    327         }
    328     }
    329 }
    330