Development Tips

 

This page provides useful tips to develop QSlide applications using LG QSlide SDK.

 

Customizing Floating Window

Issue

Customizing the views displayed in the title bar of the floating window

Solution

Developers can customize the views to be displayed in the title bar (title text & color, title bar background, full button, close button, vertical divider, and seek bar). Each view is defined in the FloatingWindow.Tag as a constant and the instance can be obtained by transmitting the constant defined in FloatingWindow.Tag to the Floatingwindow.findViewWithTag() method as an argument.

private void setWindowTitleView() {
    FloatingWindow window = getFloatingWindow();
    if (null != window) {
        Resources res = getResources(); 

        View titleBackground = (View)window.findViewWithTag
             (FloatingWindow.Tag.TITLE_BACKGROUND);
        if (titleBackground != null) {
            titleBackground.setBackground(…);
        }

        ImageView titleDivider =
                 (ImageView)window.findViewWithTag(
                                             TITLE_DIVIDER);
        if (titleDivider != null) {
            titleDivider.setBackground(…);
        }

        SeekBar seekBar = (SeekBar)
                      window.findViewWithTag(SEEKBAR);
        if (seekBar != null) {
            seekBar.setProgressDrawable(…);
        }
 
        ImageButton fullscreenButton = (ImageButton)
                window.findViewWithTag(FULLSCREEN_BUTTON);
        if (fullscreenButton != null) {
            fullscreenButton.setImageDrawable(…);
        }
 
        ImageButton closeButton = (ImageButton)
                     window.findViewWithTag(CLOSE_BUTTON);
        if (closeButton != null) {
            closeButton.setImageDrawable(…);
        }
    }
}

 

Keeping the Aspect Ratio of Floating Window

Issue

Adjusting the floating window size while keeping the aspect ratio of the floating window.

Solution

When switching to the floating window mode, transmit the layout parameter that has the resizing option to switchToFloatingMode() as an argument. To keep the aspect ratio of the floating window, set the resizeOption of the layout parameter to the FloatingWindow.ResizeOption.PROPORTIONAL.

params.width = (int)DEFAULT_WIDTH;
params.height = (int)DEFAULT_HEIGHT;

params.resizeOption = FloatingWindow.ResizeOption.PROPORTIONAL;

 

Adjusting Font Size when Changing Floating Window Size

Issue

Changing the properties such as font size of the component displayed in the content window when changing the floating window size

Solution

Execute necessary changes by overriding the onResizeFinished() of the onUpdateListener.

@Override
public void onAttachedToFloatingWindow(FloatingWindow w) {
    super.onAttachedToFloatingWindow(w);
    if (w != null) {
        w.setOnUpdateListener(new DefaultOnUpdateListener() {
            @Override
            public void onResizeFinished
                     (FloatingWindow window,
                      int width, int height) {
                // Resizing all text in the activity
                resizeAllViewTextSize(width, height);
            }
        …
    }
    …
}

 

Reflecting Changes of System Configuration

Issue

Rearranging the UI due to the changes of the font size, system language, etc.

Solution

Execute necessary UI changes by overriding the FloatableActivity.setViewForConfigChanged() method.

@Override
public void setViewForConfigChanged(
                     Configuration newConfig) {
    super.setViewForConfigChanged(newConfig);
    setWindowTitleText(); // Reconfiguration the title text
}

 

Running Other Full Screen Activity in Floating Window

Issue

To execute other full screen activity of the application by an floating window if the activity for the floating window is implemented as a separate class (e.g.: calendar – switched to the full screen when pressing the full screen switch button or the date.)

Solution

There are two methods according to which event processes the screen switch of the full screen activity.
 
1) When switching to the full screen activity by pressing the full screen button on the title bar of the floating window:
Overriding the onSwitchingFull() of the onUpdateListener and run the full screen activity in that method. If the full screen button is pressed, the current floating window is exited automatically. Therefore, developers does not have to implement the exit code before switching.
 
2) When switching to the full screen activity by user-defined button
Run the full screen activity in the handler which processes the event from the user-defined button. Developers have to exit the current floating window explicitly in that handler.
 
The example below shows how to process both 1) and 2) depending on the transmitted argument of the jumpToFullMode() method.

//switch to full screen activity
public void jumpTofullMode(boolean finishFloating) {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setClass(getApplicationContext(),
                              fullActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    startActivity(intent);
    …
 
    if (finishFloating) {
        finishFloatingMode();
    }
…

//touch switching to full window button
@Override
public void onAttachedToFloatingWindow(FloatingWindow w) {
    super.onAttachedToFloatingWindow(w);
    if (w != null) {
        w.setOnUpdateListener(
                        new DefaultOnUpdateListener() {
            @Override
            public void onSwitchingfull(
                       FloatingWindow window) {
                // set false.
                // because QSlide activity is
                // automatically finished.
                jumpTofullMode(false);
            }
        }
    }
    …
}
…

    //touch user-defined button
    @Override
    public void onClick(View v) {
       int id = v.getId();
       switch (id) {
       case R.id.month_name:
           // set true. Floating window has to be finished.
           jumpTofullMode(true);
           break;
       …
   } 

 

Layout Gets Broken when User Resizes the Floating Window

 

Issue

When a floating window becomes smaller than a certain size, its layout gets broken.

Cause

If the minimum size of a window is not defined when switching to the floating window mode, the layout gets broken when the operator reduces the window below a certain size.

Solution

When calling the switchToFloatingMode() method, transmit the layout parameter that sets the minimum size value to switchToFloatingMode() as an argument so that the window does not shrink below a certain size. The minimum size must be specified as the size to prevent the layout from being broken.
 
To specify the minimum size, the minWidthWeight and minHeightWeight of the layout parameter must be set. Set each value at a ratio of width and height to the short axis of the screen. The code below is an example of setting the value.

private FloatingWindow.LayoutParams params;
…
/* update window height, width, resizing option */
params = new FloatingWindow.LayoutParams(this);
params.minWidthWeight = MIN_SIZE_RATIO;
params.minHeightWeight = MIN_SIZE_RATIO;
switchToFloatingMode(params);

 

Switch to Full Screen is Delayed after Pressing Home Key

Issue

Switching to the full screen after pressing the Home key in the floating window mode is delayed for 5 seconds.

Cause

The QSlide generates a 5 second delay to prevent the services or broadcast receiver from calling the startActivity() for 5 seconds after pressing the Home button.
To prevent this, the android.permission.STOP_APP_SWITCHES permission must be used. But this permission is valid only for the system administrator. This means that this problem still cannot be solved with 3rd party applications.

Solution

The 3rd party application cannot solve this problem.
 

Switching between Activities in the Floating Window Mode

Issue

When switching between activities, the floating window mode is not kept.

Cause

One floating window can have only one activity.

Solution

When switching between activities is necessary, switch between fragments in an activity by using fragment transaction.

private FragmentManager fm;
…
fm = getFragmentManager();
ft = fm.beginTransaction();
mListFragment = new ListFragment();
mEditFragment = new EditFragment();
mDetailFragment = new DetailFragment();
…
switch (whichFragment) {
case FRAGMENT_CLASS_LIST:
    ft.replace(R.id.fragment_main_layout, mListFragment);
    break;
case FRAGMENT_CLASS_DETAIL:
    ft.replace(R.id.fragment_main_layout, mDetailFragment);
    break;
case FRAGMENT_CLASS_EDIT:
    ft.replace(R.id.fragment_main_layout, mEditFragment);
    break;
default:
    break;
}

 

Fragment is not Displayed in Floating Window

Issue

If the activity for the floating window is implemented as a separate class, the screen is not displayed when using the fragment.

Solution

1) Do not call the setDontFinishOnFloatingMode(true).
2) Return false in the onDetachedFromFloatingWindow().
3) Call the mContainer.addView() in the onDestroy() of the fragment.
 
It is implemented in the FloatableActivity as follows.

@Override
public boolean onDetachedFromFloatingWindow
                     (FloatingWindow w,
                     boolean isReturningTofullScreen) {
    …
    return false;
}


It is implemented in the fragment as follows.

@Override
public void onDestroy() {
    super.onDestroy();
    Activity act = getActivity();
    if (act instanceof FloatableActivity) {
        if (((FloatableActivity)act).
                     isSwitchingToFloatingMode()) {
            mContainer.addView(mView);
        }
    }
    …
}
 
…
 
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    mView = inflater.inflate
                       (R.layout.floating_month_by_week,
                       container, false);
    …
}

 

Displaying Dialog in Floating Window (1/2)

Issue

The dialog is displayed behind the floating window.

Cause

Since the Z-axis of the QSlide floating window is specified in higher position than a general dialog, the general dialog is displayed behind the floating window.

Solution

Set the window type of the dialog to TYPE_PHONE so that the dialog is always displayed on top of the screen.

AlertDialog mDialog;
…
mDialog = builder.setTitle(
        R.string.sp_reset_password_NORMAL).create();
…
mDialog.getWindow().setType(
        WindowManager.LayoutParams.TYPE_PHONE);

 

Displaying Dialog in Floating Window (2/2)

Issue

The dialog is not displayed in the floating window mode.

Cause

If it is switched to the floating window mode after setDontFinishOnFloatingMode(true) is invoked, the activity is not destroyed and moved to the background. At this time, the dialog is not displayed since the dialog is attached to the activity that exists in the background.

Solution

Specify the context as the application context which is independent of the background activity when creating the dialog to prevent the dialog to be displayed from being attached to the background activity.
The below example shows that the AlertDialog is created by applying the above solution.

Context mContext = context.getApplicationContext();
new AlertDialog.Builder(mContext).
                 setTitle(“Alert”).setMessage(“Alert”)…

 

Flicking ListView in Floating Window

Issue

When attempting to flick a ListView in the floating window, the ListView is not flicked but the floating window moves.

Cause

When the user touch and move a view that does not have the touch listener, it causes moving the floating window instead of flicking the view.

Solution

Set touch listener in the ListView and override the onTouch() callback to return true. Then the floating window does not move when touching and moving the ListView.

// don’t move floating window with wrong touching event[start]
mView.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // consume touch event for preventing
        // floating movement.
        return true;
    }
}); 

 

Hiding IME in Floating Window

Issue

The IME is set not to be displayed in the activity. However, the IME is displayed when switching to the floating window mode.

Cause

The IME setting of the full screen mode is not transmitted automatically to the floating window mode.

Solution

When switching to the floating window mode, transmit the layout parameter that has the No Use IME setting to switchToFloatingMode() as an argument. To prevent the IME from being used in the floating window, set the dontUseIme of the layout parameter to true.

params.dontUseIme = true;
switchToFloatingMode(params);

 

Not Exiting Other Activity when Floating Window is Not Displayed

Issue

If an activity for floating window is implemented as a separate class, and the currently running activity runs this activity in floating window mode,
only the current activity is terminated and the floating window of this particular activity is not displayed.

Cause

Sometimes it is not switched to the floating window mode due to reasons such as the restrictions of the maximum count of the floating windows. In this case, determine if switching to the floating window mode succeeds to process.

Solution

It is implemented in the full screen activity as follows.

//call activity in floating window mode
private static void launchAsFloatingMode(
                  Context context,long startMillis){
    Intent floatingIntent = new Intent();
    floatingIntent.setClass(context,
                                 FloatableActivity.class);
    floatingIntent.putExtra
         ("com.lge.app.floating.launchAsFloating",
          true);
    ((Activity)context).startActivityForResult
                    (floatingIntent, FLOATING_REQUEST);
}
 
…
 
//if the activity is launched successfully, than finish this full screen activity.
@Override
protected void onActivityResult(int request, int result, Intent data) {
    // If the floating window mode was launched successfully,
    // then finish the full screen activity.
if (request == UtilsEx.FLOATING_REQUEST_CODE &&
    result == RESULT_OK) {
        if (Build.VERSION.SDK_INT >=
                 Build.VERSION_CODES.JELLY_BEAN) {
            finishAffinity();
        } else {
            finish();
        }
    }
    // if not, do NOT finish this activity, do nothing
}

 
It is implemented in the activity to be run in the floating window mode as follows.

@Override
protected void onCreate(Bundle icicle) {
    super.onCreate(icicle);
 
    // set result depending on
    // whether the floating window is created or not.
    setResult( canSwitch ? RESULT_CANCELED : RESULT_OK);
    …
}

 

Exiting Floating Window when Running Other Activity

Issue

If an activity for floating window is implemented as a separate class, the existing floating window keeps being displayed without disappearing if the application is run while the floating window is displayed.

Cause

The floating window is not exited although the main activity exits because the main activity of the application and floating window activity are separate classes.

Solution

Other activity of the floating window mode must be exited separately in the main activity of the application. (Use broadcast)
 
It is implemented in the full screen activity as follows.

@Override
protected void onCreate(Bundle icicle) {
    …
    context.sendBroadcast(new Intent(ACTION_FLOATING_CLOSE));
}

 
It is implemented in the activity to be run in the floating window mode as follows. If there are many activities to be run in the floating window mode, the code below must be added to each activity.

BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (TextUtils.equals(ACTION_FLOATING_CLOSE,
                           intent.getAction())) {
            finishFloatingMode();
        }
    }
}
 
…
 
@Override
protected void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    if (isStartedAsFloating()) {
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_FLOATING_CLOSE);
        this.registerReceiver(mReceiver, filter);
    }
}
 
…
 
@Override
protected void onDestroy() {
    super.onDestroy();
    this.unregisterReceiver(mReceiver);
};

 

Re-running Background Activity in Floating Window

Issue

Other activity is run by the startActivity() in the floating window but it is not run successfully.

Cause

This Issue occurs in Jelly Bean. The activity is not run successfully if it is switched to the background by calling setDontFinishOnFloatingMode(true).

Solution

Use getApplicationContext() as the context and add the FLAG_ACTIVITY_NEW_TASK flag to the intent.

getApplicationContext().startActivity(
    new Intent(getApplicationContext(),
                 BrowserActivity.class)
             .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
             .putExtra(EXTRA_STATE, outState));

 

Using ContentObserver in Floating Window Mode

Issue

The ContentObserver does not operate properly in the floating window mode.

Cause

The location to register/unregister the observer in the floating window mode is wrong.

Solution

Register the ContentObserver in onAttachedToFloatingWindow() and unregister the ContentObserver in onDetachedToFloatingWindow().

public void onAttachedToFloatingWindow(FloatingWindow w) {
    super.onAttachedToFloatingWindow(w);
    if (w != null) {
        getContentResolver().
            registerContentObserver(
               CONTENT_URI, true, mObserver);
    }
}
 
@Override
public boolean onDetachedFromFloatingWindow
    (FloatingWindow w, boolean isReturningTofullScreen) {
    mContentResolver.unregisterContentObserver(mObserver);
    return false;
}

 

Intent is Not Received in FloatableActivity

Issue

Some intents are not received in the FloatableActivity.

Cause

If the intent_B is registered after the intent_A is registered as below, the second intent is not registered.

mFilter.addAction(intent_A);
registerReceiver(mReceiver, mFilter);
 
…
 
mFilter.addAction(intent_B);
registerReceiver(mReceiver, mFilter);

 

Solution

Register the receiver after adding all intents to the addAction() or separating them.
example below shows registering the receiver after adding all intents.

mFilter.addAction(intent_A);
mFilter.addAction(intent_B);
registerReceiver(mReceiver, mFilter);

 

Empty Floating Window is Created when Launching Application on Notification bar

Issue

When launching the QSlide application on the notification bar, the floating window is displayed even if the activity exits immediately since the initial entry conditions are not satisfied.

Cause

The process for the case of exit right after start is not set.

Solution

The return value of onStartedAsFloatingMode() must be different according to whether the entry conditions are satisfied.

@Override
public boolean onStartedAsFloatingMode() {
    if (isSatisfiedToLaunchqslide) {
       // if isSatisfiedToLaunchqslide is true,
       // then return true.
       return true;
    } else {
       // if isSatisfiedToLaunchqslide is false,
       // then finish activity and return false.
       finish();
       return false;
   }
} 

 

Setting LCD aLways Turned on in the Floating Window Mode

 

Issue

The LCD may not be turned on all the time when activity is in the floating window mode.

Cause

The FLAG_KEEP_SCREEN_ON flag setting that turns on the LCD all the time in the full screen mode is not valid in the floating window mode.

Solution

Set the FLAG_KEEP_SCREEN_ON flag on the root view in the floating window mode as well.

protected void setFloatingBacklight(boolean keepScreenOn) {
    WindowManager wm = (WindowManager)
            getSystemService(Context.WINDOW_SERVICE);
    View root = mPreview.getRootView();
    params = (WindowManager.LayoutParams)
            root.getLayoutParams();
 
    if (keepScreenOn) {
        params.flags |= WindowManager.LayoutParams
                                     .FLAG_KEEP_SCREEN_ON;
    } else {
        params.flags &= ~WindowManager.LayoutParams
                                     .FLAG_KEEP_SCREEN_ON;
    }
    wm.updateViewLayout(root, params);
}

 

Keeping Written Content when Switching Display Mode

Issue

When switching the display mode, the content the user is writing are closed.

Cause

When switching from the floating window mode to the full screen mode, the empty intent is transmitted to the onNewIntent().

Solution

Check whether the intent received in the onNewIntent() callback is valid or not. In order to verify the validation, add an extra as below and then check it in onNewIntent().

protected void onNewIntent(Intent intent) {
    // Floating Composer
    if (intent.getBooleanExtra
           ("com.lge.app.floating.returnFromFloating",
            false)){
        // When floating composer is changing to normal mode,
        // dummy intent come.
        return;
    }

 

Keeping Written Content when Changing System Configuration in Floating Window

Issue

When changing the locale and font in the floating window mode, the content the user is writing are closed.

Cause

When changing the system configuration in the floating window mode, the floating window is re-generated after calling onConfigurationChanged(). The content the user is writing are closed when re-generating.

Solution

Call onSaveInstance() explicitly if necessary when system configuration is changed in the floating window mode. And restore the saved bundle after the floating window is completely re-generated.

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (LOCAL_LOGV) {
        Log.v(TAG, "onConfigurationChanged: " +
                     newConfig);
    }
    if (isInFloatingMode() &&
        SaveFloatingConfig.isWorthSaving(newConfig)){
        SaveFloatingConfig.mSaveFloatingBundle = new Bundle();
        onSaveInstanceState(
                 SaveFloatingConfig.mSaveFloatingBundle);
    }
}
 
public static boolean isWorthSaving(Configuration config) {
    if (config == null) {
        return false;
    }
 
    int fontTypeIndex = 0;
 
    try {
        fontTypeIndex = new ConfigurationProxy(config)
                                      .getFontTypeIndex();
    } catch (UnsupportedOperationException e1) {
        e1.printStackTrace();
    }

    if (config.fontScale != fontScale ||
              fontTypeIndex != fontType ||
              config.locale.getLanguage()
                      .equals(language) == false) {
        Log.d(TAG, "Change font scale or type");
        isChange = true;
        fontScale = config.fontScale;
        try {
            fontType = new ConfigurationProxy(config)
                             .getFontTypeIndex();
        } catch (UnsupportedOperationException e) {
            e.printStackTrace();
        }
        language = config.locale.getLanguage().toString();
        return true;
    }
    return false;
}
Navigation