private static String initGeckoEnvironment() { final Context context = GeckoAppShell.getApplicationContext(); GeckoLoader.loadMozGlue(context); setState(State.MOZGLUE_READY); final Locale locale = Locale.getDefault(); final Resources res = context.getResources(); if (locale.toString().equalsIgnoreCase("zh_hk")) { final Locale mappedLocale = Locale.TRADITIONAL_CHINESE; Locale.setDefault(mappedLocale); Configuration config = res.getConfiguration(); config.locale = mappedLocale; res.updateConfiguration(config, null); } String[] pluginDirs = null; try { pluginDirs = GeckoAppShell.getPluginDirectories(); } catch (Exception e) { Log.w(LOGTAG, "Caught exception getting plugin dirs.", e); } final String resourcePath = context.getPackageResourcePath(); GeckoLoader.setupGeckoEnvironment(context, pluginDirs, context.getFilesDir().getPath()); GeckoLoader.loadSQLiteLibs(context, resourcePath); GeckoLoader.loadNSSLibs(context, resourcePath); GeckoLoader.loadGeckoLibs(context, resourcePath); setState(State.LIBS_READY); return resourcePath; }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); GeckoAppShell.registerGeckoEventListener("Preferences:Data", this); GeckoAppShell.registerGeckoEventListener("Sanitize:Finished", this); }
private static String addCustomProfileArg(String args) { String profileArg = ""; String guestArg = ""; if (GeckoAppShell.getGeckoInterface() != null) { final GeckoProfile profile = GeckoAppShell.getGeckoInterface().getProfile(); if (profile.inGuestMode()) { try { profileArg = " -profile " + profile.getDir().getCanonicalPath(); } catch (final IOException ioe) { Log.e(LOGTAG, "error getting guest profile path", ioe); } if (args == null || !args.contains(BrowserApp.GUEST_BROWSING_ARG)) { guestArg = " " + BrowserApp.GUEST_BROWSING_ARG; } } else if (!GeckoProfile.sIsUsingCustomProfile) { // If nothing was passed in the intent, make sure the default profile exists and // force Gecko to use the default profile for this activity profileArg = " -P " + profile.forceCreate().getName(); } } return (args != null ? args : "") + profileArg + guestArg; }
private boolean processKeyDown(int keyCode, KeyEvent event, boolean isPreIme) { if (DEBUG) { Log.d( LOGTAG, "IME: processKeyDown(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")"); } clampSelection(); switch (keyCode) { case KeyEvent.KEYCODE_MENU: case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_SEARCH: return false; case KeyEvent.KEYCODE_DEL: // See comments in GeckoInputConnection.onKeyDel if (onKeyDel()) { return true; } break; case KeyEvent.KEYCODE_ENTER: if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 && mIMEActionHint.equalsIgnoreCase("next")) event = new KeyEvent(event.getAction(), KeyEvent.KEYCODE_TAB); break; default: break; } if (isPreIme && mIMEState != IME_STATE_DISABLED && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) // Let active IME process pre-IME key events return false; View view = GeckoApp.mAppContext.getLayerController().getView(); KeyListener keyListener = TextKeyListener.getInstance(); // KeyListener returns true if it handled the event for us. if (mIMEState == IME_STATE_DISABLED || keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_TAB || (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 || !keyListener.onKeyDown(view, mEditable, keyCode, event)) { // Make sure selection in Gecko is up-to-date final Editable content = getEditable(); int a = Selection.getSelectionStart(content); int b = Selection.getSelectionEnd(content); GeckoAppShell.sendEventToGecko( GeckoEvent.createIMEEvent(GeckoEvent.IME_SET_SELECTION, a, b - a)); GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event)); } return true; }
private void connectToGecko() { GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoRunning); Tab selectedTab = Tabs.getInstance().getSelectedTab(); if (selectedTab != null) Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED); geckoConnected(); GeckoAppShell.setLayerClient(getLayerClientObject()); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null)); }
@Override // Service public void onCreate() { GeckoAppShell.ensureCrashHandling(); GeckoAppShell.setApplicationContext(getApplicationContext()); GeckoAppShell.setNotificationClient(new ServiceNotificationClient(getApplicationContext())); GeckoThread.onResume(); super.onCreate(); if (DEBUG) { Log.d(LOGTAG, "Created"); } }
private void getHandlers(JSONObject message) throws JSONException { final Intent intent = GeckoAppShell.getOpenURIIntent( activity, message.optString("url"), message.optString("mime"), message.optString("action"), message.optString("title")); final List<String> appList = Arrays.asList(GeckoAppShell.getHandlersForIntent(intent)); final JSONObject response = new JSONObject(); response.put("apps", new JSONArray(appList)); EventDispatcher.sendResponse(message, response); }
private static void sendDirectAccessibilityEvent(int eventType, JSONObject message) { final AccessibilityEvent accEvent = AccessibilityEvent.obtain(eventType); accEvent.setClassName(GeckoAccessibility.class.getName()); accEvent.setPackageName(GeckoAppShell.getContext().getPackageName()); populateEventFromJSON(accEvent, message); AccessibilityManager accessibilityManager = (AccessibilityManager) GeckoAppShell.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); try { accessibilityManager.sendAccessibilityEvent(accEvent); } catch (IllegalStateException e) { // Accessibility is off. } }
public void pinSite() { final int position = mTopSitesGrid.getSelectedPosition(); View v = mTopSitesGrid.getChildAt(position); TopSitesViewHolder holder = (TopSitesViewHolder) v.getTag(); final String url = holder.url; final String title = holder.titleView.getText().toString(); holder.setPinned(true); // update the database on a background thread (new GeckoAsyncTask<Void, Void, Void>(GeckoApp.mAppContext, GeckoAppShell.getHandler()) { @Override public Void doInBackground(Void... params) { final ContentResolver resolver = mActivity.getContentResolver(); BrowserDB.pinSite( resolver, url, (title == null || TextUtils.isEmpty(title) ? url : title), position); return null; } @Override public void onPostExecute(Void v) { update(EnumSet.of(UpdateFlags.TOP_SITES)); } }) .execute(); }
public void init() { int iconSize = mContext.getResources().getDimensionPixelSize(R.dimen.abouthome_addon_icon_size); sIconBounds = new Rect(0, 0, iconSize, iconSize); sSubTitleSpan = new TextAppearanceSpan(mContext, R.style.AboutHome_TextAppearance_SubTitle); inflate(); mAccountManager = AccountManager.get(mContext); // The listener will run on the background thread (see 2nd argument) mAccountManager.addOnAccountsUpdatedListener( mAccountListener = new OnAccountsUpdateListener() { public void onAccountsUpdated(Account[] accounts) { updateLayoutForSync(); } }, GeckoAppShell.getHandler(), false); mRemoteTabClickListener = new View.OnClickListener() { @Override public void onClick(View v) { int flags = Tabs.LOADURL_NEW_TAB; if (Tabs.getInstance().getSelectedTab().isPrivate()) flags |= Tabs.LOADURL_PRIVATE; Tabs.getInstance().loadUrl((String) v.getTag(), flags); } }; mPrelimPromoBoxType = (new Random()).nextFloat() < 0.5 ? AboutHomePromoBox.Type.SYNC : AboutHomePromoBox.Type.APPS; }
public Device() { // Determine device version int sdk = Build.VERSION.SDK_INT; if (sdk < Build.VERSION_CODES.HONEYCOMB) { version = "2.x"; } else { if (sdk > Build.VERSION_CODES.HONEYCOMB_MR2) { version = "4.x"; } else { version = "3.x"; } } // Determine with and height DisplayMetrics dm = new DisplayMetrics(); getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm); height = dm.heightPixels; width = dm.widthPixels; density = dm.density; // Determine device type type = "phone"; try { if (GeckoAppShell.isTablet()) { type = "tablet"; } } catch (Exception e) { mAsserter.dumpLog("Exception in detectDevice", e); } }
@Override // NativeEventListener public void handleMessage( final String event, final NativeJSObject message, final EventCallback callback) { final Context context = GeckoAppShell.getApplicationContext(); switch (event) { case "Gecko:ScheduleRun": if (DEBUG) { Log.d( LOGTAG, "Scheduling " + message.getString("action") + " @ " + message.getInt("interval") + "ms"); } final Intent intent = getIntentForAction(context, message.getString("action")); final PendingIntent pendingIntent = PendingIntent.getService( context, /* requestCode */ 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); // Cancel any previous alarm and schedule a new one. am.setInexactRepeating( AlarmManager.ELAPSED_REALTIME, message.getInt("trigger"), message.getInt("interval"), pendingIntent); break; default: throw new UnsupportedOperationException(event); } }
public int saveSentMessage(String aRecipient, String aBody, long aDate) { try { ContentValues values = new ContentValues(); values.put("address", aRecipient); values.put("body", aBody); values.put("date", aDate); // Always 'PENDING' because we always request status report. values.put("status", kInternalDeliveryStatusPending); ContentResolver cr = GeckoAppShell.getContext().getContentResolver(); Uri uri = cr.insert(kSmsSentContentUri, values); long id = ContentUris.parseId(uri); // The DOM API takes a 32bits unsigned int for the id. It's unlikely that // we happen to need more than that but it doesn't cost to check. if (id > Integer.MAX_VALUE) { throw new IdTooHighException(); } return (int) id; } catch (IdTooHighException e) { Log.e("GeckoSmsManager", "The id we received is higher than the higher allowed value."); return -1; } catch (Exception e) { Log.e("GeckoSmsManager", "Something went wrong when trying to write a sent message", e); return -1; } }
private boolean processKeyUp(int keyCode, KeyEvent event, boolean isPreIme) { if (DEBUG) { Log.d( LOGTAG, "IME: processKeyUp(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")"); } switch (keyCode) { case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_SEARCH: case KeyEvent.KEYCODE_MENU: return false; default: break; } if (isPreIme && mIMEState != IME_STATE_DISABLED && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) // Let active IME process pre-IME key events return false; View view = GeckoApp.mAppContext.getLayerController().getView(); KeyListener keyListener = TextKeyListener.getInstance(); if (mIMEState == IME_STATE_DISABLED || keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DEL || (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 || !keyListener.onKeyUp(view, mEditable, keyCode, event)) { GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event)); } return true; }
public void init() { inflate(); mAccountManager = AccountManager.get(mContext); // The listener will run on the background thread (see 2nd argument) mAccountManager.addOnAccountsUpdatedListener( mAccountListener = new OnAccountsUpdateListener() { public void onAccountsUpdated(Account[] accounts) { updateLayoutForSync(); } }, GeckoAppShell.getHandler(), false); mRemoteTabClickListener = new View.OnClickListener() { @Override public void onClick(View v) { Tabs.getInstance().loadUrl((String) v.getTag(), Tabs.LOADURL_NEW_TAB); } }; mPrelimPromoBoxType = (new Random()).nextFloat() < 0.5 ? AboutHomePromoBox.Type.SYNC : AboutHomePromoBox.Type.APPS; }
@Override public boolean setSelection(int start, int end) { GeckoAppShell.sendEventToGecko( GeckoEvent.createIMEEvent(GeckoEvent.IME_SET_SELECTION, start, end - start)); return super.setSelection(start, end); }
// Helper method to check if there are any clients available public static void areClientsAvailable( final Context context, final OnClientsAvailableListener listener) { if (listener == null) return; (new GeckoAsyncTask<Void, Void, Boolean>(GeckoApp.mAppContext, GeckoAppShell.getHandler()) { @Override protected Boolean doInBackground(Void... unused) { Uri uri = BrowserContract.Tabs.CONTENT_URI; uri = uri.buildUpon().appendQueryParameter(BrowserContract.PARAM_LIMIT, "1").build(); Cursor cursor = context .getContentResolver() .query(uri, CLIENTS_AVAILABILITY_PROJECTION, CLIENTS_SELECTION, null, null); if (cursor == null) return false; try { return cursor.moveToNext(); } finally { cursor.close(); } } @Override protected void onPostExecute(Boolean availability) { listener.areAvailable(availability); } }) .setPriority(GeckoAsyncTask.Priority.HIGH) .execute(); }
protected void unpackComponents() throws IOException, FileNotFoundException { File applicationPackage = new File(getApplication().getPackageResourcePath()); File componentsDir = new File(sGREDir, "components"); if (componentsDir.lastModified() == applicationPackage.lastModified()) return; componentsDir.mkdir(); componentsDir.setLastModified(applicationPackage.lastModified()); GeckoAppShell.killAnyZombies(); ZipFile zip = new ZipFile(applicationPackage); byte[] buf = new byte[32768]; try { if (unpackFile(zip, buf, null, "removed-files")) removeFiles(); } catch (Exception ex) { // This file may not be there, so just log any errors and move on Log.w(LOG_FILE_NAME, "error removing files", ex); } // copy any .xpi file into an extensions/ directory Enumeration<? extends ZipEntry> zipEntries = zip.entries(); while (zipEntries.hasMoreElements()) { ZipEntry entry = zipEntries.nextElement(); if (entry.getName().startsWith("extensions/") && entry.getName().endsWith(".xpi")) { Log.i("GeckoAppJava", "installing extension : " + entry.getName()); unpackFile(zip, buf, entry, entry.getName()); } } }
protected void onPostExecute(Pair<GroupList, List<ChildrenList>> result) { mCursorAdapter = new HistoryListAdapter( mContext, result.first, R.layout.awesomebar_header_row, new String[] {URLColumns.TITLE}, new int[] {R.id.title}, result.second); if (mContentObserver == null) { // Register an observer to update the history tab contents if they change. mContentObserver = new ContentObserver(GeckoAppShell.getHandler()) { public void onChange(boolean selfChange) { mQueryTask = new HistoryQueryTask(); mQueryTask.execute(); } }; BrowserDB.registerHistoryObserver(getContentResolver(), mContentObserver); } final ExpandableListView historyList = (ExpandableListView) getView(); // Hack: force this to the main thread, even though it should already be on it GeckoApp.mAppContext.mMainHandler.post( new Runnable() { public void run() { historyList.setAdapter(mCursorAdapter); expandAllGroups(historyList); } }); mQueryTask = null; }
public void unpinAllSites() { final ContentResolver resolver = mActivity.getContentResolver(); // Clear the view quickly to make things appear responsive for (int i = 0; i < mTopSitesGrid.getChildCount(); i++) { View v = mTopSitesGrid.getChildAt(i); TopSitesViewHolder holder = (TopSitesViewHolder) v.getTag(); clearThumbnail(holder); } (new GeckoAsyncTask<Void, Void, Void>(GeckoApp.mAppContext, GeckoAppShell.getHandler()) { @Override public Void doInBackground(Void... params) { ContentResolver resolver = mActivity.getContentResolver(); BrowserDB.unpinAllSites(resolver); return null; } @Override public void onPostExecute(Void v) { update(EnumSet.of(UpdateFlags.TOP_SITES)); } }) .execute(); }
/* * DoorHanger.OnButtonClickListener implementation */ @Override public void onButtonClick(DoorHanger dh, String tag) { JSONObject response = new JSONObject(); try { response.put("callback", tag); CheckBox checkBox = dh.getCheckBox(); // If the checkbox is being used, pass its value if (checkBox != null) { response.put("checked", checkBox.isChecked()); } List<PromptInput> doorHangerInputs = dh.getInputs(); if (doorHangerInputs != null) { JSONObject inputs = new JSONObject(); for (PromptInput input : doorHangerInputs) { inputs.put(input.getId(), input.getValue()); } response.put("inputs", inputs); } } catch (JSONException e) { Log.e(LOGTAG, "Error creating onClick response", e); } GeckoEvent e = GeckoEvent.createBroadcastEvent("Doorhanger:Reply", response.toString()); GeckoAppShell.sendEventToGecko(e); removeDoorHanger(dh); updatePopup(); }
/* * If the app has been launched a certain number of times, and we haven't asked for feedback before, * open a new tab with about:feedback when launching the app from the icon shortcut. */ @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); if (!Intent.ACTION_MAIN.equals(intent.getAction()) || !mInitialized) return; (new GeckoAsyncTask<Void, Void, Boolean>(mAppContext, GeckoAppShell.getHandler()) { @Override public synchronized Boolean doInBackground(Void... params) { // Check to see how many times the app has been launched. SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE); String keyName = getPackageName() + ".feedback_launch_count"; int launchCount = settings.getInt(keyName, 0); if (launchCount >= FEEDBACK_LAUNCH_COUNT) return false; // Increment the launch count and store the new value. launchCount++; settings.edit().putInt(keyName, launchCount).commit(); // If we've reached our magic number, show the feedback page. return launchCount == FEEDBACK_LAUNCH_COUNT; } @Override public void onPostExecute(Boolean shouldShowFeedbackPage) { if (shouldShowFeedbackPage) Tabs.getInstance().loadUrlInTab("about:feedback"); } }) .execute(); }
// Run all queued methods private static void flushQueuedNativeCallsLocked(final State state) { int lastSkipped = -1; for (int i = 0; i < QUEUED_CALLS.size(); i++) { final QueuedCall call = QUEUED_CALLS.get(i); if (call == null) { // We already handled the call. continue; } if (!state.isAtLeast(call.state)) { // The call is not ready yet; skip it. lastSkipped = i; continue; } // Mark as handled. QUEUED_CALLS.set(i, null); if (call.method == null) { final GeckoEvent e = (GeckoEvent) call.target; GeckoAppShell.notifyGeckoOfEvent(e); e.recycle(); continue; } invokeMethod(call.method, call.target, call.args); } if (lastSkipped < 0) { // We're done here; release the memory QUEUED_CALLS.clear(); QUEUED_CALLS.trimToSize(); } else if (lastSkipped < QUEUED_CALLS.size() - 1) { // We skipped some; free up null entries at the end, // but keep all the previous entries for later. QUEUED_CALLS.subList(lastSkipped + 1, QUEUED_CALLS.size()).clear(); } }
public void init() { int iconSize = mContext.getResources().getDimensionPixelSize(R.dimen.abouthome_addon_icon_size); sIconBounds = new Rect(0, 0, iconSize, iconSize); sSubTitleSpan = new TextAppearanceSpan(mContext, R.style.AboutHome_TextAppearance_SubTitle); inflate(); // Reload the mobile homepage on inbound tab syncs // Because the tabs URI is coarse grained, this updates the // remote tabs component on *every* tab change // The observer will run on the background thread (see constructor argument) mTabsContentObserver = new ContentObserver(GeckoAppShell.getHandler()) { public void onChange(boolean selfChange) { update(EnumSet.of(AboutHomeContent.UpdateFlags.REMOTE_TABS)); } }; mActivity .getContentResolver() .registerContentObserver(BrowserContract.Tabs.CONTENT_URI, false, mTabsContentObserver); mRemoteTabClickListener = new View.OnClickListener() { @Override public void onClick(View v) { int flags = Tabs.LOADURL_NEW_TAB; if (Tabs.getInstance().getSelectedTab().isPrivate()) flags |= Tabs.LOADURL_PRIVATE; Tabs.getInstance().loadUrl((String) v.getTag(), flags); } }; }
public void doRestart() { try { String action = "org.mozilla.gecko.restart"; Intent intent = new Intent(action); intent.setClassName(getPackageName(), getPackageName() + ".Restarter"); addEnvToIntent(intent); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); Log.i(LOG_FILE_NAME, intent.toString()); GeckoAppShell.killAnyZombies(); startActivity(intent); } catch (Exception e) { Log.i(LOG_FILE_NAME, "error doing restart", e); } finish(); // Give the restart process time to start before we die GeckoAppShell.waitForAnotherGeckoProc(); }
private void updateBufferSize() { int pixelSize = (GeckoAppShell.getScreenDepth() == 24) ? 4 : 2; int capacity = viewWidth * viewHeight * pixelSize; if (buffer == null || buffer.capacity() != capacity) { buffer = DirectBufferAllocator.free(buffer); buffer = DirectBufferAllocator.allocate(capacity); } }
/** Send current network state and connection type as a GeckoEvent, to whomever is listening. */ private void sendNetworkStateToListeners() { final Context applicationContext = GeckoAppShell.getApplicationContext(); final GeckoEvent networkEvent = GeckoEvent.createNetworkEvent( currentConnectionType.value, currentConnectionType == ConnectionType.WIFI, wifiDhcpGatewayAddress(applicationContext), currentConnectionSubtype.value); final GeckoEvent networkLinkChangeValueEvent = GeckoEvent.createNetworkLinkChangeEvent(currentNetworkStatus.value); final GeckoEvent networkLinkChangeNotificationEvent = GeckoEvent.createNetworkLinkChangeEvent(LINK_DATA_CHANGED); GeckoAppShell.sendEventToGecko(networkEvent); GeckoAppShell.sendEventToGecko(networkLinkChangeValueEvent); GeckoAppShell.sendEventToGecko(networkLinkChangeNotificationEvent); }
/** * Handle a confirmation response from the user. * * @param value String value to return to the browser context. */ public void confirmWithValue(String value) { JSONObject result = makeResult(RESULT_OK); try { result.put("textbox0", value); } catch (JSONException ex) { } GeckoAppShell.sendEventToGecko( GeckoEvent.createBroadcastEvent("Prompt:Reply", result.toString())); }
@Override public void onStop() { Log.i(LOG_FILE_NAME, "stop"); // We're about to be stopped, potentially in preparation for // being destroyed. We're killable after this point -- as I // understand it, in extreme cases the process can be terminated // without going through onDestroy. // // We might also get an onRestart after this; not sure what // that would mean for Gecko if we were to kill it here. // Instead, what we should do here is save prefs, session, // etc., and generally mark the profile as 'clean', and then // dirty it again if we get an onResume. GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_STOPPING)); super.onStop(); GeckoAppShell.putChildInBackground(); }
public double[] getCurrentInformation() { final Context applicationContext = GeckoAppShell.getApplicationContext(); final ConnectionType connectionType = currentConnectionType; return new double[] { connectionType.value, connectionType == ConnectionType.WIFI ? 1.0 : 0.0, connectionType == ConnectionType.WIFI ? wifiDhcpGatewayAddress(applicationContext) : 0.0 }; }