mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-26 07:50:13 +02:00
Merge remote-tracking branch 'upstream/master' into animationBlendChanges
This commit is contained in:
commit
b9701d2b7a
13 changed files with 118 additions and 13 deletions
|
@ -22,7 +22,8 @@
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:roundIcon="@drawable/ic_launcher">
|
android:roundIcon="@drawable/ic_launcher">
|
||||||
<activity android:name="io.highfidelity.hifiinterface.PermissionChecker">
|
<activity android:name="io.highfidelity.hifiinterface.PermissionChecker"
|
||||||
|
android:theme="@style/Theme.AppCompat.Translucent.NoActionBar.Launcher">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
@ -135,4 +136,13 @@ public class PermissionChecker extends Activity {
|
||||||
launchActivityWithPermissions();
|
launchActivityWithPermissions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
View decorView = getWindow().getDecorView();
|
||||||
|
// Hide the status bar.
|
||||||
|
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
|
||||||
|
decorView.setSystemUiVisibility(uiOptions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ public class HomeFragment extends Fragment {
|
||||||
GridLayoutManager gridLayoutMgr = new GridLayoutManager(getContext(), numberOfColumns);
|
GridLayoutManager gridLayoutMgr = new GridLayoutManager(getContext(), numberOfColumns);
|
||||||
mDomainsView.setLayoutManager(gridLayoutMgr);
|
mDomainsView.setLayoutManager(gridLayoutMgr);
|
||||||
mDomainAdapter = new DomainAdapter(getContext(), HifiUtils.getInstance().protocolVersionSignature(), nativeGetLastLocation());
|
mDomainAdapter = new DomainAdapter(getContext(), HifiUtils.getInstance().protocolVersionSignature(), nativeGetLastLocation());
|
||||||
|
mSwipeRefreshLayout.setRefreshing(true);
|
||||||
mDomainAdapter.setClickListener((view, position, domain) -> {
|
mDomainAdapter.setClickListener((view, position, domain) -> {
|
||||||
new Handler(getActivity().getMainLooper()).postDelayed(() -> {
|
new Handler(getActivity().getMainLooper()).postDelayed(() -> {
|
||||||
if (mListener != null) {
|
if (mListener != null) {
|
||||||
|
|
|
@ -60,6 +60,8 @@ import android.view.View;
|
||||||
import android.view.WindowManager.LayoutParams;
|
import android.view.WindowManager.LayoutParams;
|
||||||
import android.view.accessibility.AccessibilityEvent;
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
|
|
||||||
|
import org.qtproject.qt5.android.QtNative;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class QtActivity extends Activity {
|
public class QtActivity extends Activity {
|
||||||
public String APPLICATION_PARAMETERS = null;
|
public String APPLICATION_PARAMETERS = null;
|
||||||
|
@ -103,7 +105,7 @@ public class QtActivity extends Activity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean super_dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
|
public boolean super_dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||||
return super_dispatchPopulateAccessibilityEvent(event);
|
return super.dispatchPopulateAccessibilityEvent(event);
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -362,7 +364,25 @@ public class QtActivity extends Activity {
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
QtApplication.invokeDelegate();
|
/*
|
||||||
|
cduarte https://highfidelity.manuscript.com/f/cases/16712/App-freezes-on-opening-randomly
|
||||||
|
After Qt upgrade to 5.11 we had a black screen crash after closing the application with
|
||||||
|
the hardware button "Back" and trying to start the app again. It could only be fixed after
|
||||||
|
totally closing the app swiping it in the list of running apps.
|
||||||
|
This problem did not happen with the previous Qt version.
|
||||||
|
After analysing changes we came up with this case and change:
|
||||||
|
https://codereview.qt-project.org/#/c/218882/
|
||||||
|
In summary they've moved libs loading to the same thread as main() and as a matter of correctness
|
||||||
|
in the onDestroy method in QtActivityDelegate, they exit that thread with `QtNative.m_qtThread.exit();`
|
||||||
|
That exit call is the main reason of this problem.
|
||||||
|
|
||||||
|
In this fix we just replace the `QtApplication.invokeDelegate();` call that may end using the
|
||||||
|
entire onDestroy method including that thread exit line for other three lines that purposely
|
||||||
|
terminate qt (borrowed from QtActivityDelegate::onDestroy as well).
|
||||||
|
*/
|
||||||
|
QtNative.terminateQt();
|
||||||
|
QtNative.setActivity(null, null);
|
||||||
|
System.exit(0);
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
11
android/app/src/main/res/drawable/launch_screen.xml
Normal file
11
android/app/src/main/res/drawable/launch_screen.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
|
||||||
|
<item android:drawable="@android:color/black"/>
|
||||||
|
<item android:drawable="@drawable/hifi_logo_splash"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:top="225dp"
|
||||||
|
android:height="242dp"
|
||||||
|
android:width="242dp">
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
|
@ -7,9 +7,17 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@android:color/black">
|
android:background="@android:color/black">
|
||||||
<ImageView
|
<ImageView
|
||||||
|
android:id="@+id/hifi_logo"
|
||||||
android:layout_width="242dp"
|
android:layout_width="242dp"
|
||||||
android:layout_height="242dp"
|
android:layout_height="242dp"
|
||||||
android:src="@drawable/hifi_logo_splash"
|
android:src="@drawable/hifi_logo_splash"
|
||||||
android:layout_centerHorizontal="true"
|
android:layout_centerHorizontal="true"
|
||||||
android:layout_marginTop="225dp"/>
|
android:layout_marginTop="225dp"/>
|
||||||
|
<ProgressBar
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar"
|
||||||
|
android:theme="@style/HifiCircularProgress"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/hifi_logo"
|
||||||
|
android:layout_centerHorizontal="true"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
@ -17,4 +17,5 @@
|
||||||
<color name="colorLoginError">#FF7171</color>
|
<color name="colorLoginError">#FF7171</color>
|
||||||
<color name="black_060">#99000000</color>
|
<color name="black_060">#99000000</color>
|
||||||
<color name="statusbar_color">#292929</color>
|
<color name="statusbar_color">#292929</color>
|
||||||
|
<color name="hifiLogoColor">#23B2E7</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
<item name="windowActionBar">false</item>
|
<item name="windowActionBar">false</item>
|
||||||
<item name="windowNoTitle">true</item>
|
<item name="windowNoTitle">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
<style name="Theme.AppCompat.Translucent.NoActionBar.Launcher" parent="Theme.AppCompat.Translucent.NoActionBar">
|
||||||
|
<item name="android:windowBackground">@drawable/launch_screen</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||||
|
|
||||||
|
@ -62,4 +65,7 @@
|
||||||
<item name="android:background">@color/white_opaque</item>
|
<item name="android:background">@color/white_opaque</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="HifiCircularProgress" parent="Theme.AppCompat.Light">
|
||||||
|
<item name="colorAccent">@color/hifiLogoColor</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -262,6 +262,9 @@ int main(int argc, const char* argv[]) {
|
||||||
// Extend argv to enable WebGL rendering
|
// Extend argv to enable WebGL rendering
|
||||||
std::vector<const char*> argvExtended(&argv[0], &argv[argc]);
|
std::vector<const char*> argvExtended(&argv[0], &argv[argc]);
|
||||||
argvExtended.push_back("--ignore-gpu-blacklist");
|
argvExtended.push_back("--ignore-gpu-blacklist");
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
argvExtended.push_back("--suppress-settings-reset");
|
||||||
|
#endif
|
||||||
int argcExtended = (int)argvExtended.size();
|
int argcExtended = (int)argvExtended.size();
|
||||||
|
|
||||||
PROFILE_SYNC_END(startup, "main startup", "");
|
PROFILE_SYNC_END(startup, "main startup", "");
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, makeRunningValues,
|
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, makeRunningValues,
|
||||||
Messages, makeDispatcherModuleParameters, HMD, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
Messages, makeDispatcherModuleParameters, HMD, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||||
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE,
|
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE,
|
||||||
getEnabledModuleByName, PICK_MAX_DISTANCE, isInEditMode, Picks, makeLaserParams
|
getEnabledModuleByName, PICK_MAX_DISTANCE, isInEditMode, Picks, makeLaserParams, Entities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
|
@ -19,7 +19,7 @@ Script.include("/~/system/libraries/utils.js");
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
var MARGIN = 25;
|
var MARGIN = 25;
|
||||||
|
var TABLET_MATERIAL_ENTITY_NAME = 'Tablet-Material-Entity';
|
||||||
function InEditMode(hand) {
|
function InEditMode(hand) {
|
||||||
this.hand = hand;
|
this.hand = hand;
|
||||||
this.triggerClicked = false;
|
this.triggerClicked = false;
|
||||||
|
@ -53,7 +53,7 @@ Script.include("/~/system/libraries/utils.js");
|
||||||
return (HMD.tabletScreenID && objectID === HMD.tabletScreenID)
|
return (HMD.tabletScreenID && objectID === HMD.tabletScreenID)
|
||||||
|| (HMD.homeButtonID && objectID === HMD.homeButtonID);
|
|| (HMD.homeButtonID && objectID === HMD.homeButtonID);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.calculateNewReticlePosition = function(intersection) {
|
this.calculateNewReticlePosition = function(intersection) {
|
||||||
var dims = Controller.getViewportDimensions();
|
var dims = Controller.getViewportDimensions();
|
||||||
this.reticleMaxX = dims.x - MARGIN;
|
this.reticleMaxX = dims.x - MARGIN;
|
||||||
|
@ -75,10 +75,12 @@ Script.include("/~/system/libraries/utils.js");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) {
|
if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) {
|
||||||
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({
|
if (!this.isTabletMaterialEntity(this.selectedTarget.objectID)) {
|
||||||
method: "selectEntity",
|
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({
|
||||||
entityID: this.selectedTarget.objectID
|
method: "selectEntity",
|
||||||
}));
|
entityID: this.selectedTarget.objectID
|
||||||
|
}));
|
||||||
|
}
|
||||||
} else if (this.selectedTarget.type === Picks.INTERSECTED_OVERLAY) {
|
} else if (this.selectedTarget.type === Picks.INTERSECTED_OVERLAY) {
|
||||||
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({
|
Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({
|
||||||
method: "selectOverlay",
|
method: "selectOverlay",
|
||||||
|
@ -88,10 +90,16 @@ Script.include("/~/system/libraries/utils.js");
|
||||||
|
|
||||||
this.triggerClicked = true;
|
this.triggerClicked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sendPointingAtData(controllerData);
|
this.sendPointingAtData(controllerData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.isTabletMaterialEntity = function(entityID) {
|
||||||
|
return ((entityID === HMD.homeButtonHighlightMaterialID) ||
|
||||||
|
(entityID === HMD.homeButtonUnhighlightMaterialID));
|
||||||
|
};
|
||||||
|
|
||||||
this.sendPointingAtData = function(controllerData) {
|
this.sendPointingAtData = function(controllerData) {
|
||||||
var rayPick = controllerData.rayPicks[this.hand];
|
var rayPick = controllerData.rayPicks[this.hand];
|
||||||
var hudRayPick = controllerData.hudRayPicks[this.hand];
|
var hudRayPick = controllerData.hudRayPicks[this.hand];
|
||||||
|
|
|
@ -30,6 +30,8 @@ var INCHES_TO_METERS = 1 / 39.3701;
|
||||||
var NO_HANDS = -1;
|
var NO_HANDS = -1;
|
||||||
var DELAY_FOR_30HZ = 33; // milliseconds
|
var DELAY_FOR_30HZ = 33; // milliseconds
|
||||||
|
|
||||||
|
var TABLET_MATERIAL_ENTITY_NAME = 'Tablet-Material-Entity';
|
||||||
|
|
||||||
|
|
||||||
// will need to be recaclulated if dimensions of fbx model change.
|
// will need to be recaclulated if dimensions of fbx model change.
|
||||||
var TABLET_NATURAL_DIMENSIONS = {x: 32.083, y: 48.553, z: 2.269};
|
var TABLET_NATURAL_DIMENSIONS = {x: 32.083, y: 48.553, z: 2.269};
|
||||||
|
@ -79,6 +81,19 @@ function calcSpawnInfo(hand, landscape) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cleanUpOldMaterialEntities = function() {
|
||||||
|
var avatarEntityData = MyAvatar.getAvatarEntityData();
|
||||||
|
for (var entityID in avatarEntityData) {
|
||||||
|
var entityName = Entities.getEntityProperties(entityID, ["name"]).name;
|
||||||
|
|
||||||
|
if (entityName === TABLET_MATERIAL_ENTITY_NAME && entityID !== HMD.homeButtonHighlightMaterialID &&
|
||||||
|
entityID !== HMD.homeButtonUnhighlightMaterialID) {
|
||||||
|
Entities.deleteEntity(entityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebTablet
|
* WebTablet
|
||||||
* @param url [string] url of content to show on the tablet.
|
* @param url [string] url of content to show on the tablet.
|
||||||
|
@ -134,6 +149,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cleanUpOldTablets();
|
this.cleanUpOldTablets();
|
||||||
|
cleanUpOldMaterialEntities();
|
||||||
|
|
||||||
this.tabletEntityID = Overlays.addOverlay("model", tabletProperties);
|
this.tabletEntityID = Overlays.addOverlay("model", tabletProperties);
|
||||||
|
|
||||||
|
@ -180,6 +196,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
|
|
||||||
this.homeButtonUnhighlightMaterial = Entities.addEntity({
|
this.homeButtonUnhighlightMaterial = Entities.addEntity({
|
||||||
type: "Material",
|
type: "Material",
|
||||||
|
name: TABLET_MATERIAL_ENTITY_NAME,
|
||||||
materialURL: "materialData",
|
materialURL: "materialData",
|
||||||
localPosition: { x: 0.0, y: 0.0, z: 0.0 },
|
localPosition: { x: 0.0, y: 0.0, z: 0.0 },
|
||||||
priority: HIGH_PRIORITY,
|
priority: HIGH_PRIORITY,
|
||||||
|
@ -199,6 +216,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
|
|
||||||
this.homeButtonHighlightMaterial = Entities.addEntity({
|
this.homeButtonHighlightMaterial = Entities.addEntity({
|
||||||
type: "Material",
|
type: "Material",
|
||||||
|
name: TABLET_MATERIAL_ENTITY_NAME,
|
||||||
materialURL: "materialData",
|
materialURL: "materialData",
|
||||||
localPosition: { x: 0.0, y: 0.0, z: 0.0 },
|
localPosition: { x: 0.0, y: 0.0, z: 0.0 },
|
||||||
priority: LOW_PRIORITY,
|
priority: LOW_PRIORITY,
|
||||||
|
|
|
@ -111,6 +111,11 @@ EntityListTool = function(shouldUseEditTabletApp) {
|
||||||
return value !== undefined ? value : "";
|
return value !== undefined ? value : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function filterEntity(entityID) {
|
||||||
|
return ((entityID === HMD.homeButtonHighlightMaterialID) ||
|
||||||
|
(entityID === HMD.homeButtonUnhighlightMaterialID));
|
||||||
|
}
|
||||||
|
|
||||||
that.sendUpdate = function() {
|
that.sendUpdate = function() {
|
||||||
var entities = [];
|
var entities = [];
|
||||||
|
|
||||||
|
@ -121,6 +126,10 @@ EntityListTool = function(shouldUseEditTabletApp) {
|
||||||
ids = Entities.findEntities(MyAvatar.position, searchRadius);
|
ids = Entities.findEntities(MyAvatar.position, searchRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ids = ids.filter(function(id) {
|
||||||
|
return !filterEntity(id);
|
||||||
|
});
|
||||||
|
|
||||||
var cameraPosition = Camera.position;
|
var cameraPosition = Camera.position;
|
||||||
for (var i = 0; i < ids.length; i++) {
|
for (var i = 0; i < ids.length; i++) {
|
||||||
var id = ids[i];
|
var id = ids[i];
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
/* global Script, HMD, WebTablet, UIWebTablet, UserActivityLogger, Settings, Entities, Messages, Tablet, Overlays,
|
/* global Script, HMD, WebTablet, UIWebTablet, UserActivityLogger, Settings, Entities, Messages, Tablet, Overlays,
|
||||||
MyAvatar, Menu, AvatarInputs, Vec3 */
|
MyAvatar, Menu, AvatarInputs, Vec3, cleanUpOldMaterialEntities */
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
var tabletRezzed = false;
|
var tabletRezzed = false;
|
||||||
|
@ -31,6 +31,14 @@
|
||||||
|
|
||||||
Script.include("../libraries/WebTablet.js");
|
Script.include("../libraries/WebTablet.js");
|
||||||
|
|
||||||
|
function cleanupMaterialEntities() {
|
||||||
|
if (Window.isPhysicsEnabled()) {
|
||||||
|
cleanUpOldMaterialEntities();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Script.setTimeout(cleanupMaterialEntities, 100);
|
||||||
|
}
|
||||||
|
|
||||||
function checkTablet() {
|
function checkTablet() {
|
||||||
if (gTablet === null) {
|
if (gTablet === null) {
|
||||||
gTablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
gTablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
@ -327,4 +335,5 @@
|
||||||
HMD.homeButtonHighlightMaterialID = null;
|
HMD.homeButtonHighlightMaterialID = null;
|
||||||
HMD.homeButtonUnhighlightMaterialID = null;
|
HMD.homeButtonUnhighlightMaterialID = null;
|
||||||
});
|
});
|
||||||
|
Script.setTimeout(cleanupMaterialEntities, 100);
|
||||||
}()); // END LOCAL_SCOPE
|
}()); // END LOCAL_SCOPE
|
||||||
|
|
Loading…
Reference in a new issue